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/Format/Format.h" 15 #include "llvm/Support/Error.h" 16 #include "llvm/Support/raw_os_ostream.h" 17 #include "llvm/Testing/Support/Error.h" 18 #include "gmock/gmock.h" 19 #include "gtest/gtest.h" 20 21 namespace clang { 22 namespace clangd { 23 namespace { 24 25 using llvm::Failed; 26 using llvm::HasValue; 27 using ::testing::UnorderedElementsAreArray; 28 29 MATCHER_P2(Pos, Line, Col, "") { 30 return arg.line == int(Line) && arg.character == int(Col); 31 } 32 33 MATCHER_P(MacroName, Name, "") { return arg.Name == Name; } 34 35 /// A helper to make tests easier to read. 36 Position position(int line, int character) { 37 Position Pos; 38 Pos.line = line; 39 Pos.character = character; 40 return Pos; 41 } 42 43 Range range(const std::pair<int, int> p1, const std::pair<int, int> p2) { 44 Range range; 45 range.start = position(p1.first, p1.second); 46 range.end = position(p2.first, p2.second); 47 return range; 48 } 49 50 TEST(SourceCodeTests, lspLength) { 51 EXPECT_EQ(lspLength(""), 0UL); 52 EXPECT_EQ(lspLength("ascii"), 5UL); 53 // BMP 54 EXPECT_EQ(lspLength("↓"), 1UL); 55 EXPECT_EQ(lspLength("¥"), 1UL); 56 // astral 57 EXPECT_EQ(lspLength(""), 2UL); 58 59 WithContextValue UTF8(kCurrentOffsetEncoding, OffsetEncoding::UTF8); 60 EXPECT_EQ(lspLength(""), 0UL); 61 EXPECT_EQ(lspLength("ascii"), 5UL); 62 // BMP 63 EXPECT_EQ(lspLength("↓"), 3UL); 64 EXPECT_EQ(lspLength("¥"), 2UL); 65 // astral 66 EXPECT_EQ(lspLength(""), 4UL); 67 68 WithContextValue UTF32(kCurrentOffsetEncoding, OffsetEncoding::UTF32); 69 EXPECT_EQ(lspLength(""), 0UL); 70 EXPECT_EQ(lspLength("ascii"), 5UL); 71 // BMP 72 EXPECT_EQ(lspLength("↓"), 1UL); 73 EXPECT_EQ(lspLength("¥"), 1UL); 74 // astral 75 EXPECT_EQ(lspLength(""), 1UL); 76 } 77 78 // The = → below are ASCII (1 byte), BMP (3 bytes), and astral (4 bytes). 79 const char File[] = R"(0:0 = 0 80 1:0 → 8 81 2:0 18)"; 82 struct Line { 83 unsigned Number; 84 unsigned Offset; 85 unsigned Length; 86 }; 87 Line FileLines[] = {Line{0, 0, 7}, Line{1, 8, 9}, Line{2, 18, 11}}; 88 89 TEST(SourceCodeTests, PositionToOffset) { 90 // line out of bounds 91 EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), llvm::Failed()); 92 // first line 93 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, -1)), 94 llvm::Failed()); // out of range 95 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 0)), 96 llvm::HasValue(0)); // first character 97 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 3)), 98 llvm::HasValue(3)); // middle character 99 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 6)), 100 llvm::HasValue(6)); // last character 101 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7)), 102 llvm::HasValue(7)); // the newline itself 103 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7), false), 104 llvm::HasValue(7)); 105 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8)), 106 llvm::HasValue(7)); // out of range 107 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8), false), 108 llvm::Failed()); // out of range 109 // middle line 110 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, -1)), 111 llvm::Failed()); // out of range 112 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 0)), 113 llvm::HasValue(8)); // first character 114 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3)), 115 llvm::HasValue(11)); // middle character 116 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3), false), 117 llvm::HasValue(11)); 118 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 6)), 119 llvm::HasValue(16)); // last character 120 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 7)), 121 llvm::HasValue(17)); // the newline itself 122 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8)), 123 llvm::HasValue(17)); // out of range 124 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8), false), 125 llvm::Failed()); // out of range 126 // last line 127 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, -1)), 128 llvm::Failed()); // out of range 129 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 0)), 130 llvm::HasValue(18)); // first character 131 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 3)), 132 llvm::HasValue(21)); // middle character 133 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 5), false), 134 llvm::Failed()); // middle of surrogate pair 135 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 5)), 136 llvm::HasValue(26)); // middle of surrogate pair 137 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 6), false), 138 llvm::HasValue(26)); // end of surrogate pair 139 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 8)), 140 llvm::HasValue(28)); // last character 141 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 9)), 142 llvm::HasValue(29)); // EOF 143 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 10), false), 144 llvm::Failed()); // out of range 145 // line out of bounds 146 EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 0)), llvm::Failed()); 147 EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 1)), llvm::Failed()); 148 149 // Codepoints are similar, except near astral characters. 150 WithContextValue UTF32(kCurrentOffsetEncoding, OffsetEncoding::UTF32); 151 // line out of bounds 152 EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), llvm::Failed()); 153 // first line 154 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, -1)), 155 llvm::Failed()); // out of range 156 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 0)), 157 llvm::HasValue(0)); // first character 158 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 3)), 159 llvm::HasValue(3)); // middle character 160 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 6)), 161 llvm::HasValue(6)); // last character 162 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7)), 163 llvm::HasValue(7)); // the newline itself 164 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7), false), 165 llvm::HasValue(7)); 166 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8)), 167 llvm::HasValue(7)); // out of range 168 EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8), false), 169 llvm::Failed()); // out of range 170 // middle line 171 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, -1)), 172 llvm::Failed()); // out of range 173 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 0)), 174 llvm::HasValue(8)); // first character 175 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3)), 176 llvm::HasValue(11)); // middle character 177 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3), false), 178 llvm::HasValue(11)); 179 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 6)), 180 llvm::HasValue(16)); // last character 181 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 7)), 182 llvm::HasValue(17)); // the newline itself 183 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8)), 184 llvm::HasValue(17)); // out of range 185 EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8), false), 186 llvm::Failed()); // out of range 187 // last line 188 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, -1)), 189 llvm::Failed()); // out of range 190 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 0)), 191 llvm::HasValue(18)); // first character 192 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 4)), 193 llvm::HasValue(22)); // Before astral character. 194 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 5), false), 195 llvm::HasValue(26)); // after astral character 196 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 7)), 197 llvm::HasValue(28)); // last character 198 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 8)), 199 llvm::HasValue(29)); // EOF 200 EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 9), false), 201 llvm::Failed()); // out of range 202 // line out of bounds 203 EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 0)), llvm::Failed()); 204 EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 1)), llvm::Failed()); 205 206 // Test UTF-8, where transformations are trivial. 207 WithContextValue UTF8(kCurrentOffsetEncoding, OffsetEncoding::UTF8); 208 EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), llvm::Failed()); 209 EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 0)), llvm::Failed()); 210 for (Line L : FileLines) { 211 EXPECT_THAT_EXPECTED(positionToOffset(File, position(L.Number, -1)), 212 llvm::Failed()); // out of range 213 for (unsigned I = 0; I <= L.Length; ++I) 214 EXPECT_THAT_EXPECTED(positionToOffset(File, position(L.Number, I)), 215 llvm::HasValue(L.Offset + I)); 216 EXPECT_THAT_EXPECTED(positionToOffset(File, position(L.Number, L.Length+1)), 217 llvm::HasValue(L.Offset + L.Length)); 218 EXPECT_THAT_EXPECTED( 219 positionToOffset(File, position(L.Number, L.Length + 1), false), 220 llvm::Failed()); // out of range 221 } 222 } 223 224 TEST(SourceCodeTests, OffsetToPosition) { 225 EXPECT_THAT(offsetToPosition(File, 0), Pos(0, 0)) << "start of file"; 226 EXPECT_THAT(offsetToPosition(File, 3), Pos(0, 3)) << "in first line"; 227 EXPECT_THAT(offsetToPosition(File, 6), Pos(0, 6)) << "end of first line"; 228 EXPECT_THAT(offsetToPosition(File, 7), Pos(0, 7)) << "first newline"; 229 EXPECT_THAT(offsetToPosition(File, 8), Pos(1, 0)) << "start of second line"; 230 EXPECT_THAT(offsetToPosition(File, 12), Pos(1, 4)) << "before BMP char"; 231 EXPECT_THAT(offsetToPosition(File, 13), Pos(1, 5)) << "in BMP char"; 232 EXPECT_THAT(offsetToPosition(File, 15), Pos(1, 5)) << "after BMP char"; 233 EXPECT_THAT(offsetToPosition(File, 16), Pos(1, 6)) << "end of second line"; 234 EXPECT_THAT(offsetToPosition(File, 17), Pos(1, 7)) << "second newline"; 235 EXPECT_THAT(offsetToPosition(File, 18), Pos(2, 0)) << "start of last line"; 236 EXPECT_THAT(offsetToPosition(File, 21), Pos(2, 3)) << "in last line"; 237 EXPECT_THAT(offsetToPosition(File, 22), Pos(2, 4)) << "before astral char"; 238 EXPECT_THAT(offsetToPosition(File, 24), Pos(2, 6)) << "in astral char"; 239 EXPECT_THAT(offsetToPosition(File, 26), Pos(2, 6)) << "after astral char"; 240 EXPECT_THAT(offsetToPosition(File, 28), Pos(2, 8)) << "end of last line"; 241 EXPECT_THAT(offsetToPosition(File, 29), Pos(2, 9)) << "EOF"; 242 EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 9)) << "out of bounds"; 243 244 // Codepoints are similar, except near astral characters. 245 WithContextValue UTF32(kCurrentOffsetEncoding, OffsetEncoding::UTF32); 246 EXPECT_THAT(offsetToPosition(File, 0), Pos(0, 0)) << "start of file"; 247 EXPECT_THAT(offsetToPosition(File, 3), Pos(0, 3)) << "in first line"; 248 EXPECT_THAT(offsetToPosition(File, 6), Pos(0, 6)) << "end of first line"; 249 EXPECT_THAT(offsetToPosition(File, 7), Pos(0, 7)) << "first newline"; 250 EXPECT_THAT(offsetToPosition(File, 8), Pos(1, 0)) << "start of second line"; 251 EXPECT_THAT(offsetToPosition(File, 12), Pos(1, 4)) << "before BMP char"; 252 EXPECT_THAT(offsetToPosition(File, 13), Pos(1, 5)) << "in BMP char"; 253 EXPECT_THAT(offsetToPosition(File, 15), Pos(1, 5)) << "after BMP char"; 254 EXPECT_THAT(offsetToPosition(File, 16), Pos(1, 6)) << "end of second line"; 255 EXPECT_THAT(offsetToPosition(File, 17), Pos(1, 7)) << "second newline"; 256 EXPECT_THAT(offsetToPosition(File, 18), Pos(2, 0)) << "start of last line"; 257 EXPECT_THAT(offsetToPosition(File, 21), Pos(2, 3)) << "in last line"; 258 EXPECT_THAT(offsetToPosition(File, 22), Pos(2, 4)) << "before astral char"; 259 EXPECT_THAT(offsetToPosition(File, 24), Pos(2, 5)) << "in astral char"; 260 EXPECT_THAT(offsetToPosition(File, 26), Pos(2, 5)) << "after astral char"; 261 EXPECT_THAT(offsetToPosition(File, 28), Pos(2, 7)) << "end of last line"; 262 EXPECT_THAT(offsetToPosition(File, 29), Pos(2, 8)) << "EOF"; 263 EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 8)) << "out of bounds"; 264 265 WithContextValue UTF8(kCurrentOffsetEncoding, OffsetEncoding::UTF8); 266 for (Line L : FileLines) { 267 for (unsigned I = 0; I <= L.Length; ++I) 268 EXPECT_THAT(offsetToPosition(File, L.Offset + I), Pos(L.Number, I)); 269 } 270 EXPECT_THAT(offsetToPosition(File, 30), Pos(2, 11)) << "out of bounds"; 271 } 272 273 TEST(SourceCodeTests, IsRangeConsecutive) { 274 EXPECT_TRUE(isRangeConsecutive(range({2, 2}, {2, 3}), range({2, 3}, {2, 4}))); 275 EXPECT_FALSE( 276 isRangeConsecutive(range({0, 2}, {0, 3}), range({2, 3}, {2, 4}))); 277 EXPECT_FALSE( 278 isRangeConsecutive(range({2, 2}, {2, 3}), range({2, 4}, {2, 5}))); 279 } 280 281 TEST(SourceCodeTests, SourceLocationInMainFile) { 282 Annotations Source(R"cpp( 283 ^in^t ^foo 284 ^bar 285 ^baz ^() {} {} {} {} { }^ 286 )cpp"); 287 288 SourceManagerForFile Owner("foo.cpp", Source.code()); 289 SourceManager &SM = Owner.get(); 290 291 SourceLocation StartOfFile = SM.getLocForStartOfFile(SM.getMainFileID()); 292 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(0, 0)), 293 HasValue(StartOfFile)); 294 // End of file. 295 EXPECT_THAT_EXPECTED( 296 sourceLocationInMainFile(SM, position(4, 0)), 297 HasValue(StartOfFile.getLocWithOffset(Source.code().size()))); 298 // Column number is too large. 299 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(0, 1)), Failed()); 300 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(0, 100)), 301 Failed()); 302 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(4, 1)), Failed()); 303 // Line number is too large. 304 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, position(5, 0)), Failed()); 305 // Check all positions mentioned in the test return valid results. 306 for (auto P : Source.points()) { 307 size_t Offset = llvm::cantFail(positionToOffset(Source.code(), P)); 308 EXPECT_THAT_EXPECTED(sourceLocationInMainFile(SM, P), 309 HasValue(StartOfFile.getLocWithOffset(Offset))); 310 } 311 } 312 313 TEST(SourceCodeTests, CollectIdentifiers) { 314 auto Style = format::getLLVMStyle(); 315 auto IDs = collectIdentifiers(R"cpp( 316 #include "a.h" 317 void foo() { int xyz; int abc = xyz; return foo(); } 318 )cpp", 319 Style); 320 EXPECT_EQ(IDs.size(), 7u); 321 EXPECT_EQ(IDs["include"], 1u); 322 EXPECT_EQ(IDs["void"], 1u); 323 EXPECT_EQ(IDs["int"], 2u); 324 EXPECT_EQ(IDs["xyz"], 2u); 325 EXPECT_EQ(IDs["abc"], 1u); 326 EXPECT_EQ(IDs["return"], 1u); 327 EXPECT_EQ(IDs["foo"], 2u); 328 } 329 330 TEST(SourceCodeTests, CollectWords) { 331 auto Words = collectWords(R"cpp( 332 #define FIZZ_BUZZ 333 // this is a comment 334 std::string getSomeText() { return "magic word"; } 335 )cpp"); 336 std::set<std::string> ActualWords(Words.keys().begin(), Words.keys().end()); 337 std::set<std::string> ExpectedWords = {"define", "fizz", "buzz", "this", 338 "comment", "string", "some", "text", 339 "return", "magic", "word"}; 340 EXPECT_EQ(ActualWords, ExpectedWords); 341 } 342 343 TEST(SourceCodeTests, VisibleNamespaces) { 344 std::vector<std::pair<const char *, std::vector<std::string>>> Cases = { 345 { 346 R"cpp( 347 // Using directive resolved against enclosing namespaces. 348 using namespace foo; 349 namespace ns { 350 using namespace bar; 351 )cpp", 352 {"ns", "", "bar", "foo", "ns::bar"}, 353 }, 354 { 355 R"cpp( 356 // Don't include namespaces we've closed, ignore namespace aliases. 357 using namespace clang; 358 using std::swap; 359 namespace clang { 360 namespace clangd {} 361 namespace ll = ::llvm; 362 } 363 namespace clang { 364 )cpp", 365 {"clang", ""}, 366 }, 367 { 368 R"cpp( 369 // Using directives visible even if a namespace is reopened. 370 // Ignore anonymous namespaces. 371 namespace foo{ using namespace bar; } 372 namespace foo{ namespace { 373 )cpp", 374 {"foo", "", "bar", "foo::bar"}, 375 }, 376 { 377 R"cpp( 378 // Mismatched braces 379 namespace foo{} 380 }}} 381 namespace bar{ 382 )cpp", 383 {"bar", ""}, 384 }, 385 { 386 R"cpp( 387 // Namespaces with multiple chunks. 388 namespace a::b { 389 using namespace c::d; 390 namespace e::f { 391 )cpp", 392 { 393 "a::b::e::f", 394 "", 395 "a", 396 "a::b", 397 "a::b::c::d", 398 "a::b::e", 399 "a::c::d", 400 "c::d", 401 }, 402 }, 403 }; 404 for (const auto& Case : Cases) { 405 EXPECT_EQ(Case.second, 406 visibleNamespaces(Case.first, format::getLLVMStyle())) 407 << Case.first; 408 } 409 } 410 411 TEST(SourceCodeTests, GetMacros) { 412 Annotations Code(R"cpp( 413 #define MACRO 123 414 int abc = MA^CRO; 415 )cpp"); 416 TestTU TU = TestTU::withCode(Code.code()); 417 auto AST = TU.build(); 418 auto Loc = getBeginningOfIdentifier(AST, Code.point(), 419 AST.getSourceManager().getMainFileID()); 420 auto Result = locateMacroAt(Loc, AST.getPreprocessor()); 421 ASSERT_TRUE(Result); 422 EXPECT_THAT(*Result, MacroName("MACRO")); 423 } 424 425 TEST(SourceCodeTests, IsInsideMainFile){ 426 TestTU TU; 427 TU.HeaderCode = R"cpp( 428 #define DEFINE_CLASS(X) class X {}; 429 #define DEFINE_YY DEFINE_CLASS(YY) 430 431 class Header1 {}; 432 DEFINE_CLASS(Header2) 433 class Header {}; 434 )cpp"; 435 TU.Code = R"cpp( 436 class Main1 {}; 437 DEFINE_CLASS(Main2) 438 DEFINE_YY 439 class Main {}; 440 )cpp"; 441 TU.ExtraArgs.push_back("-DHeader=Header3"); 442 TU.ExtraArgs.push_back("-DMain=Main3"); 443 auto AST = TU.build(); 444 const auto& SM = AST.getSourceManager(); 445 auto DeclLoc = [&AST](llvm::StringRef Name) { 446 return findDecl(AST, Name).getLocation(); 447 }; 448 for (const auto *HeaderDecl : {"Header1", "Header2", "Header3"}) 449 EXPECT_FALSE(isInsideMainFile(DeclLoc(HeaderDecl), SM)); 450 451 for (const auto *MainDecl : {"Main1", "Main2", "Main3", "YY"}) 452 EXPECT_TRUE(isInsideMainFile(DeclLoc(MainDecl), SM)); 453 } 454 455 // Test for functions toHalfOpenFileRange and getHalfOpenFileRange 456 TEST(SourceCodeTests, HalfOpenFileRange) { 457 // Each marked range should be the file range of the decl with the same name 458 // and each name should be unique. 459 Annotations Test(R"cpp( 460 #define FOO(X, Y) int Y = ++X 461 #define BAR(X) X + 1 462 #define ECHO(X) X 463 template<typename T> 464 class P {}; 465 void f() { 466 $a[[P<P<P<P<P<int>>>>> a]]; 467 $b[[int b = 1]]; 468 $c[[FOO(b, c)]]; 469 $d[[FOO(BAR(BAR(b)), d)]]; 470 // FIXME: We might want to select everything inside the outer ECHO. 471 ECHO(ECHO($e[[int) ECHO(e]])); 472 } 473 )cpp"); 474 475 ParsedAST AST = TestTU::withCode(Test.code()).build(); 476 llvm::errs() << Test.code(); 477 const SourceManager &SM = AST.getSourceManager(); 478 const LangOptions &LangOpts = AST.getASTContext().getLangOpts(); 479 // Turn a SourceLocation into a pair of positions 480 auto SourceRangeToRange = [&SM](SourceRange SrcRange) { 481 return Range{sourceLocToPosition(SM, SrcRange.getBegin()), 482 sourceLocToPosition(SM, SrcRange.getEnd())}; 483 }; 484 auto CheckRange = [&](llvm::StringRef Name) { 485 const NamedDecl &Decl = findUnqualifiedDecl(AST, Name); 486 auto FileRange = toHalfOpenFileRange(SM, LangOpts, Decl.getSourceRange()); 487 SCOPED_TRACE("Checking range: " + Name); 488 ASSERT_NE(FileRange, llvm::None); 489 Range HalfOpenRange = SourceRangeToRange(*FileRange); 490 EXPECT_EQ(HalfOpenRange, Test.ranges(Name)[0]); 491 }; 492 493 CheckRange("a"); 494 CheckRange("b"); 495 CheckRange("c"); 496 CheckRange("d"); 497 CheckRange("e"); 498 } 499 500 } // namespace 501 } // namespace clangd 502 } // namespace clang 503