1//== SValExplainer.h - Symbolic value explainer -----------------*- C++ -*--==//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
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'".
13//
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
17#define LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
18
19#include "clang/AST/DeclCXX.h"
20#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
21
22namespace clang {
23
24namespace ento {
25
26class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
27private:
28  ASTContext &ACtx;
29
30  std::string printStmt(const Stmt *S) {
31    std::string Str;
32    llvm::raw_string_ostream OS(Str);
33    S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
34    return OS.str();
35  }
36
37  bool isThisObject(const SymbolicRegion *R) {
38    if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
39      if (isa<CXXThisRegion>(S->getRegion()))
40        return true;
41    return false;
42  }
43
44public:
45  SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
46
47  std::string VisitUnknownVal(UnknownVal V) {
48    return "unknown value";
49  }
50
51  std::string VisitUndefinedVal(UndefinedVal V) {
52    return "undefined value";
53  }
54
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());
62    }
63    return "pointer to " + Visit(R);
64  }
65
66  std::string VisitLocConcreteInt(loc::ConcreteInt V) {
67    llvm::APSInt I = V.getValue();
68    std::string Str;
69    llvm::raw_string_ostream OS(Str);
70    OS << "concrete memory address '" << I << "'";
71    return OS.str();
72  }
73
74  std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) {
75    return Visit(V.getSymbol());
76  }
77
78  std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
79    llvm::APSInt I = V.getValue();
80    std::string Str;
81    llvm::raw_string_ostream OS(Str);
82    OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
83       << "-bit integer '" << I << "'";
84    return OS.str();
85  }
86
87  std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
88    return "lazily frozen compound value of " + Visit(V.getRegion());
89  }
90
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);
98  }
99
100  std::string VisitSymbolConjured(const SymbolConjured *S) {
101    return "symbol of type '" + S->getType().getAsString() +
102           "' conjured at statement '" + printStmt(S->getStmt()) + "'";
103  }
104
105  std::string VisitSymbolDerived(const SymbolDerived *S) {
106    return "value derived from (" + Visit(S->getParentSymbol()) +
107           ") for " + Visit(S->getRegion());
108  }
109
110  std::string VisitSymbolExtent(const SymbolExtent *S) {
111    return "extent of " + Visit(S->getRegion());
112  }
113
114  std::string VisitSymbolMetadata(const SymbolMetadata *S) {
115    return "metadata of type '" + S->getType().getAsString() + "' tied to " +
116           Visit(S->getRegion());
117  }
118
119  std::string VisitSymIntExpr(const SymIntExpr *S) {
120    std::string Str;
121    llvm::raw_string_ostream OS(Str);
122    OS << "(" << Visit(S->getLHS()) << ") "
123       << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
124       << S->getRHS();
125    return OS.str();
126  }
127
128  // TODO: IntSymExpr doesn't appear in practice.
129  // Add the relevant code once it does.
130
131  std::string VisitSymSymExpr(const SymSymExpr *S) {
132    return "(" + Visit(S->getLHS()) + ") " +
133           std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
134           " (" + Visit(S->getRHS()) + ")";
135  }
136
137  // TODO: SymbolCast doesn't appear in practice.
138  // Add the relevant code once it does.
139
140  std::string VisitSymbolicRegion(const SymbolicRegion *R) {
141    // Explain 'this' object here.
142    // TODO: Explain CXXThisRegion itself, find a way to test it.
143    if (isThisObject(R))
144      return "'this' object";
145    return "pointee of " + Visit(R->getSymbol());
146  }
147
148  std::string VisitAllocaRegion(const AllocaRegion *R) {
149    return "region allocated by '" + printStmt(R->getExpr()) + "'";
150  }
151
152  std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) {
153    return "compound literal " + printStmt(R->getLiteralExpr());
154  }
155
156  std::string VisitStringRegion(const StringRegion *R) {
157    return "string literal " + R->getString();
158  }
159
160  std::string VisitElementRegion(const ElementRegion *R) {
161    std::string Str;
162    llvm::raw_string_ostream OS(Str);
163    OS << "element of type '" << R->getElementType().getAsString()
164       << "' with index ";
165    // For concrete index: omit type of the index integer.
166    if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
167      OS << I->getValue();
168    else
169      OS << "'" << Visit(R->getIndex()) << "'";
170    OS << " of " + Visit(R->getSuperRegion());
171    return OS.str();
172  }
173
174  std::string VisitVarRegion(const VarRegion *R) {
175    const VarDecl *VD = R->getDecl();
176    std::string Name = VD->getQualifiedNameAsString();
177    if (isa<ParmVarDecl>(VD))
178      return "parameter '" + Name + "'";
179    else if (VD->hasLocalStorage())
180      return "local variable '" + Name + "'";
181    else if (VD->isStaticLocal())
182      return "static local variable '" + Name + "'";
183    else if (VD->hasGlobalStorage())
184      return "global variable '" + Name + "'";
185    else
186      llvm_unreachable("A variable is either local or global");
187  }
188
189  std::string VisitFieldRegion(const FieldRegion *R) {
190    return "field '" + R->getDecl()->getNameAsString() + "' of " +
191           Visit(R->getSuperRegion());
192  }
193
194  std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) {
195    return "temporary object constructed at statement '" +
196           printStmt(R->getExpr()) + "'";
197  }
198
199  std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
200    return "base object '" + R->getDecl()->getQualifiedNameAsString() +
201           "' inside " + Visit(R->getSuperRegion());
202  }
203
204  std::string VisitSVal(SVal V) {
205    std::string Str;
206    llvm::raw_string_ostream OS(Str);
207    OS << V;
208    return "a value unsupported by the explainer: (" +
209           std::string(OS.str()) + ")";
210  }
211
212  std::string VisitSymExpr(SymbolRef S) {
213    std::string Str;
214    llvm::raw_string_ostream OS(Str);
215    S->dumpToStream(OS);
216    return "a symbolic expression unsupported by the explainer: (" +
217           std::string(OS.str()) + ")";
218  }
219
220  std::string VisitMemRegion(const MemRegion *R) {
221    std::string Str;
222    llvm::raw_string_ostream OS(Str);
223    OS << R;
224    return "a memory region unsupported by the explainer (" +
225           std::string(OS.str()) + ")";
226  }
227};
228
229} // end namespace ento
230
231} // end namespace clang
232
233#endif
234