xref: /freebsd/contrib/llvm-project/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===---------- ExprMutationAnalyzer.h ------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
90b57cec5SDimitry Andric #define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "clang/ASTMatchers/ASTMatchers.h"
120b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
13*0fca6ea1SDimitry Andric #include <memory>
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric namespace clang {
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric class FunctionParmMutationAnalyzer;
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric /// Analyzes whether any mutative operations are applied to an expression within
200b57cec5SDimitry Andric /// a given statement.
210b57cec5SDimitry Andric class ExprMutationAnalyzer {
22*0fca6ea1SDimitry Andric   friend class FunctionParmMutationAnalyzer;
230b57cec5SDimitry Andric 
24*0fca6ea1SDimitry Andric public:
25*0fca6ea1SDimitry Andric   struct Memoized {
26*0fca6ea1SDimitry Andric     using ResultMap = llvm::DenseMap<const Expr *, const Stmt *>;
27*0fca6ea1SDimitry Andric     using FunctionParaAnalyzerMap =
28*0fca6ea1SDimitry Andric         llvm::SmallDenseMap<const FunctionDecl *,
29*0fca6ea1SDimitry Andric                             std::unique_ptr<FunctionParmMutationAnalyzer>>;
30*0fca6ea1SDimitry Andric 
31*0fca6ea1SDimitry Andric     ResultMap Results;
32*0fca6ea1SDimitry Andric     ResultMap PointeeResults;
33*0fca6ea1SDimitry Andric     FunctionParaAnalyzerMap FuncParmAnalyzer;
34*0fca6ea1SDimitry Andric 
clearMemoized35*0fca6ea1SDimitry Andric     void clear() {
36*0fca6ea1SDimitry Andric       Results.clear();
37*0fca6ea1SDimitry Andric       PointeeResults.clear();
38*0fca6ea1SDimitry Andric       FuncParmAnalyzer.clear();
39*0fca6ea1SDimitry Andric     }
40*0fca6ea1SDimitry Andric   };
41*0fca6ea1SDimitry Andric   struct Analyzer {
AnalyzerAnalyzer42*0fca6ea1SDimitry Andric     Analyzer(const Stmt &Stm, ASTContext &Context, Memoized &Memorized)
43*0fca6ea1SDimitry Andric         : Stm(Stm), Context(Context), Memorized(Memorized) {}
44*0fca6ea1SDimitry Andric 
450b57cec5SDimitry Andric     const Stmt *findMutation(const Expr *Exp);
460b57cec5SDimitry Andric     const Stmt *findMutation(const Decl *Dec);
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric     const Stmt *findPointeeMutation(const Expr *Exp);
490b57cec5SDimitry Andric     const Stmt *findPointeeMutation(const Decl *Dec);
5081ad6265SDimitry Andric     static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm,
5181ad6265SDimitry Andric                               ASTContext &Context);
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   private:
54*0fca6ea1SDimitry Andric     using MutationFinder = const Stmt *(Analyzer::*)(const Expr *);
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric     const Stmt *findMutationMemoized(const Expr *Exp,
570b57cec5SDimitry Andric                                      llvm::ArrayRef<MutationFinder> Finders,
58*0fca6ea1SDimitry Andric                                      Memoized::ResultMap &MemoizedResults);
590b57cec5SDimitry Andric     const Stmt *tryEachDeclRef(const Decl *Dec, MutationFinder Finder);
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric     bool isUnevaluated(const Expr *Exp);
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric     const Stmt *findExprMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
640b57cec5SDimitry Andric     const Stmt *findDeclMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
650b57cec5SDimitry Andric     const Stmt *
660b57cec5SDimitry Andric     findExprPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
670b57cec5SDimitry Andric     const Stmt *
680b57cec5SDimitry Andric     findDeclPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric     const Stmt *findDirectMutation(const Expr *Exp);
710b57cec5SDimitry Andric     const Stmt *findMemberMutation(const Expr *Exp);
720b57cec5SDimitry Andric     const Stmt *findArrayElementMutation(const Expr *Exp);
730b57cec5SDimitry Andric     const Stmt *findCastMutation(const Expr *Exp);
740b57cec5SDimitry Andric     const Stmt *findRangeLoopMutation(const Expr *Exp);
750b57cec5SDimitry Andric     const Stmt *findReferenceMutation(const Expr *Exp);
760b57cec5SDimitry Andric     const Stmt *findFunctionArgMutation(const Expr *Exp);
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric     const Stmt &Stm;
790b57cec5SDimitry Andric     ASTContext &Context;
80*0fca6ea1SDimitry Andric     Memoized &Memorized;
81*0fca6ea1SDimitry Andric   };
82*0fca6ea1SDimitry Andric 
ExprMutationAnalyzer(const Stmt & Stm,ASTContext & Context)83*0fca6ea1SDimitry Andric   ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context)
84*0fca6ea1SDimitry Andric       : Memorized(), A(Stm, Context, Memorized) {}
85*0fca6ea1SDimitry Andric 
isMutated(const Expr * Exp)86*0fca6ea1SDimitry Andric   bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; }
isMutated(const Decl * Dec)87*0fca6ea1SDimitry Andric   bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; }
findMutation(const Expr * Exp)88*0fca6ea1SDimitry Andric   const Stmt *findMutation(const Expr *Exp) { return A.findMutation(Exp); }
findMutation(const Decl * Dec)89*0fca6ea1SDimitry Andric   const Stmt *findMutation(const Decl *Dec) { return A.findMutation(Dec); }
90*0fca6ea1SDimitry Andric 
isPointeeMutated(const Expr * Exp)91*0fca6ea1SDimitry Andric   bool isPointeeMutated(const Expr *Exp) {
92*0fca6ea1SDimitry Andric     return findPointeeMutation(Exp) != nullptr;
93*0fca6ea1SDimitry Andric   }
isPointeeMutated(const Decl * Dec)94*0fca6ea1SDimitry Andric   bool isPointeeMutated(const Decl *Dec) {
95*0fca6ea1SDimitry Andric     return findPointeeMutation(Dec) != nullptr;
96*0fca6ea1SDimitry Andric   }
findPointeeMutation(const Expr * Exp)97*0fca6ea1SDimitry Andric   const Stmt *findPointeeMutation(const Expr *Exp) {
98*0fca6ea1SDimitry Andric     return A.findPointeeMutation(Exp);
99*0fca6ea1SDimitry Andric   }
findPointeeMutation(const Decl * Dec)100*0fca6ea1SDimitry Andric   const Stmt *findPointeeMutation(const Decl *Dec) {
101*0fca6ea1SDimitry Andric     return A.findPointeeMutation(Dec);
102*0fca6ea1SDimitry Andric   }
103*0fca6ea1SDimitry Andric 
isUnevaluated(const Stmt * Smt,const Stmt & Stm,ASTContext & Context)104*0fca6ea1SDimitry Andric   static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm,
105*0fca6ea1SDimitry Andric                             ASTContext &Context) {
106*0fca6ea1SDimitry Andric     return Analyzer::isUnevaluated(Smt, Stm, Context);
107*0fca6ea1SDimitry Andric   }
108*0fca6ea1SDimitry Andric 
109*0fca6ea1SDimitry Andric private:
110*0fca6ea1SDimitry Andric   Memoized Memorized;
111*0fca6ea1SDimitry Andric   Analyzer A;
1120b57cec5SDimitry Andric };
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric // A convenient wrapper around ExprMutationAnalyzer for analyzing function
1150b57cec5SDimitry Andric // params.
1160b57cec5SDimitry Andric class FunctionParmMutationAnalyzer {
1170b57cec5SDimitry Andric public:
118*0fca6ea1SDimitry Andric   static FunctionParmMutationAnalyzer *
getFunctionParmMutationAnalyzer(const FunctionDecl & Func,ASTContext & Context,ExprMutationAnalyzer::Memoized & Memorized)119*0fca6ea1SDimitry Andric   getFunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context,
120*0fca6ea1SDimitry Andric                                   ExprMutationAnalyzer::Memoized &Memorized) {
121*0fca6ea1SDimitry Andric     auto it = Memorized.FuncParmAnalyzer.find(&Func);
122*0fca6ea1SDimitry Andric     if (it == Memorized.FuncParmAnalyzer.end())
123*0fca6ea1SDimitry Andric       it =
124*0fca6ea1SDimitry Andric           Memorized.FuncParmAnalyzer
125*0fca6ea1SDimitry Andric               .try_emplace(&Func, std::unique_ptr<FunctionParmMutationAnalyzer>(
126*0fca6ea1SDimitry Andric                                       new FunctionParmMutationAnalyzer(
127*0fca6ea1SDimitry Andric                                           Func, Context, Memorized)))
128*0fca6ea1SDimitry Andric               .first;
129*0fca6ea1SDimitry Andric     return it->getSecond().get();
130*0fca6ea1SDimitry Andric   }
1310b57cec5SDimitry Andric 
isMutated(const ParmVarDecl * Parm)1320b57cec5SDimitry Andric   bool isMutated(const ParmVarDecl *Parm) {
1330b57cec5SDimitry Andric     return findMutation(Parm) != nullptr;
1340b57cec5SDimitry Andric   }
1350b57cec5SDimitry Andric   const Stmt *findMutation(const ParmVarDecl *Parm);
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric private:
138*0fca6ea1SDimitry Andric   ExprMutationAnalyzer::Analyzer BodyAnalyzer;
1390b57cec5SDimitry Andric   llvm::DenseMap<const ParmVarDecl *, const Stmt *> Results;
140*0fca6ea1SDimitry Andric 
141*0fca6ea1SDimitry Andric   FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context,
142*0fca6ea1SDimitry Andric                                ExprMutationAnalyzer::Memoized &Memorized);
1430b57cec5SDimitry Andric };
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric } // namespace clang
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric #endif // LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
148