https://github.com/legrosbuffle updated https://github.com/llvm/llvm-project/pull/95901
>From 8f6ff99ddb035d63e99910f873a8d9938bd0b3e4 Mon Sep 17 00:00:00 2001 From: Clement Courbet <cour...@google.com> Date: Mon, 17 Jun 2024 15:33:34 +0000 Subject: [PATCH] [clang][transformer] Introduce a `constructExprArgs` range selector. This is similar to `callArgs` but for construct exprs like `S(42)` or `{42}`. --- .../clang/Tooling/Transformer/RangeSelector.h | 5 ++ .../lib/Tooling/Transformer/RangeSelector.cpp | 51 ++++++++++++++----- clang/unittests/Tooling/RangeSelectorTest.cpp | 42 +++++++++++++++ 3 files changed, 85 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/Tooling/Transformer/RangeSelector.h b/clang/include/clang/Tooling/Transformer/RangeSelector.h index 1e288043f0a8e..462a9da8f10eb 100644 --- a/clang/include/clang/Tooling/Transformer/RangeSelector.h +++ b/clang/include/clang/Tooling/Transformer/RangeSelector.h @@ -86,6 +86,11 @@ RangeSelector name(std::string ID); // source between the call's parentheses). RangeSelector callArgs(std::string ID); +// Given a \c CXXConstructExpr (bound to \p ID), selects the +// arguments' source text. Depending on the syntactic form of the construct, +// this is the range between parentheses or braces. +RangeSelector constructExprArgs(std::string ID); + // Given a \c CompoundStmt (bound to \p ID), selects the source of the // statements (all source between the braces). RangeSelector statements(std::string ID); diff --git a/clang/lib/Tooling/Transformer/RangeSelector.cpp b/clang/lib/Tooling/Transformer/RangeSelector.cpp index 7370baf010834..e84ddde74a707 100644 --- a/clang/lib/Tooling/Transformer/RangeSelector.cpp +++ b/clang/lib/Tooling/Transformer/RangeSelector.cpp @@ -96,13 +96,6 @@ static SourceLocation findPreviousTokenKind(SourceLocation Start, } } -static SourceLocation findOpenParen(const CallExpr &E, const SourceManager &SM, - const LangOptions &LangOpts) { - SourceLocation EndLoc = - E.getNumArgs() == 0 ? E.getRParenLoc() : E.getArg(0)->getBeginLoc(); - return findPreviousTokenKind(EndLoc, SM, LangOpts, tok::TokenKind::l_paren); -} - RangeSelector transformer::before(RangeSelector Selector) { return [Selector](const MatchResult &Result) -> Expected<CharSourceRange> { Expected<CharSourceRange> SelectedRange = Selector(Result); @@ -287,18 +280,50 @@ RangeSelector transformer::statements(std::string ID) { } namespace { -// Returns the range of the source between the call's parentheses. -CharSourceRange getCallArgumentsRange(const MatchResult &Result, - const CallExpr &CE) { + +SourceLocation getRLoc(const CallExpr &E) { return E.getRParenLoc(); } + +SourceLocation getRLoc(const CXXConstructExpr &E) { + return E.getParenOrBraceRange().getEnd(); +} + +tok::TokenKind getStartToken(const CallExpr &E) { + return tok::TokenKind::l_paren; +} + +tok::TokenKind getStartToken(const CXXConstructExpr &E) { + return isa<CXXTemporaryObjectExpr>(E) ? tok::TokenKind::l_paren + : tok::TokenKind::l_brace; +} + +template <typename ExprWithArgs> +SourceLocation findArgStartDelimiter(const ExprWithArgs &E, SourceLocation RLoc, + const SourceManager &SM, + const LangOptions &LangOpts) { + SourceLocation Loc = E.getNumArgs() == 0 ? RLoc : E.getArg(0)->getBeginLoc(); + return findPreviousTokenKind(Loc, SM, LangOpts, getStartToken(E)); +} +// Returns the range of the source between the call's or construct expr's +// parentheses/braces. +template <typename ExprWithArgs> +CharSourceRange getArgumentsRange(const MatchResult &Result, + const ExprWithArgs &CE) { + const SourceLocation RLoc = getRLoc(CE); return CharSourceRange::getCharRange( - findOpenParen(CE, *Result.SourceManager, Result.Context->getLangOpts()) + findArgStartDelimiter(CE, RLoc, *Result.SourceManager, + Result.Context->getLangOpts()) .getLocWithOffset(1), - CE.getRParenLoc()); + RLoc); } } // namespace RangeSelector transformer::callArgs(std::string ID) { - return RelativeSelector<CallExpr, getCallArgumentsRange>(std::move(ID)); + return RelativeSelector<CallExpr, getArgumentsRange<CallExpr>>(std::move(ID)); +} + +RangeSelector transformer::constructExprArgs(std::string ID) { + return RelativeSelector<CXXConstructExpr, + getArgumentsRange<CXXConstructExpr>>(std::move(ID)); } namespace { diff --git a/clang/unittests/Tooling/RangeSelectorTest.cpp b/clang/unittests/Tooling/RangeSelectorTest.cpp index 03ab66235e43c..ad2f4218a1d84 100644 --- a/clang/unittests/Tooling/RangeSelectorTest.cpp +++ b/clang/unittests/Tooling/RangeSelectorTest.cpp @@ -651,6 +651,48 @@ TEST(RangeSelectorTest, CallArgsErrors) { Failed<StringError>(withTypeErrorMessage("stmt"))); } +TEST(RangeSelectorTest, ConstructExprArgs) { + const StringRef Code = R"cc( + struct C { + C(int, int); + }; + C f() { + return C(1, 2); + } + )cc"; + const char *ID = "id"; + TestMatch Match = matchCode(Code, cxxConstructExpr().bind(ID)); + EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("1, 2")); +} + +TEST(RangeSelectorTest, ConstructExprBracedArgs) { + const StringRef Code = R"cc( + struct C { + C(int, int); + }; + C f() { + return {1, 2}; + } + )cc"; + const char *ID = "id"; + TestMatch Match = matchCode(Code, cxxConstructExpr().bind(ID)); + EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("1, 2")); +} + +TEST(RangeSelectorTest, ConstructExprNoArgs) { + const StringRef Code = R"cc( + struct C { + C(); + }; + C f() { + return C(); + } + )cc"; + const char *ID = "id"; + TestMatch Match = matchCode(Code, cxxConstructExpr().bind(ID)); + EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("")); +} + TEST(RangeSelectorTest, StatementsOp) { StringRef Code = R"cc( void g(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits