Clang Project

clang_source_code/unittests/Sema/CodeCompleteTest.cpp
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
21namespace {
22
23using namespace clang;
24using namespace clang::tooling;
25using ::testing::Each;
26using ::testing::UnorderedElementsAre;
27
28const char TestCCName[] = "test.cc";
29
30struct CompletionContext {
31  std::vector<std::stringVisitedNamespaces;
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
38class VisitedContextFinder : public CodeCompleteConsumer {
39public:
40  VisitedContextFinder(CompletionContext &ResultCtx)
41      : CodeCompleteConsumer(/*CodeCompleteOpts=*/{},
42                             /*CodeCompleteConsumer*/ false),
43        ResultCtx(ResultCtx),
44        CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {}
45
46  void ProcessCodeCompleteResults(Sema &SCodeCompletionContext 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
62private:
63  std::vector<std::stringgetVisitedNamespace(
64      CodeCompletionContext::VisitedContextSet VisitedContextsconst {
65    std::vector<std::stringNSNames;
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
76class CodeCompleteAction : public SyntaxOnlyAction {
77public:
78  CodeCompleteAction(ParsedSourceLocation PCompletionContext &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
87private:
88  // 1-based code complete position <Line, Col>;
89  ParsedSourceLocation CompletePosition;
90  CompletionContext &ResultCtx;
91};
92
93ParsedSourceLocation 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
103CompletionContext 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
112struct ParsedAnnotations {
113  std::vector<size_t> Points;
114  std::string Code;
115};
116
117ParsedAnnotations 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
134CompletionContext runCodeCompleteOnCode(StringRef AnnotatedCode) {
135  ParsedAnnotations P = parseAnnotations(AnnotatedCode);
136   (0) . __assert_fail ("P.Points.size() == 1 && \"expected exactly one annotation point\"", "/home/seafit/code_projects/clang_source/clang/unittests/Sema/CodeCompleteTest.cpp", 136, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(P.Points.size() == 1 && "expected exactly one annotation point");
137  return runCompletion(P.Code, P.Points.front());
138}
139
140std::vector<std::string>
141collectPreferredTypes(StringRef AnnotatedCode,
142                      std::string *PtrDiffType = nullptr) {
143  ParsedAnnotations P = parseAnnotations(AnnotatedCode);
144  std::vector<std::stringTypes;
145  for (size_t Point : P.Points) {
146    auto Results = runCompletion(P.Code, Point);
147    if (PtrDiffType) {
148      empty() || *PtrDiffType == Results.PtrDiffType", "/home/seafit/code_projects/clang_source/clang/unittests/Sema/CodeCompleteTest.cpp", 148, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(PtrDiffType->empty() || *PtrDiffType == Results.PtrDiffType);
149      *PtrDiffType = Results.PtrDiffType;
150    }
151    Types.push_back(Results.PreferredType);
152  }
153  return Types;
154}
155
156TEST(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
176TEST(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
188TEST(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
200TEST(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
346TEST(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
360TEST(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
375TEST(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
391TEST(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
439TEST(PreferredTypeTest, ParenExpr) {
440  StringRef Code = R"cpp(
441    const int *i = ^(^(^(^10)));
442  )cpp";
443  EXPECT_THAT(collectPreferredTypes(Code), Each("const int *"));
444}
445
446TEST(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