xref: /llvm-project/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h (revision 53ea5ffcb38d428e446d357f310e9c28957eaec7)
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