1 //=== unittests/Sema/CodeCompleteTest.cpp - Code Complete tests ==============//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/Frontend/FrontendActions.h"
12 #include "clang/Lex/Preprocessor.h"
13 #include "clang/Parse/ParseAST.h"
14 #include "clang/Sema/Sema.h"
15 #include "clang/Sema/SemaDiagnostic.h"
16 #include "clang/Tooling/Tooling.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:
41   VisitedContextFinder(CompletionContext &ResultCtx)
42       : CodeCompleteConsumer(/*CodeCompleteOpts=*/{},
43                              /*CodeCompleteConsumer*/ false),
44         ResultCtx(ResultCtx),
45         CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}
46 
47   void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
48                                   CodeCompletionResult *Results,
49                                   unsigned NumResults) override {
50     ResultCtx.VisitedNamespaces =
51         getVisitedNamespace(Context.getVisitedContexts());
52     ResultCtx.PreferredType = Context.getPreferredType().getAsString();
53     ResultCtx.PtrDiffType =
54         S.getASTContext().getPointerDiffType().getAsString();
55   }
56 
57   CodeCompletionAllocator &getAllocator() override {
58     return CCTUInfo.getAllocator();
59   }
60 
61   CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
62 
63 private:
64   std::vector<std::string> getVisitedNamespace(
65       CodeCompletionContext::VisitedContextSet VisitedContexts) const {
66     std::vector<std::string> NSNames;
67     for (const auto *Context : VisitedContexts)
68       if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context))
69         NSNames.push_back(NS->getQualifiedNameAsString());
70     return NSNames;
71   }
72 
73   CompletionContext &ResultCtx;
74   CodeCompletionTUInfo CCTUInfo;
75 };
76 
77 class CodeCompleteAction : public SyntaxOnlyAction {
78 public:
79   CodeCompleteAction(ParsedSourceLocation P, CompletionContext &ResultCtx)
80       : CompletePosition(std::move(P)), ResultCtx(ResultCtx) {}
81 
82   bool BeginInvocation(CompilerInstance &CI) override {
83     CI.getFrontendOpts().CodeCompletionAt = CompletePosition;
84     CI.setCodeCompletionConsumer(new VisitedContextFinder(ResultCtx));
85     return true;
86   }
87 
88 private:
89   // 1-based code complete position <Line, Col>;
90   ParsedSourceLocation CompletePosition;
91   CompletionContext &ResultCtx;
92 };
93 
94 ParsedSourceLocation offsetToPosition(llvm::StringRef Code, size_t Offset) {
95   Offset = std::min(Code.size(), Offset);
96   StringRef Before = Code.substr(0, Offset);
97   int Lines = Before.count('\n');
98   size_t PrevNL = Before.rfind('\n');
99   size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1);
100   return {TestCCName, static_cast<unsigned>(Lines + 1),
101           static_cast<unsigned>(Offset - StartOfLine + 1)};
102 }
103 
104 CompletionContext runCompletion(StringRef Code, size_t Offset) {
105   CompletionContext ResultCtx;
106   auto Action = llvm::make_unique<CodeCompleteAction>(
107       offsetToPosition(Code, Offset), ResultCtx);
108   clang::tooling::runToolOnCodeWithArgs(Action.release(), Code, {"-std=c++11"},
109                                         TestCCName);
110   return ResultCtx;
111 }
112 
113 struct ParsedAnnotations {
114   std::vector<size_t> Points;
115   std::string Code;
116 };
117 
118 ParsedAnnotations parseAnnotations(StringRef AnnotatedCode) {
119   ParsedAnnotations R;
120   while (!AnnotatedCode.empty()) {
121     size_t NextPoint = AnnotatedCode.find('^');
122     if (NextPoint == StringRef::npos) {
123       R.Code += AnnotatedCode;
124       AnnotatedCode = "";
125       break;
126     }
127     R.Code += AnnotatedCode.substr(0, NextPoint);
128     R.Points.push_back(R.Code.size());
129 
130     AnnotatedCode = AnnotatedCode.substr(NextPoint + 1);
131   }
132   return R;
133 }
134 
135 CompletionContext runCodeCompleteOnCode(StringRef AnnotatedCode) {
136   ParsedAnnotations P = parseAnnotations(AnnotatedCode);
137   assert(P.Points.size() == 1 && "expected exactly one annotation point");
138   return runCompletion(P.Code, P.Points.front());
139 }
140 
141 std::vector<std::string>
142 collectPreferredTypes(StringRef AnnotatedCode,
143                       std::string *PtrDiffType = nullptr) {
144   ParsedAnnotations P = parseAnnotations(AnnotatedCode);
145   std::vector<std::string> Types;
146   for (size_t Point : P.Points) {
147     auto Results = runCompletion(P.Code, Point);
148     if (PtrDiffType) {
149       assert(PtrDiffType->empty() || *PtrDiffType == Results.PtrDiffType);
150       *PtrDiffType = Results.PtrDiffType;
151     }
152     Types.push_back(Results.PreferredType);
153   }
154   return Types;
155 }
156 
157 TEST(SemaCodeCompleteTest, VisitedNSForValidQualifiedId) {
158   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
159      namespace ns1 {}
160      namespace ns2 {}
161      namespace ns3 {}
162      namespace ns3 { namespace nns3 {} }
163 
164      namespace foo {
165      using namespace ns1;
166      namespace ns4 {} // not visited
167      namespace { using namespace ns2; }
168      inline namespace bar { using namespace ns3::nns3; }
169      } // foo
170      namespace ns { foo::^ }
171   )cpp")
172                        .VisitedNamespaces;
173   EXPECT_THAT(VisitedNS, UnorderedElementsAre("foo", "ns1", "ns2", "ns3::nns3",
174                                               "foo::(anonymous)"));
175 }
176 
177 TEST(SemaCodeCompleteTest, VisitedNSForInvalideQualifiedId) {
178   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
179      namespace ns { foo::^ }
180   )cpp")
181                        .VisitedNamespaces;
182   EXPECT_TRUE(VisitedNS.empty());
183 }
184 
185 TEST(SemaCodeCompleteTest, VisitedNSWithoutQualifier) {
186   auto VisitedNS = runCodeCompleteOnCode(R"cpp(
187     namespace n1 {
188     namespace n2 {
189       void f(^) {}
190     }
191     }
192   )cpp")
193                        .VisitedNamespaces;
194   EXPECT_THAT(VisitedNS, UnorderedElementsAre("n1", "n1::n2"));
195 }
196 
197 TEST(PreferredTypeTest, BinaryExpr) {
198   // Check various operations for arithmetic types.
199   StringRef Code = R"cpp(
200     void test(int x) {
201       x = ^10;
202       x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
203       x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
204     })cpp";
205   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
206 
207   Code = R"cpp(
208     void test(float x) {
209       x = ^10;
210       x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10;
211       x + ^10; x - ^10; x * ^10; x / ^10; x % ^10;
212     })cpp";
213   EXPECT_THAT(collectPreferredTypes(Code), Each("float"));
214 
215   // Pointer types.
216   Code = R"cpp(
217     void test(int *ptr) {
218       ptr - ^ptr;
219       ptr = ^ptr;
220     })cpp";
221   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
222 
223   Code = R"cpp(
224     void test(int *ptr) {
225       ptr + ^10;
226       ptr += ^10;
227       ptr -= ^10;
228     })cpp";
229   {
230     std::string PtrDiff;
231     auto Types = collectPreferredTypes(Code, &PtrDiff);
232     EXPECT_THAT(Types, Each(PtrDiff));
233   }
234 
235   // Comparison operators.
236   Code = R"cpp(
237     void test(int i) {
238       i <= ^1; i < ^1; i >= ^1; i > ^1; i == ^1; i != ^1;
239     }
240   )cpp";
241   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
242 
243   Code = R"cpp(
244     void test(int *ptr) {
245       ptr <= ^ptr; ptr < ^ptr; ptr >= ^ptr; ptr > ^ptr;
246       ptr == ^ptr; ptr != ^ptr;
247     }
248   )cpp";
249   EXPECT_THAT(collectPreferredTypes(Code), Each("int *"));
250 
251   // Relational operations.
252   Code = R"cpp(
253     void test(int i, int *ptr) {
254       i && ^1; i || ^1;
255       ptr && ^1; ptr || ^1;
256     }
257   )cpp";
258   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
259 
260   // Bitwise operations.
261   Code = R"cpp(
262     void test(long long ll) {
263       ll | ^1; ll & ^1;
264     }
265   )cpp";
266   EXPECT_THAT(collectPreferredTypes(Code), Each("long long"));
267 
268   Code = R"cpp(
269     enum A {};
270     void test(A a) {
271       a | ^1; a & ^1;
272     }
273   )cpp";
274   EXPECT_THAT(collectPreferredTypes(Code), Each("enum A"));
275 
276   Code = R"cpp(
277     enum class A {};
278     void test(A a) {
279       // This is technically illegal with the 'enum class' without overloaded
280       // operators, but we pretend it's fine.
281       a | ^a; a & ^a;
282     }
283   )cpp";
284   EXPECT_THAT(collectPreferredTypes(Code), Each("enum A"));
285 
286   // Binary shifts.
287   Code = R"cpp(
288     void test(int i, long long ll) {
289       i << ^1; ll << ^1;
290       i <<= ^1; i <<= ^1;
291       i >> ^1; ll >> ^1;
292       i >>= ^1; i >>= ^1;
293     }
294   )cpp";
295   EXPECT_THAT(collectPreferredTypes(Code), Each("int"));
296 
297   // Comma does not provide any useful information.
298   Code = R"cpp(
299     class Cls {};
300     void test(int i, int* ptr, Cls x) {
301       (i, ^i);
302       (ptr, ^ptr);
303       (x, ^x);
304     }
305   )cpp";
306   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
307 
308   // User-defined types do not take operator overloading into account.
309   // However, they provide heuristics for some common cases.
310   Code = R"cpp(
311     class Cls {};
312     void test(Cls c) {
313       // we assume arithmetic and comparions ops take the same type.
314       c + ^c; c - ^c; c * ^c; c / ^c; c % ^c;
315       c == ^c; c != ^c; c < ^c; c <= ^c; c > ^c; c >= ^c;
316       // same for the assignments.
317       c = ^c; c += ^c; c -= ^c; c *= ^c; c /= ^c; c %= ^c;
318     }
319   )cpp";
320   EXPECT_THAT(collectPreferredTypes(Code), Each("class Cls"));
321 
322   Code = R"cpp(
323     class Cls {};
324     void test(Cls c) {
325       // we assume relational ops operate on bools.
326       c && ^c; c || ^c;
327     }
328   )cpp";
329   EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool"));
330 
331   Code = R"cpp(
332     class Cls {};
333     void test(Cls c) {
334       // we make no assumptions about the following operators, since they are
335       // often overloaded with a non-standard meaning.
336       c << ^c; c >> ^c; c | ^c; c & ^c;
337       c <<= ^c; c >>= ^c; c |= ^c; c &= ^c;
338     }
339   )cpp";
340   EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
341 }
342 
343 } // namespace
344