r257893 - [analyzer] Provide .def-files and visitors for SVal/SymExpr/MemRegion, v2.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 15 07:22:05 PST 2016


Author: dergachev
Date: Fri Jan 15 09:22:05 2016
New Revision: 257893

URL: http://llvm.org/viewvc/llvm-project?rev=257893&view=rev
Log:
[analyzer] Provide .def-files and visitors for SVal/SymExpr/MemRegion, v2.

Provide separate visitor templates for the three hierarchies, and also
the `FullSValVisitor' class, which is a union of all three visitors.

Additionally, add a particular example visitor, `SValExplainer', in order to
test the visitor templates. This visitor is capable of explaining the SVal,
SymExpr, or MemRegion in a natural language.

Compared to the reverted r257605, this fixes the test that used to fail
on some triples, and fixes build failure under -fmodules.

Differential Revision: http://reviews.llvm.org/D15448

Added:
    cfe/trunk/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
    cfe/trunk/test/Analysis/explain-svals.cpp
Modified:
    cfe/trunk/docs/analyzer/DebugChecks.rst
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
    cfe/trunk/include/clang/module.modulemap
    cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp

Modified: cfe/trunk/docs/analyzer/DebugChecks.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/analyzer/DebugChecks.rst?rev=257893&r1=257892&r2=257893&view=diff
==============================================================================
--- cfe/trunk/docs/analyzer/DebugChecks.rst (original)
+++ cfe/trunk/docs/analyzer/DebugChecks.rst Fri Jan 15 09:22:05 2016
@@ -162,6 +162,41 @@ ExprInspection checks
     } while(0);  // expected-warning{{SYMBOL DEAD}}
 
 
+- void clang_analyzer_explain(a single argument of any type);
+
+  This function explains the value of its argument in a human-readable manner
+  in the warning message. You can make as many overrides of its prototype
+  in the test code as necessary to explain various integral, pointer,
+  or even record-type values.
+
+  Example usage::
+
+    void clang_analyzer_explain(int);
+    void clang_analyzer_explain(void *);
+
+    void foo(int param, void *ptr) {
+      clang_analyzer_explain(param); // expected-warning{{argument 'param'}}
+      if (!ptr)
+        clang_analyzer_explain(ptr); // expected-warning{{memory address '0'}}
+    }
+
+- size_t clang_analyzer_getExtent(void *);
+
+  This function returns the value that represents the extent of a memory region
+  pointed to by the argument. This value is often difficult to obtain otherwise,
+  because no valid code that produces this value. However, it may be useful
+  for testing purposes, to see how well does the analyzer model region extents.
+
+  Example usage::
+
+    void foo() {
+      int x, *y;
+      size_t xs = clang_analyzer_getExtent(&x);
+      clang_analyzer_explain(xs); // expected-warning{{'4'}}
+      size_t ys = clang_analyzer_getExtent(&y);
+      clang_analyzer_explain(ys); // expected-warning{{'8'}}
+    }
+
 Statistics
 ==========
 

