1 //== SValExplainer.h - Symbolic value explainer -----------------*- C++ -*--==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines SValExplainer, a class for pretty-printing a
11 // human-readable description of a symbolic value. For example,
12 // "reg_$0<x>" is turned into "initial value of variable 'x'".
14 //===----------------------------------------------------------------------===//
16 #ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
17 #define LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
19 #include "clang/AST/DeclCXX.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
26 class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
30 std::string printStmt(const Stmt *S) {
32 llvm::raw_string_ostream OS(Str);
33 S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
37 bool isThisObject(const SymbolicRegion *R) {
38 if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
39 if (isa<CXXThisRegion>(S->getRegion()))
45 SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
47 std::string VisitUnknownVal(UnknownVal V) {
48 return "unknown value";
51 std::string VisitUndefinedVal(UndefinedVal V) {
52 return "undefined value";
55 std::string VisitLocMemRegionVal(loc::MemRegionVal V) {
56 const MemRegion *R = V.getRegion();
57 // Avoid the weird "pointer to pointee of ...".
58 if (auto SR = dyn_cast<SymbolicRegion>(R)) {
59 // However, "pointer to 'this' object" is fine.
60 if (!isThisObject(SR))
61 return Visit(SR->getSymbol());
63 return "pointer to " + Visit(R);
66 std::string VisitLocConcreteInt(loc::ConcreteInt V) {
67 llvm::APSInt I = V.getValue();
69 llvm::raw_string_ostream OS(Str);
70 OS << "concrete memory address '" << I << "'";
74 std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) {
75 return Visit(V.getSymbol());
78 std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
79 llvm::APSInt I = V.getValue();
81 llvm::raw_string_ostream OS(Str);
82 OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
83 << "-bit integer '" << I << "'";
87 std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
88 return "lazily frozen compound value of " + Visit(V.getRegion());
91 std::string VisitSymbolRegionValue(const SymbolRegionValue *S) {
92 const MemRegion *R = S->getRegion();
93 // Special handling for argument values.
94 if (auto V = dyn_cast<VarRegion>(R))
95 if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
96 return "argument '" + D->getQualifiedNameAsString() + "'";
97 return "initial value of " + Visit(R);
100 std::string VisitSymbolConjured(const SymbolConjured *S) {
101 return "symbol of type '" + S->getType().getAsString() +
102 "' conjured at statement '" + printStmt(S->getStmt()) + "'";
105 std::string VisitSymbolDerived(const SymbolDerived *S) {
106 return "value derived from (" + Visit(S->getParentSymbol()) +
107 ") for " + Visit(S->getRegion());
110 std::string VisitSymbolExtent(const SymbolExtent *S) {
111 return "extent of " + Visit(S->getRegion());
114 std::string VisitSymbolMetadata(const SymbolMetadata *S) {
115 return "metadata of type '" + S->getType().getAsString() + "' tied to " +
116 Visit(S->getRegion());
119 std::string VisitSymIntExpr(const SymIntExpr *S) {
121 llvm::raw_string_ostream OS(Str);
122 OS << "(" << Visit(S->getLHS()) << ") "
123 << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
128 // TODO: IntSymExpr doesn't appear in practice.
129 // Add the relevant code once it does.
131 std::string VisitSymSymExpr(const SymSymExpr *S) {
132 return "(" + Visit(S->getLHS()) + ") " +
133 std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
134 " (" + Visit(S->getRHS()) + ")";
137 // TODO: SymbolCast doesn't appear in practice.
138 // Add the relevant code once it does.
140 std::string VisitSymbolicRegion(const SymbolicRegion *R) {
141 // Explain 'this' object here.
142 // TODO: Explain CXXThisRegion itself, find a way to test it.
144 return "'this' object";
145 // Objective-C objects are not normal symbolic regions. At least,
146 // they're always on the heap.
147 if (R->getSymbol()->getType()
148 .getCanonicalType()->getAs<ObjCObjectPointerType>())
149 return "object at " + Visit(R->getSymbol());
150 // Other heap-based symbolic regions are also special.
151 if (isa<HeapSpaceRegion>(R->getMemorySpace()))
152 return "heap segment that starts at " + Visit(R->getSymbol());
153 return "pointee of " + Visit(R->getSymbol());
156 std::string VisitAllocaRegion(const AllocaRegion *R) {
157 return "region allocated by '" + printStmt(R->getExpr()) + "'";
160 std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) {
161 return "compound literal " + printStmt(R->getLiteralExpr());
164 std::string VisitStringRegion(const StringRegion *R) {
165 return "string literal " + R->getString();
168 std::string VisitElementRegion(const ElementRegion *R) {
170 llvm::raw_string_ostream OS(Str);
171 OS << "element of type '" << R->getElementType().getAsString()
173 // For concrete index: omit type of the index integer.
174 if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
177 OS << "'" << Visit(R->getIndex()) << "'";
178 OS << " of " + Visit(R->getSuperRegion());
182 std::string VisitVarRegion(const VarRegion *R) {
183 const VarDecl *VD = R->getDecl();
184 std::string Name = VD->getQualifiedNameAsString();
185 if (isa<ParmVarDecl>(VD))
186 return "parameter '" + Name + "'";
187 else if (VD->hasAttr<BlocksAttr>())
188 return "block variable '" + Name + "'";
189 else if (VD->hasLocalStorage())
190 return "local variable '" + Name + "'";
191 else if (VD->isStaticLocal())
192 return "static local variable '" + Name + "'";
193 else if (VD->hasGlobalStorage())
194 return "global variable '" + Name + "'";
196 llvm_unreachable("A variable is either local or global");
199 std::string VisitObjCIvarRegion(const ObjCIvarRegion *R) {
200 return "instance variable '" + R->getDecl()->getNameAsString() + "' of " +
201 Visit(R->getSuperRegion());
204 std::string VisitFieldRegion(const FieldRegion *R) {
205 return "field '" + R->getDecl()->getNameAsString() + "' of " +
206 Visit(R->getSuperRegion());
209 std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) {
210 return "temporary object constructed at statement '" +
211 printStmt(R->getExpr()) + "'";
214 std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
215 return "base object '" + R->getDecl()->getQualifiedNameAsString() +
216 "' inside " + Visit(R->getSuperRegion());
219 std::string VisitSVal(SVal V) {
221 llvm::raw_string_ostream OS(Str);
223 return "a value unsupported by the explainer: (" +
224 std::string(OS.str()) + ")";
227 std::string VisitSymExpr(SymbolRef S) {
229 llvm::raw_string_ostream OS(Str);
231 return "a symbolic expression unsupported by the explainer: (" +
232 std::string(OS.str()) + ")";
235 std::string VisitMemRegion(const MemRegion *R) {
237 llvm::raw_string_ostream OS(Str);
239 return "a memory region unsupported by the explainer (" +
240 std::string(OS.str()) + ")";
244 } // end namespace ento
246 } // end namespace clang