Summary: Useful when positions are used to target nodes, with before/after ambiguity.
Reviewers: ilya-biryukov, kbobyrev
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D71356
return !(LHS == RHS);
}
+// Ordering is meaningful only if LHS and RHS have the same FileID!
+// Otherwise use SourceManager::isBeforeInTranslationUnit().
inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) {
return LHS.getRawEncoding() < RHS.getRawEncoding();
}
+inline bool operator>(const SourceLocation &LHS, const SourceLocation &RHS) {
+ return LHS.getRawEncoding() > RHS.getRawEncoding();
+}
+inline bool operator<=(const SourceLocation &LHS, const SourceLocation &RHS) {
+ return LHS.getRawEncoding() <= RHS.getRawEncoding();
+}
+inline bool operator>=(const SourceLocation &LHS, const SourceLocation &RHS) {
+ return LHS.getRawEncoding() >= RHS.getRawEncoding();
+}
/// A trivial tuple used to represent a source range.
class SourceRange {
const SourceManager *SourceMgr;
};
+/// The spelled tokens that overlap or touch a spelling location Loc.
+/// This always returns 0-2 tokens.
+llvm::ArrayRef<syntax::Token>
+spelledTokensTouching(SourceLocation Loc, const syntax::TokenBuffer &Tokens);
+
+/// The identifier token that overlaps or touches a spelling location Loc.
+/// If there is none, returns nullptr.
+const syntax::Token *
+spelledIdentifierTouching(SourceLocation Loc,
+ const syntax::TokenBuffer &Tokens);
+
/// Lex the text buffer, corresponding to \p FID, in raw mode and record the
/// resulting spelled tokens. Does minimal post-processing on raw identifiers,
/// setting the appropriate token kind (instead of the raw_identifier reported
return E;
}
+llvm::ArrayRef<syntax::Token>
+syntax::spelledTokensTouching(SourceLocation Loc,
+ const syntax::TokenBuffer &Tokens) {
+ assert(Loc.isFileID());
+ llvm::ArrayRef<syntax::Token> All =
+ Tokens.spelledTokens(Tokens.sourceManager().getFileID(Loc));
+ // Comparing SourceLocations is well-defined within a FileID.
+ auto *Right = llvm::partition_point(
+ All, [&](const syntax::Token &Tok) { return Tok.location() < Loc; });
+ bool AcceptRight = Right != All.end() && Right->location() <= Loc;
+ bool AcceptLeft = Right != All.begin() && (Right - 1)->endLocation() >= Loc;
+ return llvm::makeArrayRef(Right - (AcceptLeft ? 1 : 0),
+ Right + (AcceptRight ? 1 : 0));
+}
+
+const syntax::Token *
+syntax::spelledIdentifierTouching(SourceLocation Loc,
+ const syntax::TokenBuffer &Tokens) {
+ for (const syntax::Token &Tok : spelledTokensTouching(Loc, Tokens)) {
+ if (Tok.kind() == tok::identifier)
+ return &Tok;
+ }
+ return nullptr;
+}
+
std::vector<const syntax::Token *>
TokenBuffer::macroExpansions(FileID FID) const {
auto FileIt = Files.find(FID);
ActualMacroRanges.push_back(Expansion->range(SM));
EXPECT_EQ(ExpectedMacroRanges, ActualMacroRanges);
}
+
+TEST_F(TokenBufferTest, Touching) {
+ llvm::Annotations Code("^i^nt^ ^a^b^=^1;^");
+ recordTokens(Code.code());
+
+ auto Touching = [&](int Index) {
+ SourceLocation Loc = SourceMgr->getComposedLoc(SourceMgr->getMainFileID(),
+ Code.points()[Index]);
+ return spelledTokensTouching(Loc, Buffer);
+ };
+ auto Identifier = [&](int Index) {
+ SourceLocation Loc = SourceMgr->getComposedLoc(SourceMgr->getMainFileID(),
+ Code.points()[Index]);
+ const syntax::Token *Tok = spelledIdentifierTouching(Loc, Buffer);
+ return Tok ? Tok->text(*SourceMgr) : "";
+ };
+
+ EXPECT_THAT(Touching(0), SameRange(findSpelled("int")));
+ EXPECT_EQ(Identifier(0), "");
+ EXPECT_THAT(Touching(1), SameRange(findSpelled("int")));
+ EXPECT_EQ(Identifier(1), "");
+ EXPECT_THAT(Touching(2), SameRange(findSpelled("int")));
+ EXPECT_EQ(Identifier(2), "");
+
+ EXPECT_THAT(Touching(3), SameRange(findSpelled("ab")));
+ EXPECT_EQ(Identifier(3), "ab");
+ EXPECT_THAT(Touching(4), SameRange(findSpelled("ab")));
+ EXPECT_EQ(Identifier(4), "ab");
+
+ EXPECT_THAT(Touching(5), SameRange(findSpelled("ab =")));
+ EXPECT_EQ(Identifier(5), "ab");
+
+ EXPECT_THAT(Touching(6), SameRange(findSpelled("= 1")));
+ EXPECT_EQ(Identifier(6), "");
+
+ EXPECT_THAT(Touching(7), SameRange(findSpelled(";")));
+ EXPECT_EQ(Identifier(7), "");
+
+ ASSERT_EQ(Code.points().size(), 8u);
+}
+
} // namespace