File indexing completed on 2026-05-10 08:37:06
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
0016 #define LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
0017
0018 #include "clang/AST/Attr.h"
0019 #include "clang/AST/DeclCXX.h"
0020 #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
0021 #include "llvm/ADT/StringExtras.h"
0022
0023 namespace clang {
0024
0025 namespace ento {
0026
0027 class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
0028 private:
0029 ASTContext &ACtx;
0030
0031 std::string printStmt(const Stmt *S) {
0032 std::string Str;
0033 llvm::raw_string_ostream OS(Str);
0034 S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
0035 return Str;
0036 }
0037
0038 bool isThisObject(const SymbolicRegion *R) {
0039 if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
0040 if (isa<CXXThisRegion>(S->getRegion()))
0041 return true;
0042 return false;
0043 }
0044
0045 bool isThisObject(const ElementRegion *R) {
0046 if (const auto *Idx = R->getIndex().getAsInteger()) {
0047 if (const auto *SR = R->getSuperRegion()->getAs<SymbolicRegion>()) {
0048 QualType Ty = SR->getPointeeStaticType();
0049 bool IsNotReinterpretCast = R->getValueType() == Ty;
0050 if (Idx->isZero() && IsNotReinterpretCast)
0051 return isThisObject(SR);
0052 }
0053 }
0054 return false;
0055 }
0056
0057 public:
0058 SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
0059
0060 std::string VisitUnknownVal(UnknownVal V) {
0061 return "unknown value";
0062 }
0063
0064 std::string VisitUndefinedVal(UndefinedVal V) {
0065 return "undefined value";
0066 }
0067
0068 std::string VisitMemRegionVal(loc::MemRegionVal V) {
0069 const MemRegion *R = V.getRegion();
0070
0071 if (auto SR = dyn_cast<SymbolicRegion>(R)) {
0072
0073 if (!isThisObject(SR))
0074 return Visit(SR->getSymbol());
0075 }
0076 return "pointer to " + Visit(R);
0077 }
0078
0079 std::string VisitConcreteInt(loc::ConcreteInt V) {
0080 const llvm::APSInt &I = V.getValue();
0081 std::string Str;
0082 llvm::raw_string_ostream OS(Str);
0083 OS << "concrete memory address '" << I << "'";
0084 return Str;
0085 }
0086
0087 std::string VisitSymbolVal(nonloc::SymbolVal V) {
0088 return Visit(V.getSymbol());
0089 }
0090
0091 std::string VisitConcreteInt(nonloc::ConcreteInt V) {
0092 const llvm::APSInt &I = V.getValue();
0093 std::string Str;
0094 llvm::raw_string_ostream OS(Str);
0095 OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
0096 << "-bit integer '" << I << "'";
0097 return Str;
0098 }
0099
0100 std::string VisitLazyCompoundVal(nonloc::LazyCompoundVal V) {
0101 return "lazily frozen compound value of " + Visit(V.getRegion());
0102 }
0103
0104 std::string VisitSymbolRegionValue(const SymbolRegionValue *S) {
0105 const MemRegion *R = S->getRegion();
0106
0107 if (auto V = dyn_cast<VarRegion>(R))
0108 if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
0109 return "argument '" + D->getQualifiedNameAsString() + "'";
0110 return "initial value of " + Visit(R);
0111 }
0112
0113 std::string VisitSymbolConjured(const SymbolConjured *S) {
0114 return "symbol of type '" + S->getType().getAsString() +
0115 "' conjured at statement '" + printStmt(S->getStmt()) + "'";
0116 }
0117
0118 std::string VisitSymbolDerived(const SymbolDerived *S) {
0119 return "value derived from (" + Visit(S->getParentSymbol()) +
0120 ") for " + Visit(S->getRegion());
0121 }
0122
0123 std::string VisitSymbolExtent(const SymbolExtent *S) {
0124 return "extent of " + Visit(S->getRegion());
0125 }
0126
0127 std::string VisitSymbolMetadata(const SymbolMetadata *S) {
0128 return "metadata of type '" + S->getType().getAsString() + "' tied to " +
0129 Visit(S->getRegion());
0130 }
0131
0132 std::string VisitSymIntExpr(const SymIntExpr *S) {
0133 std::string Str;
0134 llvm::raw_string_ostream OS(Str);
0135 OS << "(" << Visit(S->getLHS()) << ") "
0136 << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
0137 << S->getRHS();
0138 return Str;
0139 }
0140
0141
0142
0143
0144 std::string VisitSymSymExpr(const SymSymExpr *S) {
0145 return "(" + Visit(S->getLHS()) + ") " +
0146 std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
0147 " (" + Visit(S->getRHS()) + ")";
0148 }
0149
0150 std::string VisitUnarySymExpr(const UnarySymExpr *S) {
0151 return std::string(UnaryOperator::getOpcodeStr(S->getOpcode())) + " (" +
0152 Visit(S->getOperand()) + ")";
0153 }
0154
0155
0156
0157
0158 std::string VisitSymbolicRegion(const SymbolicRegion *R) {
0159
0160
0161 if (isThisObject(R))
0162 return "'this' object";
0163
0164
0165 if (R->getSymbol()->getType()
0166 .getCanonicalType()->getAs<ObjCObjectPointerType>())
0167 return "object at " + Visit(R->getSymbol());
0168
0169 if (isa<HeapSpaceRegion>(R->getMemorySpace()))
0170 return "heap segment that starts at " + Visit(R->getSymbol());
0171 return "pointee of " + Visit(R->getSymbol());
0172 }
0173
0174 std::string VisitAllocaRegion(const AllocaRegion *R) {
0175 return "region allocated by '" + printStmt(R->getExpr()) + "'";
0176 }
0177
0178 std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) {
0179 return "compound literal " + printStmt(R->getLiteralExpr());
0180 }
0181
0182 std::string VisitStringRegion(const StringRegion *R) {
0183 return "string literal " + R->getString();
0184 }
0185
0186 std::string VisitElementRegion(const ElementRegion *R) {
0187 std::string Str;
0188 llvm::raw_string_ostream OS(Str);
0189
0190
0191
0192
0193 if (isThisObject(R))
0194 return "'this' object";
0195
0196 OS << "element of type '" << R->getElementType() << "' with index ";
0197
0198 if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
0199 OS << I->getValue();
0200 else
0201 OS << "'" << Visit(R->getIndex()) << "'";
0202 OS << " of " + Visit(R->getSuperRegion());
0203 return Str;
0204 }
0205
0206 std::string VisitNonParamVarRegion(const NonParamVarRegion *R) {
0207 const VarDecl *VD = R->getDecl();
0208 std::string Name = VD->getQualifiedNameAsString();
0209 if (isa<ParmVarDecl>(VD))
0210 return "parameter '" + Name + "'";
0211 else if (VD->hasAttr<BlocksAttr>())
0212 return "block variable '" + Name + "'";
0213 else if (VD->hasLocalStorage())
0214 return "local variable '" + Name + "'";
0215 else if (VD->isStaticLocal())
0216 return "static local variable '" + Name + "'";
0217 else if (VD->hasGlobalStorage())
0218 return "global variable '" + Name + "'";
0219 else
0220 llvm_unreachable("A variable is either local or global");
0221 }
0222
0223 std::string VisitObjCIvarRegion(const ObjCIvarRegion *R) {
0224 return "instance variable '" + R->getDecl()->getNameAsString() + "' of " +
0225 Visit(R->getSuperRegion());
0226 }
0227
0228 std::string VisitFieldRegion(const FieldRegion *R) {
0229 return "field '" + R->getDecl()->getNameAsString() + "' of " +
0230 Visit(R->getSuperRegion());
0231 }
0232
0233 std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) {
0234 return "temporary object constructed at statement '" +
0235 printStmt(R->getExpr()) + "'";
0236 }
0237
0238 std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
0239 return "base object '" + R->getDecl()->getQualifiedNameAsString() +
0240 "' inside " + Visit(R->getSuperRegion());
0241 }
0242
0243 std::string VisitParamVarRegion(const ParamVarRegion *R) {
0244 std::string Str;
0245 llvm::raw_string_ostream OS(Str);
0246
0247 const ParmVarDecl *PVD = R->getDecl();
0248 std::string Name = PVD->getQualifiedNameAsString();
0249 if (!Name.empty()) {
0250 OS << "parameter '" << Name << "'";
0251 return std::string(OS.str());
0252 }
0253
0254 unsigned Index = R->getIndex() + 1;
0255 OS << Index << llvm::getOrdinalSuffix(Index) << " parameter of ";
0256 const Decl *Parent = R->getStackFrame()->getDecl();
0257 if (const auto *FD = dyn_cast<FunctionDecl>(Parent))
0258 OS << "function '" << FD->getQualifiedNameAsString() << "()'";
0259 else if (const auto *CD = dyn_cast<CXXConstructorDecl>(Parent))
0260 OS << "C++ constructor '" << CD->getQualifiedNameAsString() << "()'";
0261 else if (const auto *MD = dyn_cast<ObjCMethodDecl>(Parent)) {
0262 if (MD->isClassMethod())
0263 OS << "Objective-C method '+" << MD->getQualifiedNameAsString() << "'";
0264 else
0265 OS << "Objective-C method '-" << MD->getQualifiedNameAsString() << "'";
0266 } else if (isa<BlockDecl>(Parent)) {
0267 if (cast<BlockDecl>(Parent)->isConversionFromLambda())
0268 OS << "lambda";
0269 else
0270 OS << "block";
0271 }
0272
0273 return std::string(OS.str());
0274 }
0275
0276 std::string VisitSVal(SVal V) {
0277 std::string Str;
0278 llvm::raw_string_ostream OS(Str);
0279 OS << V;
0280 return "a value unsupported by the explainer: (" +
0281 std::string(OS.str()) + ")";
0282 }
0283
0284 std::string VisitSymExpr(SymbolRef S) {
0285 std::string Str;
0286 llvm::raw_string_ostream OS(Str);
0287 S->dumpToStream(OS);
0288 return "a symbolic expression unsupported by the explainer: (" +
0289 std::string(OS.str()) + ")";
0290 }
0291
0292 std::string VisitMemRegion(const MemRegion *R) {
0293 std::string Str;
0294 llvm::raw_string_ostream OS(Str);
0295 OS << R;
0296 return "a memory region unsupported by the explainer (" +
0297 std::string(OS.str()) + ")";
0298 }
0299 };
0300
0301 }
0302
0303 }
0304
0305 #endif