1 //===-- SourceCodeTests.cpp ------------------------------------*- C++ -*-===// 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 #include "Annotations.h" 9 #include "Context.h" 10 #include "Protocol.h" 11 #include "SourceCode.h" 12 #include "TestTU.h" 13 #include "clang/Basic/LangOptions.h" 14 #include "clang/Basic/SourceLocation.h" 15 #include "clang/Format/Format.h" 16 #include "llvm/Support/Error.h" 17 #include "llvm/Support/raw_os_ostream.h" 18 #include "llvm/Testing/Support/Annotations.h" 19 #include "llvm/Testing/Support/Error.h" 20 #include "gmock/gmock.h" 21 #include "gtest/gtest.h" 22 #include <tuple> 23 24 namespace clang { 25 namespace clangd { 26 namespace { 27 28 using llvm::Failed; 29 using llvm::HasValue; 30 using ::testing::UnorderedElementsAreArray; 31 32 MATCHER_P2(Pos, Line, Col, "") { 33 return arg.line == int(Line) && arg.character == int(Col); 34 } 35 36 MATCHER_P(MacroName, Name, "") { return arg.Name == Name; } 37 38 /// A helper to make tests easier to read. 39 Position position(int line, int character) { 40 Position Pos; 41 Pos.line = line; 42 Pos.character = character; 43 return Pos; 44 } 45 46 Range range(const std::pair<int, int> p1, const std::pair<int, int> p2) { 47 Range range; 48 range.start = position(p1.first, p1.second); 49 range.end = position(p2.first, p2.second); 50 return range; 51 } 52 53 TEST(SourceCodeTests, lspLength) { 54 EXPECT_EQ(lspLength(""), 0UL); 55 EXPECT_EQ(lspLength("ascii"), 5UL); 56 // BMP 57 EXPECT_EQ(lspLength("↓"), 1UL); 58 EXPECT_EQ(lspLength("¥"), 1UL); 59 // astral 60 EXPECT_EQ(lspLength(""), 2UL); 61 62 WithContextValue UTF8(kCurrentOffsetEncoding, OffsetEncoding::UTF8); 63 EXPECT_EQ(lspLength(""), 0UL); 64 EXPECT_EQ(lspLength("ascii"), 5UL); 65 // BMP 66 EXPECT_EQ(lspLength("↓"), 3UL); 67 EXPECT_EQ(lspLength("¥"), 2UL); 68 // astral 69 EXPECT_EQ(lspLength(""), 4UL); 70 71 WithContextValue UTF32(kCurrentOffsetEncoding, OffsetEncoding::UTF32); 72 EXPECT_EQ(lspLength(""), 0UL); 73 EXPECT_EQ(lspLength("ascii"), 5UL); 74 // BMP 75 EXPECT_EQ(lspLength("↓"), 1UL); 76 EXPECT_EQ(lspLength("¥"), 1UL); 77 // astral 78 EXPECT_EQ(lspLength(""), 1UL); 79 } 80 81 // The = → below are ASCII (1 byte), BMP (3 bytes), and astral (4 bytes). 82 const char File[] = R"(0:0 = 0 83 1:0 → 8 84 2:0 18)"; 85 struct Line { 86 unsigned Number; 87 unsigned Offset; 88 unsigned Length; 89 }; 90 Line FileLines[] = {Line{0, 0, 7}, Line{1, 8, 9}, Line{2, 18, 11}}; 91 92 TEST(SourceCodeTests, PositionToOffset) { 93 // line out of bounds 94 EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), llvm::Failed()); 95 // first line 96 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, -1)), 97 llvm::Failed()); // out of range 98 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 0)), 99 llvm::HasValue(0)); // first character 100 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 3)), 101 llvm::HasValue(3)); // middle character 102 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 6)), 103 llvm::HasValue(6)); // last character 104 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7)), 105 llvm::HasValue(7)); // the newline itself 106 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7), false), 107 llvm::HasValue(7)); 108 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8)), 109 llvm::HasValue(7)); // out of range 110 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8), false), 111 llvm::Failed()); // out of range 112 // middle line 113 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, -1)), 114 llvm::Failed()); // out of range 115 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 0)), 116 llvm::HasValue(8)); // first character 117 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3)), 118 llvm::HasValue(11)); // middle character 119 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3), false), 120 llvm::HasValue(11)); 121 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 6)), 122 llvm::HasValue(16)); // last character 123 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 7)), 124 llvm::HasValue(17)); // the newline itself 125 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8)), 126 llvm::HasValue(17)); // out of range 127 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8), false), 128 llvm::Failed()); // out of range 129 // last line 130 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, -1)), 131 llvm::Failed()); // out of range 132 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 0)), 133 llvm::HasValue(18)); // first character 134 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 3)), 135 llvm::HasValue(21)); // middle character 136 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 5), false), 137 llvm::Failed()); // middle of surrogate pair 138 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 5)), 139 llvm::HasValue(26)); // middle of surrogate pair 140 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 6), false), 141 llvm::HasValue(26)); // end of surrogate pair 142 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 8)), 143 llvm::HasValue(28)); // last character 144 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 9)), 145 llvm::HasValue(29)); // EOF 146 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 10), false), 147 llvm::Failed()); // out of range 148 // line out of bounds 149 EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 0)), llvm::Failed()); 150 EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 1)), llvm::Failed()); 151 152 // Codepoints are similar, except near astral characters. 153 WithContextValue UTF32(kCurrentOffsetEncoding, OffsetEncoding::UTF32); 154 // line out of bounds 155 EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), llvm::Failed()); 156 // first line 157 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, -1)), 158 llvm::Failed()); // out of range 159 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 0)), 160 llvm::HasValue(0)); // first character 161 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 3)), 162 llvm::HasValue(3)); // middle character 163 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 6)), 164 llvm::HasValue(6)); // last character 165 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7)), 166 llvm::HasValue(7)); // the newline itself 167 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7), false), 168 llvm::HasValue(7)); 169 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8)), 170 llvm::HasValue(7)); // out of range 171 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8), false), 172 llvm::Failed()); // out of range 173 // middle line 174 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, -1)), 175 llvm::Failed()); // out of range 176 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 0)), 177 llvm::HasValue(8)); // first character 178 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3)), 179 llvm::HasValue(11)); // middle character 180 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3), false), 181 llvm::HasValue(11)); 182 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 6)), 183 llvm::HasValue(16)); // last character 184 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 7)), 185 llvm::HasValue(17)); // the newline itself 186 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8)), 187 llvm::HasValue(17)); // out of range 188 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8), false), 189 llvm::Failed()); // out of range 190 // last line 191 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, -1)), 192 llvm::Failed()); // out of range 193 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 0)), 194 llvm::HasValue(18)); // first character 195 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 4)), 196 llvm::HasValue(22)); // Before astral character. 197 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 5), false), 198 llvm::HasValue(26)); // after astral character 199 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 7)), 200 llvm::HasValue(28)); // last character 201 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 8)), 202 llvm::HasValue(29)); // EOF 203 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 9), false), 204 llvm::Failed()); // out of range 205 // line out of bounds 206 EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 0)), llvm::Failed()); 207 EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 1)), llvm::Failed()); 208 209 // Test UTF-8, where transformations are trivial. 210 WithContextValue UTF8(kCurrentOffsetEncoding, OffsetEncoding::UTF8); 211 EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), llvm::Failed()); 212 EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 0)), llvm::Failed()); 213 for (Line L : FileLines) { 214 EXPECT_THAT_EXPECTED(positionToOffset(File, position(L.Number, -1)), 215 llvm::Failed()); // out of range 216 for (unsigned I = 0; I <= L.Length; ++I) 217 EXPECT_THAT_EXPECTED(positionToOffset(File, position(L.Number, I)), 218 llvm::HasValue(L.Offset + I)); 219 EXPECT_THAT_EXPECTED(positionToOffset(File, position(L.Number, L.Length+1)), 220 llvm::HasValue(L.Offset + L.Length)); 221 EXPECT_THAT_EXPECTED( 222 positionToOffset(File, position(L.Number, L.Length + 1), false), 223 llvm::Failed()); // out of range 224 } 225 } 226 227 TEST(SourceCodeTests, OffsetToPosition) { 228 EXPECT_THAT(offsetToPosition(File, 0), Pos(0, 0)) << "start of file"; 229 EXPECT_THAT(offsetToPosition(File, 3), Pos(0, 3)) << "in first line"; 230 EXPECT_THAT(offsetToPosition(File, 6), Pos(0, 6)) << "end of first line"; 231 EXPECT_THAT(offsetToPosition(File, 7), Pos(0, 7)) << "first newline"; 232 EXPECT_THAT(offsetToPosition(File, 8), Pos(1, 0)) << "start of second line"; 233 EXPECT_THAT(offsetToPosition(File, 12), Pos(1, 4)) << "before BMP char"; 234 EXPECT_THAT(offsetToPosition(File, 13), Pos(1, 5)) << "in BMP char"; 235 EXPECT_THAT(offsetToPosition(File, 15), Pos(1, 5)) << "after BMP char"; 236 EXPECT_THAT(offsetToPosition(File, 16), Pos(1, 6)) << "end of second line"; 237 EXPECT_THAT(offsetToPosition(File, 17), Pos(1, 7)) << "second newline"; 238 EXPECT_THAT(offsetToPosition(File, 18), Pos(2, 0)) << "start of last line"; 239 EXPECT_THAT(offsetToPosition(File, 21), Pos(2, 3)) << "in last line"; 240 EXPECT_THAT(offsetToPosition(File, 22), Pos(2, 4)) << "before astral char"; 241 EXPECT_THAT(offsetToPosition(File, 24), Pos(2, 6)) << "in astral char"; 242 EXPECT_THAT(offsetToPosition(File, 26), Pos(2, 6)) << "after astral char"; 243 EXPECT_THAT(offsetToPosition(File, 28), Pos(2, 8)) << "end of last line"; 244 EXPECT_THAT(offsetToPosition(File, 29), Pos(2, 9)) << "EOF"; 245 EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 9)) << "out of bounds"; 246 247 // Codepoints are similar, except near astral characters. 248 WithContextValue UTF32(kCurrentOffsetEncoding, OffsetEncoding::UTF32); 249 EXPECT_THAT(offsetToPosition(File, 0), Pos(0, 0)) << "start of file"; 250 EXPECT_THAT(offsetToPosition(File, 3), Pos(0, 3)) << "in first line"; 251 EXPECT_THAT(offsetToPosition(File, 6), Pos(0, 6)) << "end of first line"; 252 EXPECT_THAT(offsetToPosition(File, 7), Pos(0, 7)) << "first newline"; 253 EXPECT_THAT(offsetToPosition(File, 8), Pos(1, 0)) << "start of second line"; 254 EXPECT_THAT(offsetToPosition(File, 12), Pos(1, 4)) << "before BMP char"; 255 EXPECT_THAT(offsetToPosition(File, 13), Pos(1, 5)) << "in BMP char"; 256 EXPECT_THAT(offsetToPosition(File, 15), Pos(1, 5)) << "after BMP char"; 257 EXPECT_THAT(offsetToPosition(File, 16), Pos(1, 6)) << "end of second line"; 258 EXPECT_THAT(offsetToPosition(File, 17), Pos(1, 7)) << "second newline"; 259 EXPECT_THAT(offsetToPosition(File, 18), Pos(2, 0)) << "start of last line"; 260 EXPECT_THAT(offsetToPosition(File, 21), Pos(2, 3)) << "in last line"; 261 EXPECT_THAT(offsetToPosition(File, 22), Pos(2, 4)) << "before astral char"; 262 EXPECT_THAT(offsetToPosition(File, 24), Pos(2, 5)) << "in astral char"; 263 EXPECT_THAT(offsetToPosition(File, 26), Pos(2, 5)) << "after astral char"; 264 EXPECT_THAT(offsetToPosition(File, 28), Pos(2, 7)) << "end of last line"; 265 EXPECT_THAT(offsetToPosition(File, 29), Pos(2, 8)) << "EOF"; 266 EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 8)) << "out of bounds"; 267 268 WithContextValue UTF8(kCurrentOffsetEncoding, OffsetEncoding::UTF8); 269 for (Line L : FileLines) { 270 for (unsigned I = 0; I <= L.Length; ++I) 271 EXPECT_THAT(offsetToPosition(File, L.Offset + I), Pos(L.Number, I)); 272 } 273 EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 11)) << "out of bounds"; 274 } 275 276 TEST(SourceCodeTests, IsRangeConsecutive) { 277 EXPECT_TRUE(isRangeConsecutive(range({2, 2}, {2, 3}), range({2, 3}, {2, 4}))); 278 EXPECT_FALSE( 279 isRangeConsecutive(range({0, 2}, {0, 3}), range({2, 3}, {2, 4}))); 280 EXPECT_FALSE( 281 isRangeConsecutive(range({2, 2}, {2, 3}), range({2, 4}, {2, 5}))); 282 } 283 284 TEST(SourceCodeTests, SourceLocationInMainFile) { 285 Annotations Source(R"cpp( 286 ^in^t ^foo 287 ^bar 288 ^baz ^() {} {} {} {} { }^ 289 )cpp"); 290 291 SourceManagerForFile Owner("foo.cpp", Source.code()); 292 SourceManager &SM = Owner.get(); 293 294 SourceLocation StartOfFile = SM.getLocForStartOfFile(SM.getMainFileID()); 295 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(0, 0)), 296 HasValue(StartOfFile)); 297 // End of file. 298 EXPECT_THAT_EXPECTED( 299 sourceLocationInMainFile(SM, position(4, 0)), 300 HasValue(StartOfFile.getLocWithOffset(Source.code().size()))); 301 // Column number is too large. 302 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(0, 1)), Failed()); 303 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(0, 100)), 304 Failed()); 305 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(4, 1)), Failed()); 306 // Line number is too large. 307 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(5, 0)), Failed()); 308 // Check all positions mentioned in the test return valid results. 309 for (auto P : Source.points()) { 310 size_t Offset = llvm::cantFail(positionToOffset(Source.code(), P)); 311 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, P), 312 HasValue(StartOfFile.getLocWithOffset(Offset))); 313 } 314 } 315 316 TEST(SourceCodeTests, GetBeginningOfIdentifier) { 317 std::string Preamble = R"cpp( 318 struct Bar { int func(); }; 319 #define MACRO(X) void f() { X; } 320 Bar* bar; 321 )cpp"; 322 // First ^ is the expected beginning, last is the search position. 323 for (const std::string &Text : std::vector<std::string>{ 324 "int ^f^oo();", // inside identifier 325 "int ^foo();", // beginning of identifier 326 "int ^foo^();", // end of identifier 327 "int foo(^);", // non-identifier 328 "^int foo();", // beginning of file (can't back up) 329 "int ^f0^0();", // after a digit (lexing at N-1 is wrong) 330 "/^/ comments", // non-interesting token 331 "void f(int abc) { abc ^ ++; }", // whitespace 332 "void f(int abc) { ^abc^++; }", // range of identifier 333 "void f(int abc) { ++^abc^; }", // range of identifier 334 "void f(int abc) { ++^abc; }", // range of identifier 335 "void f(int abc) { ^+^+abc; }", // range of operator 336 "void f(int abc) { ^abc^ ++; }", // range of identifier 337 "void f(int abc) { abc ^++^; }", // range of operator 338 "void f(int abc) { ^++^ abc; }", // range of operator 339 "void f(int abc) { ++ ^abc^; }", // range of identifier 340 "void f(int abc) { ^++^/**/abc; }", // range of operator 341 "void f(int abc) { ++/**/^abc; }", // range of identifier 342 "void f(int abc) { ^abc^/**/++; }", // range of identifier 343 "void f(int abc) { abc/**/^++; }", // range of operator 344 "void f() {^ }", // outside of identifier and operator 345 "int ^λλ^λ();", // UTF-8 handled properly when backing up 346 347 // identifier in macro arg 348 "MACRO(bar->^func())", // beginning of identifier 349 "MACRO(bar->^fun^c())", // inside identifier 350 "MACRO(bar->^func^())", // end of identifier 351 "MACRO(^bar->func())", // begin identifier 352 "MACRO(^bar^->func())", // end identifier 353 "^MACRO(bar->func())", // beginning of macro name 354 "^MAC^RO(bar->func())", // inside macro name 355 "^MACRO^(bar->func())", // end of macro name 356 }) { 357 std::string WithPreamble = Preamble + Text; 358 Annotations TestCase(WithPreamble); 359 auto AST = TestTU::withCode(TestCase.code()).build(); 360 const auto &SourceMgr = AST.getSourceManager(); 361 SourceLocation Actual = getBeginningOfIdentifier( 362 TestCase.points().back(), SourceMgr, AST.getASTContext().getLangOpts()); 363 Position ActualPos = offsetToPosition( 364 TestCase.code(), 365 SourceMgr.getFileOffset(SourceMgr.getSpellingLoc(Actual))); 366 EXPECT_EQ(TestCase.points().front(), ActualPos) << Text; 367 } 368 } 369 370 TEST(SourceCodeTests, CollectIdentifiers) { 371 auto Style = format::getLLVMStyle(); 372 auto IDs = collectIdentifiers(R"cpp( 373 #include "a.h" 374 void foo() { int xyz; int abc = xyz; return foo(); } 375 )cpp", 376 Style); 377 EXPECT_EQ(IDs.size(), 7u); 378 EXPECT_EQ(IDs["include"], 1u); 379 EXPECT_EQ(IDs["void"], 1u); 380 EXPECT_EQ(IDs["int"], 2u); 381 EXPECT_EQ(IDs["xyz"], 2u); 382 EXPECT_EQ(IDs["abc"], 1u); 383 EXPECT_EQ(IDs["return"], 1u); 384 EXPECT_EQ(IDs["foo"], 2u); 385 } 386 387 TEST(SourceCodeTests, CollectWords) { 388 auto Words = collectWords(R"cpp( 389 #define FIZZ_BUZZ 390 // this is a comment 391 std::string getSomeText() { return "magic word"; } 392 )cpp"); 393 std::set<std::string> ActualWords(Words.keys().begin(), Words.keys().end()); 394 std::set<std::string> ExpectedWords = {"define", "fizz", "buzz", "this", 395 "comment", "string", "some", "text", 396 "return", "magic", "word"}; 397 EXPECT_EQ(ActualWords, ExpectedWords); 398 } 399 400 TEST(SourceCodeTests, VisibleNamespaces) { 401 std::vector<std::pair<const char *, std::vector<std::string>>> Cases = { 402 { 403 R"cpp( 404 // Using directive resolved against enclosing namespaces. 405 using namespace foo; 406 namespace ns { 407 using namespace bar; 408 )cpp", 409 {"ns", "", "bar", "foo", "ns::bar"}, 410 }, 411 { 412 R"cpp( 413 // Don't include namespaces we've closed, ignore namespace aliases. 414 using namespace clang; 415 using std::swap; 416 namespace clang { 417 namespace clangd {} 418 namespace ll = ::llvm; 419 } 420 namespace clang { 421 )cpp", 422 {"clang", ""}, 423 }, 424 { 425 R"cpp( 426 // Using directives visible even if a namespace is reopened. 427 // Ignore anonymous namespaces. 428 namespace foo{ using namespace bar; } 429 namespace foo{ namespace { 430 )cpp", 431 {"foo", "", "bar", "foo::bar"}, 432 }, 433 { 434 R"cpp( 435 // Mismatched braces 436 namespace foo{} 437 }}} 438 namespace bar{ 439 )cpp", 440 {"bar", ""}, 441 }, 442 { 443 R"cpp( 444 // Namespaces with multiple chunks. 445 namespace a::b { 446 using namespace c::d; 447 namespace e::f { 448 )cpp", 449 { 450 "a::b::e::f", 451 "", 452 "a", 453 "a::b", 454 "a::b::c::d", 455 "a::b::e", 456 "a::c::d", 457 "c::d", 458 }, 459 }, 460 { 461 "", 462 {""}, 463 }, 464 { 465 R"cpp( 466 // Parse until EOF 467 namespace bar{})cpp", 468 {""}, 469 }, 470 }; 471 for (const auto& Case : Cases) { 472 EXPECT_EQ(Case.second, 473 visibleNamespaces(Case.first, format::getLLVMStyle())) 474 << Case.first; 475 } 476 } 477 478 TEST(SourceCodeTests, GetMacros) { 479 Annotations Code(R"cpp( 480 #define MACRO 123 481 int abc = MA^CRO; 482 )cpp"); 483 TestTU TU = TestTU::withCode(Code.code()); 484 auto AST = TU.build(); 485 auto Loc = getBeginningOfIdentifier(Code.point(), AST.getSourceManager(), 486 AST.getASTContext().getLangOpts()); 487 auto Result = locateMacroAt(Loc, AST.getPreprocessor()); 488 ASSERT_TRUE(Result); 489 EXPECT_THAT(*Result, MacroName("MACRO")); 490 } 491 492 TEST(SourceCodeTests, IsInsideMainFile){ 493 TestTU TU; 494 TU.HeaderCode = R"cpp( 495 #define DEFINE_CLASS(X) class X {}; 496 #define DEFINE_YY DEFINE_CLASS(YY) 497 498 class Header1 {}; 499 DEFINE_CLASS(Header2) 500 class Header {}; 501 )cpp"; 502 TU.Code = R"cpp( 503 class Main1 {}; 504 DEFINE_CLASS(Main2) 505 DEFINE_YY 506 class Main {}; 507 )cpp"; 508 TU.ExtraArgs.push_back("-DHeader=Header3"); 509 TU.ExtraArgs.push_back("-DMain=Main3"); 510 auto AST = TU.build(); 511 const auto& SM = AST.getSourceManager(); 512 auto DeclLoc = [&AST](llvm::StringRef Name) { 513 return findDecl(AST, Name).getLocation(); 514 }; 515 for (const auto *HeaderDecl : {"Header1", "Header2", "Header3"}) 516 EXPECT_FALSE(isInsideMainFile(DeclLoc(HeaderDecl), SM)); 517 518 for (const auto *MainDecl : {"Main1", "Main2", "Main3", "YY"}) 519 EXPECT_TRUE(isInsideMainFile(DeclLoc(MainDecl), SM)); 520 } 521 522 // Test for functions toHalfOpenFileRange and getHalfOpenFileRange 523 TEST(SourceCodeTests, HalfOpenFileRange) { 524 // Each marked range should be the file range of the decl with the same name 525 // and each name should be unique. 526 Annotations Test(R"cpp( 527 #define FOO(X, Y) int Y = ++X 528 #define BAR(X) X + 1 529 #define ECHO(X) X 530 531 #define BUZZ BAZZ(ADD) 532 #define BAZZ(m) m(1) 533 #define ADD(a) int f = a + 1; 534 template<typename T> 535 class P {}; 536 537 int main() { 538 $a[[P<P<P<P<P<int>>>>> a]]; 539 $b[[int b = 1]]; 540 $c[[FOO(b, c)]]; 541 $d[[FOO(BAR(BAR(b)), d)]]; 542 // FIXME: We might want to select everything inside the outer ECHO. 543 ECHO(ECHO($e[[int) ECHO(e]])); 544 // Shouldn't crash. 545 $f[[BUZZ]]; 546 } 547 )cpp"); 548 549 ParsedAST AST = TestTU::withCode(Test.code()).build(); 550 llvm::errs() << Test.code(); 551 const SourceManager &SM = AST.getSourceManager(); 552 const LangOptions &LangOpts = AST.getASTContext().getLangOpts(); 553 // Turn a SourceLocation into a pair of positions 554 auto SourceRangeToRange = [&SM](SourceRange SrcRange) { 555 return Range{sourceLocToPosition(SM, SrcRange.getBegin()), 556 sourceLocToPosition(SM, SrcRange.getEnd())}; 557 }; 558 auto CheckRange = [&](llvm::StringRef Name) { 559 const NamedDecl &Decl = findUnqualifiedDecl(AST, Name); 560 auto FileRange = toHalfOpenFileRange(SM, LangOpts, Decl.getSourceRange()); 561 SCOPED_TRACE("Checking range: " + Name); 562 ASSERT_NE(FileRange, llvm::None); 563 Range HalfOpenRange = SourceRangeToRange(*FileRange); 564 EXPECT_EQ(HalfOpenRange, Test.ranges(Name)[0]); 565 }; 566 567 CheckRange("a"); 568 CheckRange("b"); 569 CheckRange("c"); 570 CheckRange("d"); 571 CheckRange("e"); 572 CheckRange("f"); 573 } 574 575 TEST(SourceCodeTests, HalfOpenFileRangePathologicalPreprocessor) { 576 const char *Case = R"cpp( 577 #define MACRO while(1) 578 void test() { 579 [[#include "Expand.inc" 580 br^eak]]; 581 } 582 )cpp"; 583 Annotations Test(Case); 584 auto TU = TestTU::withCode(Test.code()); 585 TU.AdditionalFiles["Expand.inc"] = "MACRO\n"; 586 auto AST = TU.build(); 587 588 const auto &Func = cast<FunctionDecl>(findDecl(AST, "test")); 589 const auto &Body = cast<CompoundStmt>(Func.getBody()); 590 const auto &Loop = cast<WhileStmt>(*Body->child_begin()); 591 llvm::Optional<SourceRange> Range = toHalfOpenFileRange( 592 AST.getSourceManager(), AST.getASTContext().getLangOpts(), 593 Loop->getSourceRange()); 594 ASSERT_TRUE(Range) << "Failed to get file range"; 595 EXPECT_EQ(AST.getSourceManager().getFileOffset(Range->getBegin()), 596 Test.llvm::Annotations::range().Begin); 597 EXPECT_EQ(AST.getSourceManager().getFileOffset(Range->getEnd()), 598 Test.llvm::Annotations::range().End); 599 } 600 601 TEST(SourceCodeTests, IncludeHashLoc) { 602 const char *Case = R"cpp( 603 $foo^#include "foo.inc" 604 #define HEADER "bar.inc" 605 $bar^# include HEADER 606 )cpp"; 607 Annotations Test(Case); 608 auto TU = TestTU::withCode(Test.code()); 609 TU.AdditionalFiles["foo.inc"] = "int foo;\n"; 610 TU.AdditionalFiles["bar.inc"] = "int bar;\n"; 611 auto AST = TU.build(); 612 const auto& SM = AST.getSourceManager(); 613 614 FileID Foo = SM.getFileID(findDecl(AST, "foo").getLocation()); 615 EXPECT_EQ(SM.getFileOffset(includeHashLoc(Foo, SM)), 616 Test.llvm::Annotations::point("foo")); 617 FileID Bar = SM.getFileID(findDecl(AST, "bar").getLocation()); 618 EXPECT_EQ(SM.getFileOffset(includeHashLoc(Bar, SM)), 619 Test.llvm::Annotations::point("bar")); 620 } 621 622 TEST(SourceCodeTests, GetEligiblePoints) { 623 constexpr struct { 624 const char *Code; 625 const char *FullyQualifiedName; 626 const char *EnclosingNamespace; 627 } Cases[] = { 628 {R"cpp(// FIXME: We should also mark positions before and after 629 //declarations/definitions as eligible. 630 namespace ns1 { 631 namespace a { namespace ns2 {} } 632 namespace ns2 {^ 633 void foo(); 634 namespace {} 635 void bar() {} 636 namespace ns3 {} 637 class T {}; 638 ^} 639 using namespace ns2; 640 })cpp", 641 "ns1::ns2::symbol", "ns1::ns2::"}, 642 {R"cpp( 643 namespace ns1 {^ 644 namespace a { namespace ns2 {} } 645 namespace b {} 646 namespace ns {} 647 ^})cpp", 648 "ns1::ns2::symbol", "ns1::"}, 649 {R"cpp( 650 namespace x { 651 namespace a { namespace ns2 {} } 652 namespace b {} 653 namespace ns {} 654 }^)cpp", 655 "ns1::ns2::symbol", ""}, 656 {R"cpp( 657 namespace ns1 { 658 namespace ns2 {^^} 659 namespace b {} 660 namespace ns2 {^^} 661 } 662 namespace ns1 {namespace ns2 {^^}})cpp", 663 "ns1::ns2::symbol", "ns1::ns2::"}, 664 {R"cpp( 665 namespace ns1 {^ 666 namespace ns {} 667 namespace b {} 668 namespace ns {} 669 ^} 670 namespace ns1 {^namespace ns {}^})cpp", 671 "ns1::ns2::symbol", "ns1::"}, 672 }; 673 for (auto Case : Cases) { 674 Annotations Test(Case.Code); 675 676 auto Res = getEligiblePoints(Test.code(), Case.FullyQualifiedName, 677 format::getLLVMStyle()); 678 EXPECT_THAT(Res.EligiblePoints, testing::ElementsAreArray(Test.points())) 679 << Test.code(); 680 EXPECT_EQ(Res.EnclosingNamespace, Case.EnclosingNamespace) << Test.code(); 681 } 682 } 683 684 TEST(SourceCodeTests, IdentifierRanges) { 685 Annotations Code(R"cpp( 686 class [[Foo]] {}; 687 // Foo 688 /* Foo */ 689 void f([[Foo]]* foo1) { 690 [[Foo]] foo2; 691 auto S = [[Foo]](); 692 // cross-line identifier is not supported. 693 F\ 694 o\ 695 o foo2; 696 } 697 )cpp"); 698 LangOptions LangOpts; 699 LangOpts.CPlusPlus = true; 700 EXPECT_EQ(Code.ranges(), 701 collectIdentifierRanges("Foo", Code.code(), LangOpts)); 702 } 703 704 } // namespace 705 } // namespace clangd 706 } // namespace clang 707