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