12 #include "clang/AST/Decl.h" 13 #include "llvm/Support/Casting.h" 14 #include "gmock/gmock.h" 15 #include "gtest/gtest.h" 20 using ::testing::UnorderedElementsAreArray;
22 SelectionTree makeSelectionTree(
const StringRef MarkedCode, ParsedAST &AST) {
23 Annotations Test(MarkedCode);
24 switch (Test.points().size()) {
26 return SelectionTree(AST.getASTContext(), AST.getTokens(),
30 AST.getASTContext(), AST.getTokens(),
34 ADD_FAILURE() <<
"Expected 1-2 points for selection.\n" << MarkedCode;
35 return SelectionTree(AST.getASTContext(), AST.getTokens(), 0u, 0u);
39 Range nodeRange(
const SelectionTree::Node *N, ParsedAST &AST) {
42 const SourceManager &SM = AST.getSourceManager();
43 const LangOptions &LangOpts = AST.getLangOpts();
44 StringRef Buffer = SM.getBufferData(SM.getMainFileID());
45 if (llvm::isa_and_nonnull<TranslationUnitDecl>(N->ASTNode.get<
Decl>()))
49 assert(FileRange &&
"We should be able to get the File Range");
55 std::string nodeKind(
const SelectionTree::Node *N) {
56 return N ? N->kind() :
"<null>";
59 std::vector<const SelectionTree::Node *> allNodes(
const SelectionTree &T) {
60 std::vector<const SelectionTree::Node *> Result = {&T.root()};
61 for (
unsigned I = 0; I < Result.size(); ++I) {
62 const SelectionTree::Node *N = Result[I];
63 Result.insert(Result.end(), N->Children.begin(), N->Children.end());
70 bool verifyCommonAncestor(
const SelectionTree::Node &Root,
71 const SelectionTree::Node *Common,
72 StringRef MarkedCode) {
76 ADD_FAILURE() <<
"Selected nodes outside common ancestor\n" << MarkedCode;
78 for (
const SelectionTree::Node *Child : Root.Children)
79 if (verifyCommonAncestor(*Child, Common, MarkedCode)) {
81 ADD_FAILURE() <<
"Saw common ancestor twice\n" << MarkedCode;
87 TEST(SelectionTest, CommonAncestor) {
92 const char *CommonAncestorKind;
98 int x = [[T::^U::]]ccc(); 100 "NestedNameSpecifierLoc",
104 struct AAA { struct BBB { static int ccc(); };}; 105 int x = AAA::[[B^B^B]]::ccc(); 111 struct AAA { struct BBB { static int ccc(); };}; 112 int x = AAA::[[B^BB^]]::ccc(); 118 struct AAA { struct BBB { static int ccc(); };}; 119 int x = [[AAA::BBB::c^c^c]](); 125 struct AAA { struct BBB { static int ccc(); };}; 126 int x = [[AAA::BBB::cc^c(^)]]; 133 void foo() { [[if (1^11) { return; } else {^ }]] } 140 #define M(foo) x(foo) 149 #define CALL_FUNCTION(X) X() 150 void bar() { CALL_FUNCTION([[f^o^o]]); } 157 #define CALL_FUNCTION(X) X() 158 void bar() { [[CALL_FUNC^TION(fo^o)]]; } 165 #define CALL_FUNCTION(X) X() 166 void bar() { [[C^ALL_FUNC^TION(foo)]]; } 173 #define CALL_FUNCTION(X) X^()^ 174 void bar() { CALL_FUNCTION(foo); } 180 struct S { S(const char*); }; 187 struct S { S(const char*); }; 194 [[^void]] (*S)(int) = nullptr; 200 [[void (*S)^(int)]] = nullptr; 202 "FunctionProtoTypeLoc",
206 [[void (^*S)(int)]] = nullptr; 208 "FunctionProtoTypeLoc",
212 [[void (*^S)(int) = nullptr]]; 218 [[void ^(*S)(int)]] = nullptr; 220 "FunctionProtoTypeLoc",
226 int bar() { return [[f^oo]](); } 233 auto lambda = [](const char*){ return 0; }; 234 int x = lambda([["y^"]]); 240 {
"void foo() { [[^foo]](); }",
"DeclRefExpr"},
241 {
"void foo() { [[f^oo]](); }",
"DeclRefExpr"},
242 {
"void foo() { [[fo^o]](); }",
"DeclRefExpr"},
243 {
"void foo() { [[foo^()]]; }",
"CallExpr"},
244 {
"void foo() { [[foo^]] (); }",
"DeclRefExpr"},
245 {
"int bar; void foo() [[{ foo (); }]]^",
"CompoundStmt"},
246 {
"int x = [[42]]^;",
"IntegerLiteral"},
249 {
"void foo() { [[foo^()]]; /*comment*/^}",
"CallExpr"},
252 {
"[[^void]] foo();",
"BuiltinTypeLoc"},
253 {
"[[void foo^()]];",
"FunctionProtoTypeLoc"},
254 {
"[[^void foo^()]];",
"FunctionDecl"},
255 {
"[[void ^foo()]];",
"FunctionDecl"},
257 {
"[[int ^a]], b;",
"VarDecl"},
258 {
"[[int a, ^b]];",
"VarDecl"},
268 "CXXCtorInitializer",
271 {
"[[st^ruct {int x;}]] y;",
"CXXRecordDecl"},
272 {
"[[struct {int x;} ^y]];",
"VarDecl"},
273 {
"struct {[[int ^x]];} y;",
"FieldDecl"},
275 {
"const [[a^uto]] x = 42;",
"AutoTypeLoc"},
276 {
"[[co^nst auto x = 42]];",
"VarDecl"},
279 {
"void foo() { [[foo^^]] (); }",
"DeclRefExpr"},
283 {
"int x = 42;^",
nullptr},
286 {
"^int x; int y;^",
nullptr},
289 {
"template <typename T> void foo() { [[^T]] t; }",
290 "TemplateTypeParmTypeLoc"},
295 template <class T> struct Foo {}; 296 template <[[template<class> class /*cursor here*/^U]]> 297 struct Foo<U<int>*> {}; 299 "TemplateTemplateParmDecl"},
309 Str makeStr(const char*); 311 for (const char* C : [[mak^eStr("foo"^)]]) 322 Foo operator""_ud(unsigned long long); 325 "UserDefinedLiteral"},
329 decltype([[^a]] + a) b; 333 for (
const Case &C : Cases) {
334 Annotations Test(C.Code);
337 TU.Code = Test.code();
341 TU.ExtraArgs.push_back(
"-fno-delayed-template-parsing");
343 auto AST = TU.build();
344 auto T = makeSelectionTree(C.Code, AST);
345 EXPECT_EQ(
"TranslationUnitDecl", nodeKind(&T.root())) << C.Code;
347 if (Test.ranges().empty()) {
349 EXPECT_FALSE(T.commonAncestor()) << C.Code <<
"\n" << T;
353 EXPECT_EQ(C.CommonAncestorKind, nodeKind(T.commonAncestor()))
357 EXPECT_EQ(nodeRange(T.commonAncestor(),
AST), Test.range())
363 EXPECT_TRUE(verifyCommonAncestor(T.root(), T.commonAncestor(), C.Code))
370 TEST(SelectionTest, InjectedClassName) {
371 const char*
Code =
"struct ^X { int x; };";
373 auto T = makeSelectionTree(Code, AST);
374 ASSERT_EQ(
"CXXRecordDecl", nodeKind(T.commonAncestor())) << T;
375 auto *D = dyn_cast<CXXRecordDecl>(T.commonAncestor()->ASTNode.get<
Decl>());
376 EXPECT_FALSE(D->isInjectedClassName());
386 const char *Cases[] = {
387 R
"cpp( int abc, xyz = [[^ab^c]]; )cpp", 388 R"cpp( int abc, xyz = [[a^bc^]]; )cpp", 389 R"cpp( int abc, xyz = $C[[^abc^]]; )cpp", 392 [[if ([[1^11]]) $C[[{ 401 struct unique_ptr {}; 402 void foo(^$C[[unique_ptr<$C[[unique_ptr<$C[[int]]>]]>]]^ a) {} 404 R"cpp(int a = [[5 >^> 1]];)cpp", 407 ECHO(EC^HO($C[[int]]) EC^HO(a)); 409 R"cpp( $C[[^$C[[int]] a^]]; )cpp", 410 R"cpp( $C[[^$C[[int]] a = $C[[5]]^]]; )cpp", 412 for (
const char *C : Cases) {
415 auto T = makeSelectionTree(C, AST);
417 std::vector<Range> Complete, Partial;
418 for (
const SelectionTree::Node *N : allNodes(T))
420 Complete.push_back(nodeRange(N, AST));
422 Partial.push_back(nodeRange(N, AST));
423 EXPECT_THAT(Complete, UnorderedElementsAreArray(Test.ranges(
"C"))) << C;
424 EXPECT_THAT(Partial, UnorderedElementsAreArray(Test.ranges())) << C;
428 TEST(SelectionTest, PathologicalPreprocessor) {
429 const char *Case = R
"cpp( 430 #define MACRO while(1) 432 #include "Expand.inc" 436 Annotations Test(Case); 439 auto AST = TU.build();
440 EXPECT_THAT(AST.getDiagnostics(), ::testing::IsEmpty());
441 auto T = makeSelectionTree(Case, AST);
443 EXPECT_EQ(
"BreakStmt", T.commonAncestor()->kind());
444 EXPECT_EQ(
"WhileStmt", T.commonAncestor()->Parent->kind());
447 TEST(SelectionTest, IncludedFile) {
448 const char *Case = R
"cpp( 450 #include "Exp^and.inc" 454 Annotations Test(Case); 457 auto AST = TU.build();
458 auto T = makeSelectionTree(Case, AST);
460 EXPECT_EQ(
"WhileStmt", T.commonAncestor()->kind());
463 TEST(SelectionTest, MacroArgExpansion) {
465 const char *Case = R
"cpp( 467 #define SQUARE(X) mul(X, X); 468 int nine = SQUARE(^3); 470 Annotations Test(Case); 472 auto T = makeSelectionTree(Case, AST);
475 EXPECT_EQ(
"CallExpr", T.commonAncestor()->kind());
476 EXPECT_FALSE(T.commonAncestor()->Selected);
477 EXPECT_EQ(2u, T.commonAncestor()->Children.size());
478 for (
const auto* N : T.commonAncestor()->Children) {
479 EXPECT_EQ(
"IntegerLiteral", N->kind());
480 EXPECT_TRUE(N->Selected);
486 void die(const char*); 487 #define assert(x) (x ? (void)0 : die(#x) 488 void foo() { assert(^42); } 490 Test = Annotations(Case); 492 T = makeSelectionTree(Case, AST); 494 EXPECT_EQ("IntegerLiteral", T.commonAncestor()->kind());
497 TEST(SelectionTest, Implicit) {
498 const char* Test = R
"cpp( 499 struct S { S(const char*); }; 504 auto T = makeSelectionTree(Test, AST);
506 const SelectionTree::Node *Str = T.commonAncestor();
507 EXPECT_EQ(
"StringLiteral", nodeKind(Str)) <<
"Implicit selected?";
508 EXPECT_EQ(
"ImplicitCastExpr", nodeKind(Str->Parent));
509 EXPECT_EQ(
"CXXConstructExpr", nodeKind(Str->Parent->Parent));
510 EXPECT_EQ(Str, &Str->Parent->Parent->ignoreImplicit())
511 <<
"Didn't unwrap " << nodeKind(&Str->Parent->Parent->ignoreImplicit());
513 EXPECT_EQ(
"CXXConstructExpr", nodeKind(&Str->outerImplicit()));
const FunctionDecl * Decl
Position offsetToPosition(llvm::StringRef Code, size_t Offset)
Turn an offset in Code into a [line, column] pair.
TEST(BackgroundQueueTest, Priority)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
static TestTU withCode(llvm::StringRef Code)
llvm::Optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
CharSourceRange Range
SourceRange for the file name.
SelectionTree::Selection Selected
llvm::StringMap< std::string > AdditionalFiles