[clang] [clang][transformer] Introduce a `constructExprArgs` range selector. (PR #95901)
Clement Courbet via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 26 06:36:08 PDT 2024
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 <courbet at 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();
More information about the cfe-commits
mailing list