28 using namespace clang;
32 class DynamicTypeChecker :
public Checker<check::PostStmt<ImplicitCastExpr>> {
33 mutable std::unique_ptr<BugType> BT;
34 void initBugType()
const {
37 new BugType(
this,
"Dynamic and static type mismatch",
"Type Error"));
42 DynamicTypeBugVisitor(
const MemRegion *Reg) : Reg(Reg) {}
44 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
50 std::shared_ptr<PathDiagnosticPiece> VisitNode(
const ExplodedNode *N,
51 BugReporterContext &BRC,
52 BugReport &BR)
override;
60 const MemRegion *Reg,
const Stmt *ReportedNode,
61 CheckerContext &C)
const;
71 const Stmt *ReportedNode,
72 CheckerContext &C)
const {
75 llvm::raw_svector_ostream
OS(Buf);
76 OS <<
"Object has a dynamic type '";
79 OS <<
"' which is incompatible with static type '";
83 std::unique_ptr<BugReport> R(
84 new BugReport(*BT, OS.str(), C.generateNonFatalErrorNode()));
85 R->markInteresting(Reg);
86 R->addVisitor(llvm::make_unique<DynamicTypeBugVisitor>(Reg));
88 C.emitReport(std::move(R));
91 std::shared_ptr<PathDiagnosticPiece>
92 DynamicTypeChecker::DynamicTypeBugVisitor::VisitNode(
const ExplodedNode *N,
93 BugReporterContext &BRC,
100 if (!TrackedType.isValid())
103 if (TrackedTypePrev.isValid() &&
104 TrackedTypePrev.getType() == TrackedType.getType())
112 const LangOptions &LangOpts = BRC.getASTContext().getLangOpts();
115 llvm::raw_svector_ostream
OS(Buf);
118 LangOpts, llvm::Twine());
119 OS <<
"' is inferred from ";
121 if (
const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) {
122 OS <<
"explicit cast (from '";
127 LangOpts, llvm::Twine());
129 }
else if (
const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) {
130 OS <<
"implicit cast (from '";
135 LangOpts, llvm::Twine());
138 OS <<
"this context";
142 PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
143 N->getLocationContext());
144 return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(),
true,
158 CheckerContext &C)
const {
163 const MemRegion *Region = C.getSVal(CE).getAsRegion();
170 if (!DynTypeInfo.isValid())
173 QualType DynType = DynTypeInfo.getType();
179 if (!DynObjCType || !StaticObjCType)
188 DynObjCType = DynObjCType->stripObjCKindOfTypeAndQuals(ASTCtxt);
198 if (DynTypeInfo.canBeASubClass() &&
202 reportTypeError(DynType, StaticType, Region, CE, C);
205 void ento::registerDynamicTypeChecker(CheckerManager &mgr) {
206 mgr.registerChecker<DynamicTypeChecker>();
209 bool ento::shouldRegisterDynamicTypeChecker(
const LangOptions &LO) {
A (possibly-)qualified type.
Stmt - This represents one statement.
Decl - This represents one declaration (or definition), e.g.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const T * getAs() const
Member-template getAs<specific type>'.
The collection of all-type qualifiers we support.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
bool isSpecialized() const
Whether this type is specialized, meaning that it has type arguments.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
const ObjCObjectPointerType * stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const
Strip off the Objective-C "kindof" type and (with it) any protocol qualifiers.
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Represents an ObjC class declaration.
static bool hasDefinition(const ObjCObjectPointerType *ObjPtr)
static const Stmt * getStmt(const ExplodedNode *N)
Given an exploded node, retrieve the statement that should be used for the diagnostic location...
CastKind getCastKind() const
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Dataflow Directional Tag Classes.
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg)
Get dynamic type information for a region.
ObjCInterfaceDecl * getDefinition()
Retrieve the definition of this class, or NULL if this class has been forward-declared (with @class) ...
Represents a pointer to an Objective C object.
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
ObjCInterfaceDecl * getInterfaceDecl() const
If this pointer points to an Objective @interface type, gets the declaration for that interface...
bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT)
canAssignObjCInterfaces - Return true if the two interface types are compatible for assignment from R...
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...