1 //===- TokensTest.cpp -----------------------------------------------------===// 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/Tooling/Syntax/Tokens.h" 10 #include "clang/AST/ASTConsumer.h" 11 #include "clang/AST/Expr.h" 12 #include "clang/Basic/Diagnostic.h" 13 #include "clang/Basic/DiagnosticIDs.h" 14 #include "clang/Basic/DiagnosticOptions.h" 15 #include "clang/Basic/FileManager.h" 16 #include "clang/Basic/FileSystemOptions.h" 17 #include "clang/Basic/LLVM.h" 18 #include "clang/Basic/LangOptions.h" 19 #include "clang/Basic/SourceLocation.h" 20 #include "clang/Basic/SourceManager.h" 21 #include "clang/Basic/TokenKinds.def" 22 #include "clang/Basic/TokenKinds.h" 23 #include "clang/Frontend/CompilerInstance.h" 24 #include "clang/Frontend/FrontendAction.h" 25 #include "clang/Frontend/Utils.h" 26 #include "clang/Lex/Lexer.h" 27 #include "clang/Lex/PreprocessorOptions.h" 28 #include "clang/Lex/Token.h" 29 #include "clang/Tooling/Tooling.h" 30 #include "llvm/ADT/ArrayRef.h" 31 #include "llvm/ADT/IntrusiveRefCntPtr.h" 32 #include "llvm/ADT/None.h" 33 #include "llvm/ADT/Optional.h" 34 #include "llvm/ADT/STLExtras.h" 35 #include "llvm/ADT/StringRef.h" 36 #include "llvm/Support/FormatVariadic.h" 37 #include "llvm/Support/MemoryBuffer.h" 38 #include "llvm/Support/VirtualFileSystem.h" 39 #include "llvm/Support/raw_os_ostream.h" 40 #include "llvm/Support/raw_ostream.h" 41 #include "llvm/Testing/Support/Annotations.h" 42 #include "llvm/Testing/Support/SupportHelpers.h" 43 #include "gmock/gmock.h" 44 #include <cassert> 45 #include <cstdlib> 46 #include <gmock/gmock.h> 47 #include <gtest/gtest.h> 48 #include <memory> 49 #include <ostream> 50 #include <string> 51 52 using namespace clang; 53 using namespace clang::syntax; 54 55 using llvm::ValueIs; 56 using ::testing::_; 57 using ::testing::AllOf; 58 using ::testing::Contains; 59 using ::testing::ElementsAre; 60 using ::testing::Field; 61 using ::testing::IsEmpty; 62 using ::testing::Matcher; 63 using ::testing::Not; 64 using ::testing::Pointee; 65 using ::testing::StartsWith; 66 67 namespace { 68 // Checks the passed ArrayRef<T> has the same begin() and end() iterators as the 69 // argument. 70 MATCHER_P(SameRange, A, "") { 71 return A.begin() == arg.begin() && A.end() == arg.end(); 72 } 73 74 Matcher<TokenBuffer::Expansion> 75 IsExpansion(Matcher<llvm::ArrayRef<syntax::Token>> Spelled, 76 Matcher<llvm::ArrayRef<syntax::Token>> Expanded) { 77 return AllOf(Field(&TokenBuffer::Expansion::Spelled, Spelled), 78 Field(&TokenBuffer::Expansion::Expanded, Expanded)); 79 } 80 // Matchers for syntax::Token. 81 MATCHER_P(Kind, K, "") { return arg.kind() == K; } 82 MATCHER_P2(HasText, Text, SourceMgr, "") { 83 return arg.text(*SourceMgr) == Text; 84 } 85 /// Checks the start and end location of a token are equal to SourceRng. 86 MATCHER_P(RangeIs, SourceRng, "") { 87 return arg.location() == SourceRng.first && 88 arg.endLocation() == SourceRng.second; 89 } 90 91 class TokenCollectorTest : public ::testing::Test { 92 public: 93 /// Run the clang frontend, collect the preprocessed tokens from the frontend 94 /// invocation and store them in this->Buffer. 95 /// This also clears SourceManager before running the compiler. 96 void recordTokens(llvm::StringRef Code) { 97 class RecordTokens : public ASTFrontendAction { 98 public: 99 explicit RecordTokens(TokenBuffer &Result) : Result(Result) {} 100 101 bool BeginSourceFileAction(CompilerInstance &CI) override { 102 assert(!Collector && "expected only a single call to BeginSourceFile"); 103 Collector.emplace(CI.getPreprocessor()); 104 return true; 105 } 106 void EndSourceFileAction() override { 107 assert(Collector && "BeginSourceFileAction was never called"); 108 Result = std::move(*Collector).consume(); 109 Result.indexExpandedTokens(); 110 } 111 112 std::unique_ptr<ASTConsumer> 113 CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override { 114 return std::make_unique<ASTConsumer>(); 115 } 116 117 private: 118 TokenBuffer &Result; 119 llvm::Optional<TokenCollector> Collector; 120 }; 121 122 constexpr const char *FileName = "./input.cpp"; 123 FS->addFile(FileName, time_t(), llvm::MemoryBuffer::getMemBufferCopy("")); 124 // Prepare to run a compiler. 125 if (!Diags->getClient()) 126 Diags->setClient(new IgnoringDiagConsumer); 127 std::vector<const char *> Args = {"tok-test", "-std=c++03", "-fsyntax-only", 128 FileName}; 129 auto CI = createInvocationFromCommandLine(Args, Diags, FS); 130 assert(CI); 131 CI->getFrontendOpts().DisableFree = false; 132 CI->getPreprocessorOpts().addRemappedFile( 133 FileName, llvm::MemoryBuffer::getMemBufferCopy(Code).release()); 134 CompilerInstance Compiler; 135 Compiler.setInvocation(std::move(CI)); 136 Compiler.setDiagnostics(Diags.get()); 137 Compiler.setFileManager(FileMgr.get()); 138 Compiler.setSourceManager(SourceMgr.get()); 139 140 this->Buffer = TokenBuffer(*SourceMgr); 141 RecordTokens Recorder(this->Buffer); 142 ASSERT_TRUE(Compiler.ExecuteAction(Recorder)) 143 << "failed to run the frontend"; 144 } 145 146 /// Record the tokens and return a test dump of the resulting buffer. 147 std::string collectAndDump(llvm::StringRef Code) { 148 recordTokens(Code); 149 return Buffer.dumpForTests(); 150 } 151 152 // Adds a file to the test VFS. 153 void addFile(llvm::StringRef Path, llvm::StringRef Contents) { 154 if (!FS->addFile(Path, time_t(), 155 llvm::MemoryBuffer::getMemBufferCopy(Contents))) { 156 ADD_FAILURE() << "could not add a file to VFS: " << Path; 157 } 158 } 159 160 /// Add a new file, run syntax::tokenize() on the range if any, run it on the 161 /// whole file otherwise and return the results. 162 std::vector<syntax::Token> tokenize(llvm::StringRef Text) { 163 llvm::Annotations Annot(Text); 164 auto FID = SourceMgr->createFileID( 165 llvm::MemoryBuffer::getMemBufferCopy(Annot.code())); 166 // FIXME: pass proper LangOptions. 167 if (Annot.ranges().empty()) 168 return syntax::tokenize(FID, *SourceMgr, LangOptions()); 169 return syntax::tokenize( 170 syntax::FileRange(FID, Annot.range().Begin, Annot.range().End), 171 *SourceMgr, LangOptions()); 172 } 173 174 // Specialized versions of matchers that hide the SourceManager from clients. 175 Matcher<syntax::Token> HasText(std::string Text) const { 176 return ::HasText(Text, SourceMgr.get()); 177 } 178 Matcher<syntax::Token> RangeIs(llvm::Annotations::Range R) const { 179 std::pair<SourceLocation, SourceLocation> Ls; 180 Ls.first = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID()) 181 .getLocWithOffset(R.Begin); 182 Ls.second = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID()) 183 .getLocWithOffset(R.End); 184 return ::RangeIs(Ls); 185 } 186 187 /// Finds a subrange in O(n * m). 188 template <class T, class U, class Eq> 189 llvm::ArrayRef<T> findSubrange(llvm::ArrayRef<U> Subrange, 190 llvm::ArrayRef<T> Range, Eq F) { 191 assert(Subrange.size() >= 1); 192 if (Range.size() < Subrange.size()) 193 return llvm::makeArrayRef(Range.end(), Range.end()); 194 for (auto Begin = Range.begin(), Last = Range.end() - Subrange.size(); 195 Begin <= Last; ++Begin) { 196 auto It = Begin; 197 for (auto ItSub = Subrange.begin(); ItSub != Subrange.end(); 198 ++ItSub, ++It) { 199 if (!F(*ItSub, *It)) 200 goto continue_outer; 201 } 202 return llvm::makeArrayRef(Begin, It); 203 continue_outer:; 204 } 205 return llvm::makeArrayRef(Range.end(), Range.end()); 206 } 207 208 /// Finds a subrange in \p Tokens that match the tokens specified in \p Query. 209 /// The match should be unique. \p Query is a whitespace-separated list of 210 /// tokens to search for. 211 llvm::ArrayRef<syntax::Token> 212 findTokenRange(llvm::StringRef Query, llvm::ArrayRef<syntax::Token> Tokens) { 213 llvm::SmallVector<llvm::StringRef, 8> QueryTokens; 214 Query.split(QueryTokens, ' ', /*MaxSplit=*/-1, /*KeepEmpty=*/false); 215 if (QueryTokens.empty()) { 216 ADD_FAILURE() << "will not look for an empty list of tokens"; 217 std::abort(); 218 } 219 // An equality test for search. 220 auto TextMatches = [this](llvm::StringRef Q, const syntax::Token &T) { 221 return Q == T.text(*SourceMgr); 222 }; 223 // Find a match. 224 auto Found = 225 findSubrange(llvm::makeArrayRef(QueryTokens), Tokens, TextMatches); 226 if (Found.begin() == Tokens.end()) { 227 ADD_FAILURE() << "could not find the subrange for " << Query; 228 std::abort(); 229 } 230 // Check that the match is unique. 231 if (findSubrange(llvm::makeArrayRef(QueryTokens), 232 llvm::makeArrayRef(Found.end(), Tokens.end()), TextMatches) 233 .begin() != Tokens.end()) { 234 ADD_FAILURE() << "match is not unique for " << Query; 235 std::abort(); 236 } 237 return Found; 238 }; 239 240 // Specialized versions of findTokenRange for expanded and spelled tokens. 241 llvm::ArrayRef<syntax::Token> findExpanded(llvm::StringRef Query) { 242 return findTokenRange(Query, Buffer.expandedTokens()); 243 } 244 llvm::ArrayRef<syntax::Token> findSpelled(llvm::StringRef Query, 245 FileID File = FileID()) { 246 if (!File.isValid()) 247 File = SourceMgr->getMainFileID(); 248 return findTokenRange(Query, Buffer.spelledTokens(File)); 249 } 250 251 // Data fields. 252 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags = 253 new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions); 254 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS = 255 new llvm::vfs::InMemoryFileSystem; 256 llvm::IntrusiveRefCntPtr<FileManager> FileMgr = 257 new FileManager(FileSystemOptions(), FS); 258 llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr = 259 new SourceManager(*Diags, *FileMgr); 260 /// Contains last result of calling recordTokens(). 261 TokenBuffer Buffer = TokenBuffer(*SourceMgr); 262 }; 263 264 TEST_F(TokenCollectorTest, RawMode) { 265 EXPECT_THAT(tokenize("int main() {}"), 266 ElementsAre(Kind(tok::kw_int), 267 AllOf(HasText("main"), Kind(tok::identifier)), 268 Kind(tok::l_paren), Kind(tok::r_paren), 269 Kind(tok::l_brace), Kind(tok::r_brace))); 270 // Comments are ignored for now. 271 EXPECT_THAT(tokenize("/* foo */int a; // more comments"), 272 ElementsAre(Kind(tok::kw_int), 273 AllOf(HasText("a"), Kind(tok::identifier)), 274 Kind(tok::semi))); 275 EXPECT_THAT(tokenize("int [[main() {]]}"), 276 ElementsAre(AllOf(HasText("main"), Kind(tok::identifier)), 277 Kind(tok::l_paren), Kind(tok::r_paren), 278 Kind(tok::l_brace))); 279 EXPECT_THAT(tokenize("int [[main() { ]]}"), 280 ElementsAre(AllOf(HasText("main"), Kind(tok::identifier)), 281 Kind(tok::l_paren), Kind(tok::r_paren), 282 Kind(tok::l_brace))); 283 // First token is partially parsed, last token is fully included even though 284 // only a part of it is contained in the range. 285 EXPECT_THAT(tokenize("int m[[ain() {ret]]urn 0;}"), 286 ElementsAre(AllOf(HasText("ain"), Kind(tok::identifier)), 287 Kind(tok::l_paren), Kind(tok::r_paren), 288 Kind(tok::l_brace), Kind(tok::kw_return))); 289 } 290 291 TEST_F(TokenCollectorTest, Basic) { 292 std::pair</*Input*/ std::string, /*Expected*/ std::string> TestCases[] = { 293 {"int main() {}", 294 R"(expanded tokens: 295 int main ( ) { } 296 file './input.cpp' 297 spelled tokens: 298 int main ( ) { } 299 no mappings. 300 )"}, 301 // All kinds of whitespace are ignored. 302 {"\t\n int\t\n main\t\n (\t\n )\t\n{\t\n }\t\n", 303 R"(expanded tokens: 304 int main ( ) { } 305 file './input.cpp' 306 spelled tokens: 307 int main ( ) { } 308 no mappings. 309 )"}, 310 // Annotation tokens are ignored. 311 {R"cpp( 312 #pragma GCC visibility push (public) 313 #pragma GCC visibility pop 314 )cpp", 315 R"(expanded tokens: 316 <empty> 317 file './input.cpp' 318 spelled tokens: 319 # pragma GCC visibility push ( public ) # pragma GCC visibility pop 320 mappings: 321 ['#'_0, '<eof>'_13) => ['<eof>'_0, '<eof>'_0) 322 )"}, 323 // Empty files should not crash. 324 {R"cpp()cpp", R"(expanded tokens: 325 <empty> 326 file './input.cpp' 327 spelled tokens: 328 <empty> 329 no mappings. 330 )"}, 331 // Should not crash on errors inside '#define' directives. Error is that 332 // stringification (#B) does not refer to a macro parameter. 333 { 334 R"cpp( 335 a 336 #define MACRO() A #B 337 )cpp", 338 R"(expanded tokens: 339 a 340 file './input.cpp' 341 spelled tokens: 342 a # define MACRO ( ) A # B 343 mappings: 344 ['#'_1, '<eof>'_9) => ['<eof>'_1, '<eof>'_1) 345 )"}}; 346 for (auto &Test : TestCases) 347 EXPECT_EQ(collectAndDump(Test.first), Test.second) 348 << collectAndDump(Test.first); 349 } 350 351 TEST_F(TokenCollectorTest, Locations) { 352 // Check locations of the tokens. 353 llvm::Annotations Code(R"cpp( 354 $r1[[int]] $r2[[a]] $r3[[=]] $r4[["foo bar baz"]] $r5[[;]] 355 )cpp"); 356 recordTokens(Code.code()); 357 // Check expanded tokens. 358 EXPECT_THAT( 359 Buffer.expandedTokens(), 360 ElementsAre(AllOf(Kind(tok::kw_int), RangeIs(Code.range("r1"))), 361 AllOf(Kind(tok::identifier), RangeIs(Code.range("r2"))), 362 AllOf(Kind(tok::equal), RangeIs(Code.range("r3"))), 363 AllOf(Kind(tok::string_literal), RangeIs(Code.range("r4"))), 364 AllOf(Kind(tok::semi), RangeIs(Code.range("r5"))), 365 Kind(tok::eof))); 366 // Check spelled tokens. 367 EXPECT_THAT( 368 Buffer.spelledTokens(SourceMgr->getMainFileID()), 369 ElementsAre(AllOf(Kind(tok::kw_int), RangeIs(Code.range("r1"))), 370 AllOf(Kind(tok::identifier), RangeIs(Code.range("r2"))), 371 AllOf(Kind(tok::equal), RangeIs(Code.range("r3"))), 372 AllOf(Kind(tok::string_literal), RangeIs(Code.range("r4"))), 373 AllOf(Kind(tok::semi), RangeIs(Code.range("r5"))))); 374 375 auto StartLoc = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID()); 376 for (auto &R : Code.ranges()) { 377 EXPECT_THAT(Buffer.spelledTokenAt(StartLoc.getLocWithOffset(R.Begin)), 378 Pointee(RangeIs(R))); 379 } 380 } 381 382 TEST_F(TokenCollectorTest, MacroDirectives) { 383 // Macro directives are not stored anywhere at the moment. 384 std::string Code = R"cpp( 385 #define FOO a 386 #include "unresolved_file.h" 387 #undef FOO 388 #ifdef X 389 #else 390 #endif 391 #ifndef Y 392 #endif 393 #if 1 394 #elif 2 395 #else 396 #endif 397 #pragma once 398 #pragma something lalala 399 400 int a; 401 )cpp"; 402 std::string Expected = 403 "expanded tokens:\n" 404 " int a ;\n" 405 "file './input.cpp'\n" 406 " spelled tokens:\n" 407 " # define FOO a # include \"unresolved_file.h\" # undef FOO " 408 "# ifdef X # else # endif # ifndef Y # endif # if 1 # elif 2 # else " 409 "# endif # pragma once # pragma something lalala int a ;\n" 410 " mappings:\n" 411 " ['#'_0, 'int'_39) => ['int'_0, 'int'_0)\n"; 412 EXPECT_EQ(collectAndDump(Code), Expected); 413 } 414 415 TEST_F(TokenCollectorTest, MacroReplacements) { 416 std::pair</*Input*/ std::string, /*Expected*/ std::string> TestCases[] = { 417 // A simple object-like macro. 418 {R"cpp( 419 #define INT int const 420 INT a; 421 )cpp", 422 R"(expanded tokens: 423 int const a ; 424 file './input.cpp' 425 spelled tokens: 426 # define INT int const INT a ; 427 mappings: 428 ['#'_0, 'INT'_5) => ['int'_0, 'int'_0) 429 ['INT'_5, 'a'_6) => ['int'_0, 'a'_2) 430 )"}, 431 // A simple function-like macro. 432 {R"cpp( 433 #define INT(a) const int 434 INT(10+10) a; 435 )cpp", 436 R"(expanded tokens: 437 const int a ; 438 file './input.cpp' 439 spelled tokens: 440 # define INT ( a ) const int INT ( 10 + 10 ) a ; 441 mappings: 442 ['#'_0, 'INT'_8) => ['const'_0, 'const'_0) 443 ['INT'_8, 'a'_14) => ['const'_0, 'a'_2) 444 )"}, 445 // Recursive macro replacements. 446 {R"cpp( 447 #define ID(X) X 448 #define INT int const 449 ID(ID(INT)) a; 450 )cpp", 451 R"(expanded tokens: 452 int const a ; 453 file './input.cpp' 454 spelled tokens: 455 # define ID ( X ) X # define INT int const ID ( ID ( INT ) ) a ; 456 mappings: 457 ['#'_0, 'ID'_12) => ['int'_0, 'int'_0) 458 ['ID'_12, 'a'_19) => ['int'_0, 'a'_2) 459 )"}, 460 // A little more complicated recursive macro replacements. 461 {R"cpp( 462 #define ADD(X, Y) X+Y 463 #define MULT(X, Y) X*Y 464 465 int a = ADD(MULT(1,2), MULT(3,ADD(4,5))); 466 )cpp", 467 "expanded tokens:\n" 468 " int a = 1 * 2 + 3 * 4 + 5 ;\n" 469 "file './input.cpp'\n" 470 " spelled tokens:\n" 471 " # define ADD ( X , Y ) X + Y # define MULT ( X , Y ) X * Y int " 472 "a = ADD ( MULT ( 1 , 2 ) , MULT ( 3 , ADD ( 4 , 5 ) ) ) ;\n" 473 " mappings:\n" 474 " ['#'_0, 'int'_22) => ['int'_0, 'int'_0)\n" 475 " ['ADD'_25, ';'_46) => ['1'_3, ';'_12)\n"}, 476 // Empty macro replacement. 477 // FIXME: the #define directives should not be glued together. 478 {R"cpp( 479 #define EMPTY 480 #define EMPTY_FUNC(X) 481 EMPTY 482 EMPTY_FUNC(1+2+3) 483 )cpp", 484 R"(expanded tokens: 485 <empty> 486 file './input.cpp' 487 spelled tokens: 488 # define EMPTY # define EMPTY_FUNC ( X ) EMPTY EMPTY_FUNC ( 1 + 2 + 3 ) 489 mappings: 490 ['#'_0, 'EMPTY'_9) => ['<eof>'_0, '<eof>'_0) 491 ['EMPTY'_9, 'EMPTY_FUNC'_10) => ['<eof>'_0, '<eof>'_0) 492 ['EMPTY_FUNC'_10, '<eof>'_18) => ['<eof>'_0, '<eof>'_0) 493 )"}, 494 // File ends with a macro replacement. 495 {R"cpp( 496 #define FOO 10+10; 497 int a = FOO 498 )cpp", 499 R"(expanded tokens: 500 int a = 10 + 10 ; 501 file './input.cpp' 502 spelled tokens: 503 # define FOO 10 + 10 ; int a = FOO 504 mappings: 505 ['#'_0, 'int'_7) => ['int'_0, 'int'_0) 506 ['FOO'_10, '<eof>'_11) => ['10'_3, '<eof>'_7) 507 )"}, 508 {R"cpp( 509 #define NUM 42 510 #define ID(a) a 511 #define M 1 + ID 512 M(NUM) 513 )cpp", 514 R"(expanded tokens: 515 1 + 42 516 file './input.cpp' 517 spelled tokens: 518 # define NUM 42 # define ID ( a ) a # define M 1 + ID M ( NUM ) 519 mappings: 520 ['#'_0, 'M'_17) => ['1'_0, '1'_0) 521 ['M'_17, '<eof>'_21) => ['1'_0, '<eof>'_3) 522 )"}, 523 }; 524 525 for (auto &Test : TestCases) { 526 std::string Dump = collectAndDump(Test.first); 527 EXPECT_EQ(Test.second, Dump) << Dump; 528 } 529 } 530 531 TEST_F(TokenCollectorTest, SpecialTokens) { 532 // Tokens coming from concatenations. 533 recordTokens(R"cpp( 534 #define CONCAT(a, b) a ## b 535 int a = CONCAT(1, 2); 536 )cpp"); 537 EXPECT_THAT(std::vector<syntax::Token>(Buffer.expandedTokens()), 538 Contains(HasText("12"))); 539 // Multi-line tokens with slashes at the end. 540 recordTokens("i\\\nn\\\nt"); 541 EXPECT_THAT(Buffer.expandedTokens(), 542 ElementsAre(AllOf(Kind(tok::kw_int), HasText("i\\\nn\\\nt")), 543 Kind(tok::eof))); 544 // FIXME: test tokens with digraphs and UCN identifiers. 545 } 546 547 TEST_F(TokenCollectorTest, LateBoundTokens) { 548 // The parser eventually breaks the first '>>' into two tokens ('>' and '>'), 549 // but we choose to record them as a single token (for now). 550 llvm::Annotations Code(R"cpp( 551 template <class T> 552 struct foo { int a; }; 553 int bar = foo<foo<int$br[[>>]]().a; 554 int baz = 10 $op[[>>]] 2; 555 )cpp"); 556 recordTokens(Code.code()); 557 EXPECT_THAT(std::vector<syntax::Token>(Buffer.expandedTokens()), 558 AllOf(Contains(AllOf(Kind(tok::greatergreater), 559 RangeIs(Code.range("br")))), 560 Contains(AllOf(Kind(tok::greatergreater), 561 RangeIs(Code.range("op")))))); 562 } 563 564 TEST_F(TokenCollectorTest, DelayedParsing) { 565 llvm::StringLiteral Code = R"cpp( 566 struct Foo { 567 int method() { 568 // Parser will visit method bodies and initializers multiple times, but 569 // TokenBuffer should only record the first walk over the tokens; 570 return 100; 571 } 572 int a = 10; 573 574 struct Subclass { 575 void foo() { 576 Foo().method(); 577 } 578 }; 579 }; 580 )cpp"; 581 std::string ExpectedTokens = 582 "expanded tokens:\n" 583 " struct Foo { int method ( ) { return 100 ; } int a = 10 ; struct " 584 "Subclass { void foo ( ) { Foo ( ) . method ( ) ; } } ; } ;\n"; 585 EXPECT_THAT(collectAndDump(Code), StartsWith(ExpectedTokens)); 586 } 587 588 TEST_F(TokenCollectorTest, MultiFile) { 589 addFile("./foo.h", R"cpp( 590 #define ADD(X, Y) X+Y 591 int a = 100; 592 #include "bar.h" 593 )cpp"); 594 addFile("./bar.h", R"cpp( 595 int b = ADD(1, 2); 596 #define MULT(X, Y) X*Y 597 )cpp"); 598 llvm::StringLiteral Code = R"cpp( 599 #include "foo.h" 600 int c = ADD(1, MULT(2,3)); 601 )cpp"; 602 603 std::string Expected = R"(expanded tokens: 604 int a = 100 ; int b = 1 + 2 ; int c = 1 + 2 * 3 ; 605 file './input.cpp' 606 spelled tokens: 607 # include "foo.h" int c = ADD ( 1 , MULT ( 2 , 3 ) ) ; 608 mappings: 609 ['#'_0, 'int'_3) => ['int'_12, 'int'_12) 610 ['ADD'_6, ';'_17) => ['1'_15, ';'_20) 611 file './foo.h' 612 spelled tokens: 613 # define ADD ( X , Y ) X + Y int a = 100 ; # include "bar.h" 614 mappings: 615 ['#'_0, 'int'_11) => ['int'_0, 'int'_0) 616 ['#'_16, '<eof>'_19) => ['int'_5, 'int'_5) 617 file './bar.h' 618 spelled tokens: 619 int b = ADD ( 1 , 2 ) ; # define MULT ( X , Y ) X * Y 620 mappings: 621 ['ADD'_3, ';'_9) => ['1'_8, ';'_11) 622 ['#'_10, '<eof>'_21) => ['int'_12, 'int'_12) 623 )"; 624 625 EXPECT_EQ(Expected, collectAndDump(Code)) 626 << "input: " << Code << "\nresults: " << collectAndDump(Code); 627 } 628 629 class TokenBufferTest : public TokenCollectorTest {}; 630 631 TEST_F(TokenBufferTest, SpelledByExpanded) { 632 recordTokens(R"cpp( 633 a1 a2 a3 b1 b2 634 )cpp"); 635 636 // Expanded and spelled tokens are stored separately. 637 EXPECT_THAT(findExpanded("a1 a2"), Not(SameRange(findSpelled("a1 a2")))); 638 // Searching for subranges of expanded tokens should give the corresponding 639 // spelled ones. 640 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3 b1 b2")), 641 ValueIs(SameRange(findSpelled("a1 a2 a3 b1 b2")))); 642 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3")), 643 ValueIs(SameRange(findSpelled("a1 a2 a3")))); 644 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("b1 b2")), 645 ValueIs(SameRange(findSpelled("b1 b2")))); 646 647 // Test search on simple macro expansions. 648 recordTokens(R"cpp( 649 #define A a1 a2 a3 650 #define B b1 b2 651 652 A split B 653 )cpp"); 654 // Ranges going across expansion boundaries. 655 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3 split b1 b2")), 656 ValueIs(SameRange(findSpelled("A split B")))); 657 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3")), 658 ValueIs(SameRange(findSpelled("A split").drop_back()))); 659 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("b1 b2")), 660 ValueIs(SameRange(findSpelled("split B").drop_front()))); 661 // Ranges not fully covering macro invocations should fail. 662 EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("a1 a2")), llvm::None); 663 EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("b2")), llvm::None); 664 EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("a2 a3 split b1 b2")), 665 llvm::None); 666 667 // Recursive macro invocations. 668 recordTokens(R"cpp( 669 #define ID(x) x 670 #define B b1 b2 671 672 ID(ID(ID(a1) a2 a3)) split ID(B) 673 )cpp"); 674 675 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("b1 b2")), 676 ValueIs(SameRange(findSpelled("( B").drop_front()))); 677 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3 split b1 b2")), 678 ValueIs(SameRange(findSpelled( 679 "ID ( ID ( ID ( a1 ) a2 a3 ) ) split ID ( B )")))); 680 // Mixed ranges with expanded and spelled tokens. 681 EXPECT_THAT( 682 Buffer.spelledForExpanded(findExpanded("a1 a2 a3 split")), 683 ValueIs(SameRange(findSpelled("ID ( ID ( ID ( a1 ) a2 a3 ) ) split")))); 684 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("split b1 b2")), 685 ValueIs(SameRange(findSpelled("split ID ( B )")))); 686 // Macro arguments 687 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1")), 688 ValueIs(SameRange(findSpelled("a1")))); 689 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a2")), 690 ValueIs(SameRange(findSpelled("a2")))); 691 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a3")), 692 ValueIs(SameRange(findSpelled("a3")))); 693 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2")), 694 ValueIs(SameRange(findSpelled("ID ( a1 ) a2")))); 695 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a1 a2 a3")), 696 ValueIs(SameRange(findSpelled("ID ( a1 ) a2 a3")))); 697 698 // Empty macro expansions. 699 recordTokens(R"cpp( 700 #define EMPTY 701 #define ID(X) X 702 703 EMPTY EMPTY ID(1 2 3) EMPTY EMPTY split1 704 EMPTY EMPTY ID(4 5 6) split2 705 ID(7 8 9) EMPTY EMPTY 706 )cpp"); 707 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("1 2 3")), 708 ValueIs(SameRange(findSpelled("1 2 3")))); 709 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("4 5 6")), 710 ValueIs(SameRange(findSpelled("4 5 6")))); 711 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("7 8 9")), 712 ValueIs(SameRange(findSpelled("7 8 9")))); 713 714 // Empty mappings coming from various directives. 715 recordTokens(R"cpp( 716 #define ID(X) X 717 ID(1) 718 #pragma lalala 719 not_mapped 720 )cpp"); 721 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("not_mapped")), 722 ValueIs(SameRange(findSpelled("not_mapped")))); 723 724 // Multiple macro arguments 725 recordTokens(R"cpp( 726 #define ID(X) X 727 #define ID2(X, Y) X Y 728 729 ID2(ID(a1), ID(a2) a3) ID2(a4, a5 a6 a7) 730 )cpp"); 731 // Should fail, spans multiple arguments. 732 EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("a1 a2")), llvm::None); 733 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a2 a3")), 734 ValueIs(SameRange(findSpelled("ID ( a2 ) a3")))); 735 EXPECT_THAT( 736 Buffer.spelledForExpanded(findExpanded("a1 a2 a3")), 737 ValueIs(SameRange(findSpelled("ID2 ( ID ( a1 ) , ID ( a2 ) a3 )")))); 738 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a5 a6")), 739 ValueIs(SameRange(findSpelled("a5 a6")))); 740 EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("a4 a5 a6 a7")), 741 ValueIs(SameRange(findSpelled("ID2 ( a4 , a5 a6 a7 )")))); 742 // Should fail, spans multiple invocations. 743 EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("a1 a2 a3 a4")), llvm::None); 744 } 745 746 TEST_F(TokenBufferTest, ExpandedTokensForRange) { 747 recordTokens(R"cpp( 748 #define SIGN(X) X##_washere 749 A SIGN(B) C SIGN(D) E SIGN(F) G 750 )cpp"); 751 752 SourceRange R(findExpanded("C").front().location(), 753 findExpanded("F_washere").front().location()); 754 // Expanded and spelled tokens are stored separately. 755 EXPECT_THAT(Buffer.expandedTokens(R), 756 SameRange(findExpanded("C D_washere E F_washere"))); 757 EXPECT_THAT(Buffer.expandedTokens(SourceRange()), testing::IsEmpty()); 758 } 759 760 TEST_F(TokenBufferTest, ExpansionsOverlapping) { 761 // Object-like macro expansions. 762 recordTokens(R"cpp( 763 #define FOO 3+4 764 int a = FOO 1; 765 int b = FOO 2; 766 )cpp"); 767 768 llvm::ArrayRef<syntax::Token> Foo1 = findSpelled("FOO 1"); 769 EXPECT_THAT( 770 Buffer.expansionStartingAt(Foo1.data()), 771 ValueIs(IsExpansion(SameRange(Foo1.drop_back()), 772 SameRange(findExpanded("3 + 4 1").drop_back())))); 773 EXPECT_THAT( 774 Buffer.expansionsOverlapping(Foo1), 775 ElementsAre(IsExpansion(SameRange(Foo1.drop_back()), 776 SameRange(findExpanded("3 + 4 1").drop_back())))); 777 778 llvm::ArrayRef<syntax::Token> Foo2 = findSpelled("FOO 2"); 779 EXPECT_THAT( 780 Buffer.expansionStartingAt(Foo2.data()), 781 ValueIs(IsExpansion(SameRange(Foo2.drop_back()), 782 SameRange(findExpanded("3 + 4 2").drop_back())))); 783 EXPECT_THAT(Buffer.expansionsOverlapping( 784 llvm::makeArrayRef(Foo1.begin(), Foo2.end())), 785 ElementsAre(IsExpansion(SameRange(Foo1.drop_back()), _), 786 IsExpansion(SameRange(Foo2.drop_back()), _))); 787 788 // Function-like macro expansions. 789 recordTokens(R"cpp( 790 #define ID(X) X 791 int a = ID(1+2+3); 792 int b = ID(ID(2+3+4)); 793 )cpp"); 794 795 llvm::ArrayRef<syntax::Token> ID1 = findSpelled("ID ( 1 + 2 + 3 )"); 796 EXPECT_THAT(Buffer.expansionStartingAt(&ID1.front()), 797 ValueIs(IsExpansion(SameRange(ID1), 798 SameRange(findExpanded("1 + 2 + 3"))))); 799 // Only the first spelled token should be found. 800 for (const auto &T : ID1.drop_front()) 801 EXPECT_EQ(Buffer.expansionStartingAt(&T), llvm::None); 802 803 llvm::ArrayRef<syntax::Token> ID2 = findSpelled("ID ( ID ( 2 + 3 + 4 ) )"); 804 EXPECT_THAT(Buffer.expansionStartingAt(&ID2.front()), 805 ValueIs(IsExpansion(SameRange(ID2), 806 SameRange(findExpanded("2 + 3 + 4"))))); 807 // Only the first spelled token should be found. 808 for (const auto &T : ID2.drop_front()) 809 EXPECT_EQ(Buffer.expansionStartingAt(&T), llvm::None); 810 811 EXPECT_THAT(Buffer.expansionsOverlapping(llvm::makeArrayRef( 812 findSpelled("1 + 2").data(), findSpelled("4").data())), 813 ElementsAre(IsExpansion(SameRange(ID1), _), 814 IsExpansion(SameRange(ID2), _))); 815 816 // PP directives. 817 recordTokens(R"cpp( 818 #define FOO 1 819 int a = FOO; 820 #pragma once 821 int b = 1; 822 )cpp"); 823 824 llvm::ArrayRef<syntax::Token> DefineFoo = findSpelled("# define FOO 1"); 825 EXPECT_THAT( 826 Buffer.expansionStartingAt(&DefineFoo.front()), 827 ValueIs(IsExpansion(SameRange(DefineFoo), 828 SameRange(findExpanded("int a").take_front(0))))); 829 // Only the first spelled token should be found. 830 for (const auto &T : DefineFoo.drop_front()) 831 EXPECT_EQ(Buffer.expansionStartingAt(&T), llvm::None); 832 833 llvm::ArrayRef<syntax::Token> PragmaOnce = findSpelled("# pragma once"); 834 EXPECT_THAT( 835 Buffer.expansionStartingAt(&PragmaOnce.front()), 836 ValueIs(IsExpansion(SameRange(PragmaOnce), 837 SameRange(findExpanded("int b").take_front(0))))); 838 // Only the first spelled token should be found. 839 for (const auto &T : PragmaOnce.drop_front()) 840 EXPECT_EQ(Buffer.expansionStartingAt(&T), llvm::None); 841 842 EXPECT_THAT( 843 Buffer.expansionsOverlapping(findSpelled("FOO ; # pragma")), 844 ElementsAre(IsExpansion(SameRange(findSpelled("FOO ;").drop_back()), _), 845 IsExpansion(SameRange(PragmaOnce), _))); 846 } 847 848 TEST_F(TokenBufferTest, TokensToFileRange) { 849 addFile("./foo.h", "token_from_header"); 850 llvm::Annotations Code(R"cpp( 851 #define FOO token_from_expansion 852 #include "./foo.h" 853 $all[[$i[[int]] a = FOO;]] 854 )cpp"); 855 recordTokens(Code.code()); 856 857 auto &SM = *SourceMgr; 858 859 // Two simple examples. 860 auto Int = findExpanded("int").front(); 861 auto Semi = findExpanded(";").front(); 862 EXPECT_EQ(Int.range(SM), FileRange(SM.getMainFileID(), Code.range("i").Begin, 863 Code.range("i").End)); 864 EXPECT_EQ(syntax::Token::range(SM, Int, Semi), 865 FileRange(SM.getMainFileID(), Code.range("all").Begin, 866 Code.range("all").End)); 867 // We don't test assertion failures because death tests are slow. 868 } 869 870 TEST_F(TokenBufferTest, MacroExpansions) { 871 llvm::Annotations Code(R"cpp( 872 #define FOO B 873 #define FOO2 BA 874 #define CALL(X) int X 875 #define G CALL(FOO2) 876 int B; 877 $macro[[FOO]]; 878 $macro[[CALL]](A); 879 $macro[[G]]; 880 )cpp"); 881 recordTokens(Code.code()); 882 auto &SM = *SourceMgr; 883 auto Expansions = Buffer.macroExpansions(SM.getMainFileID()); 884 std::vector<FileRange> ExpectedMacroRanges; 885 for (auto Range : Code.ranges("macro")) 886 ExpectedMacroRanges.push_back( 887 FileRange(SM.getMainFileID(), Range.Begin, Range.End)); 888 std::vector<FileRange> ActualMacroRanges; 889 for (auto Expansion : Expansions) 890 ActualMacroRanges.push_back(Expansion->range(SM)); 891 EXPECT_EQ(ExpectedMacroRanges, ActualMacroRanges); 892 } 893 894 TEST_F(TokenBufferTest, Touching) { 895 llvm::Annotations Code("^i^nt^ ^a^b^=^1;^"); 896 recordTokens(Code.code()); 897 898 auto Touching = [&](int Index) { 899 SourceLocation Loc = SourceMgr->getComposedLoc(SourceMgr->getMainFileID(), 900 Code.points()[Index]); 901 return spelledTokensTouching(Loc, Buffer); 902 }; 903 auto Identifier = [&](int Index) { 904 SourceLocation Loc = SourceMgr->getComposedLoc(SourceMgr->getMainFileID(), 905 Code.points()[Index]); 906 const syntax::Token *Tok = spelledIdentifierTouching(Loc, Buffer); 907 return Tok ? Tok->text(*SourceMgr) : ""; 908 }; 909 910 EXPECT_THAT(Touching(0), SameRange(findSpelled("int"))); 911 EXPECT_EQ(Identifier(0), ""); 912 EXPECT_THAT(Touching(1), SameRange(findSpelled("int"))); 913 EXPECT_EQ(Identifier(1), ""); 914 EXPECT_THAT(Touching(2), SameRange(findSpelled("int"))); 915 EXPECT_EQ(Identifier(2), ""); 916 917 EXPECT_THAT(Touching(3), SameRange(findSpelled("ab"))); 918 EXPECT_EQ(Identifier(3), "ab"); 919 EXPECT_THAT(Touching(4), SameRange(findSpelled("ab"))); 920 EXPECT_EQ(Identifier(4), "ab"); 921 922 EXPECT_THAT(Touching(5), SameRange(findSpelled("ab ="))); 923 EXPECT_EQ(Identifier(5), "ab"); 924 925 EXPECT_THAT(Touching(6), SameRange(findSpelled("= 1"))); 926 EXPECT_EQ(Identifier(6), ""); 927 928 EXPECT_THAT(Touching(7), SameRange(findSpelled(";"))); 929 EXPECT_EQ(Identifier(7), ""); 930 931 ASSERT_EQ(Code.points().size(), 8u); 932 } 933 934 TEST_F(TokenBufferTest, ExpandedBySpelled) { 935 recordTokens(R"cpp( 936 a1 a2 a3 b1 b2 937 )cpp"); 938 // Expanded and spelled tokens are stored separately. 939 EXPECT_THAT(findExpanded("a1 a2"), Not(SameRange(findSpelled("a1 a2")))); 940 // Searching for subranges of expanded tokens should give the corresponding 941 // spelled ones. 942 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("a1 a2 a3 b1 b2")), 943 ElementsAre(SameRange(findExpanded("a1 a2 a3 b1 b2")))); 944 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("a1 a2 a3")), 945 ElementsAre(SameRange(findExpanded("a1 a2 a3")))); 946 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("b1 b2")), 947 ElementsAre(SameRange(findExpanded("b1 b2")))); 948 949 // Test search on simple macro expansions. 950 recordTokens(R"cpp( 951 #define A a1 a2 a3 952 #define B b1 b2 953 954 A split B 955 )cpp"); 956 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("A split B")), 957 ElementsAre(SameRange(findExpanded("a1 a2 a3 split b1 b2")))); 958 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("A split").drop_back()), 959 ElementsAre(SameRange(findExpanded("a1 a2 a3")))); 960 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("split B").drop_front()), 961 ElementsAre(SameRange(findExpanded("b1 b2")))); 962 963 // Ranges not fully covering macro expansions should fail. 964 recordTokens(R"cpp( 965 #define ID(x) x 966 967 ID(a) 968 )cpp"); 969 // Spelled don't cover entire mapping (missing ID token) -> empty result 970 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("( a )")), IsEmpty()); 971 // Spelled don't cover entire mapping (missing ) token) -> empty result 972 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("ID ( a")), IsEmpty()); 973 974 // Recursive macro invocations. 975 recordTokens(R"cpp( 976 #define ID(x) x 977 #define B b1 b2 978 979 ID(ID(ID(a1) a2 a3)) split ID(B) 980 )cpp"); 981 982 EXPECT_THAT( 983 Buffer.expandedForSpelled(findSpelled("ID ( ID ( ID ( a1 ) a2 a3 ) )")), 984 ElementsAre(SameRange(findExpanded("a1 a2 a3")))); 985 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("ID ( B )")), 986 ElementsAre(SameRange(findExpanded("b1 b2")))); 987 EXPECT_THAT(Buffer.expandedForSpelled( 988 findSpelled("ID ( ID ( ID ( a1 ) a2 a3 ) ) split ID ( B )")), 989 ElementsAre(SameRange(findExpanded("a1 a2 a3 split b1 b2")))); 990 // FIXME: these should succeed, but we do not support macro arguments yet. 991 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("a1")), IsEmpty()); 992 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("ID ( a1 ) a2")), 993 IsEmpty()); 994 995 // Empty macro expansions. 996 recordTokens(R"cpp( 997 #define EMPTY 998 #define ID(X) X 999 1000 EMPTY EMPTY ID(1 2 3) EMPTY EMPTY split1 1001 EMPTY EMPTY ID(4 5 6) split2 1002 ID(7 8 9) EMPTY EMPTY 1003 )cpp"); 1004 // Covered by empty expansions on one of both of the sides. 1005 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("ID ( 1 2 3 )")), 1006 ElementsAre(SameRange(findExpanded("1 2 3")))); 1007 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("ID ( 4 5 6 )")), 1008 ElementsAre(SameRange(findExpanded("4 5 6")))); 1009 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("ID ( 7 8 9 )")), 1010 ElementsAre(SameRange(findExpanded("7 8 9")))); 1011 // Including the empty macro expansions on the side. 1012 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("EMPTY ID ( 1 2 3 )")), 1013 ElementsAre(SameRange(findExpanded("1 2 3")))); 1014 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("ID ( 1 2 3 ) EMPTY")), 1015 ElementsAre(SameRange(findExpanded("1 2 3")))); 1016 EXPECT_THAT( 1017 Buffer.expandedForSpelled(findSpelled("EMPTY ID ( 1 2 3 ) EMPTY")), 1018 ElementsAre(SameRange(findExpanded("1 2 3")))); 1019 1020 // Empty mappings coming from various directives. 1021 recordTokens(R"cpp( 1022 #define ID(X) X 1023 ID(1) 1024 #pragma lalala 1025 not_mapped 1026 )cpp"); 1027 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("# define ID ( X ) X")), 1028 IsEmpty()); 1029 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("# pragma lalala")), 1030 IsEmpty()); 1031 1032 // Empty macro expansion. 1033 recordTokens(R"cpp( 1034 #define EMPTY 1035 EMPTY int a = 100; 1036 )cpp"); 1037 EXPECT_THAT(Buffer.expandedForSpelled(findSpelled("EMPTY int").drop_back()), 1038 IsEmpty()); 1039 } 1040 1041 TEST_F(TokenCollectorTest, Pragmas) { 1042 // Tokens coming from concatenations. 1043 recordTokens(R"cpp( 1044 void foo() { 1045 #pragma unroll 4 1046 for(int i=0;i<4;++i); 1047 } 1048 )cpp"); 1049 } 1050 } // namespace 1051