blob: 117173ba9a09583e624208d91ba481912021c1d6 [file] [log] [blame]
//===---------- ExprMutationAnalyzer.h ------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
#define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
#include "clang/ASTMatchers/ASTMatchers.h"
#include "llvm/ADT/DenseMap.h"
#include <memory>
namespace clang {
class FunctionParmMutationAnalyzer;
/// Analyzes whether any mutative operations are applied to an expression within
/// a given statement.
class ExprMutationAnalyzer {
friend class FunctionParmMutationAnalyzer;
public:
struct Memoized {
using ResultMap = llvm::DenseMap<const Expr *, const Stmt *>;
using FunctionParaAnalyzerMap =
llvm::SmallDenseMap<const FunctionDecl *,
std::unique_ptr<FunctionParmMutationAnalyzer>>;
ResultMap Results;
ResultMap PointeeResults;
FunctionParaAnalyzerMap FuncParmAnalyzer;
void clear() {
Results.clear();
PointeeResults.clear();
FuncParmAnalyzer.clear();
}
};
struct Analyzer {
Analyzer(const Stmt &Stm, ASTContext &Context, Memoized &Memorized)
: Stm(Stm), Context(Context), Memorized(Memorized) {}
const Stmt *findMutation(const Expr *Exp);
const Stmt *findMutation(const Decl *Dec);
const Stmt *findPointeeMutation(const Expr *Exp);
const Stmt *findPointeeMutation(const Decl *Dec);
static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm,
ASTContext &Context);
private:
using MutationFinder = const Stmt *(Analyzer::*)(const Expr *);
const Stmt *findMutationMemoized(const Expr *Exp,
llvm::ArrayRef<MutationFinder> Finders,
Memoized::ResultMap &MemoizedResults);
const Stmt *tryEachDeclRef(const Decl *Dec, MutationFinder Finder);
bool isUnevaluated(const Expr *Exp);
const Stmt *findExprMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *findDeclMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *
findExprPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *
findDeclPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *findDirectMutation(const Expr *Exp);
const Stmt *findMemberMutation(const Expr *Exp);
const Stmt *findArrayElementMutation(const Expr *Exp);
const Stmt *findCastMutation(const Expr *Exp);
const Stmt *findRangeLoopMutation(const Expr *Exp);
const Stmt *findReferenceMutation(const Expr *Exp);
const Stmt *findFunctionArgMutation(const Expr *Exp);
const Stmt &Stm;
ASTContext &Context;
Memoized &Memorized;
};
ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context)
: Memorized(), A(Stm, Context, Memorized) {}
bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; }
bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; }
const Stmt *findMutation(const Expr *Exp) { return A.findMutation(Exp); }
const Stmt *findMutation(const Decl *Dec) { return A.findMutation(Dec); }
bool isPointeeMutated(const Expr *Exp) {
return findPointeeMutation(Exp) != nullptr;
}
bool isPointeeMutated(const Decl *Dec) {
return findPointeeMutation(Dec) != nullptr;
}
const Stmt *findPointeeMutation(const Expr *Exp) {
return A.findPointeeMutation(Exp);
}
const Stmt *findPointeeMutation(const Decl *Dec) {
return A.findPointeeMutation(Dec);
}
static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm,
ASTContext &Context) {
return Analyzer::isUnevaluated(Smt, Stm, Context);
}
private:
Memoized Memorized;
Analyzer A;
};
// A convenient wrapper around ExprMutationAnalyzer for analyzing function
// params.
class FunctionParmMutationAnalyzer {
public:
static FunctionParmMutationAnalyzer *
getFunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context,
ExprMutationAnalyzer::Memoized &Memorized) {
auto it = Memorized.FuncParmAnalyzer.find(&Func);
if (it == Memorized.FuncParmAnalyzer.end())
it =
Memorized.FuncParmAnalyzer
.try_emplace(&Func, std::unique_ptr<FunctionParmMutationAnalyzer>(
new FunctionParmMutationAnalyzer(
Func, Context, Memorized)))
.first;
return it->getSecond().get();
}
bool isMutated(const ParmVarDecl *Parm) {
return findMutation(Parm) != nullptr;
}
const Stmt *findMutation(const ParmVarDecl *Parm);
private:
ExprMutationAnalyzer::Analyzer BodyAnalyzer;
llvm::DenseMap<const ParmVarDecl *, const Stmt *> Results;
FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context,
ExprMutationAnalyzer::Memoized &Memorized);
};
} // namespace clang
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H