1 //===- TokensTest.cpp -----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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/STLExtras.h"
33 #include "llvm/ADT/StringRef.h"
34 #include "llvm/Support/FormatVariadic.h"
35 #include "llvm/Support/MemoryBuffer.h"
36 #include "llvm/Support/VirtualFileSystem.h"
37 #include "llvm/Support/raw_os_ostream.h"
38 #include "llvm/Support/raw_ostream.h"
39 #include "llvm/Testing/Annotations/Annotations.h"
40 #include "llvm/Testing/Support/SupportHelpers.h"
43 #include <gmock/gmock.h>
44 #include <gtest/gtest.h>
50 using namespace clang
;
51 using namespace clang::syntax
;
55 using ::testing::AllOf
;
56 using ::testing::Contains
;
57 using ::testing::ElementsAre
;
58 using ::testing::Field
;
59 using ::testing::IsEmpty
;
60 using ::testing::Matcher
;
62 using ::testing::Pointee
;
63 using ::testing::StartsWith
;
66 // Checks the passed ArrayRef<T> has the same begin() and end() iterators as the
68 MATCHER_P(SameRange
, A
, "") {
69 return A
.begin() == arg
.begin() && A
.end() == arg
.end();
72 Matcher
<TokenBuffer::Expansion
>
73 IsExpansion(Matcher
<llvm::ArrayRef
<syntax::Token
>> Spelled
,
74 Matcher
<llvm::ArrayRef
<syntax::Token
>> Expanded
) {
75 return AllOf(Field(&TokenBuffer::Expansion::Spelled
, Spelled
),
76 Field(&TokenBuffer::Expansion::Expanded
, Expanded
));
78 // Matchers for syntax::Token.
79 MATCHER_P(Kind
, K
, "") { return arg
.kind() == K
; }
80 MATCHER_P2(HasText
, Text
, SourceMgr
, "") {
81 return arg
.text(*SourceMgr
) == Text
;
83 /// Checks the start and end location of a token are equal to SourceRng.
84 MATCHER_P(RangeIs
, SourceRng
, "") {
85 return arg
.location() == SourceRng
.first
&&
86 arg
.endLocation() == SourceRng
.second
;
89 class TokenCollectorTest
: public ::testing::Test
{
91 /// Run the clang frontend, collect the preprocessed tokens from the frontend
92 /// invocation and store them in this->Buffer.
93 /// This also clears SourceManager before running the compiler.
94 void recordTokens(llvm::StringRef Code
) {
95 class RecordTokens
: public ASTFrontendAction
{
97 explicit RecordTokens(TokenBuffer
&Result
) : Result(Result
) {}
99 bool BeginSourceFileAction(CompilerInstance
&CI
) override
{
100 assert(!Collector
&& "expected only a single call to BeginSourceFile");
101 Collector
.emplace(CI
.getPreprocessor());
104 void EndSourceFileAction() override
{
105 assert(Collector
&& "BeginSourceFileAction was never called");
106 Result
= std::move(*Collector
).consume();
107 Result
.indexExpandedTokens();
110 std::unique_ptr
<ASTConsumer
>
111 CreateASTConsumer(CompilerInstance
&CI
, StringRef InFile
) override
{
112 return std::make_unique
<ASTConsumer
>();
117 std::optional
<TokenCollector
> Collector
;
120 constexpr const char *FileName
= "./input.cpp";
121 FS
->addFile(FileName
, time_t(), llvm::MemoryBuffer::getMemBufferCopy(""));
122 // Prepare to run a compiler.
123 if (!Diags
->getClient())
124 Diags
->setClient(new IgnoringDiagConsumer
);
125 std::vector
<const char *> Args
= {"tok-test", "-std=c++03", "-fsyntax-only",
127 CreateInvocationOptions CIOpts
;
128 CIOpts
.Diags
= Diags
;
130 auto CI
= createInvocation(Args
, std::move(CIOpts
));
132 CI
->getFrontendOpts().DisableFree
= false;
133 CI
->getPreprocessorOpts().addRemappedFile(
134 FileName
, llvm::MemoryBuffer::getMemBufferCopy(Code
).release());
135 CompilerInstance Compiler
;
136 Compiler
.setInvocation(std::move(CI
));
137 Compiler
.setDiagnostics(Diags
.get());
138 Compiler
.setFileManager(FileMgr
.get());
139 Compiler
.setSourceManager(SourceMgr
.get());
141 this->Buffer
= TokenBuffer(*SourceMgr
);
142 RecordTokens
Recorder(this->Buffer
);
143 ASSERT_TRUE(Compiler
.ExecuteAction(Recorder
))
144 << "failed to run the frontend";
147 /// Record the tokens and return a test dump of the resulting buffer.
148 std::string
collectAndDump(llvm::StringRef Code
) {
150 return Buffer
.dumpForTests();
153 // Adds a file to the test VFS.
154 void addFile(llvm::StringRef Path
, llvm::StringRef Contents
) {
155 if (!FS
->addFile(Path
, time_t(),
156 llvm::MemoryBuffer::getMemBufferCopy(Contents
))) {
157 ADD_FAILURE() << "could not add a file to VFS: " << Path
;
161 /// Add a new file, run syntax::tokenize() on the range if any, run it on the
162 /// whole file otherwise and return the results.
163 std::vector
<syntax::Token
> tokenize(llvm::StringRef Text
) {
164 llvm::Annotations
Annot(Text
);
165 auto FID
= SourceMgr
->createFileID(
166 llvm::MemoryBuffer::getMemBufferCopy(Annot
.code()));
167 // FIXME: pass proper LangOptions.
168 if (Annot
.ranges().empty())
169 return syntax::tokenize(FID
, *SourceMgr
, LangOptions());
170 return syntax::tokenize(
171 syntax::FileRange(FID
, Annot
.range().Begin
, Annot
.range().End
),
172 *SourceMgr
, LangOptions());
175 // Specialized versions of matchers that hide the SourceManager from clients.
176 Matcher
<syntax::Token
> HasText(std::string Text
) const {
177 return ::HasText(Text
, SourceMgr
.get());
179 Matcher
<syntax::Token
> RangeIs(llvm::Annotations::Range R
) const {
180 std::pair
<SourceLocation
, SourceLocation
> Ls
;
181 Ls
.first
= SourceMgr
->getLocForStartOfFile(SourceMgr
->getMainFileID())
182 .getLocWithOffset(R
.Begin
);
183 Ls
.second
= SourceMgr
->getLocForStartOfFile(SourceMgr
->getMainFileID())
184 .getLocWithOffset(R
.End
);
185 return ::RangeIs(Ls
);
188 /// Finds a subrange in O(n * m).
189 template <class T
, class U
, class Eq
>
190 llvm::ArrayRef
<T
> findSubrange(llvm::ArrayRef
<U
> Subrange
,
191 llvm::ArrayRef
<T
> Range
, Eq F
) {
192 assert(Subrange
.size() >= 1);
193 if (Range
.size() < Subrange
.size())
194 return llvm::ArrayRef(Range
.end(), Range
.end());
195 for (auto Begin
= Range
.begin(), Last
= Range
.end() - Subrange
.size();
196 Begin
<= Last
; ++Begin
) {
198 for (auto ItSub
= Subrange
.begin(); ItSub
!= Subrange
.end();
203 return llvm::ArrayRef(Begin
, It
);
206 return llvm::ArrayRef(Range
.end(), Range
.end());
209 /// Finds a subrange in \p Tokens that match the tokens specified in \p Query.
210 /// The match should be unique. \p Query is a whitespace-separated list of
211 /// tokens to search for.
212 llvm::ArrayRef
<syntax::Token
>
213 findTokenRange(llvm::StringRef Query
, llvm::ArrayRef
<syntax::Token
> Tokens
) {
214 llvm::SmallVector
<llvm::StringRef
, 8> QueryTokens
;
215 Query
.split(QueryTokens
, ' ', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
216 if (QueryTokens
.empty()) {
217 ADD_FAILURE() << "will not look for an empty list of tokens";
220 // An equality test for search.
221 auto TextMatches
= [this](llvm::StringRef Q
, const syntax::Token
&T
) {
222 return Q
== T
.text(*SourceMgr
);
225 auto Found
= findSubrange(llvm::ArrayRef(QueryTokens
), Tokens
, TextMatches
);
226 if (Found
.begin() == Tokens
.end()) {
227 ADD_FAILURE() << "could not find the subrange for " << Query
;
230 // Check that the match is unique.
231 if (findSubrange(llvm::ArrayRef(QueryTokens
),
232 llvm::ArrayRef(Found
.end(), Tokens
.end()), TextMatches
)
233 .begin() != Tokens
.end()) {
234 ADD_FAILURE() << "match is not unique for " << Query
;
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());
244 llvm::ArrayRef
<syntax::Token
> findSpelled(llvm::StringRef Query
,
245 FileID File
= FileID()) {
247 File
= SourceMgr
->getMainFileID();
248 return findTokenRange(Query
, Buffer
.spelledTokens(File
));
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
);
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
)),
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
)));
291 TEST_F(TokenCollectorTest
, Basic
) {
292 std::pair
</*Input*/ std::string
, /*Expected*/ std::string
> TestCases
[] = {
301 // All kinds of whitespace are ignored.
302 {"\t\n int\t\n main\t\n (\t\n )\t\n{\t\n }\t\n",
310 // Annotation tokens are ignored.
312 #pragma GCC visibility push (public)
313 #pragma GCC visibility pop
319 # pragma GCC visibility push ( public ) # pragma GCC visibility pop
321 ['#'_0, '<eof>'_13) => ['<eof>'_0, '<eof>'_0)
323 // Empty files should not crash.
324 {R
"cpp()cpp", R
"(expanded tokens:
331 // Should not crash on errors inside '#define' directives. Error is that
332 // stringification (#B) does not refer to a macro parameter.
342 a # define MACRO ( ) A # B
344 ['#'_1, '<eof>'_9) => ['<eof>'_1, '<eof>'_1)
346 for (auto &Test
: TestCases
)
347 EXPECT_EQ(collectAndDump(Test
.first
), Test
.second
)
348 << collectAndDump(Test
.first
);
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[[;]]
356 recordTokens(Code
.code());
357 // Check expanded tokens.
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"))),
366 // Check spelled tokens.
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")))));
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
)));
382 TEST_F(TokenCollectorTest
, MacroDirectives
) {
383 // Macro directives are not stored anywhere at the moment.
384 std::string Code
= R
"cpp(
386 #include "unresolved_file
.h
"
398 #pragma something lalala
402 std::string Expected
=
405 "file './input.cpp'\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"
411 " ['#'_0, 'int'_39) => ['int'_0, 'int'_0)\n";
412 EXPECT_EQ(collectAndDump(Code
), Expected
);
415 TEST_F(TokenCollectorTest
, MacroReplacements
) {
416 std::pair
</*Input*/ std::string
, /*Expected*/ std::string
> TestCases
[] = {
417 // A simple object-like macro.
419 #define INT int const
426 # define INT int const INT a ;
428 ['#'_0, 'INT'_5) => ['int'_0, 'int'_0)
429 ['INT'_5, 'a'_6) => ['int'_0, 'a'_2)
431 // A simple function-like macro.
433 #define INT(a) const int
440 # define INT ( a ) const int INT ( 10 + 10 ) a ;
442 ['#'_0, 'INT'_8) => ['const'_0, 'const'_0)
443 ['INT'_8, 'a'_14) => ['const'_0, 'a'_2)
445 // Recursive macro replacements.
448 #define INT int const
455 # define ID ( X ) X # define INT int const ID ( ID ( INT ) ) a ;
457 ['#'_0, 'ID'_12) => ['int'_0, 'int'_0)
458 ['ID'_12, 'a'_19) => ['int'_0, 'a'_2)
460 // A little more complicated recursive macro replacements.
462 #define ADD(X, Y) X+Y
463 #define MULT(X, Y) X*Y
465 int a = ADD(MULT(1,2), MULT(3,ADD(4,5)));
468 " int a = 1 * 2 + 3 * 4 + 5 ;\n"
469 "file './input.cpp'\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"
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.
480 #define EMPTY_FUNC(X)
488 # define EMPTY # define EMPTY_FUNC ( X ) EMPTY EMPTY_FUNC ( 1 + 2 + 3 )
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)
494 // File ends with a macro replacement.
503 # define FOO 10 + 10 ; int a = FOO
505 ['#'_0, 'int'_7) => ['int'_0, 'int'_0)
506 ['FOO'_10, '<eof>'_11) => ['10'_3, '<eof>'_7)
518 # define NUM 42 # define ID ( a ) a # define M 1 + ID M ( NUM )
520 ['#'_0, 'M'_17) => ['1'_0, '1'_0)
521 ['M'_17, '<eof>'_21) => ['1'_0, '<eof>'_3)
525 for (auto &Test
: TestCases
) {
526 std::string Dump
= collectAndDump(Test
.first
);
527 EXPECT_EQ(Test
.second
, Dump
) << Dump
;
531 TEST_F(TokenCollectorTest
, SpecialTokens
) {
532 // Tokens coming from concatenations.
534 #define CONCAT(a, b) a ## b
535 int a = CONCAT(1, 2);
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")),
544 // FIXME: test tokens with digraphs and UCN identifiers.
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(
552 struct foo { int a; };
553 int bar = foo<foo<int$br[[>>]]().a;
554 int baz = 10 $op[[>>]] 2;
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"))))));
564 TEST_F(TokenCollectorTest
, DelayedParsing
) {
565 llvm::StringLiteral Code
= R
"cpp(
568 // Parser will visit method bodies and initializers multiple times, but
569 // TokenBuffer should only record the first walk over the tokens;
581 std::string ExpectedTokens
=
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
));
588 TEST_F(TokenCollectorTest
, MultiFile
) {
589 addFile("./foo.h", R
"cpp(
590 #define ADD(X, Y) X+Y
594 addFile("./bar.h", R
"cpp(
596 #define MULT(X, Y) X*Y
598 llvm::StringLiteral Code
= R
"cpp(
600 int c = ADD(1, MULT(2,3));
603 std::string Expected
= R
"(expanded tokens:
604 int a = 100 ; int b = 1 + 2 ; int c = 1 + 2 * 3 ;
607 # include "foo
.h
" int c = ADD ( 1 , MULT ( 2 , 3 ) ) ;
609 ['#'_0, 'int'_3) => ['int'_12, 'int'_12)
610 ['ADD'_6, ';'_17) => ['1'_15, ';'_20)
613 # define ADD ( X , Y ) X + Y int a = 100 ; # include "bar
.h
"
615 ['#'_0, 'int'_11) => ['int'_0, 'int'_0)
616 ['#'_16, '<eof>'_19) => ['int'_5, 'int'_5)
619 int b = ADD ( 1 , 2 ) ; # define MULT ( X , Y ) X * Y
621 ['ADD'_3, ';'_9) => ['1'_8, ';'_11)
622 ['#'_10, '<eof>'_21) => ['int'_12, 'int'_12)
625 EXPECT_EQ(Expected
, collectAndDump(Code
))
626 << "input: " << Code
<< "\nresults: " << collectAndDump(Code
);
629 class TokenBufferTest
: public TokenCollectorTest
{};
631 TEST_F(TokenBufferTest
, SpelledByExpanded
) {
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
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"))));
647 // Test search on simple macro expansions.
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")), std::nullopt
);
663 EXPECT_EQ(Buffer
.spelledForExpanded(findExpanded("b2")), std::nullopt
);
664 EXPECT_EQ(Buffer
.spelledForExpanded(findExpanded("a2 a3 split b1 b2")),
667 // Recursive macro invocations.
672 ID(ID(ID(a1) a2 a3)) split ID(B)
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.
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 )"))));
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"))));
698 // Empty macro expansions.
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
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"))));
714 // Empty mappings coming from various directives.
721 EXPECT_THAT(Buffer
.spelledForExpanded(findExpanded("not_mapped")),
722 ValueIs(SameRange(findSpelled("not_mapped"))));
724 // Multiple macro arguments
727 #define ID2(X, Y) X Y
729 ID2(ID(a1), ID(a2) a3) ID2(a4, a5 a6 a7)
731 // Should fail, spans multiple arguments.
732 EXPECT_EQ(Buffer
.spelledForExpanded(findExpanded("a1 a2")), std::nullopt
);
733 EXPECT_THAT(Buffer
.spelledForExpanded(findExpanded("a2 a3")),
734 ValueIs(SameRange(findSpelled("ID ( a2 ) a3"))));
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")),
746 // https://github.com/clangd/clangd/issues/1289
748 #define FOO(X) foo(X)
749 #define INDIRECT FOO(y)
750 INDIRECT // expands to foo(y)
752 EXPECT_EQ(Buffer
.spelledForExpanded(findExpanded("y")), std::nullopt
);
758 EXPECT_THAT(Buffer
.spelledForExpanded(findExpanded("y")),
759 ValueIs(SameRange(findSpelled("y"))));
766 EXPECT_THAT(Buffer
.spelledForExpanded(findExpanded("1")),
767 ValueIs(SameRange(findSpelled(") BAR").drop_front())));
769 // Critical cases for mapping of Prev/Next in spelledForExpandedSlow.
774 #define LARGE ID(prev ID(bad))
777 EXPECT_THAT(Buffer
.spelledForExpanded(findExpanded("good")),
778 ValueIs(SameRange(findSpelled("good"))));
779 EXPECT_THAT(Buffer
.spelledForExpanded(findExpanded("good2")),
780 ValueIs(SameRange(findSpelled("good2"))));
781 EXPECT_EQ(Buffer
.spelledForExpanded(findExpanded("bad")), std::nullopt
);
787 #define LARGE PREV ID(bad)
790 EXPECT_THAT(Buffer
.spelledForExpanded(findExpanded("good")),
791 ValueIs(SameRange(findSpelled("good"))));
792 EXPECT_EQ(Buffer
.spelledForExpanded(findExpanded("bad")), std::nullopt
);
796 #define ID2(X, Y) X Y
799 #define LARGE ID2(prev, bad)
802 EXPECT_THAT(Buffer
.spelledForExpanded(findExpanded("good")),
803 ValueIs(SameRange(findSpelled("good"))));
804 EXPECT_THAT(Buffer
.spelledForExpanded(findExpanded("good2")),
805 ValueIs(SameRange(findSpelled("good2"))));
806 EXPECT_EQ(Buffer
.spelledForExpanded(findExpanded("bad")), std::nullopt
);
808 // Prev from macro body.
811 #define ID2(X, Y) X prev ID(Y)
814 EXPECT_THAT(Buffer
.spelledForExpanded(findExpanded("good")),
815 ValueIs(SameRange(findSpelled("good"))));
816 EXPECT_EQ(Buffer
.spelledForExpanded(findExpanded("prev good")), std::nullopt
);
819 TEST_F(TokenBufferTest
, ExpandedTokensForRange
) {
821 #define SIGN(X) X##_washere
822 A SIGN(B) C SIGN(D) E SIGN(F) G
825 SourceRange
R(findExpanded("C").front().location(),
826 findExpanded("F_washere").front().location());
827 // Expanded and spelled tokens are stored separately.
828 EXPECT_THAT(Buffer
.expandedTokens(R
),
829 SameRange(findExpanded("C D_washere E F_washere")));
830 EXPECT_THAT(Buffer
.expandedTokens(SourceRange()), testing::IsEmpty());
833 TEST_F(TokenBufferTest
, ExpansionsOverlapping
) {
834 // Object-like macro expansions.
841 llvm::ArrayRef
<syntax::Token
> Foo1
= findSpelled("FOO 1");
843 Buffer
.expansionStartingAt(Foo1
.data()),
844 ValueIs(IsExpansion(SameRange(Foo1
.drop_back()),
845 SameRange(findExpanded("3 + 4 1").drop_back()))));
847 Buffer
.expansionsOverlapping(Foo1
),
848 ElementsAre(IsExpansion(SameRange(Foo1
.drop_back()),
849 SameRange(findExpanded("3 + 4 1").drop_back()))));
851 llvm::ArrayRef
<syntax::Token
> Foo2
= findSpelled("FOO 2");
853 Buffer
.expansionStartingAt(Foo2
.data()),
854 ValueIs(IsExpansion(SameRange(Foo2
.drop_back()),
855 SameRange(findExpanded("3 + 4 2").drop_back()))));
857 Buffer
.expansionsOverlapping(llvm::ArrayRef(Foo1
.begin(), Foo2
.end())),
858 ElementsAre(IsExpansion(SameRange(Foo1
.drop_back()), _
),
859 IsExpansion(SameRange(Foo2
.drop_back()), _
)));
861 // Function-like macro expansions.
865 int b = ID(ID(2+3+4));
868 llvm::ArrayRef
<syntax::Token
> ID1
= findSpelled("ID ( 1 + 2 + 3 )");
869 EXPECT_THAT(Buffer
.expansionStartingAt(&ID1
.front()),
870 ValueIs(IsExpansion(SameRange(ID1
),
871 SameRange(findExpanded("1 + 2 + 3")))));
872 // Only the first spelled token should be found.
873 for (const auto &T
: ID1
.drop_front())
874 EXPECT_EQ(Buffer
.expansionStartingAt(&T
), std::nullopt
);
876 llvm::ArrayRef
<syntax::Token
> ID2
= findSpelled("ID ( ID ( 2 + 3 + 4 ) )");
877 EXPECT_THAT(Buffer
.expansionStartingAt(&ID2
.front()),
878 ValueIs(IsExpansion(SameRange(ID2
),
879 SameRange(findExpanded("2 + 3 + 4")))));
880 // Only the first spelled token should be found.
881 for (const auto &T
: ID2
.drop_front())
882 EXPECT_EQ(Buffer
.expansionStartingAt(&T
), std::nullopt
);
884 EXPECT_THAT(Buffer
.expansionsOverlapping(llvm::ArrayRef(
885 findSpelled("1 + 2").data(), findSpelled("4").data())),
886 ElementsAre(IsExpansion(SameRange(ID1
), _
),
887 IsExpansion(SameRange(ID2
), _
)));
897 llvm::ArrayRef
<syntax::Token
> DefineFoo
= findSpelled("# define FOO 1");
899 Buffer
.expansionStartingAt(&DefineFoo
.front()),
900 ValueIs(IsExpansion(SameRange(DefineFoo
),
901 SameRange(findExpanded("int a").take_front(0)))));
902 // Only the first spelled token should be found.
903 for (const auto &T
: DefineFoo
.drop_front())
904 EXPECT_EQ(Buffer
.expansionStartingAt(&T
), std::nullopt
);
906 llvm::ArrayRef
<syntax::Token
> PragmaOnce
= findSpelled("# pragma once");
908 Buffer
.expansionStartingAt(&PragmaOnce
.front()),
909 ValueIs(IsExpansion(SameRange(PragmaOnce
),
910 SameRange(findExpanded("int b").take_front(0)))));
911 // Only the first spelled token should be found.
912 for (const auto &T
: PragmaOnce
.drop_front())
913 EXPECT_EQ(Buffer
.expansionStartingAt(&T
), std::nullopt
);
916 Buffer
.expansionsOverlapping(findSpelled("FOO ; # pragma")),
917 ElementsAre(IsExpansion(SameRange(findSpelled("FOO ;").drop_back()), _
),
918 IsExpansion(SameRange(PragmaOnce
), _
)));
921 TEST_F(TokenBufferTest
, TokensToFileRange
) {
922 addFile("./foo.h", "token_from_header");
923 llvm::Annotations
Code(R
"cpp(
924 #define FOO token_from_expansion
926 $all[[$i[[int]] a = FOO;]]
928 recordTokens(Code
.code());
930 auto &SM
= *SourceMgr
;
932 // Two simple examples.
933 auto Int
= findExpanded("int").front();
934 auto Semi
= findExpanded(";").front();
935 EXPECT_EQ(Int
.range(SM
), FileRange(SM
.getMainFileID(), Code
.range("i").Begin
,
936 Code
.range("i").End
));
937 EXPECT_EQ(syntax::Token::range(SM
, Int
, Semi
),
938 FileRange(SM
.getMainFileID(), Code
.range("all").Begin
,
939 Code
.range("all").End
));
940 // We don't test assertion failures because death tests are slow.
943 TEST_F(TokenBufferTest
, MacroExpansions
) {
944 llvm::Annotations
Code(R
"cpp(
947 #define CALL(X) int X
954 recordTokens(Code
.code());
955 auto &SM
= *SourceMgr
;
956 auto Expansions
= Buffer
.macroExpansions(SM
.getMainFileID());
957 std::vector
<FileRange
> ExpectedMacroRanges
;
958 for (auto Range
: Code
.ranges("macro"))
959 ExpectedMacroRanges
.push_back(
960 FileRange(SM
.getMainFileID(), Range
.Begin
, Range
.End
));
961 std::vector
<FileRange
> ActualMacroRanges
;
962 for (auto Expansion
: Expansions
)
963 ActualMacroRanges
.push_back(Expansion
->range(SM
));
964 EXPECT_EQ(ExpectedMacroRanges
, ActualMacroRanges
);
967 TEST_F(TokenBufferTest
, Touching
) {
968 llvm::Annotations
Code("^i^nt^ ^a^b^=^1;^");
969 recordTokens(Code
.code());
971 auto Touching
= [&](int Index
) {
972 SourceLocation Loc
= SourceMgr
->getComposedLoc(SourceMgr
->getMainFileID(),
973 Code
.points()[Index
]);
974 return spelledTokensTouching(Loc
, Buffer
);
976 auto Identifier
= [&](int Index
) {
977 SourceLocation Loc
= SourceMgr
->getComposedLoc(SourceMgr
->getMainFileID(),
978 Code
.points()[Index
]);
979 const syntax::Token
*Tok
= spelledIdentifierTouching(Loc
, Buffer
);
980 return Tok
? Tok
->text(*SourceMgr
) : "";
983 EXPECT_THAT(Touching(0), SameRange(findSpelled("int")));
984 EXPECT_EQ(Identifier(0), "");
985 EXPECT_THAT(Touching(1), SameRange(findSpelled("int")));
986 EXPECT_EQ(Identifier(1), "");
987 EXPECT_THAT(Touching(2), SameRange(findSpelled("int")));
988 EXPECT_EQ(Identifier(2), "");
990 EXPECT_THAT(Touching(3), SameRange(findSpelled("ab")));
991 EXPECT_EQ(Identifier(3), "ab");
992 EXPECT_THAT(Touching(4), SameRange(findSpelled("ab")));
993 EXPECT_EQ(Identifier(4), "ab");
995 EXPECT_THAT(Touching(5), SameRange(findSpelled("ab =")));
996 EXPECT_EQ(Identifier(5), "ab");
998 EXPECT_THAT(Touching(6), SameRange(findSpelled("= 1")));
999 EXPECT_EQ(Identifier(6), "");
1001 EXPECT_THAT(Touching(7), SameRange(findSpelled(";")));
1002 EXPECT_EQ(Identifier(7), "");
1004 ASSERT_EQ(Code
.points().size(), 8u);
1007 TEST_F(TokenBufferTest
, ExpandedBySpelled
) {
1011 // Expanded and spelled tokens are stored separately.
1012 EXPECT_THAT(findExpanded("a1 a2"), Not(SameRange(findSpelled("a1 a2"))));
1013 // Searching for subranges of expanded tokens should give the corresponding
1015 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("a1 a2 a3 b1 b2")),
1016 ElementsAre(SameRange(findExpanded("a1 a2 a3 b1 b2"))));
1017 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("a1 a2 a3")),
1018 ElementsAre(SameRange(findExpanded("a1 a2 a3"))));
1019 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("b1 b2")),
1020 ElementsAre(SameRange(findExpanded("b1 b2"))));
1022 // Test search on simple macro expansions.
1029 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("A split B")),
1030 ElementsAre(SameRange(findExpanded("a1 a2 a3 split b1 b2"))));
1031 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("A split").drop_back()),
1032 ElementsAre(SameRange(findExpanded("a1 a2 a3"))));
1033 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("split B").drop_front()),
1034 ElementsAre(SameRange(findExpanded("b1 b2"))));
1036 // Ranges not fully covering macro expansions should fail.
1042 // Spelled don't cover entire mapping (missing ID token) -> empty result
1043 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("( a )")), IsEmpty());
1044 // Spelled don't cover entire mapping (missing ) token) -> empty result
1045 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("ID ( a")), IsEmpty());
1047 // Recursive macro invocations.
1052 ID(ID(ID(a1) a2 a3)) split ID(B)
1056 Buffer
.expandedForSpelled(findSpelled("ID ( ID ( ID ( a1 ) a2 a3 ) )")),
1057 ElementsAre(SameRange(findExpanded("a1 a2 a3"))));
1058 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("ID ( B )")),
1059 ElementsAre(SameRange(findExpanded("b1 b2"))));
1060 EXPECT_THAT(Buffer
.expandedForSpelled(
1061 findSpelled("ID ( ID ( ID ( a1 ) a2 a3 ) ) split ID ( B )")),
1062 ElementsAre(SameRange(findExpanded("a1 a2 a3 split b1 b2"))));
1063 // FIXME: these should succeed, but we do not support macro arguments yet.
1064 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("a1")), IsEmpty());
1065 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("ID ( a1 ) a2")),
1068 // Empty macro expansions.
1073 EMPTY EMPTY ID(1 2 3) EMPTY EMPTY split1
1074 EMPTY EMPTY ID(4 5 6) split2
1075 ID(7 8 9) EMPTY EMPTY
1077 // Covered by empty expansions on one of both of the sides.
1078 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("ID ( 1 2 3 )")),
1079 ElementsAre(SameRange(findExpanded("1 2 3"))));
1080 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("ID ( 4 5 6 )")),
1081 ElementsAre(SameRange(findExpanded("4 5 6"))));
1082 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("ID ( 7 8 9 )")),
1083 ElementsAre(SameRange(findExpanded("7 8 9"))));
1084 // Including the empty macro expansions on the side.
1085 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("EMPTY ID ( 1 2 3 )")),
1086 ElementsAre(SameRange(findExpanded("1 2 3"))));
1087 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("ID ( 1 2 3 ) EMPTY")),
1088 ElementsAre(SameRange(findExpanded("1 2 3"))));
1090 Buffer
.expandedForSpelled(findSpelled("EMPTY ID ( 1 2 3 ) EMPTY")),
1091 ElementsAre(SameRange(findExpanded("1 2 3"))));
1093 // Empty mappings coming from various directives.
1100 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("# define ID ( X ) X")),
1102 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("# pragma lalala")),
1105 // Empty macro expansion.
1110 EXPECT_THAT(Buffer
.expandedForSpelled(findSpelled("EMPTY int").drop_back()),
1114 TEST_F(TokenCollectorTest
, Pragmas
) {
1115 // Tokens coming from concatenations.
1119 for(int i=0;i<4;++i);