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

source code of clang/unittests/Sema/CodeCompleteTest.cpp