1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "clang/Lex/TokenConcatenation.h" |
14 | #include "clang/Basic/CharInfo.h" |
15 | #include "clang/Lex/Preprocessor.h" |
16 | #include "llvm/Support/ErrorHandling.h" |
17 | using namespace clang; |
18 | |
19 | |
20 | |
21 | |
22 | static bool IsStringPrefix(StringRef Str, bool CPlusPlus11) { |
23 | |
24 | if (Str[0] == 'L' || |
25 | (CPlusPlus11 && (Str[0] == 'u' || Str[0] == 'U' || Str[0] == 'R'))) { |
26 | |
27 | if (Str.size() == 1) |
28 | return true; |
29 | |
30 | |
31 | |
32 | if (Str[1] == 'R' && Str[0] != 'R' && Str.size() == 2 && CPlusPlus11) |
33 | return true; |
34 | |
35 | |
36 | if (Str[0] == 'u' && Str[1] == '8') { |
37 | if (Str.size() == 2) return true; |
38 | if (Str.size() == 3 && Str[2] == 'R') return true; |
39 | } |
40 | } |
41 | |
42 | return false; |
43 | } |
44 | |
45 | |
46 | |
47 | bool TokenConcatenation::IsIdentifierStringPrefix(const Token &Tok) const { |
48 | const LangOptions &LangOpts = PP.getLangOpts(); |
49 | |
50 | if (!Tok.needsCleaning()) { |
51 | if (Tok.getLength() < 1 || Tok.getLength() > 3) |
52 | return false; |
53 | SourceManager &SM = PP.getSourceManager(); |
54 | const char *Ptr = SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation())); |
55 | return IsStringPrefix(StringRef(Ptr, Tok.getLength()), |
56 | LangOpts.CPlusPlus11); |
57 | } |
58 | |
59 | if (Tok.getLength() < 256) { |
60 | char Buffer[256]; |
61 | const char *TokPtr = Buffer; |
62 | unsigned length = PP.getSpelling(Tok, TokPtr); |
63 | return IsStringPrefix(StringRef(TokPtr, length), LangOpts.CPlusPlus11); |
64 | } |
65 | |
66 | return IsStringPrefix(StringRef(PP.getSpelling(Tok)), LangOpts.CPlusPlus11); |
67 | } |
68 | |
69 | TokenConcatenation::TokenConcatenation(const Preprocessor &pp) : PP(pp) { |
70 | memset(TokenInfo, 0, sizeof(TokenInfo)); |
71 | |
72 | |
73 | TokenInfo[tok::identifier ] |= aci_custom; |
74 | TokenInfo[tok::numeric_constant] |= aci_custom_firstchar; |
75 | TokenInfo[tok::period ] |= aci_custom_firstchar; |
76 | TokenInfo[tok::amp ] |= aci_custom_firstchar; |
77 | TokenInfo[tok::plus ] |= aci_custom_firstchar; |
78 | TokenInfo[tok::minus ] |= aci_custom_firstchar; |
79 | TokenInfo[tok::slash ] |= aci_custom_firstchar; |
80 | TokenInfo[tok::less ] |= aci_custom_firstchar; |
81 | TokenInfo[tok::greater ] |= aci_custom_firstchar; |
82 | TokenInfo[tok::pipe ] |= aci_custom_firstchar; |
83 | TokenInfo[tok::percent ] |= aci_custom_firstchar; |
84 | TokenInfo[tok::colon ] |= aci_custom_firstchar; |
85 | TokenInfo[tok::hash ] |= aci_custom_firstchar; |
86 | TokenInfo[tok::arrow ] |= aci_custom_firstchar; |
87 | |
88 | |
89 | if (PP.getLangOpts().CPlusPlus11) { |
90 | TokenInfo[tok::string_literal ] |= aci_custom; |
91 | TokenInfo[tok::wide_string_literal ] |= aci_custom; |
92 | TokenInfo[tok::utf8_string_literal ] |= aci_custom; |
93 | TokenInfo[tok::utf16_string_literal] |= aci_custom; |
94 | TokenInfo[tok::utf32_string_literal] |= aci_custom; |
95 | TokenInfo[tok::char_constant ] |= aci_custom; |
96 | TokenInfo[tok::wide_char_constant ] |= aci_custom; |
97 | TokenInfo[tok::utf16_char_constant ] |= aci_custom; |
98 | TokenInfo[tok::utf32_char_constant ] |= aci_custom; |
99 | } |
100 | |
101 | |
102 | if (PP.getLangOpts().CPlusPlus17) |
103 | TokenInfo[tok::utf8_char_constant] |= aci_custom; |
104 | |
105 | |
106 | if (PP.getLangOpts().CPlusPlus2a) |
107 | TokenInfo[tok::lessequal ] |= aci_custom_firstchar; |
108 | |
109 | |
110 | TokenInfo[tok::amp ] |= aci_avoid_equal; |
111 | TokenInfo[tok::plus ] |= aci_avoid_equal; |
112 | TokenInfo[tok::minus ] |= aci_avoid_equal; |
113 | TokenInfo[tok::slash ] |= aci_avoid_equal; |
114 | TokenInfo[tok::less ] |= aci_avoid_equal; |
115 | TokenInfo[tok::greater ] |= aci_avoid_equal; |
116 | TokenInfo[tok::pipe ] |= aci_avoid_equal; |
117 | TokenInfo[tok::percent ] |= aci_avoid_equal; |
118 | TokenInfo[tok::star ] |= aci_avoid_equal; |
119 | TokenInfo[tok::exclaim ] |= aci_avoid_equal; |
120 | TokenInfo[tok::lessless ] |= aci_avoid_equal; |
121 | TokenInfo[tok::greatergreater] |= aci_avoid_equal; |
122 | TokenInfo[tok::caret ] |= aci_avoid_equal; |
123 | TokenInfo[tok::equal ] |= aci_avoid_equal; |
124 | } |
125 | |
126 | |
127 | |
128 | static char GetFirstChar(const Preprocessor &PP, const Token &Tok) { |
129 | if (IdentifierInfo *II = Tok.getIdentifierInfo()) { |
130 | |
131 | return II->getNameStart()[0]; |
132 | } else if (!Tok.needsCleaning()) { |
133 | if (Tok.isLiteral() && Tok.getLiteralData()) { |
134 | return *Tok.getLiteralData(); |
135 | } else { |
136 | SourceManager &SM = PP.getSourceManager(); |
137 | return *SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation())); |
138 | } |
139 | } else if (Tok.getLength() < 256) { |
140 | char Buffer[256]; |
141 | const char *TokPtr = Buffer; |
142 | PP.getSpelling(Tok, TokPtr); |
143 | return TokPtr[0]; |
144 | } else { |
145 | return PP.getSpelling(Tok)[0]; |
146 | } |
147 | } |
148 | |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | |
155 | |
156 | |
157 | |
158 | |
159 | |
160 | bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok, |
161 | const Token &PrevTok, |
162 | const Token &Tok) const { |
163 | |
164 | |
165 | |
166 | SourceManager &SM = PP.getSourceManager(); |
167 | SourceLocation PrevSpellLoc = SM.getSpellingLoc(PrevTok.getLocation()); |
168 | SourceLocation SpellLoc = SM.getSpellingLoc(Tok.getLocation()); |
169 | if (PrevSpellLoc.getLocWithOffset(PrevTok.getLength()) == SpellLoc) |
170 | return false; |
171 | |
172 | tok::TokenKind PrevKind = PrevTok.getKind(); |
173 | if (!PrevTok.isAnnotation() && PrevTok.getIdentifierInfo()) |
174 | PrevKind = tok::identifier; |
175 | |
176 | |
177 | unsigned ConcatInfo = TokenInfo[PrevKind]; |
178 | |
179 | |
180 | if (ConcatInfo == 0) return false; |
181 | |
182 | if (ConcatInfo & aci_avoid_equal) { |
183 | |
184 | if (Tok.isOneOf(tok::equal, tok::equalequal)) |
185 | return true; |
186 | ConcatInfo &= ~aci_avoid_equal; |
187 | } |
188 | if (Tok.isAnnotation()) { |
189 | |
190 | (0) . __assert_fail ("Tok.isOneOf(tok..annot_module_include, tok..annot_module_begin, tok..annot_module_end) && \"unexpected annotation in AvoidConcat\"", "/home/seafit/code_projects/clang_source/clang/lib/Lex/TokenConcatenation.cpp", 192, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Tok.isOneOf(tok::annot_module_include, tok::annot_module_begin, |
191 | (0) . __assert_fail ("Tok.isOneOf(tok..annot_module_include, tok..annot_module_begin, tok..annot_module_end) && \"unexpected annotation in AvoidConcat\"", "/home/seafit/code_projects/clang_source/clang/lib/Lex/TokenConcatenation.cpp", 192, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> tok::annot_module_end) && |
192 | (0) . __assert_fail ("Tok.isOneOf(tok..annot_module_include, tok..annot_module_begin, tok..annot_module_end) && \"unexpected annotation in AvoidConcat\"", "/home/seafit/code_projects/clang_source/clang/lib/Lex/TokenConcatenation.cpp", 192, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "unexpected annotation in AvoidConcat"); |
193 | ConcatInfo = 0; |
194 | } |
195 | |
196 | if (ConcatInfo == 0) |
197 | return false; |
198 | |
199 | |
200 | |
201 | |
202 | char FirstChar = 0; |
203 | if (ConcatInfo & aci_custom) { |
204 | |
205 | } else { |
206 | FirstChar = GetFirstChar(PP, Tok); |
207 | } |
208 | |
209 | switch (PrevKind) { |
210 | default: |
211 | llvm_unreachable("InitAvoidConcatTokenInfo built wrong"); |
212 | |
213 | case tok::raw_identifier: |
214 | llvm_unreachable("tok::raw_identifier in non-raw lexing mode!"); |
215 | |
216 | case tok::string_literal: |
217 | case tok::wide_string_literal: |
218 | case tok::utf8_string_literal: |
219 | case tok::utf16_string_literal: |
220 | case tok::utf32_string_literal: |
221 | case tok::char_constant: |
222 | case tok::wide_char_constant: |
223 | case tok::utf8_char_constant: |
224 | case tok::utf16_char_constant: |
225 | case tok::utf32_char_constant: |
226 | if (!PP.getLangOpts().CPlusPlus11) |
227 | return false; |
228 | |
229 | |
230 | |
231 | if (Tok.getIdentifierInfo()) |
232 | return true; |
233 | |
234 | |
235 | |
236 | if (!PrevTok.hasUDSuffix()) |
237 | return false; |
238 | LLVM_FALLTHROUGH; |
239 | case tok::identifier: |
240 | |
241 | if (Tok.is(tok::numeric_constant)) |
242 | return GetFirstChar(PP, Tok) != '.'; |
243 | |
244 | if (Tok.getIdentifierInfo() || |
245 | Tok.isOneOf(tok::wide_string_literal, tok::utf8_string_literal, |
246 | tok::utf16_string_literal, tok::utf32_string_literal, |
247 | tok::wide_char_constant, tok::utf8_char_constant, |
248 | tok::utf16_char_constant, tok::utf32_char_constant)) |
249 | return true; |
250 | |
251 | |
252 | if (Tok.isNot(tok::char_constant) && Tok.isNot(tok::string_literal)) |
253 | return false; |
254 | |
255 | |
256 | |
257 | return IsIdentifierStringPrefix(PrevTok); |
258 | |
259 | case tok::numeric_constant: |
260 | return isPreprocessingNumberBody(FirstChar) || |
261 | FirstChar == '+' || FirstChar == '-'; |
262 | case tok::period: |
263 | return (FirstChar == '.' && PrevPrevTok.is(tok::period)) || |
264 | isDigit(FirstChar) || |
265 | (PP.getLangOpts().CPlusPlus && FirstChar == '*'); |
266 | case tok::amp: |
267 | return FirstChar == '&'; |
268 | case tok::plus: |
269 | return FirstChar == '+'; |
270 | case tok::minus: |
271 | return FirstChar == '-' || FirstChar == '>'; |
272 | case tok::slash: |
273 | return FirstChar == '*' || FirstChar == '/'; |
274 | case tok::less: |
275 | return FirstChar == '<' || FirstChar == ':' || FirstChar == '%'; |
276 | case tok::greater: |
277 | return FirstChar == '>'; |
278 | case tok::pipe: |
279 | return FirstChar == '|'; |
280 | case tok::percent: |
281 | return FirstChar == '>' || FirstChar == ':'; |
282 | case tok::colon: |
283 | return FirstChar == '>' || |
284 | (PP.getLangOpts().CPlusPlus && FirstChar == ':'); |
285 | case tok::hash: |
286 | return FirstChar == '#' || FirstChar == '@' || FirstChar == '%'; |
287 | case tok::arrow: |
288 | return PP.getLangOpts().CPlusPlus && FirstChar == '*'; |
289 | case tok::lessequal: |
290 | return PP.getLangOpts().CPlusPlus2a && FirstChar == '>'; |
291 | } |
292 | } |
293 | |