Added: cfe/trunk/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Checkers/SValExplainer.h?rev=257893&view=auto
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Checkers/SValExplainer.h (added)
+++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/SValExplainer.h Fri Jan 15 09:22:05 2016
@@ -0,0 +1,233 @@
+//== SValExplainer.h - Symbolic value explainer -----------------*- C++ -*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines SValExplainer, a class for pretty-printing a
+//  human-readable description of a symbolic value. For example,
+//  "reg_$0<x>" is turned into "initial value of variable 'x'".
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
+#define LLVM_CLANG_STATICANALYZER_CHECKERS_SVALEXPLAINER_H
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
+
+namespace clang {
+
+namespace ento {
+
+class SValExplainer : public FullSValVisitor<SValExplainer, std::string> {
+private:
+  ASTContext &ACtx;
+
+  std::string printStmt(const Stmt *S) {
+    std::string Str;
+    llvm::raw_string_ostream OS(Str);
+    S->printPretty(OS, nullptr, PrintingPolicy(ACtx.getLangOpts()));
+    return OS.str();
+  }
+
+  bool isThisObject(const SymbolicRegion *R) {
+    if (auto S = dyn_cast<SymbolRegionValue>(R->getSymbol()))
+      if (isa<CXXThisRegion>(S->getRegion()))
+        return true;
+    return false;
+  }
+
+public:
+  SValExplainer(ASTContext &Ctx) : ACtx(Ctx) {}
+
+  std::string VisitUnknownVal(UnknownVal V) {
+    return "unknown value";
+  }
+
+  std::string VisitUndefinedVal(UndefinedVal V) {
+    return "undefined value";
+  }
+
+  std::string VisitLocMemRegionVal(loc::MemRegionVal V) {
+    const MemRegion *R = V.getRegion();
+    // Avoid the weird "pointer to pointee of ...".
+    if (auto SR = dyn_cast<SymbolicRegion>(R)) {
+      // However, "pointer to 'this' object" is fine.
+      if (!isThisObject(SR))
+        return Visit(SR->getSymbol());
+    }
+    return "pointer to " + Visit(R);
+  }
+
+  std::string VisitLocConcreteInt(loc::ConcreteInt V) {
+    llvm::APSInt I = V.getValue();
+    std::string Str;
+    llvm::raw_string_ostream OS(Str);
+    OS << "concrete memory address '" << I << "'";
+    return OS.str();
+  }
+
+  std::string VisitNonLocSymbolVal(nonloc::SymbolVal V) {
+    return Visit(V.getSymbol());
+  }
+
+  std::string VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
+    llvm::APSInt I = V.getValue();
+    std::string Str;
+    llvm::raw_string_ostream OS(Str);
+    OS << (I.isSigned() ? "signed " : "unsigned ") << I.getBitWidth()
+       << "-bit integer '" << I << "'";
+    return OS.str();
+  }
+
+  std::string VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
+    return "lazily frozen compound value of " + Visit(V.getRegion());
+  }
+
+  std::string VisitSymbolRegionValue(const SymbolRegionValue *S) {
+    const MemRegion *R = S->getRegion();
+    // Special handling for argument values.
+    if (auto V = dyn_cast<VarRegion>(R))
+      if (auto D = dyn_cast<ParmVarDecl>(V->getDecl()))
+        return "argument '" + D->getQualifiedNameAsString() + "'";
+    return "initial value of " + Visit(R);
+  }
+
+  std::string VisitSymbolConjured(const SymbolConjured *S) {
+    return "symbol of type '" + S->getType().getAsString() +
+           "' conjured at statement '" + printStmt(S->getStmt()) + "'";
+  }
+
+  std::string VisitSymbolDerived(const SymbolDerived *S) {
+    return "value derived from (" + Visit(S->getParentSymbol()) +
+           ") for " + Visit(S->getRegion());
+  }
+
+  std::string VisitSymbolExtent(const SymbolExtent *S) {
+    return "extent of " + Visit(S->getRegion());
+  }
+
+  std::string VisitSymbolMetadata(const SymbolMetadata *S) {
+    return "metadata of type '" + S->getType().getAsString() + "' tied to " +
+           Visit(S->getRegion());
+  }
+
+  std::string VisitSymIntExpr(const SymIntExpr *S) {
+    std::string Str;
+    llvm::raw_string_ostream OS(Str);
+    OS << "(" << Visit(S->getLHS()) << ") "
+       << std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) << " "
+       << S->getRHS();
+    return OS.str();
+  }
+
+  // TODO: IntSymExpr doesn't appear in practice.
+  // Add the relevant code once it does.
+
+  std::string VisitSymSymExpr(const SymSymExpr *S) {
+    return "(" + Visit(S->getLHS()) + ") " +
+           std::string(BinaryOperator::getOpcodeStr(S->getOpcode())) +
+           " (" + Visit(S->getRHS()) + ")";
+  }
+
+  // TODO: SymbolCast doesn't appear in practice.
+  // Add the relevant code once it does.
+
+  std::string VisitSymbolicRegion(const SymbolicRegion *R) {
+    // Explain 'this' object here.
+    // TODO: Explain CXXThisRegion itself, find a way to test it.
+    if (isThisObject(R))
+      return "'this' object";
+    return "pointee of " + Visit(R->getSymbol());
+  }
+
+  std::string VisitAllocaRegion(const AllocaRegion *R) {
+    return "region allocated by '" + printStmt(R->getExpr()) + "'";
+  }
+
+  std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) {
+    return "compound literal " + printStmt(R->getLiteralExpr());
+  }
+
+  std::string VisitStringRegion(const StringRegion *R) {
+    return "string literal " + R->getString();
+  }
+
+  std::string VisitElementRegion(const ElementRegion *R) {
+    std::string Str;
+    llvm::raw_string_ostream OS(Str);
+    OS << "element of type '" << R->getElementType().getAsString()
+       << "' with index ";
+    // For concrete index: omit type of the index integer.
+    if (auto I = R->getIndex().getAs<nonloc::ConcreteInt>())
+      OS << I->getValue();
+    else
+      OS << "'" << Visit(R->getIndex()) << "'";
+    OS << " of " + Visit(R->getSuperRegion());
+    return OS.str();
+  }
+
+  std::string VisitVarRegion(const VarRegion *R) {
+    const VarDecl *VD = R->getDecl();
+    std::string Name = VD->getQualifiedNameAsString();
+    if (isa<ParmVarDecl>(VD))
+      return "parameter '" + Name + "'";
+    else if (VD->hasLocalStorage())
+      return "local variable '" + Name + "'";
+    else if (VD->isStaticLocal())
+      return "static local variable '" + Name + "'";
+    else if (VD->hasGlobalStorage())
+      return "global variable '" + Name + "'";
+    else
+      llvm_unreachable("A variable is either local or global");
+  }
+
+  std::string VisitFieldRegion(const FieldRegion *R) {
+    return "field '" + R->getDecl()->getNameAsString() + "' of " +
+           Visit(R->getSuperRegion());
+  }
+
+  std::string VisitCXXTempObjectRegion(const CXXTempObjectRegion *R) {
+    return "temporary object constructed at statement '" +
+           printStmt(R->getExpr()) + "'";
+  }
+
+  std::string VisitCXXBaseObjectRegion(const CXXBaseObjectRegion *R) {
+    return "base object '" + R->getDecl()->getQualifiedNameAsString() +
+           "' inside " + Visit(R->getSuperRegion());
+  }
+
+  std::string VisitSVal(SVal V) {
+    std::string Str;
+    llvm::raw_string_ostream OS(Str);
+    OS << V;
+    return "a value unsupported by the explainer: (" +
+           std::string(OS.str()) + ")";
+  }
+
+  std::string VisitSymExpr(SymbolRef S) {
+    std::string Str;
+    llvm::raw_string_ostream OS(Str);
+    S->dumpToStream(OS);
+    return "a symbolic expression unsupported by the explainer: (" +
+           std::string(OS.str()) + ")";
+  }
+
+  std::string VisitMemRegion(const MemRegion *R) {
+    std::string Str;
+    llvm::raw_string_ostream OS(Str);
+    OS << R;
+    return "a memory region unsupported by the explainer (" +
+           std::string(OS.str()) + ")";
+  }
+};
+
+} // end namespace ento
+
+} // end namespace clang
+
+#endif

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h?rev=257893&r1=257892&r2=257893&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h Fri Jan 15 09:22:05 2016
@@ -76,51 +76,13 @@ public:
 
 /// MemRegion - The root abstract class for all memory regions.
 class MemRegion : public llvm::FoldingSetNode {
-  friend class MemRegionManager;
 public:
   enum Kind {
-    // Memory spaces.
-    CodeSpaceRegionKind,
-    StackLocalsSpaceRegionKind,
-    StackArgumentsSpaceRegionKind,
-    HeapSpaceRegionKind,
-    UnknownSpaceRegionKind,
-    StaticGlobalSpaceRegionKind,
-    GlobalInternalSpaceRegionKind,
-    GlobalSystemSpaceRegionKind,
-    GlobalImmutableSpaceRegionKind,
-    BEGIN_NON_STATIC_GLOBAL_MEMSPACES = GlobalInternalSpaceRegionKind,
-    END_NON_STATIC_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind,
-    BEGIN_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind,
-    END_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind,
-    BEGIN_MEMSPACES = CodeSpaceRegionKind,
-    END_MEMSPACES = GlobalImmutableSpaceRegionKind,
-    // Untyped regions.
-    SymbolicRegionKind,
-    AllocaRegionKind,
-    // Typed regions.
-    BEGIN_TYPED_REGIONS,
-    FunctionCodeRegionKind = BEGIN_TYPED_REGIONS,
-    BlockCodeRegionKind,
-    BlockDataRegionKind,
-    BEGIN_TYPED_VALUE_REGIONS,
-    CompoundLiteralRegionKind = BEGIN_TYPED_VALUE_REGIONS,
-    CXXThisRegionKind,
-    StringRegionKind,
-    ObjCStringRegionKind,
-    ElementRegionKind,
-    // Decl Regions.
-    BEGIN_DECL_REGIONS,
-    VarRegionKind = BEGIN_DECL_REGIONS,
-    FieldRegionKind,
-    ObjCIvarRegionKind,
-    END_DECL_REGIONS = ObjCIvarRegionKind,
-    CXXTempObjectRegionKind,
-    CXXBaseObjectRegionKind,
-    END_TYPED_VALUE_REGIONS = CXXBaseObjectRegionKind,
-    END_TYPED_REGIONS = CXXBaseObjectRegionKind
+#define REGION(Id, Parent) Id ## Kind,
+#define REGION_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last,
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
   };
-    
+
 private:
   const Kind kind;
 
@@ -386,8 +348,7 @@ public:
 
   static bool classof(const MemRegion *R) {
     Kind k = R->getKind();
-    return k >= StackLocalsSpaceRegionKind &&
-           k <= StackArgumentsSpaceRegionKind;
+    return k >= BEGIN_STACK_MEMSPACES && k <= END_STACK_MEMSPACES;
   }
 };
 
