for (Test T : Tests) {
Annotations File(T.AnnotatedCode);
auto AST = TestTU::withCode(File.code()).build();
- ASSERT_TRUE(AST.getDiagnostics().empty())
- << AST.getDiagnostics().begin()->Message;
SourceManagerForFile SM("foo.cpp", File.code());
for (Position Pos : File.points()) {
#define $2[[PREPEND]](X) MACRO##X()
#define $3[[MACROA]]() 123
int B = $1[[CONCAT]](MACRO);
- int D = $2[[PREPEND]](A)
+ int D = $2[[PREPEND]](A);
)cpp",
R"cpp(
// FIXME: Macro names in a definition are not detected.
TEST(DiagnosticsTest, DiagnosticRanges) {
// Check we report correct ranges, including various edge-cases.
Annotations Test(R"cpp(
+ // error-ok
namespace test{};
void $decl[[foo]]();
class T{$explicit[[]]$constructor[[T]](int a);};
}
TEST(DiagnosticsTest, FlagsMatter) {
- Annotations Test("[[void]] main() {}");
+ Annotations Test("[[void]] main() {} // error-ok");
auto TU = TestTU::withCode(Test.code());
EXPECT_THAT(TU.build().getDiagnostics(),
ElementsAre(AllOf(Diag(Test.range(), "'main' must return 'int'"),
TEST(DiagnosticsTest, DiagnosticPreamble) {
Annotations Test(R"cpp(
- #include $[["not-found.h"]]
+ #include $[["not-found.h"]] // error-ok
)cpp");
auto TU = TestTU::withCode(Test.code());
Annotations Main(R"cpp(
int main() {
int i = 3;
- double f = [[8]] / i;
+ double f = [[8]] / i; // error-ok
}
)cpp");
TestTU TU = TestTU::withCode(Main.code());
// We limit the size of printed code.
Annotations Source(R"cpp(
int main() {
+ // error-ok
int somereallyreallyreallyreallyreallyreallyreallyreallylongidentifier;
[[omereallyreallyreallyreallyreallyreallyreallyreallylongidentifier]]= 10;
}
"'somereallyreallyreallyreallyreallyreallyreallyreal…'"))));
// Only show changes up to a first newline.
Source = Annotations(R"cpp(
+ // error-ok
int main() {
int ident;
[[ide\
-n]] = 10;
+n]] = 10; // error-ok
}
)cpp");
- TU = TestTU::withCode(Source.code());
+ TU.Code = Source.code();
EXPECT_THAT(TU.build().getDiagnostics(),
ElementsAre(WithFix(
Fix(Source.range(), "ident", "change 'ide\\…' to 'ident'"))));
Annotations Main(R"cpp(
int main() {
int i = 3;
- double f = [[8]] / i; // NOLINT
+ double f = [[8]] / i; // NOLINT // error-ok
}
)cpp");
TestTU TU = TestTU::withCode(Main.code());
Annotations Test(R"cpp(
#ifndef FOO
#define FOO
- int a = [[b]];
+ int a = [[b]]; // error-ok
#else
int x = y;
#endif
#define RET(x) return x + 10
int* foo() {
- RET($foo[[0]]);
+ RET($foo[[0]]); // error-ok
}
int* bar() {
return $bar[[TEN]];
Annotations Test(R"cpp(
#define Define(name) void name() {}
- [[Define]](main)
+ [[Define]](main) // error-ok
)cpp");
auto TU = TestTU::withCode(Test.code());
EXPECT_THAT(TU.build().getDiagnostics(),
}
TEST(IncludeFixerTest, IncompleteType) {
- Annotations Test(R"cpp(
+ Annotations Test(R"cpp(// error-ok
$insert[[]]namespace ns {
class X;
$nested[[X::]]Nested n;
}
TEST(IncludeFixerTest, NoSuggestIncludeWhenNoDefinitionInHeader) {
- Annotations Test(R"cpp(
+ Annotations Test(R"cpp(// error-ok
$insert[[]]namespace ns {
class X;
}
}
TEST(IncludeFixerTest, Typo) {
- Annotations Test(R"cpp(
+ Annotations Test(R"cpp(// error-ok
$insert[[]]namespace ns {
void foo() {
$unqualified1[[X]] x;
}
TEST(IncludeFixerTest, MultipleMatchedSymbols) {
- Annotations Test(R"cpp(
+ Annotations Test(R"cpp(// error-ok
$insert[[]]namespace na {
namespace nb {
void foo() {
}
TEST(IncludeFixerTest, NoCrashMemebrAccess) {
- Annotations Test(R"cpp(
+ Annotations Test(R"cpp(// error-ok
struct X { int xyz; };
void g() { X x; x.$[[xy]] }
)cpp");
TEST(IncludeFixerTest, UseCachedIndexResults) {
// As index results for the identical request are cached, more than 5 fixes
// are generated.
- Annotations Test(R"cpp(
+ Annotations Test(R"cpp(// error-ok
$insert[[]]void foo() {
$x1[[X]] x;
$x2[[X]] x;
}
TEST(IncludeFixerTest, UnresolvedNameAsSpecifier) {
- Annotations Test(R"cpp(
+ Annotations Test(R"cpp(// error-ok
$insert[[]]namespace ns {
}
void g() { ns::$[[scope]]::X_Y(); }
}
TEST(IncludeFixerTest, UnresolvedSpecifierWithSemaCorrection) {
- Annotations Test(R"cpp(
+ Annotations Test(R"cpp(// error-ok
$insert[[]]namespace clang {
void f() {
// "clangd::" will be corrected to "clang::" by Sema.
}
TEST(IncludeFixerTest, SpecifiedScopeIsNamespaceAlias) {
- Annotations Test(R"cpp(
+ Annotations Test(R"cpp(// error-ok
$insert[[]]namespace a {}
namespace b = a;
namespace c {
struct A {
Templ<char> s;
- A() { [[a]]; } // this caused crashes if we compute scopes lazily.
+ A() { [[a]]; /*error-ok*/ } // crash if we compute scopes lazily.
};
)cpp");
Annotations Main(R"cpp(
#include [["a.h"]]
void foo() {})cpp");
- Annotations Header("[[no_type_spec]];");
+ Annotations Header("[[no_type_spec]]; // error-ok");
TestTU TU = TestTU::withCode(Main.code());
TU.AdditionalFiles = {{"a.h", Header.code()}};
EXPECT_THAT(TU.build().getDiagnostics(),
#include [["a.h"]]
void foo() {})cpp");
TestTU TU = TestTU::withCode(Main.code());
- TU.AdditionalFiles = {{"a.h", "#include \"b.h\""}, {"b.h", "no_type_spec;"}};
+ TU.AdditionalFiles = {{"a.h", "#include \"b.h\""},
+ {"b.h", "no_type_spec; // error-ok"}};
EXPECT_THAT(TU.build().getDiagnostics(),
UnorderedElementsAre(
Diag(Main.range(), "in included file: C++ requires a "
#include $b[["b.h"]]
void foo() {})cpp");
TestTU TU = TestTU::withCode(Main.code());
- TU.AdditionalFiles = {{"a.h", "no_type_spec;"}, {"b.h", "no_type_spec;"}};
+ TU.AdditionalFiles = {{"a.h", "no_type_spec; // error-ok"},
+ {"b.h", "no_type_spec; // error-ok"}};
EXPECT_THAT(TU.build().getDiagnostics(),
UnorderedElementsAre(
Diag(Main.range("a"), "in included file: C++ requires a type "
#include "b.h"
void foo() {})cpp");
TestTU TU = TestTU::withCode(Main.code());
- TU.AdditionalFiles = {{"a.h", "#include \"b.h\"\n"},
- {"b.h", "#ifndef X\n#define X\nno_type_spec;\n#endif"}};
+ TU.AdditionalFiles = {
+ {"a.h", "#include \"b.h\"\n"},
+ {"b.h", "#ifndef X\n#define X\nno_type_spec; // error-ok\n#endif"}};
EXPECT_THAT(TU.build().getDiagnostics(),
UnorderedElementsAre(Diag(Main.range(),
"in included file: C++ requires a type "
#include [["b.h"]]
void foo() {})cpp");
TestTU TU = TestTU::withCode(Main.code());
- TU.AdditionalFiles = {{"a.h", "#include \"c.h\"\n"},
- {"b.h", "#include \"c.h\"\n"},
- {"c.h", "#ifndef X\n#define X\nno_type_spec;\n#endif"}};
+ TU.AdditionalFiles = {
+ {"a.h", "#include \"c.h\"\n"},
+ {"b.h", "#include \"c.h\"\n"},
+ {"c.h", "#ifndef X\n#define X\nno_type_spec; // error-ok\n#endif"}};
EXPECT_THAT(TU.build().getDiagnostics(),
UnorderedElementsAre(
Diag(Main.range(), "in included file: C++ requires a "
{"c.h", R"cpp(
#ifndef X
#define X
- no_type_spec_0;
+ no_type_spec_0; // error-ok
no_type_spec_1;
no_type_spec_2;
no_type_spec_3;
#include [["a.h"]]
void foo() {})cpp");
Annotations Header(R"cpp(
- [[no_type_spec]];
+ [[no_type_spec]]; // error-ok
int x = 5/0;)cpp");
TestTU TU = TestTU::withCode(Main.code());
TU.AdditionalFiles = {{"a.h", Header.code()}};
void foo() {})cpp");
Annotations Header(R"cpp(
int x = 5/0;
- int b = [[FOO]];)cpp");
+ int b = [[FOO]]; // error-ok)cpp");
TestTU TU = TestTU::withCode(Main.code());
TU.AdditionalFiles = {{"a.h", Header.code()}};
TU.ExtraArgs = {"-DFOO=NOOO"};
TEST(DiagsInHeaders, ErrorFromMacroExpansion) {
Annotations Main(R"cpp(
void bar() {
- int fo;
+ int fo; // error-ok
#include [["a.h"]]
})cpp");
Annotations Header(R"cpp(
TEST(DiagsInHeaders, ErrorFromMacroArgument) {
Annotations Main(R"cpp(
void bar() {
- int fo;
+ int fo; // error-ok
#include [["a.h"]]
})cpp");
Annotations Header(R"cpp(
TestTU TU;
TU.HeaderCode = "class Foo{};";
Annotations Main(R"cpp(
- #include "foo.h"
void f() {
[[Foo]] foo;
}
auto TU = TestTU::withCode(A.code());
TU.ExtraArgs = Flags;
auto AST = TU.build();
- EXPECT_THAT(AST.getDiagnostics(), ::testing::IsEmpty()) << Code;
llvm::Annotations::Range R = A.range();
SelectionTree Selection(AST.getASTContext(), AST.getTokens(), R.Begin,
R.End);
TU.ExtraArgs.push_back("-std=c++2a");
auto AST = TU.build();
- for (auto &D : AST.getDiagnostics()) {
- if (D.Severity > DiagnosticsEngine::Warning)
- ADD_FAILURE() << D << Code;
- }
-
auto *TestDecl = &findDecl(AST, "foo");
if (auto *T = llvm::dyn_cast<FunctionTemplateDecl>(TestDecl))
TestDecl = T->getTemplatedDecl();
TU.ExtraArgs.push_back("-std=c++17");
TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
ASSERT_TRUE(H);
TestTU TU = TestTU::withCode(T.code());
TU.ExtraArgs.push_back("-std=c++17");
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
ASSERT_FALSE(H);
}
TU.ExtraArgs.push_back("-std=c++17");
TU.ExtraArgs.push_back("-Wno-gnu-designator");
auto AST = TU.build();
- for (const auto &D : AST.getDiagnostics())
- ADD_FAILURE() << D;
- ASSERT_TRUE(AST.getDiagnostics().empty());
auto H = getHover(AST, T.point(), format::getLLVMStyle(), Index.get());
ASSERT_TRUE(H);
TestTU TU = TestTU::withCode(T.code());
auto AST = TU.build();
- for (const auto &D : AST.getDiagnostics())
- ADD_FAILURE() << D;
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
Symbol IndexSym;
IndexSym.ID = *getSymbolID(&findDecl(AST, "X"));
IndexSym.Documentation = "comment from index";
TestTU TU = TestTU::withCode(T.code());
auto AST = TU.build();
- for (const auto &D : AST.getDiagnostics())
- ADD_FAILURE() << D;
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
for (const auto &P : T.points()) {
auto H = getHover(AST, P, format::getLLVMStyle(), nullptr);
ASSERT_TRUE(H);
TestTU TU = TestTU::withCode(T.code());
auto AST = TU.build();
- for (const auto &D : AST.getDiagnostics())
- ADD_FAILURE() << D;
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
for (auto Comment : {"doc1", "doc2", "doc3"}) {
for (const auto &P : T.points(Comment)) {
auto H = getHover(AST, P, format::getLLVMStyle(), nullptr);
Annotations T(C.Code);
TestTU TU = TestTU::withCode(T.code());
auto AST = TU.build();
- for (const auto &D : AST.getDiagnostics())
- ADD_FAILURE() << D;
-
auto H = getHover(AST, T.point(), format::getLLVMStyle(), nullptr);
ASSERT_TRUE(H);
HoverInfo ExpectedHover;
#include "foo.h"
first_token;
void test() {
+ // error-ok: invalid syntax, just examining token stream
}
last_token
)cpp";
// - preamble ends
^ID(int A);
// Macro arguments included.
- ^MACRO_ARGS(^MACRO_ARGS(^MACRO_EXP(int), A), ^ID(= 2));
+ ^MACRO_ARGS(^MACRO_ARGS(^MACRO_EXP(int), E), ^ID(= 2));
// Macro names inside other macros not included.
#define ^MACRO_ARGS2(X, Y) X Y
#define ^FOO BAR
#define ^BAR 1
- int A = ^FOO;
+ int F = ^FOO;
// Macros from token concatenations not included.
#define ^CONCAT(X) X##A()
#define ^PREPEND(X) MACRO##X()
#define ^MACROA() 123
- int B = ^CONCAT(MACRO);
- int D = ^PREPEND(A)
+ int G = ^CONCAT(MACRO);
+ int H = ^PREPEND(A);
// Macros included not from preamble not included.
#include "foo.inc"
+ int printf(const char*, ...);
+ void exit(int);
#define ^assert(COND) if (!(COND)) { printf("%s", #COND); exit(0); }
void test() {
template <template <class> class ...>
class Aux {};
template <> class ^Aux<Bar, Bar> {};
- template <template <class> T>
+ template <template <class> class T>
class ^Aux<T, T> {};)cpp",
{"<Bar, Bar>", "<T, T>"}},
{
template <>
int ^S<double> = 0;)cpp",
{"<T *>", "<double>"}},
- })),);
+ })), );
} // namespace
} // namespace clangd
} // namespace clang
int deprecated() { return 0; }
namespace { struct X { void y() { int z; } }; }
- struct S{}
+ struct S{};
)cpp";
auto AST = Test.build();
// Derived destructor explicit call.
R"cpp(
class [[Bas^e]] {};
- class Derived : public [[Bas^e]] {}
+ class Derived : public [[Bas^e]] {};
int main() {
[[Bas^e]] *foo = new Derived();
// Tricky case: CXXConstructExpr wants to claim the whole init range.
{
R"cpp(
- class X { X(int); };
+ struct X { X(int); };
class Y {
X x;
Y() : [[^x(4)]] {}
};
Str makeStr(const char*);
void loop() {
- for (const char* C : [[mak^eStr("foo"^)]])
+ for (const char C : [[mak^eStr("foo"^)]])
;
}
)cpp",
// (This is because we don't associate the stringified token with the arg).
Case = R"cpp(
void die(const char*);
- #define assert(x) (x ? (void)0 : die(#x)
+ #define assert(x) (x ? (void)0 : die(#x))
void foo() { assert(^42); }
)cpp";
Test = Annotations(Case);
R"cpp(
struct $Class[[AA]] {
int $Field[[A]];
- }
+ };
int $Variable[[B]];
$Class[[AA]] $Variable[[A]]{$Variable[[B]]};
)cpp",
};
class $Class[[Foo]] {};
class $Class[[Bar]] {
+ public:
$Class[[Foo]] $Field[[Fo]];
$Enum[[En]] $Field[[E]];
int $Field[[I]];
$Class[[G]]<$Class[[F]], &$Class[[F]]::$Method[[f]]> $LocalVariable[[GG]];
$LocalVariable[[GG]].$Method[[foo]](&$LocalVariable[[FF]]);
$Class[[A]]<$Function[[foo]]> $LocalVariable[[AA]];
+ }
)cpp",
// Tokens that share a source range but have conflicting Kinds are not
// highlighted.
$Macro[[INC_VAR]]($LocalVariable[[variable]]);
}
void $Macro[[SOME_NAME]]();
- $Macro[[DEF_VAR]]($Variable[[XYZ]], 567);
+ $Macro[[DEF_VAR]]($Variable[[MMMMM]], 567);
$Macro[[DEF_VAR_REV]](756, $Variable[[AB]]);
#define $Macro[[CALL_FN]](F) F();
struct $Class[[Foo]] {
$Class[[Foo]]<$TemplateParameter[[TT]], $TemplateParameter[[TTs]]...>
*$Field[[t]];
- }
+ };
)cpp",
// Inactive code highlighting
R"cpp(
class $Class[[A]] {
#include "imp.h"
};
- #endif
)cpp",
{{"imp.h", R"cpp(
int someMethod();
"c:TestTU.cpp@38@F@bar#I#@aaa")}},
{
R"cpp( // Lambda capture
- int ii;
- auto lam = [ii]() {
- return i^i;
- };
+ void foo() {
+ int ii;
+ auto lam = [ii]() {
+ return i^i;
+ };
+ }
)cpp",
- {CreateExpectedSymbolDetails("ii", "", "c:@ii")}},
+ {CreateExpectedSymbolDetails("ii", "foo",
+ "c:TestTU.cpp@54@F@foo#@ii")}},
{
R"cpp( // Macro reference
#define MACRO 5\nint i = MAC^RO;
#include "index/FileIndex.h"
#include "index/MemIndex.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/Utils.h"
ADD_FAILURE() << "Failed to build code:\n" << Code;
llvm_unreachable("Failed to build TestTU!");
}
+ // Check for error diagnostics and report gtest failures (unless expected).
+ // This guards against accidental syntax errors silently subverting tests.
+ // error-ok is awfully primitive - using clang -verify would be nicer.
+ // Ownership and layering makes it pretty hard.
+ if (llvm::none_of(Files, [](const auto &KV) {
+ return llvm::StringRef(KV.second).contains("error-ok");
+ })) {
+ for (const auto &D : AST->getDiagnostics())
+ if (D.Severity >= DiagnosticsEngine::Error) {
+ ADD_FAILURE()
+ << "TestTU failed to build (suppress with /*error-ok*/): \n"
+ << D << "\n\nFor code:\n"
+ << Code;
+ break; // Just report first error for simplicity.
+ }
+ }
return std::move(*AST);
}
// Simulate a header guard of the header (using an #import directive).
bool ImplicitHeaderGuard = true;
+ // By default, build() will report Error diagnostics as GTest errors.
+ // Suppress this behavior by adding an 'error-ok' comment to the code.
ParsedAST build() const;
SymbolSlab headerSymbols() const;
std::unique_ptr<SymbolIndex> index() const;
TWEAK_TEST(SwapIfBranches);
TEST_F(SwapIfBranchesTest, Test) {
Context = Function;
- EXPECT_EQ(apply("^if (true) {return 100;} else {continue;}"),
- "if (true) {continue;} else {return 100;}");
- EXPECT_EQ(apply("^if () {return 100;} else {continue;}"),
- "if () {continue;} else {return 100;}")
+ EXPECT_EQ(apply("^if (true) {return;} else {(void)0;}"),
+ "if (true) {(void)0;} else {return;}");
+ EXPECT_EQ(apply("^if (/*error-ok*/) {return;} else {(void)0;}"),
+ "if (/*error-ok*/) {(void)0;} else {return;}")
<< "broken condition";
- EXPECT_AVAILABLE("^i^f^^(^t^r^u^e^) { return 100; } ^e^l^s^e^ { continue; }");
- EXPECT_UNAVAILABLE("if (true) {^return ^100;^ } else { ^continue^;^ }");
+ EXPECT_AVAILABLE("^i^f^^(^t^r^u^e^) { return; } ^e^l^s^e^ { return; }");
+ EXPECT_UNAVAILABLE("if (true) {^return ^;^ } else { ^return^;^ }");
// Available in subexpressions of the condition;
- EXPECT_THAT("if(2 + [[2]] + 2) { return 2 + 2 + 2; } else {continue;}",
- isAvailable());
+ EXPECT_THAT("if(2 + [[2]] + 2) { return; } else {return;}", isAvailable());
// But not as part of the branches.
- EXPECT_THAT("if(2 + 2 + 2) { return 2 + [[2]] + 2; } else { continue; }",
+ EXPECT_THAT("if(2 + 2 + 2) { [[return]]; } else { return; }",
Not(isAvailable()));
// Range covers the "else" token, so available.
- EXPECT_THAT("if(2 + 2 + 2) { return 2 + [[2 + 2; } else {continue;]]}",
- isAvailable());
+ EXPECT_THAT("if(2 + 2 + 2) { return[[; } else {return;]]}", isAvailable());
// Not available in compound statements in condition.
- EXPECT_THAT(
- "if([]{return [[true]];}()) { return 2 + 2 + 2; } else { continue; }",
- Not(isAvailable()));
+ EXPECT_THAT("if([]{return [[true]];}()) { return; } else { return; }",
+ Not(isAvailable()));
// Not available if both sides aren't braced.
EXPECT_THAT("^if (1) return; else { return; }", Not(isAvailable()));
// Only one if statement is supported!
TWEAK_TEST(DumpAST);
TEST_F(DumpASTTest, Test) {
EXPECT_AVAILABLE("^int f^oo() { re^turn 2 ^+ 2; }");
- EXPECT_UNAVAILABLE("/*c^omment*/ int foo() return 2 ^ + 2; }");
+ EXPECT_UNAVAILABLE("/*c^omment*/ int foo() { return 2 ^ + 2; }");
EXPECT_THAT(apply("int x = 2 ^+ 2;"),
AllOf(StartsWith("message:"), HasSubstr("BinaryOperator"),
HasSubstr("'+'"), HasSubstr("|-IntegerLiteral"),
TWEAK_TEST(ShowSelectionTree);
TEST_F(ShowSelectionTreeTest, Test) {
EXPECT_AVAILABLE("^int f^oo() { re^turn 2 ^+ 2; }");
- EXPECT_AVAILABLE("/*c^omment*/ int foo() return 2 ^ + 2; }");
+ EXPECT_AVAILABLE("/*c^omment*/ int foo() { return 2 ^ + 2; }");
const char *Output = R"(message:
TranslationUnitDecl
EXPECT_THAT("template <typename T> struct ^X { T t; };", Not(isAvailable()));
EXPECT_THAT("enum ^X {};", Not(isAvailable()));
- EXPECT_THAT(apply("struct ^X { int x; int y; }"),
+ EXPECT_THAT(apply("struct ^X { int x; int y; };"),
AllOf(StartsWith("message:"), HasSubstr("0 | int x")));
}
EXPECT_AVAILABLE(AvailableCases);
const char *NoCrashCases = R"cpp(
+ // error-ok: broken code, but shouldn't crash
template<typename T, typename ...Args>
struct Test<T, Args...> {
Test(const T &v) :val[[(^]]) {}
for(int a = 1, b = 2, c = 3; a > [[b + c]]; [[a++]])
a = [[a + 1]];
// lambda
- auto lamb = [&[[a]], &[[b]]](int r = [[1]]) {return 1;}
+ auto lamb = [&[[a]], &[[b]]](int r = [[1]]) {return 1;};
// assignment
xyz([[a = 5]]);
xyz([[a *= 5]]);
TWEAK_TEST(ExpandMacro);
TEST_F(ExpandMacroTest, Test) {
Header = R"cpp(
+ // error-ok: not real c++, just token manipulation
#define FOO 1 2 3
#define FUNC(X) X+X+X
#define EMPTY
namespace ns {
struct Class {
struct Nested {};
- }
+ };
void Func();
}
inline namespace inl_ns {
EXPECT_EQ(apply("namespace ns { void f() { ^auto C = Class(); } }"),
"namespace ns { void f() { Class C = Class(); } }");
// undefined functions should not be replaced
- EXPECT_THAT(apply("au^to x = doesnt_exist();"),
+ EXPECT_THAT(apply("au^to x = doesnt_exist(); // error-ok"),
StartsWith("fail: Could not deduce type for 'auto' type"));
// function pointers should not be replaced
EXPECT_THAT(apply("au^to x = &ns::Func;"),
EXPECT_EQ(apply("namespace x { void y() { struct S{}; ^auto z = S(); } }"),
"namespace x { void y() { struct S{}; S z = S(); } }");
// replace array types
- EXPECT_EQ(apply(R"cpp(au^to x = "test")cpp"),
- R"cpp(const char * x = "test")cpp");
+ EXPECT_EQ(apply(R"cpp(au^to x = "test";)cpp"),
+ R"cpp(const char * x = "test";)cpp");
EXPECT_UNAVAILABLE("dec^ltype(au^to) x = 10;");
}]]
// Definition with no body.
- class Bar { Bar() = def^ault; }
+ class Bar { Bar() = def^ault; };
)cpp");
}
public:
void foo();
int x;
- static int y;
};
- Foo::y = 0;
enum En { Zero, One };
En x = Zero;
public:
void foo();
int x;
- static int y;
};
- Foo::y = 0;
enum En { Zero, One };
En x = Zero;
namespace a { class Foo{}; }
void foo();
using namespace a;
- void f^oo(){BODY})cpp",
+ void f^oo(){BODY();})cpp",
R"cpp(
#define BODY Foo
namespace a { class Foo{}; }
- void foo(){BODY}
+ void foo(){BODY();}
using namespace a;
)cpp"},
testPath("a.h"), "constexpr void foo(){}")));
// Class members don't need "inline".
- ExtraFiles["a.h"] = "struct Foo { void foo(); }";
+ ExtraFiles["a.h"] = "struct Foo { void foo(); };";
apply(R"cpp(#include "a.h"
void Foo::fo^o() {})cpp",
&EditedFiles);
EXPECT_THAT(EditedFiles,
testing::ElementsAre(FileWithContents(
- testPath("a.h"), "struct Foo { void foo(){} }")));
+ testPath("a.h"), "struct Foo { void foo(){} };")));
// Function template doesn't need to be "inline"d.
ExtraFiles["a.h"] = "template <typename T> void foo();";
// out-of-line in such cases.
EXPECT_UNAVAILABLE(R"cpp(
template <typename> struct Foo { void fo^o(){} };
- })cpp");
+ )cpp");
}
TEST_F(DefineOutlineTest, FailsWithoutSource) {
llvm::StringRef ExpectedSource;
} Cases[] = {
{R"cpp(
- namespace a { class Foo; }
+ namespace a { class Foo{}; }
using namespace a;
- Foo fo^o() { return; })cpp",
+ Foo fo^o() { return {}; })cpp",
R"cpp(
- namespace a { class Foo; }
+ namespace a { class Foo{}; }
using namespace a;
Foo foo() ;)cpp",
- "a::Foo foo() { return; }"},
+ "a::Foo foo() { return {}; }"},
{R"cpp(
namespace a {
class Foo {
})cpp",
"a::Foo::Bar a::Foo::foo() { return {}; }\n"},
{R"cpp(
- class Foo;
- Foo fo^o() { return; })cpp",
+ class Foo {};
+ Foo fo^o() { return {}; })cpp",
R"cpp(
- class Foo;
+ class Foo {};
Foo foo() ;)cpp",
- "Foo foo() { return; }"},
+ "Foo foo() { return {}; }"},
};
llvm::StringMap<std::string> EditedFiles;
for (auto &Case : Cases) {
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
for (Position Pt : Source.points()) {
const CXXRecordDecl *RD = findRecordTypeAt(AST, Pt);
EXPECT_EQ(&findDecl(AST, "Child2"), static_cast<const NamedDecl *>(RD));
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
for (Position Pt : Source.points()) {
const CXXRecordDecl *RD = findRecordTypeAt(AST, Pt);
EXPECT_EQ(&findDecl(AST, "Child2"), static_cast<const NamedDecl *>(RD));
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
for (Position Pt : Source.points()) {
const CXXRecordDecl *RD = findRecordTypeAt(AST, Pt);
// A field does not unambiguously specify a record type
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
const CXXRecordDecl *Parent =
dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
const CXXRecordDecl *Child1 =
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
const CXXRecordDecl *Parent1 =
dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent1"));
const CXXRecordDecl *Parent2 =
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
const CXXRecordDecl *Parent =
dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
const CXXRecordDecl *Child =
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
const CXXRecordDecl *Parent =
dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Parent"))->getTemplatedDecl();
const CXXRecordDecl *ParentSpec =
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
const CXXRecordDecl *Parent =
dyn_cast<CXXRecordDecl>(&findDecl(AST, "Parent"));
const CXXRecordDecl *Child =
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
const CXXRecordDecl *Parent =
dyn_cast<ClassTemplateDecl>(&findDecl(AST, "Parent"))->getTemplatedDecl();
const CXXRecordDecl *Child1 =
template <int N>
struct $SDef[[S]] : S<N + 1> {};
- S^<0> s;
+ S^<0> s; // error-ok
)cpp");
TestTU TU = TestTU::withCode(Source.code());
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
- ASSERT_TRUE(AST.getDiagnostics().empty());
-
// Make sure getTypeHierarchy() doesn't get into an infinite recursion
// for either a concrete starting point or a dependent starting point.
llvm::Optional<TypeHierarchyItem> Result = getTypeHierarchy(
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
auto Index = TU.index();
- ASSERT_TRUE(AST.getDiagnostics().empty());
llvm::Optional<TypeHierarchyItem> Result = getTypeHierarchy(
AST, Source.points()[0], 2, TypeHierarchyDirection::Children, Index.get(),
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
auto Index = TU.index();
- ASSERT_TRUE(AST.getDiagnostics().empty());
llvm::Optional<TypeHierarchyItem> Result = getTypeHierarchy(
AST, Source.points()[0], 2, TypeHierarchyDirection::Children, Index.get(),
TestTU TU = TestTU::withCode(Source.code());
auto AST = TU.build();
auto Index = TU.index();
- ASSERT_TRUE(AST.getDiagnostics().empty());
// FIXME: We'd like this to return the implicit specialization Child<int>,
// but currently libIndex does not expose relationships between
TU.ExtraArgs.push_back("-fno-delayed-template-parsing");
auto AST = TU.build();
- for (auto &D : AST.getDiagnostics())
- ADD_FAILURE() << D;
- ASSERT_TRUE(AST.getDiagnostics().empty()) << Test;
-
auto Results = locateSymbolAt(AST, T.point());
if (!WantDecl) {
R"cpp(// Forward declaration
class [[Foo]];
- class [[Foo]] {}
+ class [[Foo]] {};
int main() {
[[Fo^o]] foo;
}
int [[foo]](int) {}
int main() {
auto *X = &[[^foo]];
- [[foo]](42)
+ [[foo]](42);
}
)cpp",
for (const Case &C : Cases) {
Annotations File(C.AnnotatedCode);
auto AST = TestTU::withCode(File.code()).build();
- ASSERT_TRUE(AST.getDiagnostics().empty())
- << AST.getDiagnostics().begin()->Message;
SourceLocation SL = llvm::cantFail(
sourceLocationInMainFile(AST.getSourceManager(), File.point()));