clang-tools  14.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 "Matchers.h"
12 #include "Protocol.h"
13 #include "SemanticSelection.h"
14 #include "SourceCode.h"
15 #include "SyncAPI.h"
16 #include "TestFS.h"
17 #include "TestTU.h"
18 #include "clang/Basic/SourceLocation.h"
19 #include "clang/Basic/SourceManager.h"
20 #include "llvm/ADT/ArrayRef.h"
21 #include "llvm/Support/Error.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include <vector>
25 
26 namespace clang {
27 namespace clangd {
28 namespace {
29 
30 using ::testing::ElementsAre;
31 using ::testing::ElementsAreArray;
32 using ::testing::UnorderedElementsAreArray;
33 
34 // front() is SR.range, back() is outermost range.
35 std::vector<Range> gatherRanges(const SelectionRange &SR) {
36  std::vector<Range> Ranges;
37  for (const SelectionRange *S = &SR; S; S = S->parent.get())
38  Ranges.push_back(S->range);
39  return Ranges;
40 }
41 
42 std::vector<Range>
43 gatherFoldingRanges(llvm::ArrayRef<FoldingRange> FoldingRanges) {
44  std::vector<Range> Ranges;
45  Range NextRange;
46  for (const auto &R : FoldingRanges) {
47  NextRange.start.line = R.startLine;
48  NextRange.start.character = R.startCharacter;
49  NextRange.end.line = R.endLine;
50  NextRange.end.character = R.endCharacter;
51  Ranges.push_back(NextRange);
52  }
53  return Ranges;
54 }
55 
56 TEST(SemanticSelection, All) {
57  const char *Tests[] = {
58  R"cpp( // Single statement in a function body.
59  [[void func() [[{
60  [[[[int v = [[1^00]]]];]]
61  }]]]]
62  )cpp",
63  R"cpp( // Expression
64  [[void func() [[{
65  int a = 1;
66  // int v = (10 + 2) * (a + a);
67  [[[[int v = [[[[([[[[10^]] + 2]])]] * (a + a)]]]];]]
68  }]]]]
69  )cpp",
70  R"cpp( // Function call.
71  int add(int x, int y) { return x + y; }
72  [[void callee() [[{
73  // int res = add(11, 22);
74  [[[[int res = [[add([[1^1]], 22)]]]];]]
75  }]]]]
76  )cpp",
77  R"cpp( // Tricky macros.
78  #define MUL ) * (
79  [[void func() [[{
80  // int var = (4 + 15 MUL 6 + 10);
81  [[[[int var = [[[[([[4 + [[1^5]]]] MUL]] 6 + 10)]]]];]]
82  }]]]]
83  )cpp",
84  R"cpp( // Cursor inside a macro.
85  #define HASH(x) ((x) % 10)
86  [[void func() [[{
87  [[[[int a = [[HASH([[[[2^3]] + 34]])]]]];]]
88  }]]]]
89  )cpp",
90  R"cpp( // Cursor on a macro.
91  #define HASH(x) ((x) % 10)
92  [[void func() [[{
93  [[[[int a = [[HA^SH(23)]]]];]]
94  }]]]]
95  )cpp",
96  R"cpp( // Multiple declaration.
97  [[void func() [[{
98  [[[[int var1, var^2]], var3;]]
99  }]]]]
100  )cpp",
101  R"cpp( // Before comment.
102  [[void func() [[{
103  int var1 = 1;
104  [[[[int var2 = [[[[var1]]^ /*some comment*/ + 41]]]];]]
105  }]]]]
106  )cpp",
107  // Empty file.
108  "[[^]]",
109  // FIXME: We should get the whole DeclStmt as a range.
110  R"cpp( // Single statement in TU.
111  [[int v = [[1^00]]]];
112  )cpp",
113  R"cpp( // Cursor at end of VarDecl.
114  [[int v = [[100]]^]];
115  )cpp",
116  // FIXME: No node found associated to the position.
117  R"cpp( // Cursor in between spaces.
118  void func() {
119  int v = 100 + [[^]] 100;
120  }
121  )cpp",
122  // Structs.
123  R"cpp(
124  struct AAA { struct BBB { static int ccc(); };};
125  [[void func() [[{
126  // int x = AAA::BBB::ccc();
127  [[[[int x = [[[[AAA::BBB::c^cc]]()]]]];]]
128  }]]]]
129  )cpp",
130  R"cpp(
131  struct AAA { struct BBB { static int ccc(); };};
132  [[void func() [[{
133  // int x = AAA::BBB::ccc();
134  [[[[int x = [[[[[[[[[[AA^A]]::]]BBB::]]ccc]]()]]]];]]
135  }]]]]
136  )cpp",
137  R"cpp( // Inside struct.
138  struct A { static int a(); };
139  [[struct B {
140  [[static int b() [[{
141  [[return [[[[1^1]] + 2]]]];
142  }]]]]
143  }]];
144  )cpp",
145  // Namespaces.
146  R"cpp(
147  [[namespace nsa {
148  [[namespace nsb {
149  static int ccc();
150  [[void func() [[{
151  // int x = nsa::nsb::ccc();
152  [[[[int x = [[[[nsa::nsb::cc^c]]()]]]];]]
153  }]]]]
154  }]]
155  }]]
156  )cpp",
157 
158  };
159 
160  for (const char *Test : Tests) {
161  auto T = Annotations(Test);
162  auto AST = TestTU::withCode(T.code()).build();
163  EXPECT_THAT(gatherRanges(llvm::cantFail(getSemanticRanges(AST, T.point()))),
164  ElementsAreArray(T.ranges()))
165  << Test;
166  }
167 }
168 
169 TEST(SemanticSelection, RunViaClangdServer) {
170  MockFS FS;
171  MockCompilationDatabase CDB;
172  ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
173 
174  auto FooH = testPath("foo.h");
175  FS.Files[FooH] = R"cpp(
176  int foo(int x);
177  #define HASH(x) ((x) % 10)
178  )cpp";
179 
180  auto FooCpp = testPath("Foo.cpp");
181  const char *SourceContents = R"cpp(
182  #include "foo.h"
183  [[void bar(int& inp) [[{
184  // inp = HASH(foo(inp));
185  [[inp = [[HASH([[foo([[in^p]])]])]]]];
186  }]]]]
187  $empty[[^]]
188  )cpp";
189  Annotations SourceAnnotations(SourceContents);
190  FS.Files[FooCpp] = std::string(SourceAnnotations.code());
191  Server.addDocument(FooCpp, SourceAnnotations.code());
192 
193  auto Ranges = runSemanticRanges(Server, FooCpp, SourceAnnotations.points());
194  ASSERT_TRUE(bool(Ranges))
195  << "getSemanticRange returned an error: " << Ranges.takeError();
196  ASSERT_EQ(Ranges->size(), SourceAnnotations.points().size());
197  EXPECT_THAT(gatherRanges(Ranges->front()),
198  ElementsAreArray(SourceAnnotations.ranges()));
199  EXPECT_THAT(gatherRanges(Ranges->back()),
200  ElementsAre(SourceAnnotations.range("empty")));
201 }
202 
203 TEST(FoldingRanges, All) {
204  const char *Tests[] = {
205  R"cpp(
206  #define FOO int foo() {\
207  int Variable = 42; \
208  }
209 
210  // Do not generate folding range for braces within macro expansion.
211  FOO
212 
213  // Do not generate folding range within macro arguments.
214  #define FUNCTOR(functor) functor
215  void func() {[[
216  FUNCTOR([](){});
217  ]]}
218 
219  // Do not generate folding range with a brace coming from macro.
220  #define LBRACE {
221  void bar() LBRACE
222  int X = 42;
223  }
224  )cpp",
225  R"cpp(
226  void func() {[[
227  int Variable = 100;
228 
229  if (Variable > 5) {[[
230  Variable += 42;
231  ]]} else if (Variable++)
232  ++Variable;
233  else {[[
234  Variable--;
235  ]]}
236 
237  // Do not generate FoldingRange for empty CompoundStmts.
238  for (;;) {}
239 
240  // If there are newlines between {}, we should generate one.
241  for (;;) {[[
242 
243  ]]}
244  ]]}
245  )cpp",
246  R"cpp(
247  class Foo {
248  public:
249  Foo() {[[
250  int X = 1;
251  ]]}
252 
253  private:
254  int getBar() {[[
255  return 42;
256  ]]}
257 
258  // Braces are located at the same line: no folding range here.
259  void getFooBar() { }
260  };
261  )cpp",
262  };
263  for (const char *Test : Tests) {
264  auto T = Annotations(Test);
265  auto AST = TestTU::withCode(T.code()).build();
266  EXPECT_THAT(gatherFoldingRanges(llvm::cantFail(getFoldingRanges(AST))),
267  UnorderedElementsAreArray(T.ranges()))
268  << Test;
269  }
270 }
271 
272 } // namespace
273 } // namespace clangd
274 } // namespace clang
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:38
clang::clangd::TEST
TEST(BackgroundQueueTest, Priority)
Definition: BackgroundIndexTests.cpp:751
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:161
clang::clangd::testPath
std::string testPath(PathRef File, llvm::sys::path::Style Style)
Definition: TestFS.cpp:82
clang::clangd::TestTU::build
ParsedAST build() const
Definition: TestTU.cpp:109
TestTU.h
clang::clangd::ClangdServer::optsForTest
static Options optsForTest()
Definition: ClangdServer.cpp:135
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:103
clang::clangd::runSemanticRanges
llvm::Expected< std::vector< SelectionRange > > runSemanticRanges(ClangdServer &Server, PathRef File, const std::vector< Position > &Pos)
Definition: SyncAPI.cpp:146
Protocol.h
SemanticSelection.h
TestFS.h
SyncAPI.h
clang::clangd::TestTU::withCode
static TestTU withCode(llvm::StringRef Code)
Definition: TestTU.h:37
Annotations.h
SourceCode.h
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
ClangdServer.h
Matchers.h