Bump version to 19.1.0git
[llvm-project.git] / clang-tools-extra / clangd / unittests / SemanticSelectionTests.cpp
blob7faef6f95d8f944b3581487f149fa4fd29a574a7
1 //===-- SemanticSelectionTests.cpp ----------------*- C++ -*--------------===//
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 //===----------------------------------------------------------------------===//
9 #include "Annotations.h"
10 #include "ClangdServer.h"
11 #include "Protocol.h"
12 #include "SemanticSelection.h"
13 #include "SyncAPI.h"
14 #include "TestFS.h"
15 #include "TestTU.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/Support/Error.h"
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20 #include <vector>
22 namespace clang {
23 namespace clangd {
24 namespace {
26 using ::testing::ElementsAre;
27 using ::testing::ElementsAreArray;
28 using ::testing::UnorderedElementsAreArray;
30 // front() is SR.range, back() is outermost range.
31 std::vector<Range> gatherRanges(const SelectionRange &SR) {
32 std::vector<Range> Ranges;
33 for (const SelectionRange *S = &SR; S; S = S->parent.get())
34 Ranges.push_back(S->range);
35 return Ranges;
38 std::vector<Range>
39 gatherFoldingRanges(llvm::ArrayRef<FoldingRange> FoldingRanges) {
40 std::vector<Range> Ranges;
41 Range NextRange;
42 for (const auto &R : FoldingRanges) {
43 NextRange.start.line = R.startLine;
44 NextRange.start.character = R.startCharacter;
45 NextRange.end.line = R.endLine;
46 NextRange.end.character = R.endCharacter;
47 Ranges.push_back(NextRange);
49 return Ranges;
52 TEST(SemanticSelection, All) {
53 const char *Tests[] = {
54 R"cpp( // Single statement in a function body.
55 [[void func() [[{
56 [[[[int v = [[1^00]]]];]]
57 }]]]]
58 )cpp",
59 R"cpp( // Expression
60 [[void func() [[{
61 int a = 1;
62 // int v = (10 + 2) * (a + a);
63 [[[[int v = [[[[([[[[10^]] + 2]])]] * (a + a)]]]];]]
64 }]]]]
65 )cpp",
66 R"cpp( // Function call.
67 int add(int x, int y) { return x + y; }
68 [[void callee() [[{
69 // int res = add(11, 22);
70 [[[[int res = [[add([[1^1]], 22)]]]];]]
71 }]]]]
72 )cpp",
73 R"cpp( // Tricky macros.
74 #define MUL ) * (
75 [[void func() [[{
76 // int var = (4 + 15 MUL 6 + 10);
77 [[[[int var = [[[[([[4 + [[1^5]]]] MUL]] 6 + 10)]]]];]]
78 }]]]]
79 )cpp",
80 R"cpp( // Cursor inside a macro.
81 #define HASH(x) ((x) % 10)
82 [[void func() [[{
83 [[[[int a = [[HASH([[[[2^3]] + 34]])]]]];]]
84 }]]]]
85 )cpp",
86 R"cpp( // Cursor on a macro.
87 #define HASH(x) ((x) % 10)
88 [[void func() [[{
89 [[[[int a = [[HA^SH(23)]]]];]]
90 }]]]]
91 )cpp",
92 R"cpp( // Multiple declaration.
93 [[void func() [[{
94 [[[[int var1, var^2]], var3;]]
95 }]]]]
96 )cpp",
97 R"cpp( // Before comment.
98 [[void func() [[{
99 int var1 = 1;
100 [[[[int var2 = [[[[var1]]^ /*some comment*/ + 41]]]];]]
101 }]]]]
102 )cpp",
103 // Empty file.
104 "[[^]]",
105 // FIXME: We should get the whole DeclStmt as a range.
106 R"cpp( // Single statement in TU.
107 [[int v = [[1^00]]]];
108 )cpp",
109 R"cpp( // Cursor at end of VarDecl.
110 [[int v = [[100]]^]];
111 )cpp",
112 // FIXME: No node found associated to the position.
113 R"cpp( // Cursor in between spaces.
114 void func() {
115 int v = 100 + [[^]] 100;
117 )cpp",
118 // Structs.
119 R"cpp(
120 struct AAA { struct BBB { static int ccc(); };};
121 [[void func() [[{
122 // int x = AAA::BBB::ccc();
123 [[[[int x = [[[[AAA::BBB::c^cc]]()]]]];]]
124 }]]]]
125 )cpp",
126 R"cpp(
127 struct AAA { struct BBB { static int ccc(); };};
128 [[void func() [[{
129 // int x = AAA::BBB::ccc();
130 [[[[int x = [[[[[[[[[[AA^A]]::]]BBB::]]ccc]]()]]]];]]
131 }]]]]
132 )cpp",
133 R"cpp( // Inside struct.
134 struct A { static int a(); };
135 [[struct B {
136 [[static int b() [[{
137 [[return [[[[1^1]] + 2]]]];
138 }]]]]
139 }]];
140 )cpp",
141 // Namespaces.
142 R"cpp(
143 [[namespace nsa {
144 [[namespace nsb {
145 static int ccc();
146 [[void func() [[{
147 // int x = nsa::nsb::ccc();
148 [[[[int x = [[[[nsa::nsb::cc^c]]()]]]];]]
149 }]]]]
152 )cpp",
156 for (const char *Test : Tests) {
157 auto T = Annotations(Test);
158 auto AST = TestTU::withCode(T.code()).build();
159 EXPECT_THAT(gatherRanges(llvm::cantFail(getSemanticRanges(AST, T.point()))),
160 ElementsAreArray(T.ranges()))
161 << Test;
165 TEST(SemanticSelection, RunViaClangdServer) {
166 MockFS FS;
167 MockCompilationDatabase CDB;
168 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
170 auto FooH = testPath("foo.h");
171 FS.Files[FooH] = R"cpp(
172 int foo(int x);
173 #define HASH(x) ((x) % 10)
174 )cpp";
176 auto FooCpp = testPath("Foo.cpp");
177 const char *SourceContents = R"cpp(
178 #include "foo.h"
179 [[void bar(int& inp) [[{
180 // inp = HASH(foo(inp));
181 [[inp = [[HASH([[foo([[in^p]])]])]]]];
182 }]]]]
183 $empty[[^]]
184 )cpp";
185 Annotations SourceAnnotations(SourceContents);
186 FS.Files[FooCpp] = std::string(SourceAnnotations.code());
187 Server.addDocument(FooCpp, SourceAnnotations.code());
189 auto Ranges = runSemanticRanges(Server, FooCpp, SourceAnnotations.points());
190 ASSERT_TRUE(bool(Ranges))
191 << "getSemanticRange returned an error: " << Ranges.takeError();
192 ASSERT_EQ(Ranges->size(), SourceAnnotations.points().size());
193 EXPECT_THAT(gatherRanges(Ranges->front()),
194 ElementsAreArray(SourceAnnotations.ranges()));
195 EXPECT_THAT(gatherRanges(Ranges->back()),
196 ElementsAre(SourceAnnotations.range("empty")));
199 TEST(FoldingRanges, ASTAll) {
200 const char *Tests[] = {
201 R"cpp(
202 #define FOO int foo() {\
203 int Variable = 42; \
206 // Do not generate folding range for braces within macro expansion.
209 // Do not generate folding range within macro arguments.
210 #define FUNCTOR(functor) functor
211 void func() {[[
212 FUNCTOR([](){});
215 // Do not generate folding range with a brace coming from macro.
216 #define LBRACE {
217 void bar() LBRACE
218 int X = 42;
220 )cpp",
221 R"cpp(
222 void func() {[[
223 int Variable = 100;
225 if (Variable > 5) {[[
226 Variable += 42;
227 ]]} else if (Variable++)
228 ++Variable;
229 else {[[
230 Variable--;
233 // Do not generate FoldingRange for empty CompoundStmts.
234 for (;;) {}
236 // If there are newlines between {}, we should generate one.
237 for (;;) {[[
241 )cpp",
242 R"cpp(
243 class Foo {
244 public:
245 Foo() {[[
246 int X = 1;
249 private:
250 int getBar() {[[
251 return 42;
254 // Braces are located at the same line: no folding range here.
255 void getFooBar() { }
257 )cpp",
259 for (const char *Test : Tests) {
260 auto T = Annotations(Test);
261 auto AST = TestTU::withCode(T.code()).build();
262 EXPECT_THAT(gatherFoldingRanges(llvm::cantFail(getFoldingRanges(AST))),
263 UnorderedElementsAreArray(T.ranges()))
264 << Test;
268 TEST(FoldingRanges, PseudoParserWithoutLineFoldings) {
269 const char *Tests[] = {
270 R"cpp(
271 #define FOO int foo() {\
272 int Variable = 42; \
275 // Do not generate folding range for braces within macro expansion.
278 // Do not generate folding range within macro arguments.
279 #define FUNCTOR(functor) functor
280 void func() {[[
281 FUNCTOR([](){});
284 // Do not generate folding range with a brace coming from macro.
285 #define LBRACE {
286 void bar() LBRACE
287 int X = 42;
289 )cpp",
290 R"cpp(
291 void func() {[[
292 int Variable = 100;
294 if (Variable > 5) {[[
295 Variable += 42;
296 ]]} else if (Variable++)
297 ++Variable;
298 else {[[
299 Variable--;
302 // Do not generate FoldingRange for empty CompoundStmts.
303 for (;;) {}
305 // If there are newlines between {}, we should generate one.
306 for (;;) {[[
310 )cpp",
311 R"cpp(
312 class Foo {[[
313 public:
314 Foo() {[[
315 int X = 1;
318 private:
319 int getBar() {[[
320 return 42;
323 // Braces are located at the same line: no folding range here.
324 void getFooBar() { }
325 ]]};
326 )cpp",
327 R"cpp(
328 // Range boundaries on escaped newlines.
329 class Foo \
331 {[[ \
332 public:
333 Foo() {[[\
334 int X = 1;
335 ]]} \
336 ]]};
337 )cpp",
338 R"cpp(
339 /*[[ Multi
340 * line
341 * comment
342 ]]*/
343 )cpp",
344 R"cpp(
345 //[[ Comment
346 // 1]]
348 //[[ Comment
349 // 2]]
351 // No folding for single line comment.
353 /*[[ comment 3
354 ]]*/
356 /*[[ comment 4
357 ]]*/
359 /*[[ foo */
360 /* bar ]]*/
362 /*[[ foo */
363 // baz
364 /* bar ]]*/
366 /*[[ foo */
367 /* bar*/
368 // baz]]
370 //[[ foo
371 /* bar */]]
372 )cpp",
374 for (const char *Test : Tests) {
375 auto T = Annotations(Test);
376 EXPECT_THAT(gatherFoldingRanges(llvm::cantFail(getFoldingRanges(
377 T.code().str(), /*LineFoldingsOnly=*/false))),
378 UnorderedElementsAreArray(T.ranges()))
379 << Test;
383 TEST(FoldingRanges, PseudoParserLineFoldingsOnly) {
384 const char *Tests[] = {
385 R"cpp(
386 void func(int a) {[[
387 a++;]]
389 )cpp",
390 R"cpp(
391 // Always exclude last line for brackets.
392 void func(int a) {[[
393 if(a == 1) {[[
394 a++;]]
395 } else if (a == 2){[[
396 a--;]]
397 } else { // No folding for 2 line bracketed ranges.
400 )cpp",
401 R"cpp(
402 /*[[ comment
403 * comment]]
406 /* No folding for this comment.
409 // No folding for this comment.
411 //[[ 2 single line comment.
412 // 2 single line comment.]]
414 //[[ >=2 line comments.
415 // >=2 line comments.
416 // >=2 line comments.]]
418 //[[ foo\
419 bar\
420 baz]]
422 /*[[ foo */
423 /* bar */]]
424 /* baz */
426 /*[[ foo */
427 /* bar]]
428 * This does not fold me */
430 //[[ foo
431 /* bar */]]
432 )cpp",
433 // FIXME: Support folding template arguments.
434 // R"cpp(
435 // template <[[typename foo, class bar]]> struct baz {};
436 // )cpp",
439 auto StripColumns = [](const std::vector<Range> &Ranges) {
440 std::vector<Range> Res;
441 for (Range R : Ranges) {
442 R.start.character = R.end.character = 0;
443 Res.push_back(R);
445 return Res;
447 for (const char *Test : Tests) {
448 auto T = Annotations(Test);
449 EXPECT_THAT(
450 StripColumns(gatherFoldingRanges(llvm::cantFail(
451 getFoldingRanges(T.code().str(), /*LineFoldingsOnly=*/true)))),
452 UnorderedElementsAreArray(StripColumns(T.ranges())))
453 << Test;
456 } // namespace
457 } // namespace clangd
458 } // namespace clang