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/Support/Annotations.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=*/{}), ResultCtx(ResultCtx), 43 CCTUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {} 44 45 void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context, 46 CodeCompletionResult *Results, 47 unsigned NumResults) override { 48 ResultCtx.VisitedNamespaces = 49 getVisitedNamespace(Context.getVisitedContexts()); 50 ResultCtx.PreferredType = Context.getPreferredType().getAsString(); 51 ResultCtx.PtrDiffType = 52 S.getASTContext().getPointerDiffType().getAsString(); 53 } 54 55 CodeCompletionAllocator &getAllocator() override { 56 return CCTUInfo.getAllocator(); 57 } 58 59 CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; } 60 61 private: 62 std::vector<std::string> getVisitedNamespace( 63 CodeCompletionContext::VisitedContextSet VisitedContexts) const { 64 std::vector<std::string> NSNames; 65 for (const auto *Context : VisitedContexts) 66 if (const auto *NS = llvm::dyn_cast<NamespaceDecl>(Context)) 67 NSNames.push_back(NS->getQualifiedNameAsString()); 68 return NSNames; 69 } 70 71 CompletionContext &ResultCtx; 72 CodeCompletionTUInfo CCTUInfo; 73 }; 74 75 class CodeCompleteAction : public SyntaxOnlyAction { 76 public: 77 CodeCompleteAction(ParsedSourceLocation P, CompletionContext &ResultCtx) 78 : CompletePosition(std::move(P)), ResultCtx(ResultCtx) {} 79 80 bool BeginInvocation(CompilerInstance &CI) override { 81 CI.getFrontendOpts().CodeCompletionAt = CompletePosition; 82 CI.setCodeCompletionConsumer(new VisitedContextFinder(ResultCtx)); 83 return true; 84 } 85 86 private: 87 // 1-based code complete position <Line, Col>; 88 ParsedSourceLocation CompletePosition; 89 CompletionContext &ResultCtx; 90 }; 91 92 ParsedSourceLocation offsetToPosition(llvm::StringRef Code, size_t Offset) { 93 Offset = std::min(Code.size(), Offset); 94 StringRef Before = Code.substr(0, Offset); 95 int Lines = Before.count('\n'); 96 size_t PrevNL = Before.rfind('\n'); 97 size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1); 98 return {TestCCName, static_cast<unsigned>(Lines + 1), 99 static_cast<unsigned>(Offset - StartOfLine + 1)}; 100 } 101 102 CompletionContext runCompletion(StringRef Code, size_t Offset) { 103 CompletionContext ResultCtx; 104 clang::tooling::runToolOnCodeWithArgs( 105 std::make_unique<CodeCompleteAction>(offsetToPosition(Code, Offset), 106 ResultCtx), 107 Code, {"-std=c++11"}, TestCCName); 108 return ResultCtx; 109 } 110 111 CompletionContext runCodeCompleteOnCode(StringRef AnnotatedCode) { 112 llvm::Annotations A(AnnotatedCode); 113 return runCompletion(A.code(), A.point()); 114 } 115 116 std::vector<std::string> 117 collectPreferredTypes(StringRef AnnotatedCode, 118 std::string *PtrDiffType = nullptr) { 119 llvm::Annotations A(AnnotatedCode); 120 std::vector<std::string> Types; 121 for (size_t Point : A.points()) { 122 auto Results = runCompletion(A.code(), Point); 123 if (PtrDiffType) { 124 assert(PtrDiffType->empty() || *PtrDiffType == Results.PtrDiffType); 125 *PtrDiffType = Results.PtrDiffType; 126 } 127 Types.push_back(Results.PreferredType); 128 } 129 return Types; 130 } 131 132 TEST(SemaCodeCompleteTest, VisitedNSForValidQualifiedId) { 133 auto VisitedNS = runCodeCompleteOnCode(R"cpp( 134 namespace ns1 {} 135 namespace ns2 {} 136 namespace ns3 {} 137 namespace ns3 { namespace nns3 {} } 138 139 namespace foo { 140 using namespace ns1; 141 namespace ns4 {} // not visited 142 namespace { using namespace ns2; } 143 inline namespace bar { using namespace ns3::nns3; } 144 } // foo 145 namespace ns { foo::^ } 146 )cpp") 147 .VisitedNamespaces; 148 EXPECT_THAT(VisitedNS, UnorderedElementsAre("foo", "ns1", "ns2", "ns3::nns3", 149 "foo::(anonymous)")); 150 } 151 152 TEST(SemaCodeCompleteTest, VisitedNSForInvalidQualifiedId) { 153 auto VisitedNS = runCodeCompleteOnCode(R"cpp( 154 namespace na {} 155 namespace ns1 { 156 using namespace na; 157 foo::^ 158 } 159 )cpp") 160 .VisitedNamespaces; 161 EXPECT_THAT(VisitedNS, UnorderedElementsAre("ns1", "na")); 162 } 163 164 TEST(SemaCodeCompleteTest, VisitedNSWithoutQualifier) { 165 auto VisitedNS = runCodeCompleteOnCode(R"cpp( 166 namespace n1 { 167 namespace n2 { 168 void f(^) {} 169 } 170 } 171 )cpp") 172 .VisitedNamespaces; 173 EXPECT_THAT(VisitedNS, UnorderedElementsAre("n1", "n1::n2")); 174 } 175 176 TEST(PreferredTypeTest, BinaryExpr) { 177 // Check various operations for arithmetic types. 178 StringRef Code = R"cpp( 179 void test(int x) { 180 x = ^10; 181 x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10; 182 x + ^10; x - ^10; x * ^10; x / ^10; x % ^10; 183 })cpp"; 184 EXPECT_THAT(collectPreferredTypes(Code), Each("int")); 185 186 Code = R"cpp( 187 void test(float x) { 188 x = ^10; 189 x += ^10; x -= ^10; x *= ^10; x /= ^10; x %= ^10; 190 x + ^10; x - ^10; x * ^10; x / ^10; x % ^10; 191 })cpp"; 192 EXPECT_THAT(collectPreferredTypes(Code), Each("float")); 193 194 // Pointer types. 195 Code = R"cpp( 196 void test(int *ptr) { 197 ptr - ^ptr; 198 ptr = ^ptr; 199 })cpp"; 200 EXPECT_THAT(collectPreferredTypes(Code), Each("int *")); 201 202 Code = R"cpp( 203 void test(int *ptr) { 204 ptr + ^10; 205 ptr += ^10; 206 ptr -= ^10; 207 })cpp"; 208 { 209 std::string PtrDiff; 210 auto Types = collectPreferredTypes(Code, &PtrDiff); 211 EXPECT_THAT(Types, Each(PtrDiff)); 212 } 213 214 // Comparison operators. 215 Code = R"cpp( 216 void test(int i) { 217 i <= ^1; i < ^1; i >= ^1; i > ^1; i == ^1; i != ^1; 218 } 219 )cpp"; 220 EXPECT_THAT(collectPreferredTypes(Code), Each("int")); 221 222 Code = R"cpp( 223 void test(int *ptr) { 224 ptr <= ^ptr; ptr < ^ptr; ptr >= ^ptr; ptr > ^ptr; 225 ptr == ^ptr; ptr != ^ptr; 226 } 227 )cpp"; 228 EXPECT_THAT(collectPreferredTypes(Code), Each("int *")); 229 230 // Relational operations. 231 Code = R"cpp( 232 void test(int i, int *ptr) { 233 i && ^1; i || ^1; 234 ptr && ^1; ptr || ^1; 235 } 236 )cpp"; 237 EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool")); 238 239 // Bitwise operations. 240 Code = R"cpp( 241 void test(long long ll) { 242 ll | ^1; ll & ^1; 243 } 244 )cpp"; 245 EXPECT_THAT(collectPreferredTypes(Code), Each("long long")); 246 247 Code = R"cpp( 248 enum A {}; 249 void test(A a) { 250 a | ^1; a & ^1; 251 } 252 )cpp"; 253 EXPECT_THAT(collectPreferredTypes(Code), Each("enum A")); 254 255 Code = R"cpp( 256 enum class A {}; 257 void test(A a) { 258 // This is technically illegal with the 'enum class' without overloaded 259 // operators, but we pretend it's fine. 260 a | ^a; a & ^a; 261 } 262 )cpp"; 263 EXPECT_THAT(collectPreferredTypes(Code), Each("enum A")); 264 265 // Binary shifts. 266 Code = R"cpp( 267 void test(int i, long long ll) { 268 i << ^1; ll << ^1; 269 i <<= ^1; i <<= ^1; 270 i >> ^1; ll >> ^1; 271 i >>= ^1; i >>= ^1; 272 } 273 )cpp"; 274 EXPECT_THAT(collectPreferredTypes(Code), Each("int")); 275 276 // Comma does not provide any useful information. 277 Code = R"cpp( 278 class Cls {}; 279 void test(int i, int* ptr, Cls x) { 280 (i, ^i); 281 (ptr, ^ptr); 282 (x, ^x); 283 } 284 )cpp"; 285 EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE")); 286 287 // User-defined types do not take operator overloading into account. 288 // However, they provide heuristics for some common cases. 289 Code = R"cpp( 290 class Cls {}; 291 void test(Cls c) { 292 // we assume arithmetic and comparions ops take the same type. 293 c + ^c; c - ^c; c * ^c; c / ^c; c % ^c; 294 c == ^c; c != ^c; c < ^c; c <= ^c; c > ^c; c >= ^c; 295 // same for the assignments. 296 c = ^c; c += ^c; c -= ^c; c *= ^c; c /= ^c; c %= ^c; 297 } 298 )cpp"; 299 EXPECT_THAT(collectPreferredTypes(Code), Each("class Cls")); 300 301 Code = R"cpp( 302 class Cls {}; 303 void test(Cls c) { 304 // we assume relational ops operate on bools. 305 c && ^c; c || ^c; 306 } 307 )cpp"; 308 EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool")); 309 310 Code = R"cpp( 311 class Cls {}; 312 void test(Cls c) { 313 // we make no assumptions about the following operators, since they are 314 // often overloaded with a non-standard meaning. 315 c << ^c; c >> ^c; c | ^c; c & ^c; 316 c <<= ^c; c >>= ^c; c |= ^c; c &= ^c; 317 } 318 )cpp"; 319 EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE")); 320 } 321 322 TEST(PreferredTypeTest, Members) { 323 StringRef Code = R"cpp( 324 struct vector { 325 int *begin(); 326 vector clone(); 327 }; 328 329 void test(int *a) { 330 a = ^vector().^clone().^begin(); 331 } 332 )cpp"; 333 EXPECT_THAT(collectPreferredTypes(Code), Each("int *")); 334 } 335 336 TEST(PreferredTypeTest, Conditions) { 337 StringRef Code = R"cpp( 338 struct vector { 339 bool empty(); 340 }; 341 342 void test() { 343 if (^vector().^empty()) {} 344 while (^vector().^empty()) {} 345 for (; ^vector().^empty();) {} 346 } 347 )cpp"; 348 EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool")); 349 } 350 351 TEST(PreferredTypeTest, InitAndAssignment) { 352 StringRef Code = R"cpp( 353 struct vector { 354 int* begin(); 355 }; 356 357 void test() { 358 const int* x = ^vector().^begin(); 359 x = ^vector().^begin(); 360 361 if (const int* y = ^vector().^begin()) {} 362 } 363 )cpp"; 364 EXPECT_THAT(collectPreferredTypes(Code), Each("const int *")); 365 } 366 367 TEST(PreferredTypeTest, UnaryExprs) { 368 StringRef Code = R"cpp( 369 void test(long long a) { 370 a = +^a; 371 a = -^a 372 a = ++^a; 373 a = --^a; 374 } 375 )cpp"; 376 EXPECT_THAT(collectPreferredTypes(Code), Each("long long")); 377 378 Code = R"cpp( 379 void test(int a, int *ptr) { 380 !^a; 381 !^ptr; 382 !!!^a; 383 384 a = !^a; 385 a = !^ptr; 386 a = !!!^a; 387 } 388 )cpp"; 389 EXPECT_THAT(collectPreferredTypes(Code), Each("_Bool")); 390 391 Code = R"cpp( 392 void test(int a) { 393 const int* x = &^a; 394 } 395 )cpp"; 396 EXPECT_THAT(collectPreferredTypes(Code), Each("const int")); 397 398 Code = R"cpp( 399 void test(int *a) { 400 int x = *^a; 401 int &r = *^a; 402 } 403 )cpp"; 404 EXPECT_THAT(collectPreferredTypes(Code), Each("int *")); 405 406 Code = R"cpp( 407 void test(int a) { 408 *^a; 409 &^a; 410 } 411 412 )cpp"; 413 } 414 415 TEST(PreferredTypeTest, ParenExpr) { 416 StringRef Code = R"cpp( 417 const int *i = ^(^(^(^10))); 418 )cpp"; 419 EXPECT_THAT(collectPreferredTypes(Code), Each("const int *")); 420 } 421 422 TEST(PreferredTypeTest, FunctionArguments) { 423 StringRef Code = R"cpp( 424 void foo(const int*); 425 426 void bar(const int*); 427 void bar(const int*, int b); 428 429 struct vector { 430 const int *data(); 431 }; 432 void test() { 433 foo(^(^(^(^vec^tor^().^da^ta^())))); 434 bar(^(^(^(^vec^tor^().^da^ta^())))); 435 } 436 )cpp"; 437 EXPECT_THAT(collectPreferredTypes(Code), Each("const int *")); 438 439 Code = R"cpp( 440 void bar(int, volatile double *); 441 void bar(int, volatile double *, int, int); 442 443 struct vector { 444 double *data(); 445 }; 446 447 struct class_members { 448 void bar(int, volatile double *); 449 void bar(int, volatile double *, int, int); 450 }; 451 void test() { 452 bar(10, ^(^(^(^vec^tor^().^da^ta^())))); 453 class_members().bar(10, ^(^(^(^vec^tor^().^da^ta^())))); 454 } 455 )cpp"; 456 EXPECT_THAT(collectPreferredTypes(Code), Each("volatile double *")); 457 458 Code = R"cpp( 459 namespace ns { 460 struct vector { 461 }; 462 } 463 void accepts_vector(ns::vector); 464 465 void test() { 466 accepts_vector(^::^ns::^vector()); 467 } 468 )cpp"; 469 EXPECT_THAT(collectPreferredTypes(Code), Each("ns::vector")); 470 471 Code = R"cpp( 472 template <class T> 473 struct vector { using self = vector; }; 474 475 void accepts_vector(vector<int>); 476 int foo(int); 477 478 void test() { 479 accepts_vector(^::^vector<decltype(foo(1))>::^self); 480 } 481 )cpp"; 482 EXPECT_THAT(collectPreferredTypes(Code), Each("vector<int>")); 483 } 484 485 TEST(PreferredTypeTest, NoCrashOnInvalidTypes) { 486 StringRef Code = R"cpp( 487 auto x = decltype(&1)(^); 488 auto y = new decltype(&1)(^); 489 // GNU decimal type extension is not supported in clang. 490 auto z = new _Decimal128(^); 491 )cpp"; 492 EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE")); 493 } 494 495 } // namespace 496