xref: /freebsd/contrib/llvm-project/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
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(&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 
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