summaryrefslogtreecommitdiff
path: root/clang/lib/Tooling/Syntax/Tokens.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Tooling/Syntax/Tokens.cpp')
-rw-r--r--clang/lib/Tooling/Syntax/Tokens.cpp32
1 files changed, 32 insertions, 0 deletions
diff --git a/clang/lib/Tooling/Syntax/Tokens.cpp b/clang/lib/Tooling/Syntax/Tokens.cpp
index 234df9cb7182..8a31e776d030 100644
--- a/clang/lib/Tooling/Syntax/Tokens.cpp
+++ b/clang/lib/Tooling/Syntax/Tokens.cpp
@@ -183,7 +183,39 @@ llvm::StringRef FileRange::text(const SourceManager &SM) const {
return Text.substr(Begin, length());
}
+void TokenBuffer::indexExpandedTokens() {
+ // No-op if the index is already created.
+ if (!ExpandedTokIndex.empty())
+ return;
+ ExpandedTokIndex.reserve(ExpandedTokens.size());
+ // Index ExpandedTokens for faster lookups by SourceLocation.
+ for (size_t I = 0, E = ExpandedTokens.size(); I != E; ++I) {
+ SourceLocation Loc = ExpandedTokens[I].location();
+ if (Loc.isValid())
+ ExpandedTokIndex[Loc] = I;
+ }
+}
+
llvm::ArrayRef<syntax::Token> TokenBuffer::expandedTokens(SourceRange R) const {
+ if (R.isInvalid())
+ return {};
+ if (!ExpandedTokIndex.empty()) {
+ // Quick lookup if `R` is a token range.
+ // This is a huge win since majority of the users use ranges provided by an
+ // AST. Ranges in AST are token ranges from expanded token stream.
+ const auto B = ExpandedTokIndex.find(R.getBegin());
+ const auto E = ExpandedTokIndex.find(R.getEnd());
+ if (B != ExpandedTokIndex.end() && E != ExpandedTokIndex.end()) {
+ const Token *L = ExpandedTokens.data() + B->getSecond();
+ // Add 1 to End to make a half-open range.
+ const Token *R = ExpandedTokens.data() + E->getSecond() + 1;
+ if (L > R)
+ return {};
+ return {L, R};
+ }
+ }
+ // Slow case. Use `isBeforeInTranslationUnit` to binary search for the
+ // required range.
return getTokensCovering(expandedTokens(), R, *SourceMgr);
}