@@ -549,7 +510,7 @@ public:
 
   static bool classof(const MemRegion* R) {
     Kind k = R->getKind();
-    return k >= FunctionCodeRegionKind && k <= BlockCodeRegionKind;
+    return k >= BEGIN_CODE_TEXT_REGIONS && k <= END_CODE_TEXT_REGIONS;
   }
 };
 

Added: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def?rev=257893&view=auto
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def (added)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def Fri Jan 15 09:22:05 2016
@@ -0,0 +1,89 @@
+//===-- Regions.def - Metadata about MemRegion kinds ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of regions (MemRegion sub-classes) used in the Static Analyzer.
+// In order to use this information, users of this file must define one or more
+// of the three macros:
+//
+// REGION(Id, Parent) - for specific MemRegion sub-classes, reserving
+// enum value IdKind for their kind.
+//
+// ABSTRACT_REGION(Id, Parent) - for abstract region classes,
+//
+// REGION_RANGE(Id, First, Last) - for ranges of kind-enums,
+// allowing to determine abstract class of a region
+// based on the kind-enum value.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef REGION
+#define REGION(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_REGION
+#define ABSTRACT_REGION(Id, Parent)
+#endif
+
+#ifndef REGION_RANGE
+#define REGION_RANGE(Id, First, Last)
+#endif
+
+ABSTRACT_REGION(MemSpaceRegion, MemRegion)
+  REGION(CodeSpaceRegion, MemSpaceRegion)
+  ABSTRACT_REGION(GlobalsSpaceRegion, MemSpaceRegion)
+    ABSTRACT_REGION(NonStaticGlobalSpaceRegion, GlobalsSpaceRegion)
+      REGION(GlobalImmutableSpaceRegion, NonStaticGlobalSpaceRegion)
+      REGION(GlobalInternalSpaceRegion, NonStaticGlobalSpaceRegion)
+      REGION(GlobalSystemSpaceRegion, NonStaticGlobalSpaceRegion)
+      REGION_RANGE(NON_STATIC_GLOBAL_MEMSPACES, GlobalImmutableSpaceRegionKind,
+                                                GlobalSystemSpaceRegionKind)
+    REGION(StaticGlobalSpaceRegion, MemSpaceRegion)
+    REGION_RANGE(GLOBAL_MEMSPACES, GlobalImmutableSpaceRegionKind,
+                                   StaticGlobalSpaceRegionKind)
+  REGION(HeapSpaceRegion, MemSpaceRegion)
+  ABSTRACT_REGION(StackSpaceRegion, MemSpaceRegion)
+    REGION(StackArgumentsSpaceRegion, StackSpaceRegion)
+    REGION(StackLocalsSpaceRegion, StackSpaceRegion)
+    REGION_RANGE(STACK_MEMSPACES, StackArgumentsSpaceRegionKind,
+                                  StackLocalsSpaceRegionKind)
+  REGION(UnknownSpaceRegion, MemSpaceRegion)
+  REGION_RANGE(MEMSPACES, CodeSpaceRegionKind,
+                          UnknownSpaceRegionKind)
+ABSTRACT_REGION(SubRegion, MemRegion)
+  REGION(AllocaRegion, SubRegion)
+  REGION(SymbolicRegion, SubRegion)
+  ABSTRACT_REGION(TypedRegion, SubRegion)
+    REGION(BlockDataRegion, TypedRegion)
+    ABSTRACT_REGION(CodeTextRegion, TypedRegion)
+      REGION(BlockCodeRegion, CodeTextRegion)
+      REGION(FunctionCodeRegion, CodeTextRegion)
+      REGION_RANGE(CODE_TEXT_REGIONS, BlockCodeRegionKind,
+                                      FunctionCodeRegionKind)
+    ABSTRACT_REGION(TypedValueRegion, TypedRegion)
+      REGION(CompoundLiteralRegion, TypedValueRegion)
+      REGION(CXXBaseObjectRegion, TypedValueRegion)
+      REGION(CXXTempObjectRegion, TypedValueRegion)
+      REGION(CXXThisRegion, TypedValueRegion)
+      ABSTRACT_REGION(DeclRegion, TypedValueRegion)
+        REGION(FieldRegion, DeclRegion)
+        REGION(ObjCIvarRegion, DeclRegion)
+        REGION(VarRegion, DeclRegion)
+        REGION_RANGE(DECL_REGIONS, FieldRegionKind,
+                                   VarRegionKind)
+      REGION(ElementRegion, TypedValueRegion)
+      REGION(ObjCStringRegion, TypedValueRegion)
+      REGION(StringRegion, TypedValueRegion)
+      REGION_RANGE(TYPED_VALUE_REGIONS, CompoundLiteralRegionKind,
+                                        StringRegionKind)
+    REGION_RANGE(TYPED_REGIONS, BlockDataRegionKind,
+                                StringRegionKind)
+
+#undef REGION_RANGE
+#undef ABSTRACT_REGION
+#undef REGION

