13 #include "llvm/ADT/STLExtras.h"
16 using namespace ast_matchers;
21 return llvm::is_contained(
Node.capture_inits(), E);
25 ast_matchers::internal::Matcher<DeclStmt>, InnerMatcher) {
26 const DeclStmt *
const Range =
Node.getRangeStmt();
27 return InnerMatcher.matches(*Range, Finder, Builder);
30 AST_MATCHER_P(Expr, maybeEvalCommaExpr, ast_matchers::internal::Matcher<Expr>,
32 const Expr *Result = &
Node;
33 while (
const auto *BOComma =
34 dyn_cast_or_null<BinaryOperator>(Result->IgnoreParens())) {
35 if (!BOComma->isCommaOp())
37 Result = BOComma->getRHS();
39 return InnerMatcher.matches(*Result, Finder, Builder);
42 AST_MATCHER_P(Stmt, canResolveToExpr, ast_matchers::internal::Matcher<Stmt>,
44 auto *Exp = dyn_cast<Expr>(&
Node);
46 return stmt().matches(
Node, Finder, Builder);
49 auto DerivedToBase = [](
const ast_matchers::internal::Matcher<Expr> &Inner) {
51 hasCastKind(CK_UncheckedDerivedToBase)),
52 hasSourceExpression(Inner));
54 auto IgnoreDerivedToBase =
55 [&DerivedToBase](
const ast_matchers::internal::Matcher<Expr> &Inner) {
56 return ignoringParens(
expr(
anyOf(Inner, DerivedToBase(Inner))));
67 hasTrueExpression(ignoringParens(canResolveToExpr(InnerMatcher))),
68 hasFalseExpression(ignoringParens(canResolveToExpr(InnerMatcher)))));
70 hasTrueExpression(ignoringParens(canResolveToExpr(InnerMatcher))),
71 hasFalseExpression(ignoringParens(canResolveToExpr(InnerMatcher)))));
73 auto const ComplexMatcher = ignoringParens(
74 expr(
anyOf(IgnoreDerivedToBase(InnerMatcher),
75 maybeEvalCommaExpr(IgnoreDerivedToBase(InnerMatcher)),
76 IgnoreDerivedToBase(ConditionalOperator),
77 IgnoreDerivedToBase(ElvisOperator))));
79 return ComplexMatcher.matches(*Exp, Finder, Builder);
84 AST_MATCHER_P(InitListExpr, hasAnyInit, ast_matchers::internal::Matcher<Expr>,
86 for (
const Expr *Arg :
Node.inits()) {
87 ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
88 if (InnerMatcher.matches(*Arg, Finder, &Result)) {
89 *Builder = std::move(Result);
96 const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt, CXXTypeidExpr>
99 AST_MATCHER(CXXTypeidExpr, isPotentiallyEvaluated) {
100 return Node.isPotentiallyEvaluated();
104 ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
105 return InnerMatcher.matches(*
Node.getControllingExpr(), Finder, Builder);
108 const auto nonConstReferenceType = [] {
109 return hasUnqualifiedDesugaredType(
113 const auto nonConstPointerType = [] {
114 return hasUnqualifiedDesugaredType(
118 const auto isMoveOnly = [] {
128 template <
class T>
struct NodeID;
129 template <>
struct NodeID<Expr> {
static constexpr StringRef value =
"expr"; };
130 template <>
struct NodeID<
Decl> {
static constexpr StringRef value =
"decl"; };
131 constexpr StringRef NodeID<Expr>::value;
132 constexpr StringRef NodeID<Decl>::value;
134 template <
class T,
class F = const Stmt *(ExprMutationAnalyzer::*)(const T *)>
135 const Stmt *tryEachMatch(ArrayRef<ast_matchers::BoundNodes> Matches,
136 ExprMutationAnalyzer *Analyzer, F Finder) {
137 const StringRef
ID = NodeID<T>::value;
138 for (
const auto &
Nodes : Matches) {
139 if (
const Stmt *S = (Analyzer->*Finder)(
Nodes.getNodeAs<T>(
ID)))
148 return findMutationMemoized(Exp,
149 {&ExprMutationAnalyzer::findDirectMutation,
150 &ExprMutationAnalyzer::findMemberMutation,
151 &ExprMutationAnalyzer::findArrayElementMutation,
152 &ExprMutationAnalyzer::findCastMutation,
153 &ExprMutationAnalyzer::findRangeLoopMutation,
154 &ExprMutationAnalyzer::findReferenceMutation,
155 &ExprMutationAnalyzer::findFunctionArgMutation},
164 return findMutationMemoized(Exp, {}, PointeeResults);
171 const Stmt *ExprMutationAnalyzer::findMutationMemoized(
173 ResultMap &MemoizedResults) {
174 const auto Memoized = MemoizedResults.find(Exp);
175 if (Memoized != MemoizedResults.end())
176 return Memoized->second;
178 if (isUnevaluated(Exp))
179 return MemoizedResults[Exp] =
nullptr;
181 for (
const auto &Finder : Finders) {
182 if (
const Stmt *S = (this->*Finder)(Exp))
183 return MemoizedResults[Exp] = S;
186 return MemoizedResults[Exp] =
nullptr;
189 const Stmt *ExprMutationAnalyzer::tryEachDeclRef(
const Decl *Dec,
190 MutationFinder Finder) {
194 for (
const auto &RefNodes : Refs) {
195 const auto *E = RefNodes.getNodeAs<Expr>(NodeID<Expr>::value);
196 if ((this->*Finder)(E))
204 return selectFirst<Stmt>(
208 stmt(canResolveToExpr(equalsNode(Exp)),
224 unless(isPotentiallyEvaluated())),
230 .bind(NodeID<Expr>::value)),
231 Stm, Context)) !=
nullptr;
235 return isUnevaluated(Exp, Stm, Context);
239 ExprMutationAnalyzer::findExprMutation(ArrayRef<BoundNodes> Matches) {
244 ExprMutationAnalyzer::findDeclMutation(ArrayRef<BoundNodes> Matches) {
248 const Stmt *ExprMutationAnalyzer::findExprPointeeMutation(
249 ArrayRef<ast_matchers::BoundNodes> Matches) {
250 return tryEachMatch<Expr>(Matches,
this,
254 const Stmt *ExprMutationAnalyzer::findDeclPointeeMutation(
255 ArrayRef<ast_matchers::BoundNodes> Matches) {
256 return tryEachMatch<Decl>(Matches,
this,
260 const Stmt *ExprMutationAnalyzer::findDirectMutation(
const Expr *Exp) {
263 isAssignmentOperator(), hasLHS(canResolveToExpr(equalsNode(Exp))));
266 const auto AsIncDecOperand =
268 hasUnaryOperand(canResolveToExpr(equalsNode(Exp))));
276 on(canResolveToExpr(equalsNode(Exp)))),
278 hasArgument(0, canResolveToExpr(equalsNode(Exp)))),
284 allOf(ignoringImpCasts(canResolveToExpr(equalsNode(Exp))),
285 isTypeDependent()))),
291 canResolveToExpr(equalsNode(Exp)))),
293 canResolveToExpr(equalsNode(Exp)))))))),
298 hasObjectExpression(canResolveToExpr(
299 equalsNode(Exp)))))))));
305 const auto AsAmpersandOperand =
309 hasUnaryOperand(canResolveToExpr(equalsNode(Exp))));
310 const auto AsPointerFromArrayDecay =
311 castExpr(hasCastKind(CK_ArrayToPointerDecay),
313 has(canResolveToExpr(equalsNode(Exp))));
320 cxxMethodDecl(ofClass(isMoveOnly()), returns(nonConstPointerType()))),
321 argumentCountIs(1), hasArgument(0, canResolveToExpr(equalsNode(Exp))));
328 const auto NonConstRefParam = forEachArgumentWithParamType(
329 anyOf(canResolveToExpr(equalsNode(Exp)),
330 memberExpr(hasObjectExpression(canResolveToExpr(equalsNode(Exp))))),
331 nonConstReferenceType());
333 const auto TypeDependentCallee =
338 const auto AsNonConstRefArg =
anyOf(
339 callExpr(NonConstRefParam, NotInstantiated),
342 hasAnyArgument(canResolveToExpr(equalsNode(Exp)))),
344 hasAnyArgument(canResolveToExpr(equalsNode(Exp)))),
359 const auto AsLambdaRefCaptureInit =
lambdaExpr(hasCaptureInit(Exp));
366 const auto AsNonConstRefReturn =
367 returnStmt(hasReturnValue(canResolveToExpr(equalsNode(Exp))));
372 hasType(nonConstReferenceType())))));
374 const auto Matches =
match(
377 AsNonConstThis, AsAmpersandOperand,
378 AsPointerFromArrayDecay, AsOperatorArrowThis,
379 AsNonConstRefArg, AsLambdaRefCaptureInit,
380 AsNonConstRefReturn, AsNonConstRefRangeInit))
383 return selectFirst<Stmt>(
"stmt", Matches);
386 const Stmt *ExprMutationAnalyzer::findMemberMutation(
const Expr *Exp) {
388 const auto MemberExprs =
390 canResolveToExpr(equalsNode(Exp)))),
392 canResolveToExpr(equalsNode(Exp))))))
393 .bind(NodeID<Expr>::value)),
395 return findExprMutation(MemberExprs);
398 const Stmt *ExprMutationAnalyzer::findArrayElementMutation(
const Expr *Exp) {
400 const auto SubscriptExprs =
402 anyOf(hasBase(canResolveToExpr(equalsNode(Exp))),
404 allOf(hasCastKind(CK_ArrayToPointerDecay),
405 hasSourceExpression(canResolveToExpr(
406 equalsNode(Exp))))))))
407 .bind(NodeID<Expr>::value)),
409 return findExprMutation(SubscriptExprs);
412 const Stmt *ExprMutationAnalyzer::findCastMutation(
const Expr *Exp) {
415 const auto ExplicitCast =
match(
417 stmt(
castExpr(hasSourceExpression(canResolveToExpr(equalsNode(Exp))),
419 hasDestinationType(nonConstReferenceType()))))
423 if (
const auto *CastStmt = selectFirst<Stmt>(
"stmt", ExplicitCast))
427 const auto Casts =
match(
429 expr(
castExpr(hasSourceExpression(canResolveToExpr(equalsNode(Exp))),
431 hasDestinationType(nonConstReferenceType())),
433 nonConstReferenceType())))))
434 .bind(NodeID<Expr>::value)),
437 if (
const Stmt *S = findExprMutation(Casts))
442 hasAnyName(
"::std::move",
"::std::forward"))),
443 hasArgument(0, canResolveToExpr(equalsNode(Exp))))
446 return findExprMutation(Calls);
449 const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(
const Expr *Exp) {
456 const auto DeclStmtToNonRefToArray =
declStmt(hasSingleDecl(
varDecl(hasType(
458 const auto RefToArrayRefToElements =
match(
460 hasLoopVariable(
varDecl(hasType(nonConstReferenceType()))
461 .bind(NodeID<Decl>::value)),
462 hasRangeStmt(DeclStmtToNonRefToArray),
463 hasRangeInit(canResolveToExpr(equalsNode(Exp)))))
467 if (
const auto *BadRangeInitFromArray =
468 selectFirst<Stmt>(
"stmt", RefToArrayRefToElements))
469 return BadRangeInitFromArray;
478 const auto HasAnyNonConstIterator =
484 const auto DeclStmtToNonConstIteratorContainer =
declStmt(
488 const auto RefToContainerBadIterators =
490 hasRangeStmt(DeclStmtToNonConstIteratorContainer),
491 hasRangeInit(canResolveToExpr(equalsNode(Exp))))))
495 if (
const auto *BadIteratorsContainer =
496 selectFirst<Stmt>(
"stmt", RefToContainerBadIterators))
497 return BadIteratorsContainer;
501 const auto LoopVars =
503 hasLoopVariable(
varDecl(hasType(nonConstReferenceType()))
504 .bind(NodeID<Decl>::value)),
505 hasRangeInit(canResolveToExpr(equalsNode(Exp))))),
507 return findDeclMutation(LoopVars);
510 const Stmt *ExprMutationAnalyzer::findReferenceMutation(
const Expr *Exp) {
518 returns(nonConstReferenceType()))),
520 hasArgument(0, canResolveToExpr(equalsNode(Exp))))
521 .bind(NodeID<Expr>::value)),
523 if (
const Stmt *S = findExprMutation(Ref))
527 const auto Refs =
match(
530 hasType(nonConstReferenceType()),
531 hasInitializer(
anyOf(canResolveToExpr(equalsNode(Exp)),
533 canResolveToExpr(equalsNode(Exp)))))),
539 .bind(NodeID<Decl>::value))),
541 return findDeclMutation(Refs);
544 const Stmt *ExprMutationAnalyzer::findFunctionArgMutation(
const Expr *Exp) {
545 const auto NonConstRefParam = forEachArgumentWithParam(
546 canResolveToExpr(equalsNode(Exp)),
547 parmVarDecl(hasType(nonConstReferenceType())).bind(
"parm"));
550 const auto Matches =
match(
556 "::std::move",
"::std::forward"))))),
559 .bind(NodeID<Expr>::value))),
561 for (
const auto &
Nodes : Matches) {
562 const auto *Exp =
Nodes.getNodeAs<Expr>(NodeID<Expr>::value);
563 const auto *Func =
Nodes.getNodeAs<FunctionDecl>(
"func");
564 if (!Func->getBody() || !Func->getPrimaryTemplate())
567 const auto *Parm =
Nodes.getNodeAs<ParmVarDecl>(
"parm");
568 const ArrayRef<ParmVarDecl *> AllParams =
569 Func->getPrimaryTemplate()->getTemplatedDecl()->parameters();
571 AllParams[std::min<size_t>(Parm->getFunctionScopeIndex(),
572 AllParams.size() - 1)]
574 if (
const auto *T = ParmType->getAs<PackExpansionType>())
575 ParmType = T->getPattern();
579 if (
const auto *RefType = ParmType->getAs<RValueReferenceType>()) {
580 if (!RefType->getPointeeType().getQualifiers() &&
581 RefType->getPointeeType()->getAs<TemplateTypeParmType>()) {
582 std::unique_ptr<FunctionParmMutationAnalyzer> &Analyzer =
583 FuncParmAnalyzer[Func];
585 Analyzer.reset(
new FunctionParmMutationAnalyzer(*Func, Context));
586 if (Analyzer->findMutation(Parm))
599 : BodyAnalyzer(*Func.getBody(), Context) {
600 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(&Func)) {
605 for (
const ParmVarDecl *Parm : Ctor->parameters()) {
606 if (Results.find(Parm) != Results.end())
617 const auto Memoized = Results.find(Parm);
618 if (Memoized != Results.end())
619 return Memoized->second;
622 return Results[Parm] = S;
624 return Results[Parm] =
nullptr;