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 | 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 | |
83 | ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context) |
84 | : Memorized(), A(Stm, Context, Memorized) {} |
85 | |
86 | bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; } |
87 | bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; } |
88 | const Stmt *findMutation(const Expr *Exp) { return A.findMutation(Exp); } |
89 | const Stmt *findMutation(const Decl *Dec) { return A.findMutation(Dec); } |
90 | |
91 | bool isPointeeMutated(const Expr *Exp) { |
92 | return findPointeeMutation(Exp) != nullptr; |
93 | } |
94 | bool isPointeeMutated(const Decl *Dec) { |
95 | return findPointeeMutation(Dec) != nullptr; |
96 | } |
97 | const Stmt *findPointeeMutation(const Expr *Exp) { |
98 | return A.findPointeeMutation(Exp); |
99 | } |
100 | const Stmt *findPointeeMutation(const Decl *Dec) { |
101 | return A.findPointeeMutation(Dec); |
102 | } |
103 | |
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 * |
119 | getFunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context, |
120 | ExprMutationAnalyzer::Memoized &Memorized) { |
121 | auto it = Memorized.FuncParmAnalyzer.find(Val: &Func); |
122 | if (it == Memorized.FuncParmAnalyzer.end()) |
123 | it = |
124 | Memorized.FuncParmAnalyzer |
125 | .try_emplace(Key: &Func, Args: std::unique_ptr<FunctionParmMutationAnalyzer>( |
126 | new FunctionParmMutationAnalyzer( |
127 | Func, Context, Memorized))) |
128 | .first; |
129 | return it->getSecond().get(); |
130 | } |
131 | |
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 | |