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, VisitedNSForInvalideQualifiedId) {
177   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
178      namespace ns { foo::^ }
179   )cpp")
180                        .VisitedNamespaces;
181   EXPECT_TRUE(VisitedNS.empty());
182 }
183 
184 TEST(SemaCodeCompleteTest, VisitedNSWithoutQualifier) {
185   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
186     namespace n1 {
187     namespace n2 {
188       void f(^) {}
189     }
190     }
191   )cpp")
192                        .VisitedNamespaces;
193   EXPECT_THAT(VisitedNS, UnorderedElementsAre("n1", "n1::n2"));
194 }
195 
196 TEST(PreferredTypeTest, BinaryExpr) {
197   // Check various operations for arithmetic types.
198   StringRef Code = R"cpp(
199     void test(int x) {
200       x = ^10;
201       x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
202       x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
203     })cpp";
204   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
205 
206   Code = R"cpp(
207     void test(float x) {
208       x = ^10;
209       x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
210       x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
211     })cpp";
212   EXPECT_THAT(collectPreferredTypes(Code), Each("float"));
213 
214   // Pointer types.
215   Code = R"cpp(
216     void test(int *ptr) {
217       ptr - ^ptr;
218       ptr = ^ptr;
219     })cpp";
220   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
221 
222   Code = R"cpp(
223     void test(int *ptr) {
224       ptr + ^10;
225       ptr += ^10;
226       ptr -= ^10;
227     })cpp";
228   {
229     std::string PtrDiff;
230     auto Types = collectPreferredTypes(Code, &PtrDiff);
231     EXPECT_THAT(Types, Each(PtrDiff));
232   }
233 
234   // Comparison operators.
235   Code = R"cpp(
236     void test(int i) {
237       i <= ^1; i < ^1; i >= ^1; i > ^1; i == ^1; i != ^1;
238     }
239   )cpp";
240   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
241 
242   Code = R"cpp(
243     void test(int *ptr) {
244       ptr <= ^ptr; ptr < ^ptr; ptr >= ^ptr; ptr > ^ptr;
245       ptr == ^ptr; ptr != ^ptr;
246     }
247   )cpp";
248   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
249 
250   // Relational operations.
251   Code = R"cpp(
252     void test(int i, int *ptr) {
253       i && ^1; i || ^1;
254       ptr && ^1; ptr || ^1;
255     }
256   )cpp";
257   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
258 
259   // Bitwise operations.
260   Code = R"cpp(
261     void test(long long ll) {
262       ll | ^1; ll & ^1;
263     }
264   )cpp";
265   EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
266 
267   Code = R"cpp(
268     enum A {};
269     void test(A a) {
270       a | ^1; a & ^1;
271     }
272   )cpp";
273   EXPECT_THAT(collectPreferredTypes(Code), Each("enum A"));
274 
275   Code = R"cpp(
276     enum class A {};
277     void test(A a) {
278       // This is technically illegal with the 'enum class' without overloaded
279       // operators, but we pretend it's fine.
280       a | ^a; a & ^a;
281     }
282   )cpp";
283   EXPECT_THAT(collectPreferredTypes(Code), Each("enum A"));
284 
285   // Binary shifts.
286   Code = R"cpp(
287     void test(int i, long long ll) {
288       i << ^1; ll << ^1;
289       i <<= ^1; i <<= ^1;
290       i >> ^1; ll >> ^1;
291       i >>= ^1; i >>= ^1;
292     }
293   )cpp";
294   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
295 
296   // Comma does not provide any useful information.
297   Code = R"cpp(
298     class Cls {};
299     void test(int i, int* ptr, Cls x) {
300       (i, ^i);
301       (ptr, ^ptr);
302       (x, ^x);
303     }
304   )cpp";
305   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
306 
307   // User-defined types do not take operator overloading into account.
308   // However, they provide heuristics for some common cases.
309   Code = R"cpp(
310     class Cls {};
311     void test(Cls c) {
312       // we assume arithmetic and comparions ops take the same type.
313       c + ^c; c - ^c; c * ^c; c / ^c; c % ^c;
314       c == ^c; c != ^c; c < ^c; c <= ^c; c > ^c; c >= ^c;
315       // same for the assignments.
316       c = ^c; c += ^c; c -= ^c; c *= ^c; c /= ^c; c %= ^c;
317     }
318   )cpp";
319   EXPECT_THAT(collectPreferredTypes(Code), Each("class Cls"));
320 
321   Code = R"cpp(
322     class Cls {};
323     void test(Cls c) {
324       // we assume relational ops operate on bools.
325       c && ^c; c || ^c;
326     }
327   )cpp";
328   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
329 
330   Code = R"cpp(
331     class Cls {};
332     void test(Cls c) {
333       // we make no assumptions about the following operators, since they are
334       // often overloaded with a non-standard meaning.
335       c << ^c; c >> ^c; c | ^c; c & ^c;
336       c <<= ^c; c >>= ^c; c |= ^c; c &= ^c;
337     }
338   )cpp";
339   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
340 }
341 
342 TEST(PreferredTypeTest, Members) {
343   StringRef Code = R"cpp(
344     struct vector {
345       int *begin();
346       vector clone();
347     };
348 
349     void test(int *a) {
350       a = ^vector().^clone().^begin();
351     }
352   )cpp";
353   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
354 }
355 
356 TEST(PreferredTypeTest, Conditions) {
357   StringRef Code = R"cpp(
358     struct vector {
359       bool empty();
360     };
361 
362     void test() {
363       if (^vector().^empty()) {}
364       while (^vector().^empty()) {}
365       for (; ^vector().^empty();) {}
366     }
367   )cpp";
368   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
369 }
370 
371 TEST(PreferredTypeTest, InitAndAssignment) {
372   StringRef Code = R"cpp(
373     struct vector {
374       int* begin();
375     };
376 
377     void test() {
378       const int* x = ^vector().^begin();
379       x = ^vector().^begin();
380 
381       if (const int* y = ^vector().^begin()) {}
382     }
383   )cpp";
384   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
385 }
386 
387 TEST(PreferredTypeTest, UnaryExprs) {
388   StringRef Code = R"cpp(
389     void test(long long a) {
390       a = +^a;
391       a = -^a
392       a = ++^a;
393       a = --^a;
394     }
395   )cpp";
396   EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
397 
398   Code = R"cpp(
399     void test(int a, int *ptr) {
400       !^a;
401       !^ptr;
402       !!!^a;
403 
404       a = !^a;
405       a = !^ptr;
406       a = !!!^a;
407     }
408   )cpp";
409   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
410 
411   Code = R"cpp(
412     void test(int a) {
413       const int* x = &^a;
414     }
415   )cpp";
416   EXPECT_THAT(collectPreferredTypes(Code), Each("const int"));
417 
418   Code = R"cpp(
419     void test(int *a) {
420       int x = *^a;
421       int &r = *^a;
422     }
423   )cpp";
424   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
425 
426   Code = R"cpp(
427     void test(int a) {
428       *^a;
429       &^a;
430     }
431 
432   )cpp";
433 }
434 
435 TEST(PreferredTypeTest, ParenExpr) {
436   StringRef Code = R"cpp(
437     const int *i = ^(^(^(^10)));
438   )cpp";
439   EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
440 }
441 } // namespace
442