1 //=== unittests/Sema/CodeCompleteTest.cpp - Code Complete tests ==============//
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 "clang/Frontend/CompilerInstance.h"
10 #include "clang/Frontend/FrontendActions.h"
11 #include "clang/Lex/Preprocessor.h"
12 #include "clang/Parse/ParseAST.h"
13 #include "clang/Sema/Sema.h"
14 #include "clang/Sema/SemaDiagnostic.h"
15 #include "clang/Tooling/Tooling.h"
16 #include "gmock/gmock.h"
17 #include "gtest/gtest.h"
18 #include <cstddef>
19 #include <string>
20 
21 namespace {
22 
23 using namespace clang;
24 using namespace clang::tooling;
25 using ::testing::Each;
26 using ::testing::UnorderedElementsAre;
27 
28 const char TestCCName[] = "test.cc";
29 
30 struct CompletionContext {
31   std::vector<std::string> VisitedNamespaces;
32   std::string PreferredType;
33   // String representation of std::ptrdiff_t on a given platform. This is a hack
34   // to properly account for different configurations of clang.
35   std::string PtrDiffType;
36 };
37 
38 class VisitedContextFinder : public CodeCompleteConsumer {
39 public:
40   VisitedContextFinder(CompletionContext &ResultCtx)
41       : CodeCompleteConsumer(/*CodeCompleteOpts=*/{}), ResultCtx(ResultCtx),
42         CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}
43 
44   void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
45                                   CodeCompletionResult *Results,
46                                   unsigned NumResults) override {
47     ResultCtx.VisitedNamespaces =
48         getVisitedNamespace(Context.getVisitedContexts());
49     ResultCtx.PreferredType = Context.getPreferredType().getAsString();
50     ResultCtx.PtrDiffType =
51         S.getASTContext().getPointerDiffType().getAsString();
52   }
53 
54   CodeCompletionAllocator &getAllocator() override {
55     return CCTUInfo.getAllocator();
56   }
57 
58   CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
59 
60 private:
61   std::vector<std::string> getVisitedNamespace(
62       CodeCompletionContext::VisitedContextSet VisitedContexts) const {
63     std::vector<std::string> NSNames;
64     for (const auto *Context : VisitedContexts)
65       if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context))
66         NSNames.push_back(NS->getQualifiedNameAsString());
67     return NSNames;
68   }
69 
70   CompletionContext &ResultCtx;
71   CodeCompletionTUInfo CCTUInfo;
72 };
73 
74 class CodeCompleteAction : public SyntaxOnlyAction {
75 public:
76   CodeCompleteAction(ParsedSourceLocation P, CompletionContext &ResultCtx)
77       : CompletePosition(std::move(P)), ResultCtx(ResultCtx) {}
78 
79   bool BeginInvocation(CompilerInstance &CI) override {
80     CI.getFrontendOpts().CodeCompletionAt = CompletePosition;
81     CI.setCodeCompletionConsumer(new VisitedContextFinder(ResultCtx));
82     return true;
83   }
84 
85 private:
86   // 1-based code complete position <Line, Col>;
87   ParsedSourceLocation CompletePosition;
88   CompletionContext &ResultCtx;
89 };
90 
91 ParsedSourceLocation offsetToPosition(llvm::StringRef Code, size_t Offset) {
92   Offset = std::min(Code.size(), Offset);
93   StringRef Before = Code.substr(0, Offset);
94   int Lines = Before.count('\n');
95   size_t PrevNL = Before.rfind('\n');
96   size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1);
97   return {TestCCName, static_cast<unsigned>(Lines + 1),
98           static_cast<unsigned>(Offset - StartOfLine + 1)};
99 }
100 
101 CompletionContext runCompletion(StringRef Code, size_t Offset) {
102   CompletionContext ResultCtx;
103   auto Action = llvm::make_unique<CodeCompleteAction>(
104       offsetToPosition(Code, Offset), ResultCtx);
105   clang::tooling::runToolOnCodeWithArgs(Action.release(), Code, {"-std=c++11"},
106                                         TestCCName);
107   return ResultCtx;
108 }
109 
110 struct ParsedAnnotations {
111   std::vector<size_t> Points;
112   std::string Code;
113 };
114 
115 ParsedAnnotations parseAnnotations(StringRef AnnotatedCode) {
116   ParsedAnnotations R;
117   while (!AnnotatedCode.empty()) {
118     size_t NextPoint = AnnotatedCode.find('^');
119     if (NextPoint == StringRef::npos) {
120       R.Code += AnnotatedCode;
121       AnnotatedCode = "";
122       break;
123     }
124     R.Code += AnnotatedCode.substr(0, NextPoint);
125     R.Points.push_back(R.Code.size());
126 
127     AnnotatedCode = AnnotatedCode.substr(NextPoint + 1);
128   }
129   return R;
130 }
131 
132 CompletionContext runCodeCompleteOnCode(StringRef AnnotatedCode) {
133   ParsedAnnotations P = parseAnnotations(AnnotatedCode);
134   assert(P.Points.size() == 1 && "expected exactly one annotation point");
135   return runCompletion(P.Code, P.Points.front());
136 }
137 
138 std::vector<std::string>
139 collectPreferredTypes(StringRef AnnotatedCode,
140                       std::string *PtrDiffType = nullptr) {
141   ParsedAnnotations P = parseAnnotations(AnnotatedCode);
142   std::vector<std::string> Types;
143   for (size_t Point : P.Points) {
144     auto Results = runCompletion(P.Code, Point);
145     if (PtrDiffType) {
146       assert(PtrDiffType->empty() || *PtrDiffType == Results.PtrDiffType);
147       *PtrDiffType = Results.PtrDiffType;
148     }
149     Types.push_back(Results.PreferredType);
150   }
151   return Types;
152 }
153 
154 TEST(SemaCodeCompleteTest, VisitedNSForValidQualifiedId) {
155   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
156      namespace ns1 {}
157      namespace ns2 {}
158      namespace ns3 {}
159      namespace ns3 { namespace nns3 {} }
160 
161      namespace foo {
162      using namespace ns1;
163      namespace ns4 {} // not visited
164      namespace { using namespace ns2; }
165      inline namespace bar { using namespace ns3::nns3; }
166      } // foo
167      namespace ns { foo::^ }
168   )cpp")
169                        .VisitedNamespaces;
170   EXPECT_THAT(VisitedNS, UnorderedElementsAre("foo", "ns1", "ns2", "ns3::nns3",
171                                               "foo::(anonymous)"));
172 }
173 
174 TEST(SemaCodeCompleteTest, VisitedNSForInvalidQualifiedId) {
175   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
176      namespace na {}
177      namespace ns1 {
178      using namespace na;
179      foo::^
180      }
181   )cpp")
182                        .VisitedNamespaces;
183   EXPECT_THAT(VisitedNS, UnorderedElementsAre("ns1", "na"));
184 }
185 
186 TEST(SemaCodeCompleteTest, VisitedNSWithoutQualifier) {
187   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
188     namespace n1 {
189     namespace n2 {
190       void f(^) {}
191     }
192     }
193   )cpp")
194                        .VisitedNamespaces;
195   EXPECT_THAT(VisitedNS, UnorderedElementsAre("n1", "n1::n2"));
196 }
197 
198 TEST(PreferredTypeTest, BinaryExpr) {
199   // Check various operations for arithmetic types.
200   StringRef Code = R"cpp(
201     void test(int x) {
202       x = ^10;
203       x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
204       x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
205     })cpp";
206   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
207 
208   Code = R"cpp(
209     void test(float x) {
210       x = ^10;
211       x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
212       x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
213     })cpp";
214   EXPECT_THAT(collectPreferredTypes(Code), Each("float"));
215 
216   // Pointer types.
217   Code = R"cpp(
218     void test(int *ptr) {
219       ptr - ^ptr;
220       ptr = ^ptr;
221     })cpp";
222   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
223 
224   Code = R"cpp(
225     void test(int *ptr) {
226       ptr + ^10;
227       ptr += ^10;
228       ptr -= ^10;
229     })cpp";
230   {
231     std::string PtrDiff;
232     auto Types = collectPreferredTypes(Code, &PtrDiff);
233     EXPECT_THAT(Types, Each(PtrDiff));
234   }
235 
236   // Comparison operators.
237   Code = R"cpp(
238     void test(int i) {
239       i <= ^1; i < ^1; i >= ^1; i > ^1; i == ^1; i != ^1;
240     }
241   )cpp";
242   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
243 
244   Code = R"cpp(
245     void test(int *ptr) {
246       ptr <= ^ptr; ptr < ^ptr; ptr >= ^ptr; ptr > ^ptr;
247       ptr == ^ptr; ptr != ^ptr;
248     }
249   )cpp";
250   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
251 
252   // Relational operations.
253   Code = R"cpp(
254     void test(int i, int *ptr) {
255       i && ^1; i || ^1;
256       ptr && ^1; ptr || ^1;
257     }
258   )cpp";
259   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
260 
261   // Bitwise operations.
262   Code = R"cpp(
263     void test(long long ll) {
264       ll | ^1; ll & ^1;
265     }
266   )cpp";
267   EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
268 
269   Code = R"cpp(
270     enum A {};
271     void test(A a) {
272       a | ^1; a & ^1;
273     }
274   )cpp";
275   EXPECT_THAT(collectPreferredTypes(Code), Each("enum A"));
276 
277   Code = R"cpp(
278     enum class A {};
279     void test(A a) {
280       // This is technically illegal with the 'enum class' without overloaded
281       // operators, but we pretend it's fine.
282       a | ^a; a & ^a;
283     }
284   )cpp";
285   EXPECT_THAT(collectPreferredTypes(Code), Each("enum A"));
286 
287   // Binary shifts.
288   Code = R"cpp(
289     void test(int i, long long ll) {
290       i << ^1; ll << ^1;
291       i <<= ^1; i <<= ^1;
292       i >> ^1; ll >> ^1;
293       i >>= ^1; i >>= ^1;
294     }
295   )cpp";
296   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
297 
298   // Comma does not provide any useful information.
299   Code = R"cpp(
300     class Cls {};
301     void test(int i, int* ptr, Cls x) {
302       (i, ^i);
303       (ptr, ^ptr);
304       (x, ^x);
305     }
306   )cpp";
307   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
308 
309   // User-defined types do not take operator overloading into account.
310   // However, they provide heuristics for some common cases.
311   Code = R"cpp(
312     class Cls {};
313     void test(Cls c) {
314       // we assume arithmetic and comparions ops take the same type.
315       c + ^c; c - ^c; c * ^c; c / ^c; c % ^c;
316       c == ^c; c != ^c; c < ^c; c <= ^c; c > ^c; c >= ^c;
317       // same for the assignments.
318       c = ^c; c += ^c; c -= ^c; c *= ^c; c /= ^c; c %= ^c;
319     }
320   )cpp";
321   EXPECT_THAT(collectPreferredTypes(Code), Each("class Cls"));
322 
323   Code = R"cpp(
324     class Cls {};
325     void test(Cls c) {
326       // we assume relational ops operate on bools.
327       c && ^c; c || ^c;
328     }
329   )cpp";
330   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
331 
332   Code = R"cpp(
333     class Cls {};
334     void test(Cls c) {
335       // we make no assumptions about the following operators, since they are
336       // often overloaded with a non-standard meaning.
337       c << ^c; c >> ^c; c | ^c; c & ^c;
338       c <<= ^c; c >>= ^c; c |= ^c; c &= ^c;
339     }
340   )cpp";
341   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
342 }
343 
344 TEST(PreferredTypeTest, Members) {
345   StringRef Code = R"cpp(
346     struct vector {
347       int *begin();
348       vector clone();
349     };
350 
351     void test(int *a) {
352       a = ^vector().^clone().^begin();
353     }
354   )cpp";
355   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
356 }
357 
358 TEST(PreferredTypeTest, Conditions) {
359   StringRef Code = R"cpp(
360     struct vector {
361       bool empty();
362     };
363 
364     void test() {
365       if (^vector().^empty()) {}
366       while (^vector().^empty()) {}
367       for (; ^vector().^empty();) {}
368     }
369   )cpp";
370   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
371 }
372 
373 TEST(PreferredTypeTest, InitAndAssignment) {
374   StringRef Code = R"cpp(
375     struct vector {
376       int* begin();
377     };
378 
379     void test() {
380       const int* x = ^vector().^begin();
381       x = ^vector().^begin();
382 
383       if (const int* y = ^vector().^begin()) {}
384     }
385   )cpp";
386   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
387 }
388 
389 TEST(PreferredTypeTest, UnaryExprs) {
390   StringRef Code = R"cpp(
391     void test(long long a) {
392       a = +^a;
393       a = -^a
394       a = ++^a;
395       a = --^a;
396     }
397   )cpp";
398   EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
399 
400   Code = R"cpp(
401     void test(int a, int *ptr) {
402       !^a;
403       !^ptr;
404       !!!^a;
405 
406       a = !^a;
407       a = !^ptr;
408       a = !!!^a;
409     }
410   )cpp";
411   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
412 
413   Code = R"cpp(
414     void test(int a) {
415       const int* x = &^a;
416     }
417   )cpp";
418   EXPECT_THAT(collectPreferredTypes(Code), Each("const int"));
419 
420   Code = R"cpp(
421     void test(int *a) {
422       int x = *^a;
423       int &r = *^a;
424     }
425   )cpp";
426   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
427 
428   Code = R"cpp(
429     void test(int a) {
430       *^a;
431       &^a;
432     }
433 
434   )cpp";
435 }
436 
437 TEST(PreferredTypeTest, ParenExpr) {
438   StringRef Code = R"cpp(
439     const int *i = ^(^(^(^10)));
440   )cpp";
441   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
442 }
443 
444 TEST(PreferredTypeTest, FunctionArguments) {
445   StringRef Code = R"cpp(
446     void foo(const int*);
447 
448     void bar(const int*);
449     void bar(const int*, int b);
450 
451     struct vector {
452       const int *data();
453     };
454     void test() {
455       foo(^(^(^(^vec^tor^().^da^ta^()))));
456       bar(^(^(^(^vec^tor^().^da^ta^()))));
457     }
458   )cpp";
459   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
460 
461   Code = R"cpp(
462     void bar(int, volatile double *);
463     void bar(int, volatile double *, int, int);
464 
465     struct vector {
466       double *data();
467     };
468 
469     struct class_members {
470       void bar(int, volatile double *);
471       void bar(int, volatile double *, int, int);
472     };
473     void test() {
474       bar(10, ^(^(^(^vec^tor^().^da^ta^()))));
475       class_members().bar(10, ^(^(^(^vec^tor^().^da^ta^()))));
476     }
477   )cpp";
478   EXPECT_THAT(collectPreferredTypes(Code), Each("volatile double *"));
479 }
480 } // namespace
481