diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/utils/ExprMutationAnalyzer.cpp')
| -rw-r--r-- | clang-tools-extra/clang-tidy/utils/ExprMutationAnalyzer.cpp | 261 |
1 files changed, 0 insertions, 261 deletions
diff --git a/clang-tools-extra/clang-tidy/utils/ExprMutationAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExprMutationAnalyzer.cpp deleted file mode 100644 index ea994e44131..00000000000 --- a/clang-tools-extra/clang-tidy/utils/ExprMutationAnalyzer.cpp +++ /dev/null @@ -1,261 +0,0 @@ -//===---------- ExprMutationAnalyzer.cpp - clang-tidy ---------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -#include "ExprMutationAnalyzer.h" - -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "llvm/ADT/STLExtras.h" - -namespace clang { -namespace tidy { -namespace utils { -using namespace ast_matchers; - -namespace { - -AST_MATCHER_P(LambdaExpr, hasCaptureInit, const Expr *, E) { - return llvm::is_contained(Node.capture_inits(), E); -} - -AST_MATCHER_P(CXXForRangeStmt, hasRangeStmt, - ast_matchers::internal::Matcher<DeclStmt>, InnerMatcher) { - const DeclStmt *const Range = Node.getRangeStmt(); - return InnerMatcher.matches(*Range, Finder, Builder); -} - -const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt, CXXTypeidExpr> - cxxTypeidExpr; - -AST_MATCHER(CXXTypeidExpr, isPotentiallyEvaluated) { - return Node.isPotentiallyEvaluated(); -} - -const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt, CXXNoexceptExpr> - cxxNoexceptExpr; - -const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt, - GenericSelectionExpr> - genericSelectionExpr; - -AST_MATCHER_P(GenericSelectionExpr, hasControllingExpr, - ast_matchers::internal::Matcher<Expr>, InnerMatcher) { - return InnerMatcher.matches(*Node.getControllingExpr(), Finder, Builder); -} - -const auto nonConstReferenceType = [] { - return referenceType(pointee(unless(isConstQualified()))); -}; - -} // namespace - -const Stmt *ExprMutationAnalyzer::findMutation(const Expr *Exp) { - const auto Memoized = Results.find(Exp); - if (Memoized != Results.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}) { - if (const Stmt *S = (this->*Finder)(Exp)) - return Results[Exp] = S; - } - - return Results[Exp] = nullptr; -} - -bool ExprMutationAnalyzer::isUnevaluated(const Expr *Exp) { - return selectFirst<Expr>( - "expr", - match( - findAll( - expr(equalsNode(Exp), - anyOf( - // `Exp` is part of the underlying expression of - // decltype/typeof if it has an ancestor of - // typeLoc. - hasAncestor(typeLoc(unless( - hasAncestor(unaryExprOrTypeTraitExpr())))), - hasAncestor(expr(anyOf( - // `UnaryExprOrTypeTraitExpr` is unevaluated - // unless it's sizeof on VLA. - unaryExprOrTypeTraitExpr(unless(sizeOfExpr( - hasArgumentOfType(variableArrayType())))), - // `CXXTypeidExpr` is unevaluated unless it's - // applied to an expression of glvalue of - // polymorphic class type. - cxxTypeidExpr( - unless(isPotentiallyEvaluated())), - // The controlling expression of - // `GenericSelectionExpr` is unevaluated. - genericSelectionExpr(hasControllingExpr( - hasDescendant(equalsNode(Exp)))), - cxxNoexceptExpr()))))) - .bind("expr")), - *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; -} - -const Stmt * -ExprMutationAnalyzer::findDeclMutation(ArrayRef<BoundNodes> Matches) { - for (const auto &DeclNodes : Matches) { - if (const Stmt *S = findDeclMutation(DeclNodes.getNodeAs<Decl>("decl"))) - return S; - } - return nullptr; -} - -const Stmt *ExprMutationAnalyzer::findDeclMutation(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::findDirectMutation(const Expr *Exp) { - // LHS of any assignment operators. - const auto AsAssignmentLhs = - binaryOperator(isAssignmentOperator(), hasLHS(equalsNode(Exp))); - - // Operand of increment/decrement operators. - const auto AsIncDecOperand = - unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--")), - hasUnaryOperand(equalsNode(Exp))); - - // Invoking non-const member function. - const auto NonConstMethod = cxxMethodDecl(unless(isConst())); - const auto AsNonConstThis = - expr(anyOf(cxxMemberCallExpr(callee(NonConstMethod), on(equalsNode(Exp))), - cxxOperatorCallExpr(callee(NonConstMethod), - hasArgument(0, equalsNode(Exp))))); - - // Taking address of 'Exp'. - // We're assuming 'Exp' is mutated as soon as its address is taken, though in - // theory we can follow the pointer and see whether it escaped `Stm` or is - // dereferenced and then mutated. This is left for future improvements. - const auto AsAmpersandOperand = - unaryOperator(hasOperatorName("&"), - // A NoOp implicit cast is adding const. - unless(hasParent(implicitCastExpr(hasCastKind(CK_NoOp)))), - hasUnaryOperand(equalsNode(Exp))); - const auto AsPointerFromArrayDecay = - castExpr(hasCastKind(CK_ArrayToPointerDecay), - unless(hasParent(arraySubscriptExpr())), has(equalsNode(Exp))); - - // Used as non-const-ref argument when calling a function. - const auto NonConstRefParam = forEachArgumentWithParam( - equalsNode(Exp), parmVarDecl(hasType(nonConstReferenceType()))); - const auto AsNonConstRefArg = - anyOf(callExpr(NonConstRefParam), cxxConstructExpr(NonConstRefParam)); - - // Captured by a lambda by reference. - // If we're initializing a capture with 'Exp' directly then we're initializing - // a reference capture. - // For value captures there will be an ImplicitCastExpr <LValueToRValue>. - const auto AsLambdaRefCaptureInit = lambdaExpr(hasCaptureInit(Exp)); - - // Returned as non-const-ref. - // If we're returning 'Exp' directly then it's returned as non-const-ref. - // For returning by value there will be an ImplicitCastExpr <LValueToRValue>. - // For returning by const-ref there will be an ImplicitCastExpr <NoOp> (for - // adding const.) - const auto AsNonConstRefReturn = returnStmt(hasReturnValue(equalsNode(Exp))); - - const auto Matches = - match(findAll(stmt(anyOf(AsAssignmentLhs, AsIncDecOperand, AsNonConstThis, - AsAmpersandOperand, AsPointerFromArrayDecay, - AsNonConstRefArg, AsLambdaRefCaptureInit, - AsNonConstRefReturn)) - .bind("stmt")), - *Stm, *Context); - return selectFirst<Stmt>("stmt", Matches); -} - -const Stmt *ExprMutationAnalyzer::findMemberMutation(const Expr *Exp) { - // Check whether any member of 'Exp' is mutated. - const auto MemberExprs = match( - findAll(memberExpr(hasObjectExpression(equalsNode(Exp))).bind("expr")), - *Stm, *Context); - return findExprMutation(MemberExprs); -} - -const Stmt *ExprMutationAnalyzer::findArrayElementMutation(const Expr *Exp) { - // Check whether any element of an array is mutated. - const auto SubscriptExprs = match( - findAll(arraySubscriptExpr(hasBase(ignoringImpCasts(equalsNode(Exp)))) - .bind("expr")), - *Stm, *Context); - return findExprMutation(SubscriptExprs); -} - -const Stmt *ExprMutationAnalyzer::findCastMutation(const Expr *Exp) { - // If 'Exp' is casted to any non-const reference type, check the castExpr. - const auto Casts = - match(findAll(castExpr(hasSourceExpression(equalsNode(Exp)), - anyOf(explicitCastExpr(hasDestinationType( - nonConstReferenceType())), - implicitCastExpr(hasImplicitDestinationType( - nonConstReferenceType())))) - .bind("expr")), - *Stm, *Context); - return findExprMutation(Casts); -} - -const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(const Expr *Exp) { - // If range for looping over 'Exp' with a non-const reference loop variable, - // check all declRefExpr of the loop variable. - const auto LoopVars = - match(findAll(cxxForRangeStmt( - hasLoopVariable( - varDecl(hasType(nonConstReferenceType())).bind("decl")), - hasRangeInit(equalsNode(Exp)))), - *Stm, *Context); - return findDeclMutation(LoopVars); -} - -const Stmt *ExprMutationAnalyzer::findReferenceMutation(const Expr *Exp) { - // If 'Exp' is bound to a non-const reference, check all declRefExpr to that. - const auto Refs = match( - stmt(forEachDescendant( - varDecl( - hasType(nonConstReferenceType()), - hasInitializer(anyOf(equalsNode(Exp), - conditionalOperator(anyOf( - hasTrueExpression(equalsNode(Exp)), - hasFalseExpression(equalsNode(Exp)))))), - hasParent(declStmt().bind("stmt")), - // Don't follow the reference in range statement, we've handled - // that separately. - unless(hasParent(declStmt(hasParent( - cxxForRangeStmt(hasRangeStmt(equalsBoundNode("stmt")))))))) - .bind("decl"))), - *Stm, *Context); - return findDeclMutation(Refs); -} - -} // namespace utils -} // namespace tidy -} // namespace clang - |

