Skip to content

Commit e8a90aa

Browse files
legrosbuffleAlexisPerry
authored andcommitted
[clang][transformer] Introduce a constructExprArgs range selector. (llvm#95901)
This is similar to `callArgs` but for construct exprs like `S(42)` or `{42}`.
1 parent e0427a3 commit e8a90aa

File tree

3 files changed

+85
-13
lines changed

3 files changed

+85
-13
lines changed

clang/include/clang/Tooling/Transformer/RangeSelector.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ RangeSelector name(std::string ID);
8686
// source between the call's parentheses).
8787
RangeSelector callArgs(std::string ID);
8888

89+
// Given a \c CXXConstructExpr (bound to \p ID), selects the
90+
// arguments' source text. Depending on the syntactic form of the construct,
91+
// this is the range between parentheses or braces.
92+
RangeSelector constructExprArgs(std::string ID);
93+
8994
// Given a \c CompoundStmt (bound to \p ID), selects the source of the
9095
// statements (all source between the braces).
9196
RangeSelector statements(std::string ID);

clang/lib/Tooling/Transformer/RangeSelector.cpp

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,6 @@ static SourceLocation findPreviousTokenKind(SourceLocation Start,
9696
}
9797
}
9898

99-
static SourceLocation findOpenParen(const CallExpr &E, const SourceManager &SM,
100-
const LangOptions &LangOpts) {
101-
SourceLocation EndLoc =
102-
E.getNumArgs() == 0 ? E.getRParenLoc() : E.getArg(0)->getBeginLoc();
103-
return findPreviousTokenKind(EndLoc, SM, LangOpts, tok::TokenKind::l_paren);
104-
}
105-
10699
RangeSelector transformer::before(RangeSelector Selector) {
107100
return [Selector](const MatchResult &Result) -> Expected<CharSourceRange> {
108101
Expected<CharSourceRange> SelectedRange = Selector(Result);
@@ -287,18 +280,50 @@ RangeSelector transformer::statements(std::string ID) {
287280
}
288281

289282
namespace {
290-
// Returns the range of the source between the call's parentheses.
291-
CharSourceRange getCallArgumentsRange(const MatchResult &Result,
292-
const CallExpr &CE) {
283+
284+
SourceLocation getRLoc(const CallExpr &E) { return E.getRParenLoc(); }
285+
286+
SourceLocation getRLoc(const CXXConstructExpr &E) {
287+
return E.getParenOrBraceRange().getEnd();
288+
}
289+
290+
tok::TokenKind getStartToken(const CallExpr &E) {
291+
return tok::TokenKind::l_paren;
292+
}
293+
294+
tok::TokenKind getStartToken(const CXXConstructExpr &E) {
295+
return isa<CXXTemporaryObjectExpr>(E) ? tok::TokenKind::l_paren
296+
: tok::TokenKind::l_brace;
297+
}
298+
299+
template <typename ExprWithArgs>
300+
SourceLocation findArgStartDelimiter(const ExprWithArgs &E, SourceLocation RLoc,
301+
const SourceManager &SM,
302+
const LangOptions &LangOpts) {
303+
SourceLocation Loc = E.getNumArgs() == 0 ? RLoc : E.getArg(0)->getBeginLoc();
304+
return findPreviousTokenKind(Loc, SM, LangOpts, getStartToken(E));
305+
}
306+
// Returns the range of the source between the call's or construct expr's
307+
// parentheses/braces.
308+
template <typename ExprWithArgs>
309+
CharSourceRange getArgumentsRange(const MatchResult &Result,
310+
const ExprWithArgs &CE) {
311+
const SourceLocation RLoc = getRLoc(CE);
293312
return CharSourceRange::getCharRange(
294-
findOpenParen(CE, *Result.SourceManager, Result.Context->getLangOpts())
313+
findArgStartDelimiter(CE, RLoc, *Result.SourceManager,
314+
Result.Context->getLangOpts())
295315
.getLocWithOffset(1),
296-
CE.getRParenLoc());
316+
RLoc);
297317
}
298318
} // namespace
299319

300320
RangeSelector transformer::callArgs(std::string ID) {
301-
return RelativeSelector<CallExpr, getCallArgumentsRange>(std::move(ID));
321+
return RelativeSelector<CallExpr, getArgumentsRange<CallExpr>>(std::move(ID));
322+
}
323+
324+
RangeSelector transformer::constructExprArgs(std::string ID) {
325+
return RelativeSelector<CXXConstructExpr,
326+
getArgumentsRange<CXXConstructExpr>>(std::move(ID));
302327
}
303328

304329
namespace {

clang/unittests/Tooling/RangeSelectorTest.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,48 @@ TEST(RangeSelectorTest, CallArgsErrors) {
651651
Failed<StringError>(withTypeErrorMessage("stmt")));
652652
}
653653

654+
TEST(RangeSelectorTest, ConstructExprArgs) {
655+
const StringRef Code = R"cc(
656+
struct C {
657+
C(int, int);
658+
};
659+
C f() {
660+
return C(1, 2);
661+
}
662+
)cc";
663+
const char *ID = "id";
664+
TestMatch Match = matchCode(Code, cxxTemporaryObjectExpr().bind(ID));
665+
EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("1, 2"));
666+
}
667+
668+
TEST(RangeSelectorTest, ConstructExprBracedArgs) {
669+
const StringRef Code = R"cc(
670+
struct C {
671+
C(int, int);
672+
};
673+
C f() {
674+
return {1, 2};
675+
}
676+
)cc";
677+
const char *ID = "id";
678+
TestMatch Match = matchCode(Code, cxxConstructExpr().bind(ID));
679+
EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue("1, 2"));
680+
}
681+
682+
TEST(RangeSelectorTest, ConstructExprNoArgs) {
683+
const StringRef Code = R"cc(
684+
struct C {
685+
C();
686+
};
687+
C f() {
688+
return C();
689+
}
690+
)cc";
691+
const char *ID = "id";
692+
TestMatch Match = matchCode(Code, cxxTemporaryObjectExpr().bind(ID));
693+
EXPECT_THAT_EXPECTED(select(constructExprArgs(ID), Match), HasValue(""));
694+
}
695+
654696
TEST(RangeSelectorTest, StatementsOp) {
655697
StringRef Code = R"cc(
656698
void g();

0 commit comments

Comments
 (0)