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