1//===- SSAFAnalysesCommon.h -------------------------------------*- C++ -*-===//
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//
9// Common code in SSAF analyses implementations
10//
11//===----------------------------------------------------------------------===//
12#ifndef LLVM_CLANG_SCALABLESTATICANALYSIS_ANALYSES_SSAFANALYSESCOMMON_H
13#define LLVM_CLANG_SCALABLESTATICANALYSIS_ANALYSES_SSAFANALYSESCOMMON_H
14
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/ASTTypeTraits.h"
17#include "clang/AST/Decl.h"
18#include "clang/Frontend/SSAFOptions.h"
19#include "clang/ScalableStaticAnalysis/Core/Model/EntityId.h"
20#include "clang/ScalableStaticAnalysis/Core/TUSummary/TUSummaryBuilder.h"
21#include "clang/ScalableStaticAnalysis/Core/TUSummary/TUSummaryExtractor.h"
22#include "llvm/ADT/DenseMap.h"
23#include "llvm/ADT/STLFunctionalExtras.h"
24#include "llvm/Support/Debug.h"
25#include "llvm/Support/Error.h"
26#include "llvm/Support/JSON.h"
27#include "llvm/Support/raw_ostream.h"
28#include <memory>
29
30namespace clang::ssaf {
31class SSAFOptions;
32
33///\return a short descriptions of a json::Value
34std::string describeJSONValue(const llvm::json::Value &V);
35///\return a short descriptions of a json::Array
36std::string describeJSONValue(const llvm::json::Array &A);
37///\return a short descriptions of a json::Object
38std::string describeJSONValue(const llvm::json::Object &O);
39
40template <typename NodeTy, typename... Ts>
41llvm::Error makeErrAtNode(clang::ASTContext &Ctx, const NodeTy *N,
42 llvm::StringRef Fmt, const Ts &...Args) {
43 std::string LocStr = N->getBeginLoc().printToString(Ctx.getSourceManager());
44 return llvm::createStringError((Fmt + " at %s").str().c_str(), Args...,
45 LocStr.c_str());
46}
47
48template <typename JSONTy, typename... Ts>
49llvm::Error makeSawButExpectedError(const JSONTy &Saw, llvm::StringRef Expected,
50 const Ts &...ExpectedArgs) {
51 std::string Fmt = ("saw %s but expected " + Expected).str();
52 std::string SawStr = describeJSONValue(Saw);
53
54 return llvm::createStringError(Fmt.c_str(), SawStr.c_str(), ExpectedArgs...);
55}
56
57///\return true iff expression `E` has pointer or array type.
58inline bool hasPtrOrArrType(const Expr *E) {
59 return llvm::isa<clang::PointerType, clang::ArrayType>(
60 Val: E->getType().getCanonicalType());
61}
62
63///\return true iff Decl `D` has (reference-to) pointer or array type.
64inline bool hasPtrOrArrType(const ValueDecl *D) {
65 return llvm::isa<clang::PointerType, clang::ArrayType>(
66 Val: D->getType().getNonReferenceType().getCanonicalType());
67}
68
69llvm::Error makeEntityNameErr(clang::ASTContext &Ctx,
70 const clang::NamedDecl *D);
71
72/// Log a warning from an llvm::Error
73inline void logWarningFromError(llvm::Error Err) {
74 DEBUG_WITH_TYPE("ssaf-analyses", llvm::errs() << Err);
75 llvm::consumeError(Err: std::move(Err));
76}
77
78/// Find all contributors in an AST. The found contributors are organized as a
79/// map from the canonical declaration of each entity to all of its
80/// declarations.
81///
82/// \p Options controls which declarations qualify as contributors. By default
83/// the visitor preserves the original SSAF behavior of skipping block-scope
84/// (function-local) variable declarations; setting
85/// \c Options.IncludeLocalEntities to \c true also collects local variables
86/// (excluding function parameters, which are addressed via their parent
87/// function's USR).
88void findContributors(
89 ASTContext &Ctx, const SSAFOptions &Options,
90 llvm::DenseMap<const NamedDecl *, std::vector<const NamedDecl *>>
91 &Contributors,
92 bool ExtractFromSystemHeaders = true);
93
94/// Perform "MatchAction" on each Stmt and Decl belonging to the `Contributor`.
95/// \param Contributor
96/// \param MatchActionRef a reference (view) to a "MatchAction"
97void findMatchesIn(
98 const NamedDecl *Contributor,
99 llvm::function_ref<void(const DynTypedNode &)> MatchActionRef);
100
101/// The standard contributor-summary extraction procedure:
102/// 1. Find and group all contributor decls by their canonical decls.
103/// 2. Use \p Extract to get an EntitySummary of a contributor from all of its
104/// decls.
105/// 3. Insert the EntitySummary into the \p Builder.
106///
107/// \param ExtractorFnT the template parameter that should be a function type
108/// 'std::unique_ptr<SummaryT>(std::vector<const NamedDecl *>)' for different
109/// entity summary type `SummaryT`s
110/// \param ExtractFn The function that extracts summaries of a contributor from
111/// its decls.
112/// \param ExtractorName The optional information inserted into the warning
113/// message when duplicate contributor names (EntityNames) are seen.
114template <typename ExtractorFnT>
115void extractAndAddSummaries(TUSummaryExtractor &Extractor,
116 TUSummaryBuilder &Builder, ASTContext &Ctx,
117 ExtractorFnT ExtractFn,
118 llvm::StringRef ExtractorName = "") {
119 llvm::DenseMap<const NamedDecl *, std::vector<const NamedDecl *>>
120 Contributors;
121 findContributors(Ctx, Options: Extractor.getOptions(), Contributors,
122 ExtractFromSystemHeaders: Extractor.getOptions().ExtractFromSystemHeaders);
123 for (const auto &[Cano, Decls] : Contributors) {
124 assert(!Decls.empty() &&
125 "'findContributors' guarantees that 'Decls' are non-empty");
126 assert(!Decls[0]->isImplicit() &&
127 "'findContributors' guarantees that 'Decls' are non-implicit");
128
129 // Templates are skipped, but their instantiations are handled. The idea
130 // is that we can conclude facts about a template through all of its
131 // instantiations.
132 if (Decls[0]->isTemplated())
133 continue;
134
135 auto Summary = ExtractFn(Decls);
136 assert(Summary);
137 if (Summary->empty())
138 continue;
139
140 if (auto Id = Extractor.addEntity(D: Decls[0])) {
141 if (!Builder.addSummary(*Id, std::move(Summary)).second)
142 logWarningFromError(Err: makeErrAtNode(
143 Ctx, N: Decls[0], Fmt: "dropping duplicate %s summary for entity %s",
144 Args: ExtractorName.str().c_str(), Args: Decls[0]->getNameAsString().c_str()));
145 } else
146 logWarningFromError(Err: makeEntityNameErr(Ctx, D: Decls[0]));
147 }
148}
149
150} // namespace clang::ssaf
151
152#endif // LLVM_CLANG_SCALABLESTATICANALYSIS_ANALYSES_SSAFANALYSESCOMMON_H
153