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