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 35 void clear() { 36 Results.clear(); 37 PointeeResults.clear(); 38 FuncParmAnalyzer.clear(); 39 } 40 }; 41 struct Analyzer { 42 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 51 private: 52 using MutationFinder = const Stmt *(Analyzer::*)(const Expr *); 53 54 const Stmt *findMutationMemoized(const Expr *Exp, 55 llvm::ArrayRef<MutationFinder> Finders, 56 Memoized::ResultMap &MemoizedResults); 57 const Stmt *tryEachDeclRef(const Decl *Dec, MutationFinder Finder); 58 59 const Stmt *findExprMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 60 const Stmt *findDeclMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 61 const Stmt * 62 findExprPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 63 const Stmt * 64 findDeclPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches); 65 66 const Stmt *findDirectMutation(const Expr *Exp); 67 const Stmt *findMemberMutation(const Expr *Exp); 68 const Stmt *findArrayElementMutation(const Expr *Exp); 69 const Stmt *findCastMutation(const Expr *Exp); 70 const Stmt *findRangeLoopMutation(const Expr *Exp); 71 const Stmt *findReferenceMutation(const Expr *Exp); 72 const Stmt *findFunctionArgMutation(const Expr *Exp); 73 74 const Stmt *findPointeeValueMutation(const Expr *Exp); 75 const Stmt *findPointeeMemberMutation(const Expr *Exp); 76 const Stmt *findPointeeToNonConst(const Expr *Exp); 77 78 const Stmt &Stm; 79 ASTContext &Context; 80 Memoized &Memorized; 81 }; 82 83 ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context) 84 : Memorized(), A(Stm, Context, Memorized) {} 85 86 /// check whether stmt is unevaluated. mutation analyzer will ignore the 87 /// content in unevaluated stmt. 88 static bool isUnevaluated(const Stmt *Stm, ASTContext &Context); 89 90 bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; } 91 bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; } 92 const Stmt *findMutation(const Expr *Exp) { return A.findMutation(Exp); } 93 const Stmt *findMutation(const Decl *Dec) { return A.findMutation(Dec); } 94 95 bool isPointeeMutated(const Expr *Exp) { 96 return findPointeeMutation(Exp) != nullptr; 97 } 98 bool isPointeeMutated(const Decl *Dec) { 99 return findPointeeMutation(Dec) != nullptr; 100 } 101 const Stmt *findPointeeMutation(const Expr *Exp) { 102 return A.findPointeeMutation(Exp); 103 } 104 const Stmt *findPointeeMutation(const Decl *Dec) { 105 return A.findPointeeMutation(Dec); 106 } 107 108 private: 109 Memoized Memorized; 110 Analyzer A; 111 }; 112 113 // A convenient wrapper around ExprMutationAnalyzer for analyzing function 114 // params. 115 class FunctionParmMutationAnalyzer { 116 public: 117 static FunctionParmMutationAnalyzer * 118 getFunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context, 119 ExprMutationAnalyzer::Memoized &Memorized) { 120 auto it = Memorized.FuncParmAnalyzer.find(&Func); 121 if (it == Memorized.FuncParmAnalyzer.end()) { 122 // Creating a new instance of FunctionParmMutationAnalyzer below may add 123 // additional elements to FuncParmAnalyzer. If we did try_emplace before 124 // creating a new instance, the returned iterator of try_emplace could be 125 // invalidated. 126 it = 127 Memorized.FuncParmAnalyzer 128 .try_emplace(&Func, std::unique_ptr<FunctionParmMutationAnalyzer>( 129 new FunctionParmMutationAnalyzer( 130 Func, Context, Memorized))) 131 .first; 132 } 133 return it->getSecond().get(); 134 } 135 136 bool isMutated(const ParmVarDecl *Parm) { 137 return findMutation(Parm) != nullptr; 138 } 139 const Stmt *findMutation(const ParmVarDecl *Parm); 140 141 private: 142 ExprMutationAnalyzer::Analyzer BodyAnalyzer; 143 llvm::DenseMap<const ParmVarDecl *, const Stmt *> Results; 144 145 FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context, 146 ExprMutationAnalyzer::Memoized &Memorized); 147 }; 148 149 } // namespace clang 150 151 #endif // LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H 152