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