PR37189 Fix incorrect end source location and spelling for a split '>>' token.
When a '>>' token is split into two '>' tokens (in C++11 onwards), or (as an
extension) when we do the same for other tokens starting with a '>', we can't
just use a location pointing to the first '>' as the location of the split
token, because that would result in our miscomputing the length and spelling
for the token. As a consequence, for example, a refactoring replacing 'A<X>'
with something else would sometimes replace one character too many, and
similarly diagnostics highlighting a template-id source range would highlight
one character too many.
Fix this by creating an expansion range covering the first character of the
'>>' token, whose spelling is '>'. For this to work, we generalize the
expansion range of a macro FileID to be either a token range (the common case)
or a character range (used in this new case).
llvm-svn: 331155
diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp
index 6a72b00..9bda79a 100644
--- a/clang/lib/Frontend/TextDiagnostic.cpp
+++ b/clang/lib/Frontend/TextDiagnostic.cpp
@@ -852,23 +852,14 @@
// Ignore invalid ranges.
if (!RI->isValid()) continue;
- FullSourceLoc B =
- FullSourceLoc(RI->getBegin(), Loc.getManager()).getExpansionLoc();
- FullSourceLoc E =
- FullSourceLoc(RI->getEnd(), Loc.getManager()).getExpansionLoc();
+ auto &SM = Loc.getManager();
+ SourceLocation B = SM.getExpansionLoc(RI->getBegin());
+ CharSourceRange ERange = SM.getExpansionRange(RI->getEnd());
+ SourceLocation E = ERange.getEnd();
+ bool IsTokenRange = ERange.isTokenRange();
- // If the End location and the start location are the same and are a
- // macro location, then the range was something that came from a
- // macro expansion or _Pragma. If this is an object-like macro, the
- // best we can do is to highlight the range. If this is a
- // function-like macro, we'd also like to highlight the arguments.
- if (B == E && RI->getEnd().isMacroID())
- E = FullSourceLoc(RI->getEnd(), Loc.getManager())
- .getExpansionRange()
- .second;
-
- std::pair<FileID, unsigned> BInfo = B.getDecomposedLoc();
- std::pair<FileID, unsigned> EInfo = E.getDecomposedLoc();
+ std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
+ std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
// If the start or end of the range is in another file, just discard
// it.
@@ -878,11 +869,14 @@
// Add in the length of the token, so that we cover multi-char
// tokens.
unsigned TokSize = 0;
- if (RI->isTokenRange())
- TokSize = Lexer::MeasureTokenLength(E, E.getManager(), LangOpts);
+ if (IsTokenRange)
+ TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
- OS << '{' << B.getLineNumber() << ':' << B.getColumnNumber() << '-'
- << E.getLineNumber() << ':' << (E.getColumnNumber() + TokSize) << '}';
+ FullSourceLoc BF(B, SM), EF(E, SM);
+ OS << '{'
+ << BF.getLineNumber() << ':' << BF.getColumnNumber() << '-'
+ << EF.getLineNumber() << ':' << (EF.getColumnNumber() + TokSize)
+ << '}';
PrintedRange = true;
}