teak-llvm/clang-tools-extra/clangd/unittests/SymbolInfoTests.cpp
Sam McCall d3260bf5b2 [clangd] Errors in TestTU cause test failures unless suppressed with error-ok.
Summary:
The historic behavior of TestTU is to gather diagnostics and otherwise ignore
them. So if a test has a syntax error, and doesn't assert diagnostics, it
silently misbehaves.
This can be annoying when developing tests, as evidenced by various tests
gaining "assert no diagnostics" where that's not really the point of the test.

This patch aims to make that default behavior. For the first error
(not warning), TestTU will call ADD_FAILURE().

This can be suppressed with a comment containing "error-ok". For now that will
suppress any errors in the TU. We can make this stricter later -verify style.
(-verify itself is hard to reuse because of DiagnosticConsumer interfaces...)
A magic-comment was chosen over a TestTU option because of table-driven tests.

In addition to the behavior change, this patch:
  - adds //error-ok where we're knowingly testing invalid code
    (e.g. for diagnostics, crash-resilience, or token-level tests)
  - fixes a bunch of errors in the checked-in tests, mostly trivial (missing ;)
  - removes a bunch of now-redundant instances of "assert no diagnostics"

Reviewers: kadircet

Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D73199
2020-01-24 11:16:27 +01:00

343 lines
10 KiB
C++

