clang-tools  15.0.0git
SemanticSelectionTests.cpp
Go to the documentation of this file.
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 //===----------------------------------------------------------------------===//
8 
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>
21 
22 namespace clang {
23 namespace clangd {
24 namespace {
25 
26 using ::testing::ElementsAre;
27 using ::testing::ElementsAreArray;
28 using ::testing::UnorderedElementsAreArray;
29 
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;
36 }
37 
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);
48  }
49  return Ranges;
50 }
51 
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;
116  }
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  }]]]]
150  }]]
151  }]]
152  )cpp",
153 
154  };
155 
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;
162  }
163 }
164 
165 TEST(SemanticSelection, RunViaClangdServer) {
166  MockFS FS;
167  MockCompilationDatabase CDB;
168  ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
169 
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";
175 
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());
188 
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")));
197 }
198 
199 TEST(FoldingRanges, All) {
200  const char *Tests[] = {
201  R"cpp(
202  #define FOO int foo() {\
203  int Variable = 42; \
204  }
205 
206  // Do not generate folding range for braces within macro expansion.
207  FOO
208 
209  // Do not generate folding range within macro arguments.
210  #define FUNCTOR(functor) functor
211  void func() {[[
212  FUNCTOR([](){});
213  ]]}
214 
215  // Do not generate folding range with a brace coming from macro.
216  #define LBRACE {
217  void bar() LBRACE
218  int X = 42;
219  }
220  )cpp",
221  R"cpp(
222  void func() {[[
223  int Variable = 100;
224 
225  if (Variable > 5) {[[
226  Variable += 42;
227  ]]} else if (Variable++)
228  ++Variable;
229  else {[[
230  Variable--;
231  ]]}
232 
233  // Do not generate FoldingRange for empty CompoundStmts.
234  for (;;) {}
235 
236  // If there are newlines between {}, we should generate one.
237  for (;;) {[[
238 
239  ]]}
240  ]]}
241  )cpp",
242  R"cpp(
243  class Foo {
244  public:
245  Foo() {[[
246  int X = 1;
247  ]]}
248 
249  private:
250  int getBar() {[[
251  return 42;
252  ]]}
253 
254  // Braces are located at the same line: no folding range here.
255  void getFooBar() { }
256  };
257  )cpp",
258  };
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;
265  }
266 }
267 
268 } // namespace
269 } // namespace clangd
270 } // namespace clang
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
clang::clangd::TEST
TEST(BackgroundQueueTest, Priority)
Definition: BackgroundIndexTests.cpp:750
clang::clangd::getFoldingRanges
llvm::Expected< std::vector< FoldingRange > > getFoldingRanges(ParsedAST &AST)
Returns a list of ranges whose contents might be collapsible in an editor.
Definition: SemanticSelection.cpp:159
clang::clangd::testPath
std::string testPath(PathRef File, llvm::sys::path::Style Style)
Definition: TestFS.cpp:94
clang::clangd::TestTU::build
ParsedAST build() const
Definition: TestTU.cpp:109
TestTU.h
clang::clangd::ClangdServer::optsForTest
static Options optsForTest()
Definition: ClangdServer.cpp:154
clang::clangd::getSemanticRanges
llvm::Expected< SelectionRange > getSemanticRanges(ParsedAST &AST, Position Pos)
Returns the list of all interesting ranges around the Position Pos.
Definition: SemanticSelection.cpp:101
clang::clangd::runSemanticRanges
llvm::Expected< std::vector< SelectionRange > > runSemanticRanges(ClangdServer &Server, PathRef File, const std::vector< Position > &Pos)
Definition: SyncAPI.cpp:148
Protocol.h
SemanticSelection.h
TestFS.h
SyncAPI.h
clang::clangd::TestTU::withCode
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:36
Annotations.h
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
ClangdServer.h