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