Author: Daniil Dudkin Date: 2026-03-01T21:27:36+03:00 New Revision: 1dc85c60410f8366e59fd518afa1d9cf22a909e6
URL: https://github.com/llvm/llvm-project/commit/1dc85c60410f8366e59fd518afa1d9cf22a909e6 DIFF: https://github.com/llvm/llvm-project/commit/1dc85c60410f8366e59fd518afa1d9cf22a909e6.diff LOG: [clang-tidy][NFC] Add `getCommentsInRange` utility (#183940) Added: Modified: clang-tools-extra/clang-tidy/utils/LexerUtils.cpp clang-tools-extra/clang-tidy/utils/LexerUtils.h clang-tools-extra/unittests/clang-tidy/LexerUtilsTest.cpp Removed: ################################################################################ diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp index a9a8c7bbf4c89..4c36d4cacd1ec 100644 --- a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp +++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp @@ -100,9 +100,14 @@ bool rangeContainsExpansionsOrDirectives(SourceRange Range, return false; } -std::vector<CommentToken> -getTrailingCommentsInRange(CharSourceRange Range, const SourceManager &SM, - const LangOptions &LangOpts) { +namespace { +enum class CommentCollectionMode { AllComments, TrailingComments }; +} // namespace + +static std::vector<CommentToken> +collectCommentsInRange(CharSourceRange Range, const SourceManager &SM, + const LangOptions &LangOpts, + CommentCollectionMode Mode) { std::vector<CommentToken> Comments; if (Range.isInvalid()) return Comments; @@ -149,7 +154,7 @@ getTrailingCommentsInRange(CharSourceRange Range, const SourceManager &SM, Tok.getLocation(), StringRef(Buffer.begin() + CommentLoc.second, Tok.getLength()), }); - } else { + } else if (Mode == CommentCollectionMode::TrailingComments) { // Clear comments found before the diff erent token, e.g. comma. Callers // use this to retrieve only the contiguous comment block that directly // precedes a token of interest. @@ -160,6 +165,20 @@ getTrailingCommentsInRange(CharSourceRange Range, const SourceManager &SM, return Comments; } +std::vector<CommentToken> getCommentsInRange(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts) { + return collectCommentsInRange(Range, SM, LangOpts, + CommentCollectionMode::AllComments); +} + +std::vector<CommentToken> +getTrailingCommentsInRange(CharSourceRange Range, const SourceManager &SM, + const LangOptions &LangOpts) { + return collectCommentsInRange(Range, SM, LangOpts, + CommentCollectionMode::TrailingComments); +} + std::optional<Token> getQualifyingToken(tok::TokenKind TK, CharSourceRange Range, const ASTContext &Context, diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.h b/clang-tools-extra/clang-tidy/utils/LexerUtils.h index 38123ae14cff7..681fc6194d45c 100644 --- a/clang-tools-extra/clang-tidy/utils/LexerUtils.h +++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.h @@ -120,6 +120,11 @@ struct CommentToken { StringRef Text; }; +/// Returns all comment tokens found in the given range. +std::vector<CommentToken> getCommentsInRange(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts); + /// Returns comment tokens found in the given range. If a non-comment token is /// encountered, clears previously collected comments and continues. std::vector<CommentToken> diff --git a/clang-tools-extra/unittests/clang-tidy/LexerUtilsTest.cpp b/clang-tools-extra/unittests/clang-tidy/LexerUtilsTest.cpp index 438a78b4694ee..0e0c3d60dedfe 100644 --- a/clang-tools-extra/unittests/clang-tidy/LexerUtilsTest.cpp +++ b/clang-tools-extra/unittests/clang-tidy/LexerUtilsTest.cpp @@ -43,6 +43,125 @@ static CharSourceRange rangeFromAnnotations(const llvm::Annotations &A, namespace { +TEST(LexerUtilsTest, GetCommentsInRangeAdjacentComments) { + llvm::Annotations Code(R"cpp( +void f() { + $range[[/*first*/ /*second*/]] + int x = 0; +} +)cpp"); + std::unique_ptr<ASTUnit> AST = buildAST(Code.code()); + ASSERT_TRUE(AST); + const ASTContext &Context = AST->getASTContext(); + const SourceManager &SM = Context.getSourceManager(); + const LangOptions &LangOpts = Context.getLangOpts(); + + const CharSourceRange Range = + rangeFromAnnotations(Code, SM, SM.getMainFileID(), "range"); + const std::vector<utils::lexer::CommentToken> Comments = + utils::lexer::getCommentsInRange(Range, SM, LangOpts); + ASSERT_EQ(2u, Comments.size()); + EXPECT_EQ("/*first*/", Comments[0].Text); + EXPECT_EQ("/*second*/", Comments[1].Text); + const StringRef CodeText = Code.code(); + const size_t FirstOffset = CodeText.find("/*first*/"); + ASSERT_NE(StringRef::npos, FirstOffset); + const size_t SecondOffset = CodeText.find("/*second*/"); + ASSERT_NE(StringRef::npos, SecondOffset); + EXPECT_EQ(FirstOffset, SM.getFileOffset(Comments[0].Loc)); + EXPECT_EQ(SecondOffset, SM.getFileOffset(Comments[1].Loc)); +} + +TEST(LexerUtilsTest, GetCommentsInRangeKeepsCommentsAcrossTokens) { + llvm::Annotations Code(R"cpp( +void f() { + int x = ($range[[/*first*/ 0, /*second*/]] 1); +} +)cpp"); + std::unique_ptr<ASTUnit> AST = buildAST(Code.code()); + ASSERT_TRUE(AST); + const ASTContext &Context = AST->getASTContext(); + const SourceManager &SM = Context.getSourceManager(); + const LangOptions &LangOpts = Context.getLangOpts(); + + const CharSourceRange Range = + rangeFromAnnotations(Code, SM, SM.getMainFileID(), "range"); + const std::vector<utils::lexer::CommentToken> Comments = + utils::lexer::getCommentsInRange(Range, SM, LangOpts); + ASSERT_EQ(2u, Comments.size()); + EXPECT_EQ("/*first*/", Comments[0].Text); + EXPECT_EQ("/*second*/", Comments[1].Text); + const StringRef CodeText = Code.code(); + const size_t FirstOffset = CodeText.find("/*first*/"); + ASSERT_NE(StringRef::npos, FirstOffset); + const size_t SecondOffset = CodeText.find("/*second*/"); + ASSERT_NE(StringRef::npos, SecondOffset); + EXPECT_EQ(FirstOffset, SM.getFileOffset(Comments[0].Loc)); + EXPECT_EQ(SecondOffset, SM.getFileOffset(Comments[1].Loc)); +} + +TEST(LexerUtilsTest, GetCommentsInRangeLineComments) { + llvm::Annotations Code(R"cpp( +void f() { + $range[[// first + // second + ]] + int x = 0; +} +)cpp"); + std::unique_ptr<ASTUnit> AST = buildAST(Code.code()); + ASSERT_TRUE(AST); + const ASTContext &Context = AST->getASTContext(); + const SourceManager &SM = Context.getSourceManager(); + const LangOptions &LangOpts = Context.getLangOpts(); + + const CharSourceRange Range = + rangeFromAnnotations(Code, SM, SM.getMainFileID(), "range"); + const std::vector<utils::lexer::CommentToken> Comments = + utils::lexer::getCommentsInRange(Range, SM, LangOpts); + ASSERT_EQ(2u, Comments.size()); + EXPECT_EQ("// first", Comments[0].Text); + EXPECT_EQ("// second", Comments[1].Text); + const StringRef CodeText = Code.code(); + const size_t FirstOffset = CodeText.find("// first"); + ASSERT_NE(StringRef::npos, FirstOffset); + const size_t SecondOffset = CodeText.find("// second"); + ASSERT_NE(StringRef::npos, SecondOffset); + EXPECT_EQ(FirstOffset, SM.getFileOffset(Comments[0].Loc)); + EXPECT_EQ(SecondOffset, SM.getFileOffset(Comments[1].Loc)); +} + +TEST(LexerUtilsTest, GetCommentsInRangeNoComments) { + llvm::Annotations Code(R"cpp( +void f() { + int x = $range[[0 + 1]]; +} +)cpp"); + std::unique_ptr<ASTUnit> AST = buildAST(Code.code()); + ASSERT_TRUE(AST); + const ASTContext &Context = AST->getASTContext(); + const SourceManager &SM = Context.getSourceManager(); + const LangOptions &LangOpts = Context.getLangOpts(); + + const CharSourceRange Range = + rangeFromAnnotations(Code, SM, SM.getMainFileID(), "range"); + const std::vector<utils::lexer::CommentToken> Comments = + utils::lexer::getCommentsInRange(Range, SM, LangOpts); + EXPECT_TRUE(Comments.empty()); +} + +TEST(LexerUtilsTest, GetCommentsInRangeInvalidRange) { + std::unique_ptr<ASTUnit> AST = buildAST("int value = 0;"); + ASSERT_TRUE(AST); + const ASTContext &Context = AST->getASTContext(); + const SourceManager &SM = Context.getSourceManager(); + const LangOptions &LangOpts = Context.getLangOpts(); + + const std::vector<utils::lexer::CommentToken> Comments = + utils::lexer::getCommentsInRange(CharSourceRange(), SM, LangOpts); + EXPECT_TRUE(Comments.empty()); +} + TEST(LexerUtilsTest, GetTrailingCommentsInRangeAdjacentComments) { llvm::Annotations Code(R"cpp( void f() { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
