Index: include/clang/StaticAnalyzer/Checkers/SValExplainer.h =================================================================== --- include/clang/StaticAnalyzer/Checkers/SValExplainer.h +++ include/clang/StaticAnalyzer/Checkers/SValExplainer.h @@ -142,6 +142,14 @@ // TODO: Explain CXXThisRegion itself, find a way to test it. if (isThisObject(R)) return "'this' object"; + // Objective-C objects are not normal symbolic regions. At least, + // they're always on the heap. + if (R->getSymbol()->getType() + .getCanonicalType()->getAs()) + return "object at " + Visit(R->getSymbol()); + // Other heap-based symbolic regions are also special. + if (isa(R->getMemorySpace())) + return "heap segment that starts at " + Visit(R->getSymbol()); return "pointee of " + Visit(R->getSymbol()); } @@ -176,6 +184,8 @@ std::string Name = VD->getQualifiedNameAsString(); if (isa(VD)) return "parameter '" + Name + "'"; + else if (VD->hasAttr()) + return "block variable '" + Name + "'"; else if (VD->hasLocalStorage()) return "local variable '" + Name + "'"; else if (VD->isStaticLocal()) @@ -186,6 +196,11 @@ llvm_unreachable("A variable is either local or global"); } + std::string VisitObjCIvarRegion(const ObjCIvarRegion *R) { + return "instance variable '" + R->getDecl()->getNameAsString() + "' of " + + Visit(R->getSuperRegion()); + } + std::string VisitFieldRegion(const FieldRegion *R) { return "field '" + R->getDecl()->getNameAsString() + "' of " + Visit(R->getSuperRegion()); Index: test/Analysis/explain-svals.cpp =================================================================== --- test/Analysis/explain-svals.cpp +++ test/Analysis/explain-svals.cpp @@ -47,7 +47,7 @@ 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\]'$}}}} + clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of heap segment that starts at 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; Index: test/Analysis/explain-svals.m =================================================================== --- /dev/null +++ test/Analysis/explain-svals.m @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -w -triple i386-apple-darwin10 -fblocks -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s + +#include "Inputs/system-header-simulator-objc.h" + +void clang_analyzer_explain(void *); + +@interface Object : NSObject { +@public + Object *x; +} +@end + +void test_1(Object *p) { + clang_analyzer_explain(p); // expected-warning-re{{{{^argument 'p'$}}}} + clang_analyzer_explain(p->x); // expected-warning-re{{{{^initial value of instance variable 'x' of object at argument 'p'$}}}} + Object *q = [[Object alloc] init]; + clang_analyzer_explain(q); // expected-warning-re{{{{^symbol of type 'Object \*' conjured at statement '\[\[Object alloc\] init\]'$}}}} + clang_analyzer_explain(q->x); // expected-warning-re{{{{^initial value of instance variable 'x' of object at symbol of type 'Object \*' conjured at statement '\[\[Object alloc\] init\]'$}}}} +} + +void test_2() { + __block int x; + ^{ + clang_analyzer_explain(&x); // expected-warning-re{{{{^pointer to block variable 'x'$}}}} + }; + clang_analyzer_explain(&x); // expected-warning-re{{{{^pointer to block variable 'x'$}}}} +}