@@ -101,6 +101,54 @@ static bool spelledInMacroDefinition(SourceLocation Loc,
101
101
return false ;
102
102
}
103
103
104
+ // Returns the expansion char-range of `Loc` if `Loc` is a split token. For
105
+ // example, `>>` in nested templates needs the first `>` to be split, otherwise
106
+ // the `SourceLocation` of the token would lex as `>>` instead of `>`.
107
+ static std::optional<CharSourceRange>
108
+ getExpansionForSplitToken (SourceLocation Loc, const SourceManager &SM,
109
+ const LangOptions &LangOpts) {
110
+ if (Loc.isMacroID ()) {
111
+ bool Invalid = false ;
112
+ auto &SLoc = SM.getSLocEntry (SM.getFileID (Loc), &Invalid);
113
+ if (Invalid)
114
+ return std::nullopt;
115
+ if (auto &Expansion = SLoc.getExpansion ();
116
+ !Expansion.isExpansionTokenRange ()) {
117
+ // A char-range expansion is only used where a token-range would be
118
+ // incorrect, and so identifies this as a split token (and importantly,
119
+ // not as a macro).
120
+ return Expansion.getExpansionLocRange ();
121
+ }
122
+ }
123
+ return std::nullopt;
124
+ }
125
+
126
+ // If `Range` covers a split token, returns the expansion range, otherwise
127
+ // returns `Range`.
128
+ static CharSourceRange getRangeForSplitTokens (CharSourceRange Range,
129
+ const SourceManager &SM,
130
+ const LangOptions &LangOpts) {
131
+ if (Range.isTokenRange ()) {
132
+ auto BeginToken = getExpansionForSplitToken (Range.getBegin (), SM, LangOpts);
133
+ auto EndToken = getExpansionForSplitToken (Range.getEnd (), SM, LangOpts);
134
+ if (EndToken) {
135
+ SourceLocation BeginLoc =
136
+ BeginToken ? BeginToken->getBegin () : Range.getBegin ();
137
+ // We can't use the expansion location with a token-range, because that
138
+ // will incorrectly lex the end token, so use a char-range that ends at
139
+ // the split.
140
+ return CharSourceRange::getCharRange (BeginLoc, EndToken->getEnd ());
141
+ } else if (BeginToken) {
142
+ // Since the end token is not split, the whole range covers the split, so
143
+ // the only adjustment we make is to use the expansion location of the
144
+ // begin token.
145
+ return CharSourceRange::getTokenRange (BeginToken->getBegin (),
146
+ Range.getEnd ());
147
+ }
148
+ }
149
+ return Range;
150
+ }
151
+
104
152
static CharSourceRange getRange (const CharSourceRange &EditRange,
105
153
const SourceManager &SM,
106
154
const LangOptions &LangOpts,
@@ -109,13 +157,14 @@ static CharSourceRange getRange(const CharSourceRange &EditRange,
109
157
if (IncludeMacroExpansion) {
110
158
Range = Lexer::makeFileCharRange (EditRange, SM, LangOpts);
111
159
} else {
112
- if (spelledInMacroDefinition (EditRange.getBegin (), SM) ||
113
- spelledInMacroDefinition (EditRange.getEnd (), SM))
160
+ auto AdjustedRange = getRangeForSplitTokens (EditRange, SM, LangOpts);
161
+ if (spelledInMacroDefinition (AdjustedRange.getBegin (), SM) ||
162
+ spelledInMacroDefinition (AdjustedRange.getEnd (), SM))
114
163
return {};
115
164
116
- auto B = SM.getSpellingLoc (EditRange .getBegin ());
117
- auto E = SM.getSpellingLoc (EditRange .getEnd ());
118
- if (EditRange .isTokenRange ())
165
+ auto B = SM.getSpellingLoc (AdjustedRange .getBegin ());
166
+ auto E = SM.getSpellingLoc (AdjustedRange .getEnd ());
167
+ if (AdjustedRange .isTokenRange ())
119
168
E = Lexer::getLocForEndOfToken (E, 0 , SM, LangOpts);
120
169
Range = CharSourceRange::getCharRange (B, E);
121
170
}
0 commit comments