diff --git a/clang/lib/Tooling/Transformer/SourceCode.cpp b/clang/lib/Tooling/Transformer/SourceCode.cpp index 922dafeddf416..fa9bf3427b8a0 100644 --- a/clang/lib/Tooling/Transformer/SourceCode.cpp +++ b/clang/lib/Tooling/Transformer/SourceCode.cpp @@ -86,8 +86,12 @@ llvm::Error clang::tooling::validateEditRange(const CharSourceRange &Range, return validateRange(Range, SM, /*AllowSystemHeaders=*/false); } -static bool spelledInMacroDefinition(SourceLocation Loc, - const SourceManager &SM) { +// Returns the location of the top-level macro argument that is the spelling for +// the expansion `Loc` is from. If `Loc` is spelled in the macro definition, +// returns an invalid `SourceLocation`. +static SourceLocation getMacroArgumentSpellingLoc(SourceLocation Loc, + const SourceManager &SM) { + assert(Loc.isMacroID() && "Location must be in a macro"); while (Loc.isMacroID()) { const auto &Expansion = SM.getSLocEntry(SM.getFileID(Loc)).getExpansion(); if (Expansion.isMacroArgExpansion()) { @@ -95,9 +99,26 @@ static bool spelledInMacroDefinition(SourceLocation Loc, // in a macro expansion. Loc = Expansion.getSpellingLoc(); } else { - return true; + return {}; } } + return Loc; +} + +static bool spelledInMacroDefinition(CharSourceRange Range, + const SourceManager &SM) { + if (Range.getBegin().isMacroID() && Range.getEnd().isMacroID()) { + // Check whether the range is entirely within a single macro argument. + auto B = getMacroArgumentSpellingLoc(Range.getBegin(), SM); + auto E = getMacroArgumentSpellingLoc(Range.getEnd(), SM); + return B.isInvalid() || B != E; + } + + if (Range.getBegin().isMacroID()) + return getMacroArgumentSpellingLoc(Range.getBegin(), SM).isInvalid(); + if (Range.getEnd().isMacroID()) + return getMacroArgumentSpellingLoc(Range.getEnd(), SM).isInvalid(); + return false; } @@ -158,8 +179,7 @@ static CharSourceRange getRange(const CharSourceRange &EditRange, Range = Lexer::makeFileCharRange(EditRange, SM, LangOpts); } else { auto AdjustedRange = getRangeForSplitTokens(EditRange, SM, LangOpts); - if (spelledInMacroDefinition(AdjustedRange.getBegin(), SM) || - spelledInMacroDefinition(AdjustedRange.getEnd(), SM)) + if (spelledInMacroDefinition(AdjustedRange, SM)) return {}; auto B = SM.getSpellingLoc(AdjustedRange.getBegin()); diff --git a/clang/unittests/Tooling/SourceCodeTest.cpp b/clang/unittests/Tooling/SourceCodeTest.cpp index 549b77752f1c2..2f59ced0ebc83 100644 --- a/clang/unittests/Tooling/SourceCodeTest.cpp +++ b/clang/unittests/Tooling/SourceCodeTest.cpp @@ -510,10 +510,12 @@ TEST(SourceCodeTest, EditInvolvingExpansionIgnoringExpansionShouldFail) { #define M1(x) x(1) #define M2(x, y) x ## y #define M3(x) foobar(x) +#define M4(x, y) x y int foobar(int); int a = M1(foobar); int b = M2(foo, bar(2)); int c = M3(3); +int d = M4(foobar, (4)); )cpp"); CallsVisitor Visitor;