Added: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h?rev=257893&view=auto
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h (added)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h Fri Jan 15 09:22:05 2016
@@ -0,0 +1,151 @@
+//===--- SValVisitor.h - Visitor for SVal subclasses ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the SValVisitor, SymExprVisitor, and MemRegionVisitor
+//  interfaces, and also FullSValVisitor, which visits all three hierarchies.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALVISITOR_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+
+namespace clang {
+
+namespace ento {
+
+/// SValVisitor - this class implements a simple visitor for SVal
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class SValVisitor {
+public:
+
+#define DISPATCH(NAME, CLASS) \
+  return static_cast<ImplClass *>(this)->Visit ## NAME(V.castAs<CLASS>())
+
+  RetTy Visit(SVal V) {
+    // Dispatch to VisitFooVal for each FooVal.
+    // Take namespaces (loc:: and nonloc::) into account.
+    switch (V.getBaseKind()) {
+#define BASIC_SVAL(Id, Parent) case SVal::Id ## Kind: DISPATCH(Id, Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+    case SVal::LocKind:
+      switch (V.getSubKind()) {
+#define LOC_SVAL(Id, Parent) \
+      case loc::Id ## Kind: DISPATCH(Loc ## Id, loc :: Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+      }
+      llvm_unreachable("Unknown Loc sub-kind!");
+    case SVal::NonLocKind:
+      switch (V.getSubKind()) {
+#define NONLOC_SVAL(Id, Parent) \
+      case nonloc::Id ## Kind: DISPATCH(NonLoc ## Id, nonloc :: Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+      }
+      llvm_unreachable("Unknown NonLoc sub-kind!");
+    }
+    llvm_unreachable("Unknown SVal kind!");
+  }
+
+#define BASIC_SVAL(Id, Parent) \
+  RetTy Visit ## Id(Id V) { DISPATCH(Parent, Id); }
+#define ABSTRACT_SVAL(Id, Parent) \
+  BASIC_SVAL(Id, Parent)
+#define LOC_SVAL(Id, Parent) \
+  RetTy VisitLoc ## Id(loc::Id V) { DISPATCH(Parent, Parent); }
+#define NONLOC_SVAL(Id, Parent) \
+  RetTy VisitNonLoc ## Id(nonloc::Id V) { DISPATCH(Parent, Parent); }
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+
+  // Base case, ignore it. :)
+  RetTy VisitSVal(SVal V) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// SymExprVisitor - this class implements a simple visitor for SymExpr
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class SymExprVisitor {
+public:
+
+#define DISPATCH(CLASS) \
+    return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(S))
+
+  RetTy Visit(SymbolRef S) {
+    // Dispatch to VisitSymbolFoo for each SymbolFoo.
+    switch (S->getKind()) {
+#define SYMBOL(Id, Parent) \
+    case SymExpr::Id ## Kind: DISPATCH(Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
+    }
+    llvm_unreachable("Unknown SymExpr kind!");
+  }
+
+  // If the implementation chooses not to implement a certain visit method, fall
+  // back on visiting the superclass.
+#define SYMBOL(Id, Parent) RetTy Visit ## Id(const Id *S) { DISPATCH(Parent); }
+#define ABSTRACT_SYMBOL(Id, Parent) SYMBOL(Id, Parent)
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
+
+  // Base case, ignore it. :)
+  RetTy VisitSymExpr(SymbolRef S) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// MemRegionVisitor - this class implements a simple visitor for MemRegion
+/// subclasses.
+template <typename ImplClass, typename RetTy = void> class MemRegionVisitor {
+public:
+
+#define DISPATCH(CLASS) \
+  return static_cast<ImplClass *>(this)->Visit ## CLASS(cast<CLASS>(R))
+
+  RetTy Visit(const MemRegion *R) {
+    // Dispatch to VisitFooRegion for each FooRegion.
+    switch (R->getKind()) {
+#define REGION(Id, Parent) case MemRegion::Id ## Kind: DISPATCH(Id);
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
+    }
+    llvm_unreachable("Unknown MemRegion kind!");
+  }
+
+  // If the implementation chooses not to implement a certain visit method, fall
+  // back on visiting the superclass.
+#define REGION(Id, Parent) \
+  RetTy Visit ## Id(const Id *R) { DISPATCH(Parent); }
+#define ABSTRACT_REGION(Id, Parent) \
+  REGION(Id, Parent)
+#include "clang/StaticAnalyzer/Core/PathSensitive/Regions.def"
+
+  // Base case, ignore it. :)
+  RetTy VisitMemRegion(const MemRegion *R) { return RetTy(); }
+
+#undef DISPATCH
+};
+
+/// FullSValVisitor - a convenient mixed visitor for all three:
+/// SVal, SymExpr and MemRegion subclasses.
+template <typename ImplClass, typename RetTy = void>
+class FullSValVisitor : public SValVisitor<ImplClass, RetTy>,
+                        public SymExprVisitor<ImplClass, RetTy>,
+                        public MemRegionVisitor<ImplClass, RetTy> {
+public:
+  using SValVisitor<ImplClass, RetTy>::Visit;
+  using SymExprVisitor<ImplClass, RetTy>::Visit;
+  using MemRegionVisitor<ImplClass, RetTy>::Visit;
+};
+
+} // end namespace ento
+
+} // end namespace clang
+
+#endif

Added: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def?rev=257893&view=auto
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def (added)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.def Fri Jan 15 09:22:05 2016
@@ -0,0 +1,74 @@
+//===-- SVals.def - Metadata about SVal kinds -------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of symbolic values (SVal kinds and sub-kinds) used in the Static
+// Analyzer. The distinction between loc:: and nonloc:: SVal namespaces is
+// currently hardcoded, because it is too peculiar and explicit to be handled
+// uniformly. In order to use this information, users of this file must define
+// one or more of the following macros:
+//
+// BASIC_SVAL(Id, Parent) - for specific SVal sub-kinds, which are
+// neither in loc:: nor in nonloc:: namespace; these classes occupy
+// their own base kind IdKind.
+//
+// ABSTRACT_SVAL(Id, Parent) - for abstract SVal classes which are
+// neither in loc:: nor in nonloc:: namespace,
+//
+// ABSTRACT_SVAL_WITH_KIND(Id, Parent) - for SVal classes which are also
+// neither in loc:: nor in nonloc:: namespace, but occupy a whole base kind
+// identifier IdKind, much like BASIC_SVALs.
+//
+// LOC_SVAL(Id, Parent) - for values in loc:: namespace, which occupy a sub-kind
+// loc::IdKind.
+//
+// NONLOC_SVAL(Id, Parent) - for values in nonloc:: namespace, which occupy a
+// sub-kind nonloc::IdKind.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BASIC_SVAL
+#define BASIC_SVAL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SVAL
+#define ABSTRACT_SVAL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SVAL_WITH_KIND
+#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) ABSTRACT_SVAL(Id, Parent)
+#endif
+
+#ifndef LOC_SVAL
+#define LOC_SVAL(Id, Parent)
+#endif
+
+#ifndef NONLOC_SVAL
+#define NONLOC_SVAL(Id, Parent)
+#endif
+
+BASIC_SVAL(UndefinedVal, SVal)
+ABSTRACT_SVAL(DefinedOrUnknownSVal, SVal)
+  BASIC_SVAL(UnknownVal, DefinedOrUnknownSVal)
+  ABSTRACT_SVAL(DefinedSVal, DefinedOrUnknownSVal)
+    ABSTRACT_SVAL_WITH_KIND(Loc, DefinedSVal)
+      LOC_SVAL(ConcreteInt, Loc)
+      LOC_SVAL(GotoLabel, Loc)
+      LOC_SVAL(MemRegionVal, Loc)
+    ABSTRACT_SVAL_WITH_KIND(NonLoc, DefinedSVal)
+      NONLOC_SVAL(CompoundVal, NonLoc)
+      NONLOC_SVAL(ConcreteInt, NonLoc)
+      NONLOC_SVAL(LazyCompoundVal, NonLoc)
+      NONLOC_SVAL(LocAsInteger, NonLoc)
+      NONLOC_SVAL(SymbolVal, NonLoc)
+
+#undef NONLOC_SVAL
+#undef LOC_SVAL
+#undef ABSTRACT_SVAL_WITH_KIND
+#undef ABSTRACT_SVAL
+#undef BASIC_SVAL

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h?rev=257893&r1=257892&r2=257893&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h Fri Jan 15 09:22:05 2016
@@ -45,11 +45,9 @@ class SVal {
 public:
   enum BaseKind {
     // The enumerators must be representable using 2 bits.
-    UndefinedValKind = 0,  // for subclass UndefinedVal (an uninitialized value)
-    UnknownValKind = 1,    // for subclass UnknownVal (a void value)
-    LocKind = 2,        // for subclass Loc (an L-value)
-    NonLocKind = 3      // for subclass NonLoc (an R-value that's not
-                        //   an L-value)
+#define BASIC_SVAL(Id, Parent) Id ## Kind,
+#define ABSTRACT_SVAL_WITH_KIND(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
   };
   enum { BaseBits = 2, BaseMask = 0x3 };
 
@@ -306,8 +304,10 @@ private:
 
 namespace nonloc {
 
-enum Kind { ConcreteIntKind, SymbolValKind,
-            LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
+enum Kind {
+#define NONLOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
 
 /// \brief Represents symbolic expression.
 class SymbolVal : public NonLoc {
@@ -465,7 +465,10 @@ private:
 
 namespace loc {
 
-enum Kind { GotoLabelKind, MemRegionValKind, ConcreteIntKind };
+enum Kind {
+#define LOC_SVAL(Id, Parent) Id ## Kind,
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
+};
 
 class GotoLabel : public Loc {
 public:

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h?rev=257893&r1=257892&r2=257893&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h Fri Jan 15 09:22:05 2016
@@ -43,19 +43,9 @@ class SymExpr : public llvm::FoldingSetN
   virtual void anchor();
 public:
   enum Kind {
-    SymbolRegionValueKind,
-    SymbolConjuredKind,
-    SymbolDerivedKind,
-    SymbolExtentKind,
-    SymbolMetadataKind,
-    BEGIN_SYMBOLS = SymbolRegionValueKind,
-    END_SYMBOLS = SymbolMetadataKind,
-    SymIntExprKind,
-    IntSymExprKind,
-    SymSymExprKind,
-    BEGIN_BINARYSYMEXPRS = SymIntExprKind,
-    END_BINARYSYMEXPRS = SymSymExprKind,
-    SymbolCastKind
+#define SYMBOL(Id, Parent) Id ## Kind,
+#define SYMBOL_RANGE(Id, First, Last) BEGIN_##Id = First, END_##Id = Last,
+#include "clang/StaticAnalyzer/Core/PathSensitive/Symbols.def"
   };
 
 private:

Added: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def?rev=257893&view=auto
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def (added)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Symbols.def Fri Jan 15 09:22:05 2016
@@ -0,0 +1,55 @@
+//===-- Symbols.def - Metadata about SymExpr kinds --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The list of symbols (SymExpr sub-classes) used in the Static Analyzer.
+// In order to use this information, users of this file must define
+// one or more of the three macros:
+//
+// SYMBOL(Id, Parent) - for specific SymExpr sub-classes, reserving the
+// IdKind identifier for its kind enumeration value.
+//
+// ABSTRACT_SYMBOL(Id, Parent) - for abstract symbol classes,
+//
+// SYMBOL_RANGE(Id, First, Last) - for ranges of kind-enums,
+// allowing to determine abstract class of a symbol
+// based on the kind enumeration value.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SYMBOL
+#define SYMBOL(Id, Parent)
+#endif
+
+#ifndef ABSTRACT_SYMBOL
+#define ABSTRACT_SYMBOL(Id, Parent)
+#endif
+
+#ifndef SYMBOL_RANGE
+#define SYMBOL_RANGE(Id, First, Last)
+#endif
+
+ABSTRACT_SYMBOL(BinarySymExpr, SymExpr)
+  SYMBOL(IntSymExpr, BinarySymExpr)
+  SYMBOL(SymIntExpr, BinarySymExpr)
+  SYMBOL(SymSymExpr, BinarySymExpr)
+SYMBOL_RANGE(BINARYSYMEXPRS, IntSymExprKind, SymSymExprKind)
+
+SYMBOL(SymbolCast, SymExpr)
+
+ABSTRACT_SYMBOL(SymbolData, SymExpr)
+  SYMBOL(SymbolConjured, SymbolData)
+  SYMBOL(SymbolDerived, SymbolData)
+  SYMBOL(SymbolExtent, SymbolData)
+  SYMBOL(SymbolMetadata, SymbolData)
+  SYMBOL(SymbolRegionValue, SymbolData)
+SYMBOL_RANGE(SYMBOLS, SymbolConjuredKind, SymbolRegionValueKind)
+
+#undef SYMBOL
+#undef ABSTRACT_SYMBOL
+#undef SYMBOL_RANGE

Modified: cfe/trunk/include/clang/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/module.modulemap?rev=257893&r1=257892&r2=257893&view=diff
==============================================================================
--- cfe/trunk/include/clang/module.modulemap (original)
+++ cfe/trunk/include/clang/module.modulemap Fri Jan 15 09:22:05 2016
@@ -108,6 +108,9 @@ module Clang_StaticAnalyzer_Core {
   umbrella "StaticAnalyzer/Core"
 
   textual header "StaticAnalyzer/Core/Analyses.def"
+  textual header "StaticAnalyzer/Core/PathSensitive/SVals.def"
+  textual header "StaticAnalyzer/Core/PathSensitive/Symbols.def"
+  textual header "StaticAnalyzer/Core/PathSensitive/Regions.def"
 
   module * { export * }
 }

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp?rev=257893&r1=257892&r2=257893&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp Fri Jan 15 09:22:05 2016
@@ -11,6 +11,7 @@
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Checkers/SValExplainer.h"
 #include "llvm/ADT/StringSwitch.h"
 
 using namespace clang;
@@ -25,17 +26,21 @@ class ExprInspectionChecker : public Che
   void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const;
   void analyzerCrash(const CallExpr *CE, CheckerContext &C) const;
   void analyzerWarnOnDeadSymbol(const CallExpr *CE, CheckerContext &C) const;
+  void analyzerExplain(const CallExpr *CE, CheckerContext &C) const;
+  void analyzerGetExtent(const CallExpr *CE, CheckerContext &C) const;
 
   typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
                                                  CheckerContext &C) const;
 
+  void reportBug(llvm::StringRef Msg, CheckerContext &C) const;
+
 public:
   bool evalCall(const CallExpr *CE, CheckerContext &C) const;
   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
 };
 }
 
-REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols, const void *)
+REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols, SymbolRef)
 
 bool ExprInspectionChecker::evalCall(const CallExpr *CE,
                                      CheckerContext &C) const {
@@ -50,6 +55,8 @@ bool ExprInspectionChecker::evalCall(con
           &ExprInspectionChecker::analyzerWarnIfReached)
     .Case("clang_analyzer_warnOnDeadSymbol",
           &ExprInspectionChecker::analyzerWarnOnDeadSymbol)
+    .Case("clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain)
+    .Case("clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent)
     .Default(nullptr);
 
   if (!Handler)
@@ -91,6 +98,18 @@ static const char *getArgumentValueStrin
   }
 }
 
+void ExprInspectionChecker::reportBug(llvm::StringRef Msg,
+                                      CheckerContext &C) const {
+  if (!BT)
+    BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
+
+  ExplodedNode *N = C.generateNonFatalErrorNode();
+  if (!N)
+    return;
+
+  C.emitReport(llvm::make_unique<BugReport>(*BT, Msg, N));
+}
+
 void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
                                          CheckerContext &C) const {
   const LocationContext *LC = C.getPredecessor()->getLocationContext();
@@ -100,26 +119,12 @@ void ExprInspectionChecker::analyzerEval
   if (LC->getCurrentStackFrame()->getParent() != nullptr)
     return;
 
-  if (!BT)
-    BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
-
-  ExplodedNode *N = C.generateNonFatalErrorNode();
-  if (!N)
-    return;
-  C.emitReport(
-      llvm::make_unique<BugReport>(*BT, getArgumentValueString(CE, C), N));
+  reportBug(getArgumentValueString(CE, C), C);
 }
 
 void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE,
                                                   CheckerContext &C) const {
-
-  if (!BT)
-    BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
-
-  ExplodedNode *N = C.generateNonFatalErrorNode();
-  if (!N)
-    return;
-  C.emitReport(llvm::make_unique<BugReport>(*BT, "REACHABLE", N));
+  reportBug("REACHABLE", C);
 }
 
 void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
@@ -134,14 +139,32 @@ void ExprInspectionChecker::analyzerChec
   if (LC->getCurrentStackFrame()->getParent() == nullptr)
     return;
 
-  if (!BT)
-    BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
+  reportBug(getArgumentValueString(CE, C), C);
+}
 
-  ExplodedNode *N = C.generateNonFatalErrorNode();
-  if (!N)
-    return;
-  C.emitReport(
-      llvm::make_unique<BugReport>(*BT, getArgumentValueString(CE, C), N));
+void ExprInspectionChecker::analyzerExplain(const CallExpr *CE,
+                                            CheckerContext &C) const {
+  if (CE->getNumArgs() == 0)
+    reportBug("Missing argument for explaining", C);
+
+  SVal V = C.getSVal(CE->getArg(0));
+  SValExplainer Ex(C.getASTContext());
+  reportBug(Ex.Visit(V), C);
+}
+
+void ExprInspectionChecker::analyzerGetExtent(const CallExpr *CE,
+                                              CheckerContext &C) const {
+  if (CE->getNumArgs() == 0)
+    reportBug("Missing region for obtaining extent", C);
+
+  auto MR = dyn_cast_or_null<SubRegion>(C.getSVal(CE->getArg(0)).getAsRegion());
+  if (!MR)
+    reportBug("Obtaining extent of a non-region", C);
+
+  ProgramStateRef State = C.getState();
+  State = State->BindExpr(CE, C.getLocationContext(),
+                          MR->getExtent(C.getSValBuilder()));
+  C.addTransition(State);
 }
 
 void ExprInspectionChecker::analyzerWarnOnDeadSymbol(const CallExpr *CE,
@@ -163,20 +186,14 @@ void ExprInspectionChecker::checkDeadSym
   ProgramStateRef State = C.getState();
   const MarkedSymbolsTy &Syms = State->get<MarkedSymbols>();
   for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) {
-    SymbolRef Sym = static_cast<SymbolRef>(*I);
+    SymbolRef Sym = *I;
     if (!SymReaper.isDead(Sym))
       continue;
 
-    if (!BT)
-      BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
-
-    ExplodedNode *N = C.generateNonFatalErrorNode();
-    if (!N)
-      return;
-
-    C.emitReport(llvm::make_unique<BugReport>(*BT, "SYMBOL DEAD", N));
-    C.addTransition(State->remove<MarkedSymbols>(Sym), N);
+    reportBug("SYMBOL DEAD", C);
+    State = State->remove<MarkedSymbols>(Sym);
   }
+  C.addTransition(State);
 }
 
 void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,

Added: cfe/trunk/test/Analysis/explain-svals.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/explain-svals.cpp?rev=257893&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/explain-svals.cpp (added)
+++ cfe/trunk/test/Analysis/explain-svals.cpp Fri Jan 15 09:22:05 2016
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection,unix.cstring -verify %s
+
+typedef unsigned long size_t;
+
+struct S {
+  struct S3 {
+    int y[10];
+  };
+  struct S2 : S3 {
+    int *x;
+  } s2[10];
+  int z;
+};
+
+
+void clang_analyzer_explain(int);
+void clang_analyzer_explain(void *);
+void clang_analyzer_explain(S);
+
+size_t clang_analyzer_getExtent(void *);
+
+size_t strlen(const char *);
+
+int conjure();
+S conjure_S();
+
+int glob;
+static int stat_glob;
+void *glob_ptr;
+
+// Test strings are regex'ed because we need to match exact string
+// rather than a substring.
+
+void test_1(int param, void *ptr) {
+  clang_analyzer_explain(&glob); // expected-warning-re{{{{^pointer to global variable 'glob'$}}}}
+  clang_analyzer_explain(param); // expected-warning-re{{{{^argument 'param'$}}}}
+  clang_analyzer_explain(ptr); // expected-warning-re{{{{^argument 'ptr'$}}}}
+  if (param == 42)
+    clang_analyzer_explain(param); // expected-warning-re{{{{^signed 32-bit integer '42'$}}}}
+}
+
+void test_2(char *ptr, int ext) {
+  clang_analyzer_explain((void *) "asdf"); // expected-warning-re{{{{^pointer to element of type 'char' with index 0 of string literal "asdf"$}}}}
+  clang_analyzer_explain(strlen(ptr)); // expected-warning-re{{{{^metadata of type 'unsigned long' tied to pointee of argument 'ptr'$}}}}
+  clang_analyzer_explain(conjure()); // expected-warning-re{{{{^symbol of type 'int' conjured at statement 'conjure\(\)'$}}}}
+  clang_analyzer_explain(glob); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob'$}}}}
+  clang_analyzer_explain(glob_ptr); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob_ptr'$}}}}
+  clang_analyzer_explain(clang_analyzer_getExtent(ptr)); // expected-warning-re{{{{^extent of pointee of argument 'ptr'$}}}}
+  int *x = new int[ext];
+  clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of pointee of symbol of type 'int \*' conjured at statement 'new int \[ext\]'$}}}}
+  // Sic! What gets computed is the extent of the element-region.
+  clang_analyzer_explain(clang_analyzer_getExtent(x)); // expected-warning-re{{{{^signed 32-bit integer '4'$}}}}
+  delete[] x;
+}
+
+void test_3(S s) {
+  clang_analyzer_explain(&s); // expected-warning-re{{{{^pointer to parameter 's'$}}}}
+  clang_analyzer_explain(s.z); // expected-warning-re{{{{^initial value of field 'z' of parameter 's'$}}}}
+  clang_analyzer_explain(&s.s2[5].y[3]); // expected-warning-re{{{{^pointer to element of type 'int' with index 3 of field 'y' of base object 'S::S3' inside element of type 'struct S::S2' with index 5 of field 's2' of parameter 's'$}}}}
+  if (!s.s2[7].x) {
+    clang_analyzer_explain(s.s2[7].x); // expected-warning-re{{{{^concrete memory address '0'$}}}}
+    // FIXME: we need to be explaining '1' rather than '0' here; not explainer bug.
+    clang_analyzer_explain(s.s2[7].x + 1); // expected-warning-re{{{{^concrete memory address '0'$}}}}
+  }
+}
+
+void test_4(int x, int y) {
+  int z;
+  static int stat;
+  clang_analyzer_explain(x + 1); // expected-warning-re{{{{^\(argument 'x'\) \+ 1$}}}}
+  clang_analyzer_explain(1 + y); // expected-warning-re{{{{^\(argument 'y'\) \+ 1$}}}}
+  clang_analyzer_explain(x + y); // expected-warning-re{{{{^unknown value$}}}}
+  clang_analyzer_explain(z); // expected-warning-re{{{{^undefined value$}}}}
+  clang_analyzer_explain(&z); // expected-warning-re{{{{^pointer to local variable 'z'$}}}}
+  clang_analyzer_explain(stat); // expected-warning-re{{{{^signed 32-bit integer '0'$}}}}
+  clang_analyzer_explain(&stat); // expected-warning-re{{{{^pointer to static local variable 'stat'$}}}}
+  clang_analyzer_explain(stat_glob); // expected-warning-re{{{{^initial value of global variable 'stat_glob'$}}}}
+  clang_analyzer_explain(&stat_glob); // expected-warning-re{{{{^pointer to global variable 'stat_glob'$}}}}
+  clang_analyzer_explain((int[]){1, 2, 3}); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of compound literal \(int \[3\]\)\{1, 2, 3\}$}}}}
+}
+
+namespace {
+class C {
+  int x[10];
+
+public:
+  void test_5(int i) {
+    clang_analyzer_explain(this); // expected-warning-re{{{{^pointer to 'this' object$}}}}
+    clang_analyzer_explain(&x[i]); // expected-warning-re{{{{^pointer to element of type 'int' with index 'argument 'i'' of field 'x' of 'this' object$}}}}
+    clang_analyzer_explain(__builtin_alloca(i)); // expected-warning-re{{{{^pointer to region allocated by '__builtin_alloca\(i\)'$}}}}
+  }
+};
+} // end of anonymous namespace
+
+void test_6() {
+  clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^lazily frozen compound value of temporary object constructed at statement 'conjure_S\(\)'$}}}}
+  clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'struct S' conjured at statement 'conjure_S\(\)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}}
+}




More information about the cfe-commits mailing list