diff options
author | Sam McCall <sam.mccall@gmail.com> | 2022-09-26 03:22:09 +0200 |
---|---|---|
committer | Tobias Hieta <tobias@hieta.se> | 2022-10-10 08:49:22 +0200 |
commit | 27e075fcfad137b43367734052c63abe12555403 (patch) | |
tree | cb49363975cfa94f0eae951bc4660ce4d8a1f03d /clang/unittests | |
parent | 359ef0c932404d31347ce25895fdcadee1004381 (diff) | |
download | llvm-27e075fcfad137b43367734052c63abe12555403.zip llvm-27e075fcfad137b43367734052c63abe12555403.tar.gz llvm-27e075fcfad137b43367734052c63abe12555403.tar.bz2 |
[Syntax] Fix macro-arg handling in TokenBuffer::spelledForExpanded
A few cases were not handled correctly. Notably:
#define ID(X) X
#define HIDE a ID(b)
HIDE
spelledForExpanded() would claim HIDE is an equivalent range of the 'b' it
contains, despite the fact that HIDE also covers 'a'.
While trying to fix this bug, I found findCommonRangeForMacroArgs hard
to understand (both the implementation and how it's used in spelledForExpanded).
It relies on details of the SourceLocation graph that are IMO fairly obscure.
So I've added/revised quite a lot of comments and made some naming tweaks.
Fixes https://github.com/clangd/clangd/issues/1289
Differential Revision: https://reviews.llvm.org/D134618
(cherry picked from commit 67268ee11c220b1dfdf84afb10a12371c5ae6400)
Diffstat (limited to 'clang/unittests')
-rw-r--r-- | clang/unittests/Tooling/Syntax/TokensTest.cpp | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp index 77f719c..85fc837 100644 --- a/clang/unittests/Tooling/Syntax/TokensTest.cpp +++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp @@ -743,6 +743,62 @@ TEST_F(TokenBufferTest, SpelledByExpanded) { ValueIs(SameRange(findSpelled("ID2 ( a4 , a5 a6 a7 )")))); // Should fail, spans multiple invocations. EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("a1 a2 a3 a4")), llvm::None); + + // https://github.com/clangd/clangd/issues/1289 + recordTokens(R"cpp( + #define FOO(X) foo(X) + #define INDIRECT FOO(y) + INDIRECT // expands to foo(y) + )cpp"); + EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("y")), llvm::None); + + recordTokens(R"cpp( + #define FOO(X) a X b + FOO(y) + )cpp"); + EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("y")), + ValueIs(SameRange(findSpelled("y")))); + + recordTokens(R"cpp( + #define ID(X) X + #define BAR ID(1) + BAR + )cpp"); + EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("1")), + ValueIs(SameRange(findSpelled(") BAR").drop_front()))); + + // Critical cases for mapping of Prev/Next in spelledForExpandedSlow. + recordTokens(R"cpp( + #define ID(X) X + ID(prev ID(good)) + #define LARGE ID(prev ID(bad)) + LARGE + )cpp"); + EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("good")), + ValueIs(SameRange(findSpelled("good")))); + EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("bad")), llvm::None); + + recordTokens(R"cpp( + #define PREV prev + #define ID(X) X + PREV ID(good) + #define LARGE PREV ID(bad) + LARGE + )cpp"); + EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("good")), + ValueIs(SameRange(findSpelled("good")))); + EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("bad")), llvm::None); + + recordTokens(R"cpp( + #define ID(X) X + #define ID2(X, Y) X Y + ID2(prev, ID(good)) + #define LARGE ID2(prev, bad) + LARGE + )cpp"); + EXPECT_THAT(Buffer.spelledForExpanded(findExpanded("good")), + ValueIs(SameRange(findSpelled("good")))); + EXPECT_EQ(Buffer.spelledForExpanded(findExpanded("bad")), llvm::None); } TEST_F(TokenBufferTest, ExpandedTokensForRange) { |