clang 24.0.0git
Tokens.cpp
Go to the documentation of this file.
1//===- Tokens.cpp - collect tokens from preprocessing ---------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
9
12#include "clang/Basic/LLVM.h"
19#include "clang/Lex/Token.h"
20#include "llvm/ADT/ArrayRef.h"
21#include "llvm/ADT/STLExtras.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/ErrorHandling.h"
24#include "llvm/Support/FormatVariadic.h"
25#include "llvm/Support/Path.h"
26#include "llvm/Support/raw_ostream.h"
27#include <cassert>
28#include <optional>
29#include <string>
30#include <utility>
31#include <vector>
32
33using namespace clang;
34using namespace clang::syntax;
35
36namespace {
37// Finds the smallest consecutive subsuquence of Toks that covers R.
39getTokensCovering(llvm::ArrayRef<syntax::Token> Toks, SourceRange R,
40 const SourceManager &SM) {
41 if (R.isInvalid())
42 return {};
43 const syntax::Token *Begin =
44 llvm::partition_point(Toks, [&](const syntax::Token &T) {
45 return SM.isBeforeInTranslationUnit(T.location(), R.getBegin());
46 });
47 const syntax::Token *End =
48 llvm::partition_point(Toks, [&](const syntax::Token &T) {
49 return !SM.isBeforeInTranslationUnit(R.getEnd(), T.location());
50 });
51 if (Begin > End)
52 return {};
53 return {Begin, End};
54}
55
56// Finds the range within FID corresponding to expanded tokens [First, Last].
57// Prev precedes First and Next follows Last, these must *not* be included.
58// If no range satisfies the criteria, returns an invalid range.
59//
60// #define ID(x) x
61// ID(ID(ID(a1) a2))
62// ~~ -> a1
63// ~~ -> a2
64// ~~~~~~~~~ -> a1 a2
65SourceRange spelledForExpandedSlow(SourceLocation First, SourceLocation Last,
67 FileID TargetFile,
68 const SourceManager &SM) {
69 // There are two main parts to this algorithm:
70 // - identifying which spelled range covers the expanded tokens
71 // - validating that this range doesn't cover any extra tokens (First/Last)
72 //
73 // We do these in order. However as we transform the expanded range into the
74 // spelled one, we adjust First/Last so the validation remains simple.
75
76 assert(SM.getSLocEntry(TargetFile).isFile());
77 // In most cases, to select First and Last we must return their expansion
78 // range, i.e. the whole of any macros they are included in.
79 //
80 // When First and Last are part of the *same macro arg* of a macro written
81 // in TargetFile, we that slice of the arg, i.e. their spelling range.
82 //
83 // Unwrap such macro calls. If the target file has A(B(C)), the
84 // SourceLocation stack of a token inside C shows us the expansion of A first,
85 // then B, then any macros inside C's body, then C itself.
86 // (This is the reverse of the order the PP applies the expansions in).
87 while (First.isMacroID() && Last.isMacroID()) {
88 auto DecFirst = SM.getDecomposedLoc(First);
89 auto DecLast = SM.getDecomposedLoc(Last);
90 auto &ExpFirst = SM.getSLocEntry(DecFirst.first).getExpansion();
91 auto &ExpLast = SM.getSLocEntry(DecLast.first).getExpansion();
92
93 if (!ExpFirst.isMacroArgExpansion() || !ExpLast.isMacroArgExpansion())
94 break;
95 // Locations are in the same macro arg if they expand to the same place.
96 // (They may still have different FileIDs - an arg can have >1 chunks!)
97 if (ExpFirst.getExpansionLocStart() != ExpLast.getExpansionLocStart())
98 break;
99 // Careful, given:
100 // #define HIDE ID(ID(a))
101 // ID(ID(HIDE))
102 // The token `a` is wrapped in 4 arg-expansions, we only want to unwrap 2.
103 // We distinguish them by whether the macro expands into the target file.
104 // Fortunately, the target file ones will always appear first.
105 auto ExpFileID = SM.getFileID(ExpFirst.getExpansionLocStart());
106 if (ExpFileID == TargetFile)
107 break;
108 // Replace each endpoint with its spelling inside the macro arg.
109 // (This is getImmediateSpellingLoc without repeating lookups).
110 First = ExpFirst.getSpellingLoc().getLocWithOffset(DecFirst.second);
111 Last = ExpLast.getSpellingLoc().getLocWithOffset(DecLast.second);
112 }
113
114 // In all remaining cases we need the full containing macros.
115 // If this overlaps Prev or Next, then no range is possible.
116 SourceRange Candidate =
118 auto DecFirst = SM.getDecomposedExpansionLoc(Candidate.getBegin());
119 auto DecLast = SM.getDecomposedExpansionLoc(Candidate.getEnd());
120 // Can end up in the wrong file due to bad input or token-pasting shenanigans.
121 if (Candidate.isInvalid() || DecFirst.first != TargetFile ||
122 DecLast.first != TargetFile)
123 return SourceRange();
124 // Check bounds, which may still be inside macros.
125 if (Prev.isValid()) {
126 auto Dec = SM.getDecomposedLoc(SM.getExpansionRange(Prev).getBegin());
127 if (Dec.first != DecFirst.first || Dec.second >= DecFirst.second)
128 return SourceRange();
129 }
130 if (Next.isValid()) {
132 if (Dec.first != DecLast.first || Dec.second <= DecLast.second)
133 return SourceRange();
134 }
135 // Now we know that Candidate is a file range that covers [First, Last]
136 // without encroaching on {Prev, Next}. Ship it!
137 return Candidate;
138}
139
140} // namespace
141
142syntax::Token::Token(SourceLocation Location, unsigned Length,
143 tok::TokenKind Kind)
144 : Location(Location), Length(Length), Kind(Kind) {
145 assert(Location.isValid());
146}
147
149 : Token(T.getLocation(), T.getLength(), T.getKind()) {
150 assert(!T.isAnnotation());
151}
152
153llvm::StringRef syntax::Token::text(const SourceManager &SM) const {
154 bool Invalid = false;
155 const char *Start = SM.getCharacterData(location(), &Invalid);
156 assert(!Invalid);
157 return llvm::StringRef(Start, length());
158}
159
161 assert(location().isFileID() && "must be a spelled token");
162 FileID File;
163 unsigned StartOffset;
164 std::tie(File, StartOffset) = SM.getDecomposedLoc(location());
165 return FileRange(File, StartOffset, StartOffset + length());
166}
167
169 const syntax::Token &First,
170 const syntax::Token &Last) {
171 auto F = First.range(SM);
172 auto L = Last.range(SM);
173 assert(F.file() == L.file() && "tokens from different files");
174 assert((F == L || F.endOffset() <= L.beginOffset()) &&
175 "wrong order of tokens");
176 return FileRange(F.file(), F.beginOffset(), L.endOffset());
177}
178
179llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, const Token &T) {
180 return OS << T.str();
181}
182
183FileRange::FileRange(FileID File, unsigned BeginOffset, unsigned EndOffset)
184 : File(File), Begin(BeginOffset), End(EndOffset) {
185 assert(File.isValid());
186 assert(BeginOffset <= EndOffset);
187}
188
190 unsigned Length) {
191 assert(BeginLoc.isValid());
192 assert(BeginLoc.isFileID());
193
194 std::tie(File, Begin) = SM.getDecomposedLoc(BeginLoc);
195 End = Begin + Length;
196}
198 SourceLocation EndLoc) {
199 assert(BeginLoc.isValid());
200 assert(BeginLoc.isFileID());
201 assert(EndLoc.isValid());
202 assert(EndLoc.isFileID());
203 assert(SM.getFileID(BeginLoc) == SM.getFileID(EndLoc));
204 assert(SM.getFileOffset(BeginLoc) <= SM.getFileOffset(EndLoc));
205
206 std::tie(File, Begin) = SM.getDecomposedLoc(BeginLoc);
207 End = SM.getFileOffset(EndLoc);
208}
209
210llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS,
211 const FileRange &R) {
212 return OS << llvm::formatv("FileRange(file = {0}, offsets = {1}-{2})",
213 R.file().getHashValue(), R.beginOffset(),
214 R.endOffset());
215}
216
217llvm::StringRef FileRange::text(const SourceManager &SM) const {
218 bool Invalid = false;
219 StringRef Text = SM.getBufferData(File, &Invalid);
220 if (Invalid)
221 return "";
222 assert(Begin <= Text.size());
223 assert(End <= Text.size());
224 return Text.substr(Begin, length());
225}
226
228 // No-op if the index is already created.
229 if (!ExpandedTokIndex.empty())
230 return;
231 ExpandedTokIndex.reserve(ExpandedTokens.size());
232 // Index ExpandedTokens for faster lookups by SourceLocation.
233 for (size_t I = 0, E = ExpandedTokens.size(); I != E; ++I) {
234 SourceLocation Loc = ExpandedTokens[I].location();
235 if (Loc.isValid())
236 ExpandedTokIndex[Loc] = I;
237 }
238}
239
241 if (R.isInvalid())
242 return {};
243 if (!ExpandedTokIndex.empty()) {
244 // Quick lookup if `R` is a token range.
245 // This is a huge win since majority of the users use ranges provided by an
246 // AST. Ranges in AST are token ranges from expanded token stream.
247 const auto B = ExpandedTokIndex.find(R.getBegin());
248 const auto E = ExpandedTokIndex.find(R.getEnd());
249 if (B != ExpandedTokIndex.end() && E != ExpandedTokIndex.end()) {
250 const Token *L = ExpandedTokens.data() + B->getSecond();
251 // Add 1 to End to make a half-open range.
252 const Token *R = ExpandedTokens.data() + E->getSecond() + 1;
253 if (L > R)
254 return {};
255 return {L, R};
256 }
257 }
258 // Slow case. Use `isBeforeInTranslationUnit` to binary search for the
259 // required range.
260 return getTokensCovering(expandedTokens(), R, *SourceMgr);
261}
262
264 return CharSourceRange(
265 SourceRange(SM.getComposedLoc(File, Begin), SM.getComposedLoc(File, End)),
266 /*IsTokenRange=*/false);
267}
268
269std::pair<const syntax::Token *, const TokenBuffer::Mapping *>
270TokenBuffer::spelledForExpandedToken(const syntax::Token *Expanded) const {
271 assert(Expanded);
272 assert(ExpandedTokens.data() <= Expanded &&
273 Expanded < ExpandedTokens.data() + ExpandedTokens.size());
274
275 auto FileIt = Files.find(
276 SourceMgr->getFileID(SourceMgr->getExpansionLoc(Expanded->location())));
277 assert(FileIt != Files.end() && "no file for an expanded token");
278
279 const MarkedFile &File = FileIt->second;
280
281 unsigned ExpandedIndex = Expanded - ExpandedTokens.data();
282 // Find the first mapping that produced tokens after \p Expanded.
283 auto It = llvm::partition_point(File.Mappings, [&](const Mapping &M) {
284 return M.BeginExpanded <= ExpandedIndex;
285 });
286 // Our token could only be produced by the previous mapping.
287 if (It == File.Mappings.begin()) {
288 // No previous mapping, no need to modify offsets.
289 return {&File.SpelledTokens[ExpandedIndex - File.BeginExpanded],
290 /*Mapping=*/nullptr};
291 }
292 --It; // 'It' now points to last mapping that started before our token.
293
294 // Check if the token is part of the mapping.
295 if (ExpandedIndex < It->EndExpanded)
296 return {&File.SpelledTokens[It->BeginSpelled], /*Mapping=*/&*It};
297
298 // Not part of the mapping, use the index from previous mapping to compute the
299 // corresponding spelled token.
300 return {
301 &File.SpelledTokens[It->EndSpelled + (ExpandedIndex - It->EndExpanded)],
302 /*Mapping=*/nullptr};
303}
304
305const TokenBuffer::Mapping *
306TokenBuffer::mappingStartingBeforeSpelled(const MarkedFile &F,
307 const syntax::Token *Spelled) {
308 assert(F.SpelledTokens.data() <= Spelled);
309 unsigned SpelledI = Spelled - F.SpelledTokens.data();
310 assert(SpelledI < F.SpelledTokens.size());
311
312 auto It = llvm::partition_point(F.Mappings, [SpelledI](const Mapping &M) {
313 return M.BeginSpelled <= SpelledI;
314 });
315 if (It == F.Mappings.begin())
316 return nullptr;
317 --It;
318 return &*It;
319}
320
321llvm::SmallVector<llvm::ArrayRef<syntax::Token>, 1>
323 if (Spelled.empty())
324 return {};
325 const auto &File = fileForSpelled(Spelled);
326
327 auto *FrontMapping = mappingStartingBeforeSpelled(File, &Spelled.front());
328 unsigned SpelledFrontI = &Spelled.front() - File.SpelledTokens.data();
329 assert(SpelledFrontI < File.SpelledTokens.size());
330 unsigned ExpandedBegin;
331 if (!FrontMapping) {
332 // No mapping that starts before the first token of Spelled, we don't have
333 // to modify offsets.
334 ExpandedBegin = File.BeginExpanded + SpelledFrontI;
335 } else if (SpelledFrontI < FrontMapping->EndSpelled) {
336 // This mapping applies to Spelled tokens.
337 if (SpelledFrontI != FrontMapping->BeginSpelled) {
338 // Spelled tokens don't cover the entire mapping, returning empty result.
339 return {}; // FIXME: support macro arguments.
340 }
341 // Spelled tokens start at the beginning of this mapping.
342 ExpandedBegin = FrontMapping->BeginExpanded;
343 } else {
344 // Spelled tokens start after the mapping ends (they start in the hole
345 // between 2 mappings, or between a mapping and end of the file).
346 ExpandedBegin =
347 FrontMapping->EndExpanded + (SpelledFrontI - FrontMapping->EndSpelled);
348 }
349
350 auto *BackMapping = mappingStartingBeforeSpelled(File, &Spelled.back());
351 unsigned SpelledBackI = &Spelled.back() - File.SpelledTokens.data();
352 unsigned ExpandedEnd;
353 if (!BackMapping) {
354 // No mapping that starts before the last token of Spelled, we don't have to
355 // modify offsets.
356 ExpandedEnd = File.BeginExpanded + SpelledBackI + 1;
357 } else if (SpelledBackI < BackMapping->EndSpelled) {
358 // This mapping applies to Spelled tokens.
359 if (SpelledBackI + 1 != BackMapping->EndSpelled) {
360 // Spelled tokens don't cover the entire mapping, returning empty result.
361 return {}; // FIXME: support macro arguments.
362 }
363 ExpandedEnd = BackMapping->EndExpanded;
364 } else {
365 // Spelled tokens end after the mapping ends.
366 ExpandedEnd =
367 BackMapping->EndExpanded + (SpelledBackI - BackMapping->EndSpelled) + 1;
368 }
369
370 assert(ExpandedBegin < ExpandedTokens.size());
371 assert(ExpandedEnd < ExpandedTokens.size());
372 // Avoid returning empty ranges.
373 if (ExpandedBegin == ExpandedEnd)
374 return {};
375 return {llvm::ArrayRef(ExpandedTokens.data() + ExpandedBegin,
376 ExpandedTokens.data() + ExpandedEnd)};
377}
378
380 auto It = Files.find(FID);
381 assert(It != Files.end());
382 return It->second.SpelledTokens;
383}
384
385const syntax::Token *
387 assert(Loc.isFileID());
388 const auto *Tok = llvm::partition_point(
389 spelledTokens(SourceMgr->getFileID(Loc)),
390 [&](const syntax::Token &Tok) { return Tok.endLocation() <= Loc; });
391 if (!Tok || Loc < Tok->location())
392 return nullptr;
393 return Tok;
394}
395
396std::string TokenBuffer::Mapping::str() const {
397 return std::string(
398 llvm::formatv("spelled tokens: [{0},{1}), expanded tokens: [{2},{3})",
399 BeginSpelled, EndSpelled, BeginExpanded, EndExpanded));
400}
401
402std::optional<llvm::ArrayRef<syntax::Token>>
404 // In cases of invalid code, AST nodes can have source ranges that include
405 // the `eof` token. As there's no spelling for this token, exclude it from
406 // the range.
407 if (!Expanded.empty() && Expanded.back().kind() == tok::eof) {
408 Expanded = Expanded.drop_back();
409 }
410 // Mapping an empty range is ambiguous in case of empty mappings at either end
411 // of the range, bail out in that case.
412 if (Expanded.empty())
413 return std::nullopt;
414 const syntax::Token *First = &Expanded.front();
415 const syntax::Token *Last = &Expanded.back();
416 auto [FirstSpelled, FirstMapping] = spelledForExpandedToken(First);
417 auto [LastSpelled, LastMapping] = spelledForExpandedToken(Last);
418
419 FileID FID = SourceMgr->getFileID(FirstSpelled->location());
420 // FIXME: Handle multi-file changes by trying to map onto a common root.
421 if (FID != SourceMgr->getFileID(LastSpelled->location()))
422 return std::nullopt;
423
424 const MarkedFile &File = Files.find(FID)->second;
425
426 // If the range is within one macro argument, the result may be only part of a
427 // Mapping. We must use the general (SourceManager-based) algorithm.
428 if (FirstMapping && FirstMapping == LastMapping &&
429 SourceMgr->isMacroArgExpansion(First->location()) &&
430 SourceMgr->isMacroArgExpansion(Last->location())) {
431 // We use excluded Prev/Next token for bounds checking.
432 SourceLocation Prev = (First == &ExpandedTokens.front())
434 : (First - 1)->location();
435 SourceLocation Next = (Last == &ExpandedTokens.back())
437 : (Last + 1)->location();
438 SourceRange Range = spelledForExpandedSlow(
439 First->location(), Last->location(), Prev, Next, FID, *SourceMgr);
440 if (Range.isInvalid())
441 return std::nullopt;
442 return getTokensCovering(File.SpelledTokens, Range, *SourceMgr);
443 }
444
445 // Otherwise, use the fast version based on Mappings.
446 // Do not allow changes that doesn't cover full expansion.
447 unsigned FirstExpanded = Expanded.begin() - ExpandedTokens.data();
448 unsigned LastExpanded = Expanded.end() - ExpandedTokens.data();
449 if (FirstMapping && FirstExpanded != FirstMapping->BeginExpanded)
450 return std::nullopt;
451 if (LastMapping && LastMapping->EndExpanded != LastExpanded)
452 return std::nullopt;
453 return llvm::ArrayRef(
454 FirstMapping ? File.SpelledTokens.data() + FirstMapping->BeginSpelled
455 : FirstSpelled,
456 LastMapping ? File.SpelledTokens.data() + LastMapping->EndSpelled
457 : LastSpelled + 1);
458}
459
460TokenBuffer::Expansion TokenBuffer::makeExpansion(const MarkedFile &F,
461 const Mapping &M) const {
462 Expansion E;
463 E.Spelled = llvm::ArrayRef(F.SpelledTokens.data() + M.BeginSpelled,
464 F.SpelledTokens.data() + M.EndSpelled);
465 E.Expanded = llvm::ArrayRef(ExpandedTokens.data() + M.BeginExpanded,
466 ExpandedTokens.data() + M.EndExpanded);
467 return E;
468}
469
470const TokenBuffer::MarkedFile &
471TokenBuffer::fileForSpelled(llvm::ArrayRef<syntax::Token> Spelled) const {
472 assert(!Spelled.empty());
473 assert(Spelled.front().location().isFileID() && "not a spelled token");
474 auto FileIt = Files.find(SourceMgr->getFileID(Spelled.front().location()));
475 assert(FileIt != Files.end() && "file not tracked by token buffer");
476 const auto &File = FileIt->second;
477 assert(File.SpelledTokens.data() <= Spelled.data() &&
478 Spelled.end() <=
479 (File.SpelledTokens.data() + File.SpelledTokens.size()) &&
480 "Tokens not in spelled range");
481#ifndef NDEBUG
482 auto T1 = Spelled.back().location();
483 auto T2 = File.SpelledTokens.back().location();
484 assert(T1 == T2 || sourceManager().isBeforeInTranslationUnit(T1, T2));
485#endif
486 return File;
487}
488
489std::optional<TokenBuffer::Expansion>
491 assert(Spelled);
492 const auto &File = fileForSpelled(*Spelled);
493
494 unsigned SpelledIndex = Spelled - File.SpelledTokens.data();
495 auto M = llvm::partition_point(File.Mappings, [&](const Mapping &M) {
496 return M.BeginSpelled < SpelledIndex;
497 });
498 if (M == File.Mappings.end() || M->BeginSpelled != SpelledIndex)
499 return std::nullopt;
500 return makeExpansion(File, *M);
501}
502
503std::vector<TokenBuffer::Expansion> TokenBuffer::expansionsOverlapping(
504 llvm::ArrayRef<syntax::Token> Spelled) const {
505 if (Spelled.empty())
506 return {};
507 const auto &File = fileForSpelled(Spelled);
508
509 // Find the first overlapping range, and then copy until we stop overlapping.
510 unsigned SpelledBeginIndex = Spelled.begin() - File.SpelledTokens.data();
511 unsigned SpelledEndIndex = Spelled.end() - File.SpelledTokens.data();
512 auto M = llvm::partition_point(File.Mappings, [&](const Mapping &M) {
513 return M.EndSpelled <= SpelledBeginIndex;
514 });
515 std::vector<TokenBuffer::Expansion> Expansions;
516 for (; M != File.Mappings.end() && M->BeginSpelled < SpelledEndIndex; ++M)
517 Expansions.push_back(makeExpansion(File, *M));
518 return Expansions;
519}
520
524 assert(Loc.isFileID());
525
526 auto *Right = llvm::partition_point(
527 Tokens, [&](const syntax::Token &Tok) { return Tok.location() < Loc; });
528 bool AcceptRight = Right != Tokens.end() && Right->location() <= Loc;
529 bool AcceptLeft =
530 Right != Tokens.begin() && (Right - 1)->endLocation() >= Loc;
531 return llvm::ArrayRef(Right - (AcceptLeft ? 1 : 0),
532 Right + (AcceptRight ? 1 : 0));
533}
534
537 const syntax::TokenBuffer &Tokens) {
539 Loc, Tokens.spelledTokens(Tokens.sourceManager().getFileID(Loc)));
540}
541
542const syntax::Token *
545 for (const syntax::Token &Tok : spelledTokensTouching(Loc, Tokens)) {
546 if (Tok.kind() == tok::identifier)
547 return &Tok;
548 }
549 return nullptr;
550}
551
552const syntax::Token *
558
559std::vector<const syntax::Token *>
561 auto FileIt = Files.find(FID);
562 assert(FileIt != Files.end() && "file not tracked by token buffer");
563 auto &File = FileIt->second;
564 std::vector<const syntax::Token *> Expansions;
565 auto &Spelled = File.SpelledTokens;
566 for (auto Mapping : File.Mappings) {
567 const syntax::Token *Token = &Spelled[Mapping.BeginSpelled];
568 if (Token->kind() == tok::TokenKind::identifier)
569 Expansions.push_back(Token);
570 }
571 return Expansions;
572}
573
574std::vector<syntax::Token> syntax::tokenize(const FileRange &FR,
575 const SourceManager &SM,
576 const LangOptions &LO) {
577 std::vector<syntax::Token> Tokens;
578 IdentifierTable Identifiers(LO);
579 auto AddToken = [&](clang::Token T) {
580 // Fill the proper token kind for keywords, etc.
581 if (T.getKind() == tok::raw_identifier && !T.needsCleaning() &&
582 !T.hasUCN()) { // FIXME: support needsCleaning and hasUCN cases.
583 clang::IdentifierInfo &II = Identifiers.get(T.getRawIdentifier());
584 T.setIdentifierInfo(&II);
585 T.setKind(II.getTokenID());
586 }
587 Tokens.push_back(syntax::Token(T));
588 };
589
590 auto SrcBuffer = SM.getBufferData(FR.file());
591 Lexer L(SM.getLocForStartOfFile(FR.file()), LO, SrcBuffer.data(),
592 SrcBuffer.data() + FR.beginOffset(),
593 // We can't make BufEnd point to FR.endOffset, as Lexer requires a
594 // null terminated buffer.
595 SrcBuffer.data() + SrcBuffer.size());
596
598 while (!L.LexFromRawLexer(T) && L.getCurrentBufferOffset() < FR.endOffset())
599 AddToken(T);
600 // LexFromRawLexer returns true when it parses the last token of the file, add
601 // it iff it starts within the range we are interested in.
602 if (SM.getFileOffset(T.getLocation()) < FR.endOffset())
603 AddToken(T);
604 return Tokens;
605}
606
607std::vector<syntax::Token> syntax::tokenize(FileID FID, const SourceManager &SM,
608 const LangOptions &LO) {
609 return tokenize(syntax::FileRange(FID, 0, SM.getFileIDSize(FID)), SM, LO);
610}
611
612/// Records information reqired to construct mappings for the token buffer that
613/// we are collecting.
615public:
616 CollectPPExpansions(TokenCollector &C) : Collector(&C) {}
617
618 /// Disabled instance will stop reporting anything to TokenCollector.
619 /// This ensures that uses of the preprocessor after TokenCollector::consume()
620 /// is called do not access the (possibly invalid) collector instance.
621 void disable() { Collector = nullptr; }
622
623 void MacroExpands(const clang::Token &MacroNameTok, const MacroDefinition &MD,
624 SourceRange Range, const MacroArgs *Args) override {
625 if (!Collector)
626 return;
627 const auto &SM = Collector->PP.getSourceManager();
628 // Only record top-level expansions that directly produce expanded tokens.
629 // This excludes those where:
630 // - the macro use is inside a macro body,
631 // - the macro appears in an argument to another macro.
632 // However macro expansion isn't really a tree, it's token rewrite rules,
633 // so there are other cases, e.g.
634 // #define B(X) X
635 // #define A 1 + B
636 // A(2)
637 // Both A and B produce expanded tokens, though the macro name 'B' comes
638 // from an expansion. The best we can do is merge the mappings for both.
639
640 // The *last* token of any top-level macro expansion must be in a file.
641 // (In the example above, see the closing paren of the expansion of B).
642 if (!Range.getEnd().isFileID())
643 return;
644 // If there's a current expansion that encloses this one, this one can't be
645 // top-level.
646 if (LastExpansionEnd.isValid() &&
647 !SM.isBeforeInTranslationUnit(LastExpansionEnd, Range.getEnd()))
648 return;
649
650 // If the macro invocation (B) starts in a macro (A) but ends in a file,
651 // we'll create a merged mapping for A + B by overwriting the endpoint for
652 // A's startpoint.
653 if (!Range.getBegin().isFileID()) {
654 Range.setBegin(SM.getExpansionLoc(Range.getBegin()));
655 assert(Collector->Expansions.count(Range.getBegin()) &&
656 "Overlapping macros should have same expansion location");
657 }
658
659 Collector->Expansions[Range.getBegin()] = Range.getEnd();
660 LastExpansionEnd = Range.getEnd();
661 }
662 // FIXME: handle directives like #pragma, #include, etc.
663private:
664 TokenCollector *Collector;
665 /// Used to detect recursive macro expansions.
666 SourceLocation LastExpansionEnd;
667};
668
669/// Fills in the TokenBuffer by tracing the run of a preprocessor. The
670/// implementation tracks the tokens, macro expansions and directives coming
671/// from the preprocessor and:
672/// - for each token, figures out if it is a part of an expanded token stream,
673/// spelled token stream or both. Stores the tokens appropriately.
674/// - records mappings from the spelled to expanded token ranges, e.g. for macro
675/// expansions.
676/// FIXME: also properly record:
677/// - #include directives,
678/// - #pragma, #line and other PP directives,
679/// - skipped pp regions,
680/// - ...
681
683 // Collect the expanded token stream during preprocessing.
684 PP.setTokenWatcher([this](const clang::Token &T) {
685 if (T.is(tok::annot_module_name)) {
686 auto &SM = this->PP.getSourceManager();
687 StringRef Text = Lexer::getSourceText(
688 CharSourceRange::getTokenRange(T.getAnnotationRange()), SM,
689 this->PP.getLangOpts());
690 Expanded.push_back(
691 syntax::Token(T.getLocation(), Text.size(), tok::annot_module_name));
692 return;
693 }
694
695 // These tokens do not have a one-to-one raw spelling.
696 if (T.isAnnotation() || T.is(tok::eod))
697 return;
698
699 Expanded.push_back(syntax::Token(T));
700 DEBUG_WITH_TYPE("collect-tokens", llvm::dbgs()
701 << "Token: "
702 << syntax::Token(T).dumpForTests(
703 this->PP.getSourceManager())
704 << "\n"
705
706 );
707 });
708 // And locations of macro calls, to properly recover boundaries of those in
709 // case of empty expansions.
710 auto CB = std::make_unique<CollectPPExpansions>(*this);
711 this->Collector = CB.get();
712 PP.addPPCallbacks(std::move(CB));
713}
714
715/// Builds mappings and spelled tokens in the TokenBuffer based on the expanded
716/// token stream.
718public:
719 Builder(std::vector<syntax::Token> Expanded, PPExpansions CollectedExpansions,
720 const SourceManager &SM, const LangOptions &LangOpts)
721 : Result(SM), CollectedExpansions(std::move(CollectedExpansions)), SM(SM),
722 LangOpts(LangOpts) {
723 Result.ExpandedTokens = std::move(Expanded);
724 }
725
727 assert(!Result.ExpandedTokens.empty());
728
729 // When the parser hits a hard limit (e.g. bracket depth or function scope
730 // depth), it halts prematurely and leaves the expanded token stream
731 // truncated with no final `eof` token. To keep the invariant, synthesize an
732 // `eof` at the location of the last collected token.
733 if (Result.ExpandedTokens.back().kind() != tok::eof) {
734 SourceLocation Loc = Result.ExpandedTokens.back().location();
735 Result.ExpandedTokens.emplace_back(Loc, 0, tok::eof);
736 }
737
738 // Tokenize every file that contributed tokens to the expanded stream.
739 buildSpelledTokens();
740
741 // The expanded token stream consists of runs of tokens that came from
742 // the same source (a macro expansion, part of a file etc).
743 // Between these runs are the logical positions of spelled tokens that
744 // didn't expand to anything.
745 while (NextExpanded < Result.ExpandedTokens.size() - 1 /* eof */) {
746 // Create empty mappings for spelled tokens that expanded to nothing here.
747 // May advance NextSpelled, but NextExpanded is unchanged.
748 discard();
749 // Create mapping for a contiguous run of expanded tokens.
750 // Advances NextExpanded past the run, and NextSpelled accordingly.
751 unsigned OldPosition = NextExpanded;
752 advance();
753 if (NextExpanded == OldPosition)
754 diagnoseAdvanceFailure();
755 }
756 // If any tokens remain in any of the files, they didn't expand to anything.
757 // Create empty mappings up until the end of the file.
758 for (const auto &File : Result.Files)
759 discard(File.first);
760
761#ifndef NDEBUG
762 for (auto &pair : Result.Files) {
763 auto &mappings = pair.second.Mappings;
764 assert(llvm::is_sorted(mappings, [](const TokenBuffer::Mapping &M1,
765 const TokenBuffer::Mapping &M2) {
766 return M1.BeginSpelled < M2.BeginSpelled &&
767 M1.EndSpelled < M2.EndSpelled &&
768 M1.BeginExpanded < M2.BeginExpanded &&
769 M1.EndExpanded < M2.EndExpanded;
770 }));
771 }
772#endif
773
774 return std::move(Result);
775 }
776
777private:
778 // Consume a sequence of spelled tokens that didn't expand to anything.
779 // In the simplest case, skips spelled tokens until finding one that produced
780 // the NextExpanded token, and creates an empty mapping for them.
781 // If Drain is provided, skips remaining tokens from that file instead.
782 void discard(std::optional<FileID> Drain = std::nullopt) {
784 Drain ? SM.getLocForEndOfFile(*Drain)
785 : SM.getExpansionLoc(
786 Result.ExpandedTokens[NextExpanded].location());
788 const auto &SpelledTokens = Result.Files[File].SpelledTokens;
789 auto &NextSpelled = this->NextSpelled[File];
790
791 TokenBuffer::Mapping Mapping;
792 Mapping.BeginSpelled = NextSpelled;
793 // When dropping trailing tokens from a file, the empty mapping should
794 // be positioned within the file's expanded-token range (at the end).
795 Mapping.BeginExpanded = Mapping.EndExpanded =
796 Drain ? Result.Files[*Drain].EndExpanded : NextExpanded;
797 // We may want to split into several adjacent empty mappings.
798 // FlushMapping() emits the current mapping and starts a new one.
799 auto FlushMapping = [&, this] {
800 Mapping.EndSpelled = NextSpelled;
801 if (Mapping.BeginSpelled != Mapping.EndSpelled)
802 Result.Files[File].Mappings.push_back(Mapping);
803 Mapping.BeginSpelled = NextSpelled;
804 };
805
806 while (NextSpelled < SpelledTokens.size() &&
807 SpelledTokens[NextSpelled].location() < Target) {
808 // If we know mapping bounds at [NextSpelled, KnownEnd] (macro expansion)
809 // then we want to partition our (empty) mapping.
810 // [Start, NextSpelled) [NextSpelled, KnownEnd] (KnownEnd, Target)
811 SourceLocation KnownEnd =
812 CollectedExpansions.lookup(SpelledTokens[NextSpelled].location());
813 if (KnownEnd.isValid()) {
814 FlushMapping(); // Emits [Start, NextSpelled)
815 while (NextSpelled < SpelledTokens.size() &&
816 SpelledTokens[NextSpelled].location() <= KnownEnd)
817 ++NextSpelled;
818 FlushMapping(); // Emits [NextSpelled, KnownEnd]
819 // Now the loop continues and will emit (KnownEnd, Target).
820 } else {
821 ++NextSpelled;
822 }
823 }
824 FlushMapping();
825 }
826
827 // Consumes the NextExpanded token and others that are part of the same run.
828 // Increases NextExpanded and NextSpelled by at least one, and adds a mapping
829 // (unless this is a run of file tokens, which we represent with no mapping).
830 void advance() {
831 const syntax::Token &Tok = Result.ExpandedTokens[NextExpanded];
832 SourceLocation Expansion = SM.getExpansionLoc(Tok.location());
833 FileID File = SM.getFileID(Expansion);
834 const auto &SpelledTokens = Result.Files[File].SpelledTokens;
835 auto &NextSpelled = this->NextSpelled[File];
836
837 if (Tok.location().isFileID()) {
838 // A run of file tokens continues while the expanded/spelled tokens match.
839 while (NextSpelled < SpelledTokens.size() &&
840 NextExpanded < Result.ExpandedTokens.size() &&
841 SpelledTokens[NextSpelled].location() ==
842 Result.ExpandedTokens[NextExpanded].location()) {
843 ++NextSpelled;
844 ++NextExpanded;
845 }
846 // We need no mapping for file tokens copied to the expanded stream.
847 } else {
848 // We found a new macro expansion. We should have its spelling bounds.
849 auto End = CollectedExpansions.lookup(Expansion);
850 assert(End.isValid() && "Macro expansion wasn't captured?");
851
852 // Mapping starts here...
853 TokenBuffer::Mapping Mapping;
854 Mapping.BeginExpanded = NextExpanded;
855 Mapping.BeginSpelled = NextSpelled;
856 // ... consumes spelled tokens within bounds we captured ...
857 while (NextSpelled < SpelledTokens.size() &&
858 SpelledTokens[NextSpelled].location() <= End)
859 ++NextSpelled;
860 // ... consumes expanded tokens rooted at the same expansion ...
861 while (NextExpanded < Result.ExpandedTokens.size() &&
863 Result.ExpandedTokens[NextExpanded].location()) == Expansion)
864 ++NextExpanded;
865 // ... and ends here.
866 Mapping.EndExpanded = NextExpanded;
867 Mapping.EndSpelled = NextSpelled;
868 Result.Files[File].Mappings.push_back(Mapping);
869 }
870 }
871
872 // advance() is supposed to consume at least one token - if not, we crash.
873 void diagnoseAdvanceFailure() {
874#ifndef NDEBUG
875 // Show the failed-to-map token in context.
876 for (unsigned I = (NextExpanded < 10) ? 0 : NextExpanded - 10;
877 I < NextExpanded + 5 && I < Result.ExpandedTokens.size(); ++I) {
878 const char *L =
879 (I == NextExpanded) ? "!! " : (I < NextExpanded) ? "ok " : " ";
880 llvm::errs() << L << Result.ExpandedTokens[I].dumpForTests(SM) << "\n";
881 }
882#endif
883 llvm_unreachable("Couldn't map expanded token to spelled tokens!");
884 }
885
886 /// Initializes TokenBuffer::Files and fills spelled tokens and expanded
887 /// ranges for each of the files.
888 void buildSpelledTokens() {
889 for (unsigned I = 0; I < Result.ExpandedTokens.size(); ++I) {
890 const auto &Tok = Result.ExpandedTokens[I];
891 auto FID = SM.getFileID(SM.getExpansionLoc(Tok.location()));
892 auto It = Result.Files.try_emplace(FID);
893 TokenBuffer::MarkedFile &File = It.first->second;
894
895 // The eof token should not be considered part of the main-file's range.
896 File.EndExpanded = Tok.kind() == tok::eof ? I : I + 1;
897
898 if (!It.second)
899 continue; // we have seen this file before.
900 // This is the first time we see this file.
901 File.BeginExpanded = I;
902 File.SpelledTokens = tokenize(FID, SM, LangOpts);
903 }
904 }
905
906 TokenBuffer Result;
907 unsigned NextExpanded = 0; // cursor in ExpandedTokens
908 llvm::DenseMap<FileID, unsigned> NextSpelled; // cursor in SpelledTokens
909 PPExpansions CollectedExpansions;
910 const SourceManager &SM;
911 const LangOptions &LangOpts;
912};
913
915 PP.setTokenWatcher(nullptr);
916 Collector->disable();
917 return Builder(std::move(Expanded), std::move(Expansions),
918 PP.getSourceManager(), PP.getLangOpts())
919 .build();
920}
921
922std::string syntax::Token::str() const {
923 return std::string(llvm::formatv("Token({0}, length = {1})",
925}
926
927std::string syntax::Token::dumpForTests(const SourceManager &SM) const {
928 return std::string(llvm::formatv("Token(`{0}`, {1}, length = {2})", text(SM),
930}
931
932std::string TokenBuffer::dumpForTests() const {
933 auto PrintToken = [this](const syntax::Token &T) -> std::string {
934 if (T.kind() == tok::eof)
935 return "<eof>";
936 return std::string(T.text(*SourceMgr));
937 };
938
939 auto DumpTokens = [this, &PrintToken](llvm::raw_ostream &OS,
941 if (Tokens.empty()) {
942 OS << "<empty>";
943 return;
944 }
945 OS << Tokens[0].text(*SourceMgr);
946 for (unsigned I = 1; I < Tokens.size(); ++I) {
947 if (Tokens[I].kind() == tok::eof)
948 continue;
949 OS << " " << PrintToken(Tokens[I]);
950 }
951 };
952
953 std::string Dump;
954 llvm::raw_string_ostream OS(Dump);
955
956 OS << "expanded tokens:\n"
957 << " ";
958 // (!) we do not show '<eof>'.
959 DumpTokens(OS, llvm::ArrayRef(ExpandedTokens).drop_back());
960 OS << "\n";
961
962 std::vector<FileID> Keys;
963 for (const auto &F : Files)
964 Keys.push_back(F.first);
965 llvm::sort(Keys);
966
967 for (FileID ID : Keys) {
968 const MarkedFile &File = Files.find(ID)->second;
969 auto Entry = SourceMgr->getFileEntryRefForID(ID);
970 if (!Entry)
971 continue; // Skip builtin files.
972 std::string Path = llvm::sys::path::convert_to_slash(Entry->getName());
973 OS << llvm::formatv("file '{0}'\n", Path) << " spelled tokens:\n"
974 << " ";
975 DumpTokens(OS, File.SpelledTokens);
976 OS << "\n";
977
978 if (File.Mappings.empty()) {
979 OS << " no mappings.\n";
980 continue;
981 }
982 OS << " mappings:\n";
983 for (auto &M : File.Mappings) {
984 OS << llvm::formatv(
985 " ['{0}'_{1}, '{2}'_{3}) => ['{4}'_{5}, '{6}'_{7})\n",
986 PrintToken(File.SpelledTokens[M.BeginSpelled]), M.BeginSpelled,
987 M.EndSpelled == File.SpelledTokens.size()
988 ? "<eof>"
989 : PrintToken(File.SpelledTokens[M.EndSpelled]),
990 M.EndSpelled, PrintToken(ExpandedTokens[M.BeginExpanded]),
991 M.BeginExpanded, PrintToken(ExpandedTokens[M.EndExpanded]),
992 M.EndExpanded);
993 }
994 }
995 return Dump;
996}
Defines the Diagnostic-related interfaces.
static Decl::Kind getKind(const Decl *D)
Token Tok
The Token.
FormatToken * Next
The next token in the unwrapped line.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
Result
Implement __builtin_bit_cast and related operations.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::LangOptions interface.
llvm::MachO::Target Target
Definition MachO.h:51
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
Defines the PPCallbacks interface.
static ParseState advance(ParseState S, size_t N)
Definition Parsing.cpp:137
Defines the clang::Preprocessor interface.
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Defines the clang::TokenKind enum and support functions.
Builds mappings and spelled tokens in the TokenBuffer based on the expanded token stream.
Definition Tokens.cpp:717
TokenBuffer build() &&
Definition Tokens.cpp:726
Builder(std::vector< syntax::Token > Expanded, PPExpansions CollectedExpansions, const SourceManager &SM, const LangOptions &LangOpts)
Definition Tokens.cpp:719
Records information reqired to construct mappings for the token buffer that we are collecting.
Definition Tokens.cpp:614
CollectPPExpansions(TokenCollector &C)
Definition Tokens.cpp:616
void disable()
Disabled instance will stop reporting anything to TokenCollector.
Definition Tokens.cpp:621
void MacroExpands(const clang::Token &MacroNameTok, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override
Called by Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is found.
Definition Tokens.cpp:623
Represents a byte-granular source range.
static CharSourceRange getTokenRange(SourceRange R)
SourceLocation getEnd() const
SourceLocation getBegin() const
SourceRange getAsRange() const
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
One of these records is kept for each identifier that is lexed.
tok::TokenKind getTokenID() const
If this is a source-language token (e.g.
Implements an efficient mapping from strings to IdentifierInfo nodes.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.
Definition Lexer.h:79
static StringRef getSourceText(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts, bool *Invalid=nullptr)
Returns a string for the source that the range encompasses.
Definition Lexer.cpp:1075
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
Definition Lexer.h:236
unsigned getCurrentBufferOffset()
Returns the current lexing offset.
Definition Lexer.h:313
MacroArgs - An instance of this class captures information about the formal arguments specified to a ...
Definition MacroArgs.h:30
A description of the current definition of a macro.
Definition MacroInfo.h:596
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition PPCallbacks.h:37
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
SourceManager & getSourceManager() const
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
FileIDAndOffset getDecomposedExpansionLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
FileIDAndOffset getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
SourceLocation getComposedLoc(FileID FID, unsigned Offset) const
Form a SourceLocation from a FileID and Offset pair.
SourceLocation getLocForEndOfFile(FileID FID) const
Return the source location corresponding to the last byte of the specified file.
const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const
Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer.
unsigned getFileIDSize(FileID FID) const
The size of the SLocEntry that FID represents.
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
A trivial tuple used to represent a source range.
bool isInvalid() const
SourceLocation getEnd() const
SourceLocation getBegin() const
const ExpansionInfo & getExpansion() const
Token - This structure provides full information about a lexed token.
Definition Token.h:36
A list of tokens obtained by preprocessing a text buffer and operations to map between the expanded a...
Definition Tokens.h:174
const syntax::Token * spelledTokenContaining(SourceLocation Loc) const
Returns the spelled Token containing the Loc, if there are no such tokens returns nullptr.
Definition Tokens.cpp:386
const SourceManager & sourceManager() const
Definition Tokens.h:309
void indexExpandedTokens()
Builds a cache to make future calls to expandedToken(SourceRange) faster.
Definition Tokens.cpp:227
llvm::SmallVector< llvm::ArrayRef< syntax::Token >, 1 > expandedForSpelled(llvm::ArrayRef< syntax::Token > Spelled) const
Find the subranges of expanded tokens, corresponding to Spelled.
Definition Tokens.cpp:322
llvm::ArrayRef< syntax::Token > expandedTokens() const
All tokens produced by the preprocessor after all macro replacements, directives, etc.
Definition Tokens.h:190
std::string dumpForTests() const
Definition Tokens.cpp:932
std::optional< llvm::ArrayRef< syntax::Token > > spelledForExpanded(llvm::ArrayRef< syntax::Token > Expanded) const
Returns the subrange of spelled tokens corresponding to AST node spanning Expanded.
Definition Tokens.cpp:403
std::vector< Expansion > expansionsOverlapping(llvm::ArrayRef< syntax::Token > Spelled) const
Returns all expansions (partially) expanded from the specified tokens.
Definition Tokens.cpp:503
std::optional< Expansion > expansionStartingAt(const syntax::Token *Spelled) const
If Spelled starts a mapping (e.g.
Definition Tokens.cpp:490
llvm::ArrayRef< syntax::Token > spelledTokens(FileID FID) const
Lexed tokens of a file before preprocessing.
Definition Tokens.cpp:379
std::vector< const syntax::Token * > macroExpansions(FileID FID) const
Get all tokens that expand a macro in FID.
Definition Tokens.cpp:560
TokenBuffer consume() &&
Finalizes token collection.
Definition Tokens.cpp:914
TokenCollector(Preprocessor &P)
Adds the hooks to collect the tokens.
Definition Tokens.cpp:682
A token coming directly from a file or from a macro invocation.
Definition Tokens.h:103
std::string str() const
For debugging purposes.
Definition Tokens.cpp:922
llvm::StringRef text(const SourceManager &SM) const
Get the substring covered by the token.
Definition Tokens.cpp:153
tok::TokenKind kind() const
Definition Tokens.h:109
FileRange range(const SourceManager &SM) const
Gets a range of this token.
Definition Tokens.cpp:160
Token(SourceLocation Location, unsigned Length, tok::TokenKind Kind)
Definition Tokens.cpp:142
std::string dumpForTests(const SourceManager &SM) const
Definition Tokens.cpp:927
SourceLocation location() const
Location of the first character of a token.
Definition Tokens.h:111
bool Dec(InterpState &S, CodePtr OpPC, bool CanOverflow)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value decreased by ...
Definition Interp.h:1066
const syntax::Token * spelledIdentifierTouching(SourceLocation Loc, llvm::ArrayRef< syntax::Token > Tokens)
The identifier token that overlaps or touches a spelling location Loc.
Definition Tokens.cpp:543
std::vector< syntax::Token > tokenize(FileID FID, const SourceManager &SM, const LangOptions &LO)
Lex the text buffer, corresponding to FID, in raw mode and record the resulting spelled tokens.
Definition Tokens.cpp:607
raw_ostream & operator<<(raw_ostream &OS, NodeKind K)
For debugging purposes.
Definition Nodes.cpp:13
llvm::ArrayRef< syntax::Token > spelledTokensTouching(SourceLocation Loc, const syntax::TokenBuffer &Tokens)
The spelled tokens that overlap or touch a spelling location Loc.
Definition Tokens.cpp:536
const char * getTokenName(TokenKind Kind) LLVM_READNONE
Determines the name of a token as used within the front end.
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
Definition TokenKinds.h:33
Top level wrappers for InstallAPI frontend operations.
@ Result
The result type of a method or function.
Definition TypeBase.h:906
const FunctionProtoType * T
float __ovld __cnfn length(float)
Return the length of vector p, i.e., sqrt(p.x2 + p.y 2 + ...)
A half-open character range inside a particular file, the start offset is included and the end offset...
Definition Tokens.h:50
CharSourceRange toCharRange(const SourceManager &SM) const
Convert to the clang range.
Definition Tokens.cpp:263
unsigned length() const
Definition Tokens.h:66
FileRange(FileID File, unsigned BeginOffset, unsigned EndOffset)
EXPECTS: File.isValid() && Begin <= End.
Definition Tokens.cpp:183
unsigned beginOffset() const
Start is a start offset (inclusive) in the corresponding file.
Definition Tokens.h:62
FileID file() const
Definition Tokens.h:60
llvm::StringRef text(const SourceManager &SM) const
Gets the substring that this FileRange refers to.
Definition Tokens.cpp:217
unsigned endOffset() const
End offset (exclusive) in the corresponding file.
Definition Tokens.h:64
An expansion produced by the preprocessor, includes macro expansions and preprocessor directives.
Definition Tokens.h:273
llvm::ArrayRef< syntax::Token > Spelled
Definition Tokens.h:274