|
25 | 25 | #include "clang/Lex/PreprocessorOptions.h" |
26 | 26 | #include "gmock/gmock.h" |
27 | 27 | #include "gtest/gtest.h" |
| 28 | +#include <memory> |
28 | 29 | #include <vector> |
29 | 30 |
|
30 | 31 | namespace { |
@@ -65,7 +66,7 @@ class LexerTest : public ::testing::Test { |
65 | 66 |
|
66 | 67 | std::vector<Token> Lex(StringRef Source) { |
67 | 68 | TrivialModuleLoader ModLoader; |
68 | | - auto PP = CreatePP(Source, ModLoader); |
| 69 | + PP = CreatePP(Source, ModLoader); |
69 | 70 |
|
70 | 71 | std::vector<Token> toks; |
71 | 72 | while (1) { |
@@ -109,6 +110,7 @@ class LexerTest : public ::testing::Test { |
109 | 110 | LangOptions LangOpts; |
110 | 111 | std::shared_ptr<TargetOptions> TargetOpts; |
111 | 112 | IntrusiveRefCntPtr<TargetInfo> Target; |
| 113 | + std::unique_ptr<Preprocessor> PP; |
112 | 114 | }; |
113 | 115 |
|
114 | 116 | TEST_F(LexerTest, GetSourceTextExpandsToMaximumInMacroArgument) { |
@@ -264,12 +266,14 @@ TEST_F(LexerTest, GetSourceTextExpandsRecursively) { |
264 | 266 |
|
265 | 267 | TEST_F(LexerTest, LexAPI) { |
266 | 268 | std::vector<tok::TokenKind> ExpectedTokens; |
| 269 | + // Line 1 (after the #defines) |
267 | 270 | ExpectedTokens.push_back(tok::l_square); |
268 | 271 | ExpectedTokens.push_back(tok::identifier); |
269 | 272 | ExpectedTokens.push_back(tok::r_square); |
270 | 273 | ExpectedTokens.push_back(tok::l_square); |
271 | 274 | ExpectedTokens.push_back(tok::identifier); |
272 | 275 | ExpectedTokens.push_back(tok::r_square); |
| 276 | + // Line 2 |
273 | 277 | ExpectedTokens.push_back(tok::identifier); |
274 | 278 | ExpectedTokens.push_back(tok::identifier); |
275 | 279 | ExpectedTokens.push_back(tok::identifier); |
@@ -357,6 +361,65 @@ TEST_F(LexerTest, LexAPI) { |
357 | 361 | EXPECT_EQ("N", Lexer::getImmediateMacroName(idLoc4, SourceMgr, LangOpts)); |
358 | 362 | } |
359 | 363 |
|
| 364 | +TEST_F(LexerTest, HandlesSplitTokens) { |
| 365 | + std::vector<tok::TokenKind> ExpectedTokens; |
| 366 | + // Line 1 (after the #defines) |
| 367 | + ExpectedTokens.push_back(tok::identifier); |
| 368 | + ExpectedTokens.push_back(tok::less); |
| 369 | + ExpectedTokens.push_back(tok::identifier); |
| 370 | + ExpectedTokens.push_back(tok::less); |
| 371 | + ExpectedTokens.push_back(tok::greatergreater); |
| 372 | + // Line 2 |
| 373 | + ExpectedTokens.push_back(tok::identifier); |
| 374 | + ExpectedTokens.push_back(tok::less); |
| 375 | + ExpectedTokens.push_back(tok::identifier); |
| 376 | + ExpectedTokens.push_back(tok::less); |
| 377 | + ExpectedTokens.push_back(tok::greatergreater); |
| 378 | + |
| 379 | + std::vector<Token> toks = CheckLex("#define TY ty\n" |
| 380 | + "#define RANGLE ty<ty<>>\n" |
| 381 | + "TY<ty<>>\n" |
| 382 | + "RANGLE", |
| 383 | + ExpectedTokens); |
| 384 | + |
| 385 | + SourceLocation outerTyLoc = toks[0].getLocation(); |
| 386 | + SourceLocation innerTyLoc = toks[2].getLocation(); |
| 387 | + SourceLocation gtgtLoc = toks[4].getLocation(); |
| 388 | + // Split the token to simulate the action of the parser and force creation of |
| 389 | + // an `ExpansionTokenRange`. |
| 390 | + SourceLocation rangleLoc = PP->SplitToken(gtgtLoc, 1); |
| 391 | + |
| 392 | + // Verify that it only captures the first greater-then and not the second one. |
| 393 | + CharSourceRange range = Lexer::makeFileCharRange( |
| 394 | + CharSourceRange::getTokenRange(innerTyLoc, rangleLoc), SourceMgr, |
| 395 | + LangOpts); |
| 396 | + EXPECT_TRUE(range.isCharRange()); |
| 397 | + EXPECT_EQ(range.getAsRange(), |
| 398 | + SourceRange(innerTyLoc, gtgtLoc.getLocWithOffset(1))); |
| 399 | + |
| 400 | + // Verify case where range begins in a macro expansion. |
| 401 | + range = Lexer::makeFileCharRange( |
| 402 | + CharSourceRange::getTokenRange(outerTyLoc, rangleLoc), SourceMgr, |
| 403 | + LangOpts); |
| 404 | + EXPECT_TRUE(range.isCharRange()); |
| 405 | + EXPECT_EQ(range.getAsRange(), |
| 406 | + SourceRange(SourceMgr.getExpansionLoc(outerTyLoc), |
| 407 | + gtgtLoc.getLocWithOffset(1))); |
| 408 | + |
| 409 | + SourceLocation macroInnerTyLoc = toks[7].getLocation(); |
| 410 | + SourceLocation macroGtgtLoc = toks[9].getLocation(); |
| 411 | + // Split the token to simulate the action of the parser and force creation of |
| 412 | + // an `ExpansionTokenRange`. |
| 413 | + SourceLocation macroRAngleLoc = PP->SplitToken(macroGtgtLoc, 1); |
| 414 | + |
| 415 | + // Verify that it fails (because it only captures the first greater-then and |
| 416 | + // not the second one, so it doesn't span the entire macro expansion). |
| 417 | + range = Lexer::makeFileCharRange( |
| 418 | + CharSourceRange::getTokenRange(macroInnerTyLoc, macroRAngleLoc), |
| 419 | + SourceMgr, LangOpts); |
| 420 | + EXPECT_TRUE(range.isInvalid()); |
| 421 | +} |
| 422 | + |
360 | 423 | TEST_F(LexerTest, DontMergeMacroArgsFromDifferentMacroFiles) { |
361 | 424 | std::vector<Token> toks = |
362 | 425 | Lex("#define helper1 0\n" |
|
0 commit comments