unless(isDeleted()))))));
};
+template <class T> struct NodeID;
+template <> struct NodeID<Expr> { static const std::string value; };
+template <> struct NodeID<Decl> { static const std::string value; };
+const std::string NodeID<Expr>::value = "expr";
+const std::string NodeID<Decl>::value = "decl";
+
+template <class T, class F = const Stmt *(ExprMutationAnalyzer::*)(const T *)>
+const Stmt *tryEachMatch(ArrayRef<ast_matchers::BoundNodes> Matches,
+ ExprMutationAnalyzer *Analyzer, F Finder) {
+ const StringRef ID = NodeID<T>::value;
+ for (const auto &Nodes : Matches) {
+ if (const Stmt *S = (Analyzer->*Finder)(Nodes.getNodeAs<T>(ID)))
+ return S;
+ }
+ return nullptr;
+}
+
} // namespace
const Stmt *ExprMutationAnalyzer::findMutation(const Expr *Exp) {
- const auto Memoized = Results.find(Exp);
- if (Memoized != Results.end())
+ return findMutationMemoized(Exp,
+ {&ExprMutationAnalyzer::findDirectMutation,
+ &ExprMutationAnalyzer::findMemberMutation,
+ &ExprMutationAnalyzer::findArrayElementMutation,
+ &ExprMutationAnalyzer::findCastMutation,
+ &ExprMutationAnalyzer::findRangeLoopMutation,
+ &ExprMutationAnalyzer::findReferenceMutation,
+ &ExprMutationAnalyzer::findFunctionArgMutation},
+ Results);
+}
+
+const Stmt *ExprMutationAnalyzer::findMutation(const Decl *Dec) {
+ return tryEachDeclRef(Dec, &ExprMutationAnalyzer::findMutation);
+}
+
+const Stmt *ExprMutationAnalyzer::findPointeeMutation(const Expr *Exp) {
+ return findMutationMemoized(Exp, {/*TODO*/}, PointeeResults);
+}
+
+const Stmt *ExprMutationAnalyzer::findPointeeMutation(const Decl *Dec) {
+ return tryEachDeclRef(Dec, &ExprMutationAnalyzer::findPointeeMutation);
+}
+
+const Stmt *ExprMutationAnalyzer::findMutationMemoized(
+ const Expr *Exp, llvm::ArrayRef<MutationFinder> Finders,
+ ResultMap &MemoizedResults) {
+ const auto Memoized = MemoizedResults.find(Exp);
+ if (Memoized != MemoizedResults.end())
return Memoized->second;
if (isUnevaluated(Exp))
- return Results[Exp] = nullptr;
-
- for (const auto &Finder : {&ExprMutationAnalyzer::findDirectMutation,
- &ExprMutationAnalyzer::findMemberMutation,
- &ExprMutationAnalyzer::findArrayElementMutation,
- &ExprMutationAnalyzer::findCastMutation,
- &ExprMutationAnalyzer::findRangeLoopMutation,
- &ExprMutationAnalyzer::findReferenceMutation,
- &ExprMutationAnalyzer::findFunctionArgMutation}) {
+ return MemoizedResults[Exp] = nullptr;
+
+ for (const auto &Finder : Finders) {
if (const Stmt *S = (this->*Finder)(Exp))
- return Results[Exp] = S;
+ return MemoizedResults[Exp] = S;
}
- return Results[Exp] = nullptr;
+ return MemoizedResults[Exp] = nullptr;
+}
+
+const Stmt *ExprMutationAnalyzer::tryEachDeclRef(const Decl *Dec,
+ MutationFinder Finder) {
+ const auto Refs =
+ match(findAll(declRefExpr(to(equalsNode(Dec))).bind(NodeID<Expr>::value)),
+ Stm, Context);
+ for (const auto &RefNodes : Refs) {
+ const auto *E = RefNodes.getNodeAs<Expr>(NodeID<Expr>::value);
+ if ((this->*Finder)(E))
+ return E;
+ }
+ return nullptr;
}
bool ExprMutationAnalyzer::isUnevaluated(const Expr *Exp) {
return selectFirst<Expr>(
- "expr",
+ NodeID<Expr>::value,
match(
findAll(
expr(equalsNode(Exp),
genericSelectionExpr(hasControllingExpr(
hasDescendant(equalsNode(Exp)))),
cxxNoexceptExpr())))))
- .bind("expr")),
+ .bind(NodeID<Expr>::value)),
Stm, Context)) != nullptr;
}
const Stmt *
ExprMutationAnalyzer::findExprMutation(ArrayRef<BoundNodes> Matches) {
- for (const auto &Nodes : Matches) {
- if (const Stmt *S = findMutation(Nodes.getNodeAs<Expr>("expr")))
- return S;
- }
- return nullptr;
+ return tryEachMatch<Expr>(Matches, this, &ExprMutationAnalyzer::findMutation);
}
const Stmt *
ExprMutationAnalyzer::findDeclMutation(ArrayRef<BoundNodes> Matches) {
- for (const auto &DeclNodes : Matches) {
- if (const Stmt *S = findMutation(DeclNodes.getNodeAs<Decl>("decl")))
- return S;
- }
- return nullptr;
+ return tryEachMatch<Decl>(Matches, this, &ExprMutationAnalyzer::findMutation);
}
-const Stmt *ExprMutationAnalyzer::findMutation(const Decl *Dec) {
- const auto Refs = match(
- findAll(declRefExpr(to(equalsNode(Dec))).bind("expr")), Stm, Context);
- for (const auto &RefNodes : Refs) {
- const auto *E = RefNodes.getNodeAs<Expr>("expr");
- if (findMutation(E))
- return E;
- }
- return nullptr;
+const Stmt *ExprMutationAnalyzer::findExprPointeeMutation(
+ ArrayRef<ast_matchers::BoundNodes> Matches) {
+ return tryEachMatch<Expr>(Matches, this,
+ &ExprMutationAnalyzer::findPointeeMutation);
+}
+
+const Stmt *ExprMutationAnalyzer::findDeclPointeeMutation(
+ ArrayRef<ast_matchers::BoundNodes> Matches) {
+ return tryEachMatch<Decl>(Matches, this,
+ &ExprMutationAnalyzer::findPointeeMutation);
}
const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
match(findAll(expr(anyOf(memberExpr(hasObjectExpression(equalsNode(Exp))),
cxxDependentScopeMemberExpr(
hasObjectExpression(equalsNode(Exp)))))
- .bind("expr")),
+ .bind(NodeID<Expr>::value)),
Stm, Context);
return findExprMutation(MemberExprs);
}
// Check whether any element of an array is mutated.
const auto SubscriptExprs = match(
findAll(arraySubscriptExpr(hasBase(ignoringImpCasts(equalsNode(Exp))))
- .bind("expr")),
+ .bind(NodeID<Expr>::value)),
Stm, Context);
return findExprMutation(SubscriptExprs);
}
nonConstReferenceType())),
implicitCastExpr(hasImplicitDestinationType(
nonConstReferenceType()))))
- .bind("expr")),
+ .bind(NodeID<Expr>::value)),
Stm, Context);
return findExprMutation(Casts);
}
// check all declRefExpr of the loop variable.
const auto LoopVars =
match(findAll(cxxForRangeStmt(
- hasLoopVariable(
- varDecl(hasType(nonConstReferenceType())).bind("decl")),
+ hasLoopVariable(varDecl(hasType(nonConstReferenceType()))
+ .bind(NodeID<Decl>::value)),
hasRangeInit(equalsNode(Exp)))),
Stm, Context);
return findDeclMutation(LoopVars);
callee(cxxMethodDecl(ofClass(isMoveOnly()),
returns(nonConstReferenceType()))),
argumentCountIs(1), hasArgument(0, equalsNode(Exp)))
- .bind("expr")),
+ .bind(NodeID<Expr>::value)),
Stm, Context);
if (const Stmt *S = findExprMutation(Ref))
return S;
// that separately.
unless(hasParent(declStmt(hasParent(
cxxForRangeStmt(hasRangeStmt(equalsBoundNode("stmt"))))))))
- .bind("decl"))),
+ .bind(NodeID<Decl>::value))),
Stm, Context);
return findDeclMutation(Refs);
}
findAll(expr(anyOf(callExpr(NonConstRefParam, IsInstantiated, FuncDecl),
cxxConstructExpr(NonConstRefParam, IsInstantiated,
FuncDecl)))
- .bind("expr")),
+ .bind(NodeID<Expr>::value)),
Stm, Context);
for (const auto &Nodes : Matches) {
- const auto *Exp = Nodes.getNodeAs<Expr>("expr");
+ const auto *Exp = Nodes.getNodeAs<Expr>(NodeID<Expr>::value);
const auto *Func = Nodes.getNodeAs<FunctionDecl>("func");
if (!Func->getBody())
return Exp;