xref: /freebsd/contrib/llvm-project/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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  
clearMemoized35      void clear() {
36        Results.clear();
37        PointeeResults.clear();
38        FuncParmAnalyzer.clear();
39      }
40    };
41    struct Analyzer {
AnalyzerAnalyzer42      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  
ExprMutationAnalyzer(const Stmt & Stm,ASTContext & Context)83    ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context)
84        : Memorized(), A(Stm, Context, Memorized) {}
85  
isMutated(const Expr * Exp)86    bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; }
isMutated(const Decl * Dec)87    bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; }
findMutation(const Expr * Exp)88    const Stmt *findMutation(const Expr *Exp) { return A.findMutation(Exp); }
findMutation(const Decl * Dec)89    const Stmt *findMutation(const Decl *Dec) { return A.findMutation(Dec); }
90  
isPointeeMutated(const Expr * Exp)91    bool isPointeeMutated(const Expr *Exp) {
92      return findPointeeMutation(Exp) != nullptr;
93    }
isPointeeMutated(const Decl * Dec)94    bool isPointeeMutated(const Decl *Dec) {
95      return findPointeeMutation(Dec) != nullptr;
96    }
findPointeeMutation(const Expr * Exp)97    const Stmt *findPointeeMutation(const Expr *Exp) {
98      return A.findPointeeMutation(Exp);
99    }
findPointeeMutation(const Decl * Dec)100    const Stmt *findPointeeMutation(const Decl *Dec) {
101      return A.findPointeeMutation(Dec);
102    }
103  
isUnevaluated(const Stmt * Smt,const Stmt & Stm,ASTContext & Context)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 *
getFunctionParmMutationAnalyzer(const FunctionDecl & Func,ASTContext & Context,ExprMutationAnalyzer::Memoized & Memorized)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  
isMutated(const ParmVarDecl * Parm)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