//===-- SymbolInfoTests.cpp -----------------------*- C++ -*--------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Annotations.h"
#include "Compiler.h"
#include "Matchers.h"
#include "ParsedAST.h"
#include "SyncAPI.h"
#include "TestFS.h"
#include "TestTU.h"
#include "XRefs.h"
#include "index/FileIndex.h"
#include "index/SymbolCollector.h"
#include "clang/Index/IndexingAction.h"
#include "llvm/Support/Path.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace clang {
namespace clangd {
namespace {
using ::testing::UnorderedElementsAreArray;
auto CreateExpectedSymbolDetails = [](const std::string &name,
const std::string &container,
const std::string &USR) {
return SymbolDetails{name, container, USR, SymbolID(USR)};
};
TEST(SymbolInfoTests, All) {
std::pair<const char *, std::vector<SymbolDetails>>
TestInputExpectedOutput[] = {
{
R"cpp( // Simple function reference - declaration
void foo();
int bar() {
fo^o();
}
)cpp",
{CreateExpectedSymbolDetails("foo", "", "c:@F@foo#")}},
{
R"cpp( // Simple function reference - definition
void foo() {}
int bar() {
fo^o();
}
)cpp",
{CreateExpectedSymbolDetails("foo", "", "c:@F@foo#")}},
{
R"cpp( // Function in namespace reference
namespace bar {
void foo();
int baz() {
fo^o();
}
}
)cpp",
{CreateExpectedSymbolDetails("foo", "bar::", "c:@N@bar@F@foo#")}},
{
R"cpp( // Function in different namespace reference
namespace bar {
void foo();
}
namespace barbar {
int baz() {
bar::fo^o();
}
}
)cpp",
{CreateExpectedSymbolDetails("foo", "bar::", "c:@N@bar@F@foo#")}},
{
R"cpp( // Function in global namespace reference
void foo();
namespace Nbar {
namespace Nbaz {
int baz() {
::fo^o();
}
}
}
)cpp",
{CreateExpectedSymbolDetails("foo", "", "c:@F@foo#")}},
{
R"cpp( // Function in anonymous namespace reference
namespace {
void foo();
}
namespace barbar {
int baz() {
fo^o();
}
}
)cpp",
{CreateExpectedSymbolDetails("foo", "(anonymous)",
"c:TestTU.cpp@aN@F@foo#")}},
{
R"cpp( // Function reference - ADL
namespace bar {
struct BarType {};
void foo(const BarType&);
}
namespace barbar {
int baz() {
bar::BarType b;
fo^o(b);
}
}
)cpp",
{CreateExpectedSymbolDetails(
"foo", "bar::", "c:@N@bar@F@foo#&1$@N@bar@S@BarType#")}},
{
R"cpp( // Global value reference
int value;
void foo(int) { }
void bar() {
foo(val^ue);
}
)cpp",
{CreateExpectedSymbolDetails("value", "", "c:@value")}},
{
R"cpp( // Local value reference
void foo() { int aaa; int bbb = aa^a; }
)cpp",
{CreateExpectedSymbolDetails("aaa", "foo",
"c:TestTU.cpp@49@F@foo#@aaa")}},
{
R"cpp( // Function param
void bar(int aaa) {
int bbb = a^aa;
}
)cpp",
{CreateExpectedSymbolDetails("aaa", "bar",
"c:TestTU.cpp@38@F@bar#I#@aaa")}},
{
R"cpp( // Lambda capture
void foo() {
int ii;
auto lam = [ii]() {
return i^i;
};
}
)cpp",
{CreateExpectedSymbolDetails("ii", "foo",
"c:TestTU.cpp@54@F@foo#@ii")}},
{
R"cpp( // Macro reference
#define MACRO 5\nint i = MAC^RO;
)cpp",
{CreateExpectedSymbolDetails("MACRO", "",
"c:TestTU.cpp@38@macro@MACRO")}},
{
R"cpp( // Macro reference
#define MACRO 5\nint i = MACRO^;
)cpp",
{CreateExpectedSymbolDetails("MACRO", "",
"c:TestTU.cpp@38@macro@MACRO")}},
{
R"cpp( // Multiple symbols returned - using overloaded function name
void foo() {}
void foo(bool) {}
void foo(int) {}
namespace bar {
using ::fo^o;
}
)cpp",
{CreateExpectedSymbolDetails("foo", "", "c:@F@foo#"),
CreateExpectedSymbolDetails("foo", "", "c:@F@foo#b#"),
CreateExpectedSymbolDetails("foo", "", "c:@F@foo#I#"),
CreateExpectedSymbolDetails("foo", "bar::", "c:@N@bar@UD@foo")}},
{
R"cpp( // Multiple symbols returned - implicit conversion
struct foo {};
struct bar {
bar(const foo&) {}
};
void func_baz1(bar) {}
void func_baz2() {
foo ff;
func_baz1(f^f);
}
)cpp",
{CreateExpectedSymbolDetails(
"ff", "func_baz2", "c:TestTU.cpp@218@F@func_baz2#@ff")}},
{
R"cpp( // Type reference - declaration
struct foo;
void bar(fo^o*);
)cpp",
{CreateExpectedSymbolDetails("foo", "", "c:@S@foo")}},
{
R"cpp( // Type reference - definition
struct foo {};
void bar(fo^o*);
)cpp",
{CreateExpectedSymbolDetails("foo", "", "c:@S@foo")}},
{
R"cpp( // Type Reference - template argumen
struct foo {};
template<class T> struct bar {};
void baz() {
bar<fo^o> b;
}
)cpp",
{CreateExpectedSymbolDetails("foo", "", "c:@S@foo")}},
{
R"cpp( // Template parameter reference - type param
template<class TT> struct bar {
T^T t;
};
)cpp",
{CreateExpectedSymbolDetails("TT", "bar::", "c:TestTU.cpp@65")}},
{
R"cpp( // Template parameter reference - type param
template<int NN> struct bar {
int a = N^N;
};
)cpp",
{CreateExpectedSymbolDetails("NN", "bar::", "c:TestTU.cpp@65")}},
{
R"cpp( // Class member reference - objec
struct foo {
int aa;
};
void bar() {
foo f;
f.a^a;
}
)cpp",
{CreateExpectedSymbolDetails("aa", "foo::", "c:@S@foo@FI@aa")}},
{
R"cpp( // Class member reference - pointer
struct foo {
int aa;
};
void bar() {
&foo::a^a;
}
)cpp",
{CreateExpectedSymbolDetails("aa", "foo::", "c:@S@foo@FI@aa")}},
{
R"cpp( // Class method reference - objec
struct foo {
void aa() {}
};
void bar() {
foo f;
f.a^a();
}
)cpp",
{CreateExpectedSymbolDetails("aa", "foo::", "c:@S@foo@F@aa#")}},
{
R"cpp( // Class method reference - pointer
struct foo {
void aa() {}
};
void bar() {
&foo::a^a;
}
)cpp",
{CreateExpectedSymbolDetails("aa", "foo::", "c:@S@foo@F@aa#")}},
{
R"cpp( // Typedef
typedef int foo;
void bar() {
fo^o a;
}
)cpp",
{CreateExpectedSymbolDetails("foo", "", "c:TestTU.cpp@T@foo")}},
{
R"cpp( // Type alias
using foo = int;
void bar() {
fo^o a;
}
)cpp",
{CreateExpectedSymbolDetails("foo", "", "c:@foo")}},
{
R"cpp( // Namespace reference
namespace foo {}
using namespace fo^o;
)cpp",
{CreateExpectedSymbolDetails("foo", "", "c:@N@foo")}},
{
R"cpp( // Enum value reference
enum foo { bar, baz };
void f() {
foo fff = ba^r;
}
)cpp",
{CreateExpectedSymbolDetails("bar", "foo", "c:@E@foo@bar")}},
{
R"cpp( // Enum class value reference
enum class foo { bar, baz };
void f() {
foo fff = foo::ba^r;
}
)cpp",
{CreateExpectedSymbolDetails("bar", "foo::", "c:@E@foo@bar")}},
{
R"cpp( // Parameters in declarations
void foo(int ba^r);
)cpp",
{CreateExpectedSymbolDetails("bar", "foo",
"c:TestTU.cpp@50@F@foo#I#@bar")}},
{
R"cpp( // Type inference with auto keyword
struct foo {};
foo getfoo() { return foo{}; }
void f() {
au^to a = getfoo();
}
)cpp",
{/* not implemented */}},
{
R"cpp( // decltype
struct foo {};
void f() {
foo f;
declt^ype(f);
}
)cpp",
{/* not implemented */}},
};
for (const auto &T : TestInputExpectedOutput) {
Annotations TestInput(T.first);
auto AST = TestTU::withCode(TestInput.code()).build();
EXPECT_THAT(getSymbolInfo(AST, TestInput.point()),
UnorderedElementsAreArray(T.second))
<< T.first;
}
}
} // namespace
} // namespace clangd
} // namespace clang