1 //===-- SelectionTests.cpp - ----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "Annotations.h"
9 #include "Selection.h"
10 #include "SourceCode.h"
11 #include "TestTU.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
14 
15 namespace clang {
16 namespace clangd {
17 namespace {
18 using ::testing::UnorderedElementsAreArray;
19 
makeSelectionTree(const StringRef MarkedCode,ParsedAST & AST)20 SelectionTree makeSelectionTree(const StringRef MarkedCode, ParsedAST &AST) {
21   Annotations Test(MarkedCode);
22   switch (Test.points().size()) {
23   case 1: // Point selection.
24     return SelectionTree(AST.getASTContext(),
25                          cantFail(positionToOffset(Test.code(), Test.point())));
26   case 2: // Range selection.
27     return SelectionTree(
28         AST.getASTContext(),
29         cantFail(positionToOffset(Test.code(), Test.points()[0])),
30         cantFail(positionToOffset(Test.code(), Test.points()[1])));
31   default:
32     ADD_FAILURE() << "Expected 1-2 points for selection.\n" << MarkedCode;
33     return SelectionTree(AST.getASTContext(), 0u, 0u);
34   }
35 }
36 
nodeRange(const SelectionTree::Node * N,ParsedAST & AST)37 Range nodeRange(const SelectionTree::Node *N, ParsedAST &AST) {
38   if (!N)
39     return Range{};
40   SourceManager &SM = AST.getSourceManager();
41   StringRef Buffer = SM.getBufferData(SM.getMainFileID());
42   SourceRange SR = N->ASTNode.getSourceRange();
43   SR.setBegin(SM.getFileLoc(SR.getBegin()));
44   SR.setEnd(SM.getFileLoc(SR.getEnd()));
45   CharSourceRange R =
46       Lexer::getAsCharRange(SR, SM, AST.getASTContext().getLangOpts());
47   return Range{offsetToPosition(Buffer, SM.getFileOffset(R.getBegin())),
48                offsetToPosition(Buffer, SM.getFileOffset(R.getEnd()))};
49 }
50 
nodeKind(const SelectionTree::Node * N)51 std::string nodeKind(const SelectionTree::Node *N) {
52   if (!N)
53     return "<null>";
54   return N->ASTNode.getNodeKind().asStringRef().str();
55 }
56 
allNodes(const SelectionTree & T)57 std::vector<const SelectionTree::Node *> allNodes(const SelectionTree &T) {
58   std::vector<const SelectionTree::Node *> Result = {T.root()};
59   for (unsigned I = 0; I < Result.size(); ++I) {
60     const SelectionTree::Node *N = Result[I];
61     Result.insert(Result.end(), N->Children.begin(), N->Children.end());
62   }
63   return Result;
64 }
65 
66 // Returns true if Common is a descendent of Root.
67 // Verifies nothing is selected above Common.
verifyCommonAncestor(const SelectionTree::Node * Root,const SelectionTree::Node * Common,StringRef MarkedCode)68 bool verifyCommonAncestor(const SelectionTree::Node *Root,
69                           const SelectionTree::Node *Common,
70                           StringRef MarkedCode) {
71   if (Root == Common)
72     return true;
73   if (Root->Selected)
74     ADD_FAILURE() << "Selected nodes outside common ancestor\n" << MarkedCode;
75   bool Seen = false;
76   for (const SelectionTree::Node *Child : Root->Children)
77     if (verifyCommonAncestor(Child, Common, MarkedCode)) {
78       if (Seen)
79         ADD_FAILURE() << "Saw common ancestor twice\n" << MarkedCode;
80       Seen = true;
81     }
82   return Seen;
83 }
84 
TEST(SelectionTest,CommonAncestor)85 TEST(SelectionTest, CommonAncestor) {
86   struct Case {
87     // Selection is between ^marks^.
88     // common ancestor marked with a [[range]].
89     const char *Code;
90     const char *CommonAncestorKind;
91   };
92   Case Cases[] = {
93       {
94           R"cpp(
95             template <typename T>
96             int x = [[T::^U::]]ccc();
97           )cpp",
98           "NestedNameSpecifierLoc",
99       },
100       {
101           R"cpp(
102             struct AAA { struct BBB { static int ccc(); };};
103             int x = AAA::[[B^B^B]]::ccc();
104           )cpp",
105           "TypeLoc",
106       },
107       {
108           R"cpp(
109             struct AAA { struct BBB { static int ccc(); };};
110             int x = AAA::[[B^BB^]]::ccc();
111           )cpp",
112           "TypeLoc",
113       },
114       {
115           R"cpp(
116             struct AAA { struct BBB { static int ccc(); };};
117             int x = [[AAA::BBB::c^c^c]]();
118           )cpp",
119           "DeclRefExpr",
120       },
121       {
122           R"cpp(
123             struct AAA { struct BBB { static int ccc(); };};
124             int x = [[AAA::BBB::cc^c(^)]];
125           )cpp",
126           "CallExpr",
127       },
128 
129       {
130           R"cpp(
131             void foo() { [[if (1^11) { return; } else {^ }]] }
132           )cpp",
133           "IfStmt",
134       },
135       {
136           R"cpp(
137             void foo();
138             #define CALL_FUNCTION(X) X()
139             void bar() { CALL_FUNCTION([[f^o^o]]); }
140           )cpp",
141           "DeclRefExpr",
142       },
143       {
144           R"cpp(
145             void foo();
146             #define CALL_FUNCTION(X) X()
147             void bar() [[{ CALL_FUNC^TION(fo^o); }]]
148           )cpp",
149           "CompoundStmt",
150       },
151       {
152           R"cpp(
153             void foo();
154             #define CALL_FUNCTION(X) X()
155             void bar() [[{ C^ALL_FUNC^TION(foo); }]]
156           )cpp",
157           "CompoundStmt",
158       },
159       {
160           R"cpp(
161             void foo();
162             #define CALL_FUNCTION(X) X^()^
163             void bar() { CALL_FUNCTION(foo); }
164           )cpp",
165           nullptr,
166       },
167       {
168           R"cpp(
169             struct S { S(const char*); };
170             S [[s ^= "foo"]];
171           )cpp",
172           "CXXConstructExpr",
173       },
174       {
175           R"cpp(
176             struct S { S(const char*); };
177             [[S ^s = "foo"]];
178           )cpp",
179           "VarDecl",
180       },
181       {
182           R"cpp(
183             [[^void]] (*S)(int) = nullptr;
184           )cpp",
185           "TypeLoc",
186       },
187       {
188           R"cpp(
189             [[void (*S)^(int)]] = nullptr;
190           )cpp",
191           "TypeLoc",
192       },
193       {
194           R"cpp(
195             [[void (^*S)(int)]] = nullptr;
196           )cpp",
197           "TypeLoc",
198       },
199       {
200           R"cpp(
201             [[void (*^S)(int) = nullptr]];
202           )cpp",
203           "VarDecl",
204       },
205       {
206           R"cpp(
207             [[void ^(*S)(int)]] = nullptr;
208           )cpp",
209           "TypeLoc",
210       },
211 
212       // Point selections.
213       {"void foo() { [[^foo]](); }", "DeclRefExpr"},
214       {"void foo() { [[f^oo]](); }", "DeclRefExpr"},
215       {"void foo() { [[fo^o]](); }", "DeclRefExpr"},
216       {"void foo() { [[foo^()]]; }", "CallExpr"},
217       {"void foo() { [[foo^]] (); }", "DeclRefExpr"},
218       {"int bar; void foo() [[{ foo (); }]]^", "CompoundStmt"},
219 
220       // Tricky case: FunctionTypeLoc in FunctionDecl has a hole in it.
221       {"[[^void]] foo();", "TypeLoc"},
222       {"[[void foo^()]];", "TypeLoc"},
223       {"[[^void foo^()]];", "FunctionDecl"},
224       {"[[void ^foo()]];", "FunctionDecl"},
225       // Tricky case: two VarDecls share a specifier.
226       {"[[int ^a]], b;", "VarDecl"},
227       {"[[int a, ^b]];", "VarDecl"},
228       // Tricky case: anonymous struct is a sibling of the VarDecl.
229       {"[[st^ruct {int x;}]] y;", "CXXRecordDecl"},
230       {"[[struct {int x;} ^y]];", "VarDecl"},
231       {"struct {[[int ^x]];} y;", "FieldDecl"},
232 
233       {"^", nullptr},
234       {"void foo() { [[foo^^]] (); }", "DeclRefExpr"},
235 
236       // FIXME: Ideally we'd get a declstmt or the VarDecl itself here.
237       // This doesn't happen now; the RAV doesn't traverse a node containing ;.
238       {"int x = 42;^", nullptr},
239       {"int x = 42^;", nullptr},
240 
241       // Node types that have caused problems in the past.
242       {"template <typename T> void foo() { [[^T]] t; }", "TypeLoc"},
243 
244       // No crash
245       {
246           R"cpp(
247             template <class T> struct Foo {};
248             template <[[template<class> class /*cursor here*/^U]]>
249              struct Foo<U<int>*> {};
250           )cpp",
251           "TemplateTemplateParmDecl"},
252   };
253   for (const Case &C : Cases) {
254     Annotations Test(C.Code);
255     auto AST = TestTU::withCode(Test.code()).build();
256     auto T = makeSelectionTree(C.Code, AST);
257 
258     if (Test.ranges().empty()) {
259       // If no [[range]] is marked in the example, there should be no selection.
260       EXPECT_FALSE(T.commonAncestor()) << C.Code << "\n" << T;
261       EXPECT_FALSE(T.root()) << C.Code << "\n" << T;
262     } else {
263       // If there is an expected selection, both common ancestor and root
264       // should exist with the appropriate node types in them.
265       EXPECT_EQ(C.CommonAncestorKind, nodeKind(T.commonAncestor()))
266           << C.Code << "\n"
267           << T;
268       EXPECT_EQ("TranslationUnitDecl", nodeKind(T.root())) << C.Code;
269       // Convert the reported common ancestor to a range and verify it.
270       EXPECT_EQ(nodeRange(T.commonAncestor(), AST), Test.range())
271           << C.Code << "\n"
272           << T;
273 
274       // Check that common ancestor is reachable on exactly one path from root,
275       // and no nodes outside it are selected.
276       EXPECT_TRUE(verifyCommonAncestor(T.root(), T.commonAncestor(), C.Code))
277           << C.Code;
278     }
279   }
280 }
281 
282 // Regression test: this used to match the injected X, not the outer X.
TEST(SelectionTest,InjectedClassName)283 TEST(SelectionTest, InjectedClassName) {
284   const char* Code = "struct ^X { int x; };";
285   auto AST = TestTU::withCode(Annotations(Code).code()).build();
286   auto T = makeSelectionTree(Code, AST);
287   ASSERT_EQ("CXXRecordDecl", nodeKind(T.commonAncestor())) << T;
288   auto *D = dyn_cast<CXXRecordDecl>(T.commonAncestor()->ASTNode.get<Decl>());
289   EXPECT_FALSE(D->isInjectedClassName());
290 }
291 
TEST(SelectionTest,Selected)292 TEST(SelectionTest, Selected) {
293   // Selection with ^marks^.
294   // Partially selected nodes marked with a [[range]].
295   // Completely selected nodes marked with a $C[[range]].
296   const char *Cases[] = {
297       R"cpp( int abc, xyz = [[^ab^c]]; )cpp",
298       R"cpp( int abc, xyz = [[a^bc^]]; )cpp",
299       R"cpp( int abc, xyz = $C[[^abc^]]; )cpp",
300       R"cpp(
301         void foo() {
302           [[if ([[1^11]]) $C[[{
303             $C[[return]];
304           }]] else [[{^
305           }]]]]
306         }
307       )cpp",
308       R"cpp(
309           template <class T>
310           struct unique_ptr {};
311           void foo(^$C[[unique_ptr<unique_ptr<$C[[int]]>>]]^ a) {}
312       )cpp",
313   };
314   for (const char *C : Cases) {
315     Annotations Test(C);
316     auto AST = TestTU::withCode(Test.code()).build();
317     auto T = makeSelectionTree(C, AST);
318 
319     std::vector<Range> Complete, Partial;
320     for (const SelectionTree::Node *N : allNodes(T))
321       if (N->Selected == SelectionTree::Complete)
322         Complete.push_back(nodeRange(N, AST));
323       else if (N->Selected == SelectionTree::Partial)
324         Partial.push_back(nodeRange(N, AST));
325     EXPECT_THAT(Complete, UnorderedElementsAreArray(Test.ranges("C"))) << C;
326     EXPECT_THAT(Partial, UnorderedElementsAreArray(Test.ranges())) << C;
327   }
328 }
329 
330 } // namespace
331 } // namespace clangd
332 } // namespace clang
333