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