13#include "clang/AST/ASTConcept.h"
14#include "clang/AST/Decl.h"
15#include "llvm/Support/Casting.h"
16#include "gmock/gmock.h"
17#include "gtest/gtest.h"
22using ::testing::ElementsAreArray;
23using ::testing::UnorderedElementsAreArray;
28SelectionTree makeSelectionTree(
const StringRef MarkedCode, ParsedAST &
AST) {
29 Annotations Test(MarkedCode);
30 switch (Test.points().size()) {
38 AST.getASTContext(),
AST.getTokens(),
42 ADD_FAILURE() <<
"Expected 1-2 points for selection.\n" << MarkedCode;
48Range nodeRange(
const SelectionTree::Node *N, ParsedAST &
AST) {
51 const SourceManager &SM =
AST.getSourceManager();
52 const LangOptions &LangOpts =
AST.getLangOpts();
53 StringRef Buffer = SM.getBufferData(SM.getMainFileID());
54 if (llvm::isa_and_nonnull<TranslationUnitDecl>(N->ASTNode.get<
Decl>()))
58 assert(FileRange &&
"We should be able to get the File Range");
64std::string nodeKind(
const SelectionTree::Node *N) {
65 return N ? N->kind() :
"<null>";
68std::vector<const SelectionTree::Node *> allNodes(
const SelectionTree &T) {
69 std::vector<const SelectionTree::Node *> Result = {&
T.root()};
70 for (
unsigned I = 0; I < Result.size(); ++I) {
71 const SelectionTree::Node *N = Result[I];
72 Result.insert(Result.end(), N->Children.begin(), N->Children.end());
79bool verifyCommonAncestor(
const SelectionTree::Node &
Root,
80 const SelectionTree::Node *Common,
81 StringRef MarkedCode) {
85 ADD_FAILURE() <<
"Selected nodes outside common ancestor\n" << MarkedCode;
87 for (
const SelectionTree::Node *Child :
Root.Children)
88 if (verifyCommonAncestor(*Child, Common, MarkedCode)) {
90 ADD_FAILURE() <<
"Saw common ancestor twice\n" << MarkedCode;
96TEST(SelectionTest, CommonAncestor) {
101 const char *CommonAncestorKind;
106 template <typename T>
107 int x = [[T::^U::]]ccc();
109 "NestedNameSpecifierLoc",
113 struct AAA { struct BBB { static int ccc(); };};
114 int x = AAA::[[B^B^B]]::ccc();
120 struct AAA { struct BBB { static int ccc(); };};
121 int x = AAA::[[B^BB^]]::ccc();
127 struct AAA { struct BBB { static int ccc(); };};
128 int x = [[AAA::BBB::c^c^c]]();
134 struct AAA { struct BBB { static int ccc(); };};
135 int x = [[AAA::BBB::cc^c(^)]];
142 void foo() { [[if (1^11) { return; } else {^ }]] }
149 #define M(foo) x(foo)
158 #define CALL_FUNCTION(X) X()
159 void bar() { CALL_FUNCTION([[f^o^o]]); }
166 #define CALL_FUNCTION(X) X()
167 void bar() { [[CALL_FUNC^TION(fo^o)]]; }
174 #define CALL_FUNCTION(X) X()
175 void bar() { [[C^ALL_FUNC^TION(foo)]]; }
182 #^define CALL_FUNCTION(X) X(^)
183 void bar() { CALL_FUNCTION(foo); }
190 #define CALL_FUNCTION(X) X()
191 void bar() { CALL_FUNCTION(foo^)^; }
207 #define TARGET void foo()
208 [[TAR^GET{ return; }]]
214 struct S { S(const char*); };
224 struct S { S(const char*); };
231 [[^void]] (*S)(int) = nullptr;
237 [[void (*S)^(int)]] = nullptr;
239 "FunctionProtoTypeLoc",
243 [[void (^*S)(int)]] = nullptr;
249 [[void (*^S)(int) = nullptr]];
255 [[void ^(*S)(int)]] = nullptr;
263 int bar() { return [[f^oo]](); }
270 auto lambda = [](const char*){ return 0; };
271 int x = lambda([["y^"]]);
278 struct Bar : [[v^ir^tual private Foo]] {};
285 struct Bar : private [[Fo^o]] {};
292 struct Bar : [[Fo^o]] {};
298 {
"void foo() { [[^foo]](); }",
"DeclRefExpr"},
299 {
"void foo() { [[f^oo]](); }",
"DeclRefExpr"},
300 {
"void foo() { [[fo^o]](); }",
"DeclRefExpr"},
301 {
"void foo() { [[foo^()]]; }",
"CallExpr"},
302 {
"void foo() { [[foo^]] (); }",
"DeclRefExpr"},
303 {
"int bar; void foo() [[{ foo (); }]]^",
"CompoundStmt"},
304 {
"int x = [[42]]^;",
"IntegerLiteral"},
307 {
"void foo() { [[foo^()]]; /*comment*/^}",
"CallExpr"},
310 {
"[[^void]] foo();",
"BuiltinTypeLoc"},
311 {
"[[void foo^()]];",
"FunctionProtoTypeLoc"},
312 {
"[[^void foo^()]];",
"FunctionDecl"},
313 {
"[[void ^foo()]];",
"FunctionDecl"},
315 {
"[[int ^a]], b;",
"VarDecl"},
316 {
"[[int a, ^b]];",
"VarDecl"},
320 struct X { X(int); };
326 "CXXCtorInitializer",
329 {
"[[st^ruct {int x;}]] y;",
"CXXRecordDecl"},
330 {
"[[struct {int x;} ^y]];",
"VarDecl"},
331 {
"struct {[[int ^x]];} y;",
"FieldDecl"},
334 {
"const int x = 1, y = 2; int array[^[[x]]][10][y];",
"DeclRefExpr"},
335 {
"const int x = 1, y = 2; int array[x][10][^[[y]]];",
"DeclRefExpr"},
336 {
"const int x = 1, y = 2; int array[x][^[[10]]][y];",
"IntegerLiteral"},
337 {
"const int x = 1, y = 2; [[i^nt]] array[x][10][y];",
"BuiltinTypeLoc"},
338 {
"void func(int x) { int v_array[^[[x]]][10]; }",
"DeclRefExpr"},
340 {
"int (*getFunc([[do^uble]]))(int);",
"BuiltinTypeLoc"},
344 {
"class X{}; [[int X::^*]]y[10];",
"MemberPointerTypeLoc"},
345 {
"template<typename ...T> void foo([[T*^...]]x);",
346 "PackExpansionTypeLoc"},
347 {
"template<typename ...T> void foo([[^T]]*...x);",
348 "TemplateTypeParmTypeLoc"},
351 {
"const [[a^uto]] x = 42;",
"AutoTypeLoc"},
352 {
"co^nst auto x = 42;",
nullptr},
355 {
"void foo() { [[foo^^]] (); }",
"DeclRefExpr"},
359 {
"int x = 42;^",
nullptr},
362 {
"^int x; int y;^",
nullptr},
365 {
"template <typename T> void foo() { [[^T]] t; }",
366 "TemplateTypeParmTypeLoc"},
371 template <class T> struct Foo {};
372 template <[[template<class> class /*cursor here*/^U]]>
373 struct Foo<U<int>*> {};
375 "TemplateTemplateParmDecl"},
385 Str makeStr(const char*);
387 for (const char C : [[mak^eStr("foo"^)]])
398 Foo operator""_ud(unsigned long long);
401 "UserDefinedLiteral"},
406 decltype([[^a]] + a) b;
409 {
"[[decltype^(1)]] b;",
"DecltypeTypeLoc"},
411 {
"[[de^cltype(a^uto)]] a = 1;",
"AutoTypeLoc"},
417 @property(nullable) [[^I]] *x;
420 "ObjCInterfaceTypeLoc"},
424 - (void)doSomething:(nonnull [[i^d]])argument;
435 @property(retain) I*x;
436 @property(retain) I*y;
438 void test(I *f) { [[^f]].x.y = 0; }
444 @property(retain) I*x;
445 @property(retain) I*y;
447 void test(I *f) { [[f.^x]].y = 0; }
449 "ObjCPropertyRefExpr"},
456 int test(I *f) { return 42 + [[^f]].foo; }
464 int test(I *f) { return 42 + [[f.^foo]]; }
466 "ObjCPropertyRefExpr"},
467 {
"struct foo { [[int has^h<:32:>]]; };",
"FieldDecl"},
468 {
"struct foo { [[op^erator int()]]; };",
"CXXConversionDecl"},
469 {
"struct foo { [[^~foo()]]; };",
"CXXDestructorDecl"},
470 {
"struct foo { [[~^foo()]]; };",
"CXXDestructorDecl"},
471 {
"template <class T> struct foo { ~foo<[[^T]]>(){} };",
472 "TemplateTypeParmTypeLoc"},
473 {
"struct foo {}; void bar(foo *f) { [[f->~^foo]](); }",
"MemberExpr"},
474 {
"struct foo { [[fo^o(){}]] };",
"CXXConstructorDecl"},
477 struct S1 { void f(); };
478 struct S2 { S1 * operator->(); };
487 template <typename> class Vector {};
488 template <template <typename> class Container> class A {};
491 "TemplateArgumentLoc"},
495 void f(int * __attribute__(([[no^nnull]])) );
500 // Digraph syntax for attributes to avoid accidental annotations.
501 class <:[gsl::Owner([[in^t]])]:> X{};
508 [[@property(retain, nonnull) <:[My^Object2]:> *x]]; // error-ok
515 enum Bar : [[Fo^o]] {};
527 auto l = [^[[foo = bar]]] { };
532 void func() [[{^]])cpp",
535 void func() { [[__^func__]]; }
541 namespace ns { enum class A {}; };
542 using enum ns::[[^A]];
546 namespace ns { enum class A {}; using B = A; };
547 using enum ns::[[^B]];
551 namespace ns { enum class A {}; };
552 using enum [[^ns::]]A;
554 "NestedNameSpecifierLoc"},
556 namespace ns { enum class A {}; };
557 [[using ^enum ns::A]];
561 namespace ns { enum class A {}; };
562 [[^using enum ns::A]];
568 template <class> concept C = true;
569 auto x = [[^C<int>]];
573 template <class> concept C = true;
578 template <class> concept C = true;
579 void foo([[^C]] auto x) {}
583 template <class> concept C = true;
584 template <[[^C]] x> int i = 0;
588 namespace ns { template <class> concept C = true; }
589 auto x = [[ns::^C<int>]];
593 template <typename T, typename K>
595 template <typename T> void g(D<[[^T]]> auto abc) {}
597 "TemplateTypeParmTypeLoc"},
600 for (
const Case &
C : Cases) {
601 trace::TestTracer Tracer;
602 Annotations Test(
C.Code);
605 TU.Code = std::string(Test.code());
607 TU.ExtraArgs.push_back(
"-xobjective-c++");
608 TU.ExtraArgs.push_back(
"-std=c++20");
610 auto AST = TU.build();
611 auto T = makeSelectionTree(
C.Code,
AST);
612 EXPECT_EQ(
"TranslationUnitDecl", nodeKind(&
T.root())) <<
C.Code;
614 if (Test.ranges().empty()) {
616 EXPECT_FALSE(
T.commonAncestor()) <<
C.Code <<
"\n" <<
T;
617 EXPECT_THAT(Tracer.takeMetric(
"selection_recovery",
"C++"),
622 EXPECT_EQ(
C.CommonAncestorKind, nodeKind(
T.commonAncestor()))
626 EXPECT_EQ(nodeRange(
T.commonAncestor(),
AST), Test.range())
632 EXPECT_TRUE(verifyCommonAncestor(
T.root(),
T.commonAncestor(),
C.Code))
634 EXPECT_THAT(Tracer.takeMetric(
"selection_recovery",
"C++"),
635 ElementsAreArray({0}));
641TEST(SelectionTest, InjectedClassName) {
642 const char *
Code =
"struct ^X { int x; };";
644 auto T = makeSelectionTree(
Code,
AST);
645 ASSERT_EQ(
"CXXRecordDecl", nodeKind(
T.commonAncestor())) <<
T;
646 auto *D = dyn_cast<CXXRecordDecl>(
T.commonAncestor()->ASTNode.get<
Decl>());
647 EXPECT_FALSE(D->isInjectedClassName());
650TEST(SelectionTree, Metrics) {
651 const char *
Code = R
"cpp(
652 // error-ok: testing behavior on recovery expression
658 trace::TestTracer Tracer;
659 auto T = makeSelectionTree(
Code,
AST);
660 EXPECT_THAT(Tracer.takeMetric(
"selection_recovery",
"C++"),
661 ElementsAreArray({1}));
662 EXPECT_THAT(Tracer.takeMetric(
"selection_recovery_type",
"C++"),
663 ElementsAreArray({1}));
673 const char *Cases[] = {
674 R
"cpp( int abc, xyz = [[^ab^c]]; )cpp",
675 R"cpp( int abc, xyz = [[a^bc^]]; )cpp",
676 R"cpp( int abc, xyz = $C[[^abc^]]; )cpp",
679 [[if ([[1^11]]) $C[[{
688 struct unique_ptr {};
689 void foo(^$C[[unique_ptr<$C[[unique_ptr<$C[[int]]>]]>]]^ a) {}
691 R"cpp(int a = [[5 >^> 1]];)cpp",
694 ECHO(EC^HO($C[[int]]) EC^HO(a));
696 R"cpp( $C[[^$C[[int]] a^]]; )cpp",
697 R"cpp( $C[[^$C[[int]] a = $C[[5]]^]]; )cpp",
699 for (
const char *
C : Cases) {
702 auto T = makeSelectionTree(
C,
AST);
704 std::vector<Range> Complete, Partial;
705 for (
const SelectionTree::Node *N : allNodes(T))
707 Complete.push_back(nodeRange(N,
AST));
709 Partial.push_back(nodeRange(N,
AST));
710 EXPECT_THAT(Complete, UnorderedElementsAreArray(Test.ranges(
"C"))) <<
C;
711 EXPECT_THAT(Partial, UnorderedElementsAreArray(Test.ranges())) <<
C;
715TEST(SelectionTest, PathologicalPreprocessor) {
716 const char *Case = R
"cpp(
717#define MACRO while(1)
723 Annotations Test(Case);
725 TU.AdditionalFiles[
"Expand.inc"] =
"MACRO\n";
726 auto AST = TU.build();
727 EXPECT_THAT(
AST.getDiagnostics(), ::testing::IsEmpty());
728 auto T = makeSelectionTree(Case,
AST);
730 EXPECT_EQ(
"BreakStmt",
T.commonAncestor()->kind());
731 EXPECT_EQ(
"WhileStmt",
T.commonAncestor()->Parent->kind());
734TEST(SelectionTest, IncludedFile) {
735 const char *Case = R
"cpp(
737#include "Exp^and.inc"
741 Annotations Test(Case);
743 TU.AdditionalFiles[
"Expand.inc"] =
"while(1)\n";
744 auto AST = TU.build();
745 auto T = makeSelectionTree(Case,
AST);
747 EXPECT_EQ(
nullptr,
T.commonAncestor());
750TEST(SelectionTest, MacroArgExpansion) {
753 const char *Case = R
"cpp(
755 #define SQUARE(X) mul(X, X);
756 int nine = SQUARE(^3);
758 Annotations Test(Case);
760 auto T = makeSelectionTree(Case,
AST);
761 EXPECT_EQ(
"IntegerLiteral",
T.commonAncestor()->kind());
762 EXPECT_TRUE(
T.commonAncestor()->Selected);
767 void die(const char*);
768 #define assert(x) (x ? (void)0 : die(#x))
769 void foo() { assert(^42); }
771 Test = Annotations(Case);
773 T = makeSelectionTree(Case, AST);
774 EXPECT_EQ("IntegerLiteral",
T.commonAncestor()->kind());
781 template <typename T> class S {};
787 Test = Annotations(Case);
789 T = makeSelectionTree(Case, AST);
791 EXPECT_EQ(
"VarDecl",
T.commonAncestor()->kind());
794TEST(SelectionTest, Implicit) {
795 const char *Test = R
"cpp(
796 struct S { S(const char*); };
802 TU.ExtraArgs.push_back(
"-std=c++17");
803 auto AST = TU.build();
804 auto T = makeSelectionTree(Test,
AST);
806 const SelectionTree::Node *Str =
T.commonAncestor();
807 EXPECT_EQ(
"StringLiteral", nodeKind(Str)) <<
"Implicit selected?";
808 EXPECT_EQ(
"ImplicitCastExpr", nodeKind(Str->Parent));
809 EXPECT_EQ(
"CXXConstructExpr", nodeKind(Str->Parent->Parent));
810 const SelectionTree::Node *ICE = Str->Parent->Parent->Parent;
811 EXPECT_EQ(
"ImplicitCastExpr", nodeKind(ICE));
812 EXPECT_EQ(
"CallExpr", nodeKind(ICE->Parent));
813 EXPECT_EQ(Str, &ICE->ignoreImplicit())
814 <<
"Didn't unwrap " << nodeKind(&ICE->ignoreImplicit());
816 EXPECT_EQ(ICE, &Str->outerImplicit());
819TEST(SelectionTest, CreateAll) {
820 llvm::Annotations Test(
"int$unique^ a=1$ambiguous^+1; $empty^");
824 AST.getASTContext(),
AST.getTokens(), Test.point(
"ambiguous"),
825 Test.point(
"ambiguous"), [&](SelectionTree T) {
828 EXPECT_EQ(
"BinaryOperator", nodeKind(T.commonAncestor()));
829 }
else if (Seen == 1) {
830 EXPECT_EQ(
"IntegerLiteral", nodeKind(
T.commonAncestor()));
839 Test.point(
"ambiguous"), Test.point(
"ambiguous"),
840 [&](SelectionTree T) {
844 EXPECT_EQ(1u, Seen) <<
"Return true --> stop iterating";
848 Test.point(
"unique"), Test.point(
"unique"),
849 [&](SelectionTree T) {
853 EXPECT_EQ(1u, Seen) <<
"no ambiguity --> only one tree";
857 Test.point(
"empty"), Test.point(
"empty"),
858 [&](SelectionTree T) {
859 EXPECT_FALSE(T.commonAncestor());
863 EXPECT_EQ(1u, Seen) <<
"empty tree still created";
867 Test.point(
"unique"), Test.point(
"ambiguous"),
868 [&](SelectionTree T) {
872 EXPECT_EQ(1u, Seen) <<
"one tree for nontrivial selection";
875TEST(SelectionTest, DeclContextIsLexical) {
876 llvm::Annotations Test(
"namespace a { void $1^foo(); } void a::$2^foo();");
880 Test.point(
"1"), Test.point(
"1"));
881 EXPECT_FALSE(ST.commonAncestor()->getDeclContext().isTranslationUnit());
885 Test.point(
"2"), Test.point(
"2"));
886 EXPECT_TRUE(ST.commonAncestor()->getDeclContext().isTranslationUnit());
890TEST(SelectionTest, DeclContextLambda) {
891 llvm::Annotations Test(R
"cpp(
899 Test.point(
"1"), Test.point(
"1"));
900 EXPECT_TRUE(ST.commonAncestor()->getDeclContext().isFunctionOrMethod());
903TEST(SelectionTest, UsingConcepts) {
904 llvm::Annotations Test(R
"cpp(
912template <Fo^o... T, Fo^o auto U>
913auto Func(Fo^o auto V) -> Fo^o decltype(auto) {
919 TU.ExtraArgs.emplace_back(
"-std=c++2c");
920 auto AST = TU.build();
921 for (
auto Point : Test.points()) {
924 auto *
C = ST.commonAncestor()->ASTNode.get<ConceptReference>();
925 EXPECT_TRUE(
C &&
C->getFoundDecl() &&
926 C->getFoundDecl()->getKind() == Decl::UsingShadow);
const FunctionDecl * Decl
CharSourceRange Range
SourceRange for the file name.
SelectionTree::Selection Selected
static bool createEach(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End, llvm::function_ref< bool(SelectionTree)> Func)
static SelectionTree createRight(ASTContext &AST, const syntax::TokenBuffer &Tokens, unsigned Begin, unsigned End)
std::optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
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.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static TestTU withCode(llvm::StringRef Code)