https://github.com/tJener created 
https://github.com/llvm/llvm-project/pull/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.

>From a79d0dc0356921020bcafc3011b143502a92be9d Mon Sep 17 00:00:00 2001
From: Eric Li <[email protected]>
Date: Wed, 26 Nov 2025 23:33:24 -0500
Subject: [PATCH] [clang][Tooling] Fix `getFileRange` returning a range
 spanning across macro arguments

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 fully spelled in a
single sequence of characters in source.
---
 clang/lib/Tooling/Transformer/SourceCode.cpp | 30 ++++++++++++++++----
 clang/unittests/Tooling/SourceCodeTest.cpp   |  2 ++
 2 files changed, 27 insertions(+), 5 deletions(-)

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..4932e0bd9431b 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, (2));
 )cpp");
 
   CallsVisitor Visitor;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to