Skip to content

Commit 4099121

Browse files
authored
[clang][Tooling] Fix getFileRange returning a range spanning across macro arguments (#169757)
When the start and end token are both spelled in macro arguments, we still want to reject the range if they come from two separate macro arguments, as the original specified range is not precisely spelled in a single sequence of characters in source.
1 parent 1748e23 commit 4099121

File tree

2 files changed

+27
-5
lines changed

2 files changed

+27
-5
lines changed

clang/lib/Tooling/Transformer/SourceCode.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,18 +86,39 @@ llvm::Error clang::tooling::validateEditRange(const CharSourceRange &Range,
8686
return validateRange(Range, SM, /*AllowSystemHeaders=*/false);
8787
}
8888

89-
static bool spelledInMacroDefinition(SourceLocation Loc,
90-
const SourceManager &SM) {
89+
// Returns the location of the top-level macro argument that is the spelling for
90+
// the expansion `Loc` is from. If `Loc` is spelled in the macro definition,
91+
// returns an invalid `SourceLocation`.
92+
static SourceLocation getMacroArgumentSpellingLoc(SourceLocation Loc,
93+
const SourceManager &SM) {
94+
assert(Loc.isMacroID() && "Location must be in a macro");
9195
while (Loc.isMacroID()) {
9296
const auto &Expansion = SM.getSLocEntry(SM.getFileID(Loc)).getExpansion();
9397
if (Expansion.isMacroArgExpansion()) {
9498
// Check the spelling location of the macro arg, in case the arg itself is
9599
// in a macro expansion.
96100
Loc = Expansion.getSpellingLoc();
97101
} else {
98-
return true;
102+
return {};
99103
}
100104
}
105+
return Loc;
106+
}
107+
108+
static bool spelledInMacroDefinition(CharSourceRange Range,
109+
const SourceManager &SM) {
110+
if (Range.getBegin().isMacroID() && Range.getEnd().isMacroID()) {
111+
// Check whether the range is entirely within a single macro argument.
112+
auto B = getMacroArgumentSpellingLoc(Range.getBegin(), SM);
113+
auto E = getMacroArgumentSpellingLoc(Range.getEnd(), SM);
114+
return B.isInvalid() || B != E;
115+
}
116+
117+
if (Range.getBegin().isMacroID())
118+
return getMacroArgumentSpellingLoc(Range.getBegin(), SM).isInvalid();
119+
if (Range.getEnd().isMacroID())
120+
return getMacroArgumentSpellingLoc(Range.getEnd(), SM).isInvalid();
121+
101122
return false;
102123
}
103124

@@ -158,8 +179,7 @@ static CharSourceRange getRange(const CharSourceRange &EditRange,
158179
Range = Lexer::makeFileCharRange(EditRange, SM, LangOpts);
159180
} else {
160181
auto AdjustedRange = getRangeForSplitTokens(EditRange, SM, LangOpts);
161-
if (spelledInMacroDefinition(AdjustedRange.getBegin(), SM) ||
162-
spelledInMacroDefinition(AdjustedRange.getEnd(), SM))
182+
if (spelledInMacroDefinition(AdjustedRange, SM))
163183
return {};
164184

165185
auto B = SM.getSpellingLoc(AdjustedRange.getBegin());

clang/unittests/Tooling/SourceCodeTest.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,10 +510,12 @@ TEST(SourceCodeTest, EditInvolvingExpansionIgnoringExpansionShouldFail) {
510510
#define M1(x) x(1)
511511
#define M2(x, y) x ## y
512512
#define M3(x) foobar(x)
513+
#define M4(x, y) x y
513514
int foobar(int);
514515
int a = M1(foobar);
515516
int b = M2(foo, bar(2));
516517
int c = M3(3);
518+
int d = M4(foobar, (4));
517519
)cpp");
518520

519521
CallsVisitor Visitor;

0 commit comments

Comments
 (0)