10b57cec5SDimitry Andric //===---------- ExprMutationAnalyzer.h ------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H 90b57cec5SDimitry Andric #define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "clang/ASTMatchers/ASTMatchers.h" 120b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 13*0fca6ea1SDimitry Andric #include <memory> 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric namespace clang { 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric class FunctionParmMutationAnalyzer; 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric /// Analyzes whether any mutative operations are applied to an expression within 200b57cec5SDimitry Andric /// a given statement. 210b57cec5SDimitry Andric class ExprMutationAnalyzer { 22*0fca6ea1SDimitry Andric friend class FunctionParmMutationAnalyzer; 230b57cec5SDimitry Andric 24*0fca6ea1SDimitry Andric public: 25*0fca6ea1SDimitry Andric struct Memoized { 26*0fca6ea1SDimitry Andric using ResultMap = llvm::DenseMap<const Expr *, const Stmt *>; 27*0fca6ea1SDimitry Andric using FunctionParaAnalyzerMap = 28*0fca6ea1SDimitry Andric llvm::SmallDenseMap<const FunctionDecl *, 29*0fca6ea1SDimitry Andric std::unique_ptr<FunctionParmMutationAnalyzer>>; 30*0fca6ea1SDimitry Andric 31*0fca6ea1SDimitry Andric ResultMap Results; 32*0fca6ea1SDimitry Andric ResultMap PointeeResults; 33*0fca6ea1SDimitry Andric FunctionParaAnalyzerMap FuncParmAnalyzer; 34*0fca6ea1SDimitry Andric clearMemoized35*0fca6ea1SDimitry Andric void clear() { 36*0fca6ea1SDimitry Andric Results.clear(); 37*0fca6ea1SDimitry Andric PointeeResults.clear(); 38*0fca6ea1SDimitry Andric FuncParmAnalyzer.clear(); 39*0fca6ea1SDimitry Andric } 40*0fca6ea1SDimitry Andric }; 41*0fca6ea1SDimitry Andric struct Analyzer { AnalyzerAnalyzer42*0fca6ea1SDimitry Andric Analyzer(const Stmt &Stm, ASTContext &Context, Memoized &Memorized) 43*0fca6ea1SDimitry Andric : Stm(Stm), Context(Context), Memorized(Memorized) {} 44*0fca6ea1SDimitry Andric 450b57cec5SDimitry Andric const Stmt *findMutation(const Expr *Exp); 460b57cec5SDimitry Andric const Stmt *findMutation(const Decl *Dec); 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric const Stmt *findPointeeMutation(const Expr *Exp); 490b57cec5SDimitry Andric const Stmt *findPointeeMutation(const Decl *Dec); 5081ad6265SDimitry Andric static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm, 5181ad6265SDimitry Andric ASTContext &Context); 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric private: 54*0fca6ea1SDimitry Andric using MutationFinder = const Stmt *(Analyzer::*)(const Expr *); 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric const Stmt *findMutationMemoized(const Expr *Exp, 570b57cec5SDimitry Andric llvm::ArrayRef<MutationFinder> Finders, 58*0fca6ea1SDimitry Andric Memoized::ResultMap &MemoizedResults); 590b57cec5SDimitry Andric const Stmt *tryEachDeclRef(const Decl *Dec, MutationFinder Finder); 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric bool isUnevaluated(const Expr *Exp); 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric const Stmt *findExprMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 640b57cec5SDimitry Andric const Stmt *findDeclMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 650b57cec5SDimitry Andric const Stmt * 660b57cec5SDimitry Andric findExprPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 670b57cec5SDimitry Andric const Stmt * 680b57cec5SDimitry Andric findDeclPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric const Stmt *findDirectMutation(const Expr *Exp); 710b57cec5SDimitry Andric const Stmt *findMemberMutation(const Expr *Exp); 720b57cec5SDimitry Andric const Stmt *findArrayElementMutation(const Expr *Exp); 730b57cec5SDimitry Andric const Stmt *findCastMutation(const Expr *Exp); 740b57cec5SDimitry Andric const Stmt *findRangeLoopMutation(const Expr *Exp); 750b57cec5SDimitry Andric const Stmt *findReferenceMutation(const Expr *Exp); 760b57cec5SDimitry Andric const Stmt *findFunctionArgMutation(const Expr *Exp); 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric const Stmt &Stm; 790b57cec5SDimitry Andric ASTContext &Context; 80*0fca6ea1SDimitry Andric Memoized &Memorized; 81*0fca6ea1SDimitry Andric }; 82*0fca6ea1SDimitry Andric ExprMutationAnalyzer(const Stmt & Stm,ASTContext & Context)83*0fca6ea1SDimitry Andric ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context) 84*0fca6ea1SDimitry Andric : Memorized(), A(Stm, Context, Memorized) {} 85*0fca6ea1SDimitry Andric isMutated(const Expr * Exp)86*0fca6ea1SDimitry Andric bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; } isMutated(const Decl * Dec)87*0fca6ea1SDimitry Andric bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; } findMutation(const Expr * Exp)88*0fca6ea1SDimitry Andric const Stmt *findMutation(const Expr *Exp) { return A.findMutation(Exp); } findMutation(const Decl * Dec)89*0fca6ea1SDimitry Andric const Stmt *findMutation(const Decl *Dec) { return A.findMutation(Dec); } 90*0fca6ea1SDimitry Andric isPointeeMutated(const Expr * Exp)91*0fca6ea1SDimitry Andric bool isPointeeMutated(const Expr *Exp) { 92*0fca6ea1SDimitry Andric return findPointeeMutation(Exp) != nullptr; 93*0fca6ea1SDimitry Andric } isPointeeMutated(const Decl * Dec)94*0fca6ea1SDimitry Andric bool isPointeeMutated(const Decl *Dec) { 95*0fca6ea1SDimitry Andric return findPointeeMutation(Dec) != nullptr; 96*0fca6ea1SDimitry Andric } findPointeeMutation(const Expr * Exp)97*0fca6ea1SDimitry Andric const Stmt *findPointeeMutation(const Expr *Exp) { 98*0fca6ea1SDimitry Andric return A.findPointeeMutation(Exp); 99*0fca6ea1SDimitry Andric } findPointeeMutation(const Decl * Dec)100*0fca6ea1SDimitry Andric const Stmt *findPointeeMutation(const Decl *Dec) { 101*0fca6ea1SDimitry Andric return A.findPointeeMutation(Dec); 102*0fca6ea1SDimitry Andric } 103*0fca6ea1SDimitry Andric isUnevaluated(const Stmt * Smt,const Stmt & Stm,ASTContext & Context)104*0fca6ea1SDimitry Andric static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm, 105*0fca6ea1SDimitry Andric ASTContext &Context) { 106*0fca6ea1SDimitry Andric return Analyzer::isUnevaluated(Smt, Stm, Context); 107*0fca6ea1SDimitry Andric } 108*0fca6ea1SDimitry Andric 109*0fca6ea1SDimitry Andric private: 110*0fca6ea1SDimitry Andric Memoized Memorized; 111*0fca6ea1SDimitry Andric Analyzer A; 1120b57cec5SDimitry Andric }; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric // A convenient wrapper around ExprMutationAnalyzer for analyzing function 1150b57cec5SDimitry Andric // params. 1160b57cec5SDimitry Andric class FunctionParmMutationAnalyzer { 1170b57cec5SDimitry Andric public: 118*0fca6ea1SDimitry Andric static FunctionParmMutationAnalyzer * getFunctionParmMutationAnalyzer(const FunctionDecl & Func,ASTContext & Context,ExprMutationAnalyzer::Memoized & Memorized)119*0fca6ea1SDimitry Andric getFunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context, 120*0fca6ea1SDimitry Andric ExprMutationAnalyzer::Memoized &Memorized) { 121*0fca6ea1SDimitry Andric auto it = Memorized.FuncParmAnalyzer.find(&Func); 122*0fca6ea1SDimitry Andric if (it == Memorized.FuncParmAnalyzer.end()) 123*0fca6ea1SDimitry Andric it = 124*0fca6ea1SDimitry Andric Memorized.FuncParmAnalyzer 125*0fca6ea1SDimitry Andric .try_emplace(&Func, std::unique_ptr<FunctionParmMutationAnalyzer>( 126*0fca6ea1SDimitry Andric new FunctionParmMutationAnalyzer( 127*0fca6ea1SDimitry Andric Func, Context, Memorized))) 128*0fca6ea1SDimitry Andric .first; 129*0fca6ea1SDimitry Andric return it->getSecond().get(); 130*0fca6ea1SDimitry Andric } 1310b57cec5SDimitry Andric isMutated(const ParmVarDecl * Parm)1320b57cec5SDimitry Andric bool isMutated(const ParmVarDecl *Parm) { 1330b57cec5SDimitry Andric return findMutation(Parm) != nullptr; 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric const Stmt *findMutation(const ParmVarDecl *Parm); 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric private: 138*0fca6ea1SDimitry Andric ExprMutationAnalyzer::Analyzer BodyAnalyzer; 1390b57cec5SDimitry Andric llvm::DenseMap<const ParmVarDecl *, const Stmt *> Results; 140*0fca6ea1SDimitry Andric 141*0fca6ea1SDimitry Andric FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context, 142*0fca6ea1SDimitry Andric ExprMutationAnalyzer::Memoized &Memorized); 1430b57cec5SDimitry Andric }; 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric } // namespace clang 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric #endif // LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H 148