1 //===---------- ExprMutationAnalyzer.h ------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H 9 #define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H 10 11 #include "clang/ASTMatchers/ASTMatchers.h" 12 #include "llvm/ADT/DenseMap.h" 13 #include <memory> 14 15 namespace clang { 16 17 class FunctionParmMutationAnalyzer; 18 19 /// Analyzes whether any mutative operations are applied to an expression within 20 /// a given statement. 21 class ExprMutationAnalyzer { 22 friend class FunctionParmMutationAnalyzer; 23 24 public: 25 struct Memoized { 26 using ResultMap = llvm::DenseMap<const Expr *, const Stmt *>; 27 using FunctionParaAnalyzerMap = 28 llvm::SmallDenseMap<const FunctionDecl *, 29 std::unique_ptr<FunctionParmMutationAnalyzer>>; 30 31 ResultMap Results; 32 ResultMap PointeeResults; 33 FunctionParaAnalyzerMap FuncParmAnalyzer; 34 clearMemoized35 void clear() { 36 Results.clear(); 37 PointeeResults.clear(); 38 FuncParmAnalyzer.clear(); 39 } 40 }; 41 struct Analyzer { AnalyzerAnalyzer42 Analyzer(const Stmt &Stm, ASTContext &Context, Memoized &Memorized) 43 : Stm(Stm), Context(Context), Memorized(Memorized) {} 44 45 const Stmt *findMutation(const Expr *Exp); 46 const Stmt *findMutation(const Decl *Dec); 47 48 const Stmt *findPointeeMutation(const Expr *Exp); 49 const Stmt *findPointeeMutation(const Decl *Dec); 50 static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm, 51 ASTContext &Context); 52 53 private: 54 using MutationFinder = const Stmt *(Analyzer::*)(const Expr *); 55 56 const Stmt *findMutationMemoized(const Expr *Exp, 57 llvm::ArrayRef<MutationFinder> Finders, 58 Memoized::ResultMap &MemoizedResults); 59 const Stmt *tryEachDeclRef(const Decl *Dec, MutationFinder Finder); 60 61 bool isUnevaluated(const Expr *Exp); 62 63 const Stmt *findExprMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 64 const Stmt *findDeclMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 65 const Stmt * 66 findExprPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 67 const Stmt * 68 findDeclPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 69 70 const Stmt *findDirectMutation(const Expr *Exp); 71 const Stmt *findMemberMutation(const Expr *Exp); 72 const Stmt *findArrayElementMutation(const Expr *Exp); 73 const Stmt *findCastMutation(const Expr *Exp); 74 const Stmt *findRangeLoopMutation(const Expr *Exp); 75 const Stmt *findReferenceMutation(const Expr *Exp); 76 const Stmt *findFunctionArgMutation(const Expr *Exp); 77 78 const Stmt &Stm; 79 ASTContext &Context; 80 Memoized &Memorized; 81 }; 82 ExprMutationAnalyzer(const Stmt & Stm,ASTContext & Context)83 ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context) 84 : Memorized(), A(Stm, Context, Memorized) {} 85 isMutated(const Expr * Exp)86 bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; } isMutated(const Decl * Dec)87 bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; } findMutation(const Expr * Exp)88 const Stmt *findMutation(const Expr *Exp) { return A.findMutation(Exp); } findMutation(const Decl * Dec)89 const Stmt *findMutation(const Decl *Dec) { return A.findMutation(Dec); } 90 isPointeeMutated(const Expr * Exp)91 bool isPointeeMutated(const Expr *Exp) { 92 return findPointeeMutation(Exp) != nullptr; 93 } isPointeeMutated(const Decl * Dec)94 bool isPointeeMutated(const Decl *Dec) { 95 return findPointeeMutation(Dec) != nullptr; 96 } findPointeeMutation(const Expr * Exp)97 const Stmt *findPointeeMutation(const Expr *Exp) { 98 return A.findPointeeMutation(Exp); 99 } findPointeeMutation(const Decl * Dec)100 const Stmt *findPointeeMutation(const Decl *Dec) { 101 return A.findPointeeMutation(Dec); 102 } 103 isUnevaluated(const Stmt * Smt,const Stmt & Stm,ASTContext & Context)104 static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm, 105 ASTContext &Context) { 106 return Analyzer::isUnevaluated(Smt, Stm, Context); 107 } 108 109 private: 110 Memoized Memorized; 111 Analyzer A; 112 }; 113 114 // A convenient wrapper around ExprMutationAnalyzer for analyzing function 115 // params. 116 class FunctionParmMutationAnalyzer { 117 public: 118 static FunctionParmMutationAnalyzer * getFunctionParmMutationAnalyzer(const FunctionDecl & Func,ASTContext & Context,ExprMutationAnalyzer::Memoized & Memorized)119 getFunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context, 120 ExprMutationAnalyzer::Memoized &Memorized) { 121 auto it = Memorized.FuncParmAnalyzer.find(&Func); 122 if (it == Memorized.FuncParmAnalyzer.end()) 123 it = 124 Memorized.FuncParmAnalyzer 125 .try_emplace(&Func, std::unique_ptr<FunctionParmMutationAnalyzer>( 126 new FunctionParmMutationAnalyzer( 127 Func, Context, Memorized))) 128 .first; 129 return it->getSecond().get(); 130 } 131 isMutated(const ParmVarDecl * Parm)132 bool isMutated(const ParmVarDecl *Parm) { 133 return findMutation(Parm) != nullptr; 134 } 135 const Stmt *findMutation(const ParmVarDecl *Parm); 136 137 private: 138 ExprMutationAnalyzer::Analyzer BodyAnalyzer; 139 llvm::DenseMap<const ParmVarDecl *, const Stmt *> Results; 140 141 FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context, 142 ExprMutationAnalyzer::Memoized &Memorized); 143 }; 144 145 } // namespace clang 146 147 #endif // LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H 148