34#include "llvm/ADT/STLExtras.h"
52class DynamicTypePropagation
53 :
public CheckerFamily<check::PreCall, check::PostCall, check::DeadSymbols,
54 check::PostStmt<CastExpr>,
55 check::PostStmt<CXXNewExpr>, check::PreObjCMessage,
56 check::PostObjCMessage> {
75 GenericsBugVisitor(
SymbolRef S) : Sym(S) {}
77 void Profile(llvm::FoldingSetNodeID &ID)
const override {
95 const Stmt *ReportedNode =
nullptr)
const;
107 StringRef
getDebugTag()
const override {
return "DynamicTypePropagation"; }
112 return PointerType->getObjectType()->isObjCClass();
119 bool Precise =
false;
121 operator bool()
const {
return Type !=
nullptr; }
155 if (
const auto *ObjTy =
157 return {ObjTy->getObjectType(),
true};
168 SVal ReceiverSVal =
C.getSVal(RecE);
178 if (InferredType.
isNull()) {
179 InferredType = ReceiverSymbol->getType();
184 if (isObjCClassType(InferredType)) {
193 SVal SelfSVal = State->getSelfSVal(
C.getLocationContext());
197 if (ReceiverSVal == SelfSVal) {
201 dyn_cast<ObjCMethodDecl>(
C.getStackFrame()->getDecl()))
203 MD->getClassInterface()->getTypeForDecl()))
210 if (InferredType.
isNull()) {
216 if (
const auto *ReceiverInferredType =
217 dyn_cast<ObjCObjectPointerType>(InferredType)) {
218 return {ReceiverInferredType->getObjectType()};
226void DynamicTypePropagation::checkDeadSymbols(
SymbolReaper &SR,
231 MostSpecializedTypeArgsMapTy TyArgMap =
232 State->get<MostSpecializedTypeArgsMap>();
233 for (
SymbolRef Sym : llvm::make_first_range(TyArgMap)) {
235 State = State->remove<MostSpecializedTypeArgsMap>(Sym);
239 C.addTransition(State);
252 C.addTransition(State);
255void DynamicTypePropagation::checkPreCall(
const CallEvent &
Call,
266 switch (Ctor->getOriginExpr()->getConstructionKind()) {
283 if (!Dtor->isBaseDestructor())
290 const Decl *D = Dtor->getDecl();
299void DynamicTypePropagation::checkPostCall(
const CallEvent &
Call,
305 const MemRegion *RetReg =
Call.getReturnValue().getAsRegion();
313 switch (Msg->getMethodFamily()) {
323 RuntimeType ObjTy = inferReceiverType(*Msg,
C);
329 C.getASTContext().getObjCObjectPointerType(
QualType(ObjTy.Type, 0));
344 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
358 switch (Ctor->getOriginExpr()->getConstructionKind()) {
380 if (isa_and_nonnull<InitListExpr, CXXParenListInitExpr>(
395ExplodedNode *DynamicTypePropagation::dynamicTypePropagationOnCasts(
398 const MemRegion *ToR =
C.getSVal(CE).getAsRegion();
400 return C.getPredecessor();
403 return C.getPredecessor();
405 if (
const Type *NewTy = getBetterObjCType(CE,
C)) {
407 return C.addTransition(State);
409 return C.getPredecessor();
412void DynamicTypePropagation::checkPostStmt(
const CXXNewExpr *NewE,
418 const MemRegion *MR =
C.getSVal(NewE).getAsRegion();
430DynamicTypePropagation::getBetterObjCType(
const Expr *CastE,
432 const MemRegion *ToR =
C.getSVal(CastE).getAsRegion();
470 return MostInformativeCandidate;
482 const auto *SuperOfTo =
486 C.getObjCObjectPointerType(
QualType(SuperOfTo, 0));
493 MostInformativeCandidate,
C);
564 State = State->set<MostSpecializedTypeArgsMap>(Sym, StaticLowerBound);
570 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
575 if (
C.canAssignObjCInterfaces(StaticLowerBound, *Current)) {
580 if (
C.canAssignObjCInterfaces(*Current, StaticUpperBound)) {
586 if (WithMostInfo == *Current)
588 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
595 if (WithMostInfo != *Current) {
596 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
606void DynamicTypePropagation::checkPostStmt(
const CastExpr *CE,
617 if (!OrigObjectPtrType || !DestObjectPtrType)
621 ExplodedNode *AfterTypeProp = dynamicTypePropagationOnCasts(CE, State,
C);
630 OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt);
633 if (OrigObjectPtrType->isUnspecialized() &&
642 State->get<MostSpecializedTypeArgsMap>(Sym);
654 State = State->remove<MostSpecializedTypeArgsMap>(Sym);
655 C.addTransition(State, AfterTypeProp);
678 "IllegalConversion");
680 C.generateNonFatalErrorNode(State, AfterTypeProp, &IllegalConv);
682 reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym,
C);
690 if (OrigToDest && !DestToOrig)
691 std::swap(LowerBound, UpperBound);
694 LowerBound = LowerBound->
isObjCIdType() ? UpperBound : LowerBound;
695 UpperBound = UpperBound->
isObjCIdType() ? LowerBound : UpperBound;
699 C.addTransition(State, AfterTypeProp);
716 class IsObjCTypeParamDependentTypeVisitor
719 IsObjCTypeParamDependentTypeVisitor() =
default;
720 bool VisitObjCTypeParamType(ObjCTypeParamType *
Type)
override {
730 IsObjCTypeParamDependentTypeVisitor Visitor;
731 Visitor.TraverseType(
Type);
732 return Visitor.Result;
777 QualType StaticResultType = Method->getReturnType();
780 if (StaticResultType ==
C.getObjCInstanceType())
795void DynamicTypePropagation::checkPreObjCMessage(
const ObjCMethodCall &M,
803 State->get<MostSpecializedTypeArgsMap>(Sym);
850 std::optional<ArrayRef<QualType>> TypeArgs =
851 (*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
857 for (
unsigned i = 0; i < Method->param_size(); i++) {
859 const ParmVarDecl *Param = Method->parameters()[i];
861 QualType OrigParamType = Param->getType();
869 const auto *ArgObjectPtrType =
871 if (!ParamObjectPtrType || !ArgObjectPtrType)
880 State->get<MostSpecializedTypeArgsMap>(ArgSym);
881 if (TrackedArgType &&
883 ArgObjectPtrType = *TrackedArgType;
891 reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym,
C, Arg);
904void DynamicTypePropagation::checkPostObjCMessage(
const ObjCMethodCall &M,
918 if (RuntimeType ReceiverRuntimeType = inferReceiverType(M,
C)) {
920 ReceiverRuntimeType.Type->getSuperClassType();
921 QualType ReceiverClassType(ReceiverRuntimeType.Type, 0);
924 if (ReceiverRuntimeType.Type->isSpecialized() &&
925 ReceiverRuntimeType.Precise) {
927 C.getASTContext().getObjCObjectPointerType(ReceiverClassType);
928 const auto *InferredType =
930 State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType);
935 !ReceiverRuntimeType.Precise);
937 C.addTransition(State);
945 if (RuntimeType ReceiverRuntimeType = inferReceiverType(M,
C)) {
949 ReceiverRuntimeType.Type->getSuperClassType();
955 if (!ReceiversSuperClass.
isNull()) {
958 State, RetSym, ReceiversSuperClass, !ReceiverRuntimeType.Precise);
960 C.addTransition(State);
972 State->get<MostSpecializedTypeArgsMap>(RecSym);
982 std::optional<ArrayRef<QualType>> TypeArgs =
983 (*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
1004 Pred =
C.addTransition(State);
1009 if (!ResultPtrType || ResultPtrType->isUnspecialized())
1014 if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) {
1015 State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType);
1016 C.addTransition(State, Pred);
1020void DynamicTypePropagation::reportGenericsBug(
1023 const Stmt *ReportedNode)
const {
1024 if (!ObjCGenericsChecker.isEnabled())
1028 llvm::raw_svector_ostream
OS(Buf);
1029 OS <<
"Conversion from value of type '";
1031 OS <<
"' to incompatible type '";
1034 auto R = std::make_unique<PathSensitiveBugReport>(ObjCGenericsChecker,
1036 R->markInteresting(Sym);
1037 R->addVisitor(std::make_unique<GenericsBugVisitor>(Sym));
1040 C.emitReport(std::move(R));
1050 state->get<MostSpecializedTypeArgsMap>(Sym);
1052 statePrev->get<MostSpecializedTypeArgsMap>(Sym);
1056 if (TrackedTypePrev && *TrackedTypePrev == *TrackedType)
1067 llvm::raw_svector_ostream
OS(Buf);
1070 OS <<
"' is inferred from ";
1072 if (
const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) {
1073 OS <<
"explicit cast (from '";
1078 LangOpts, llvm::Twine());
1080 }
else if (
const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) {
1081 OS <<
"implicit cast (from '";
1086 LangOpts, llvm::Twine());
1089 OS <<
"this context";
1095 return std::make_shared<PathDiagnosticEventPiece>(Pos,
OS.str(),
true);
1100 Mgr.
getChecker<DynamicTypePropagation>()->ObjCGenericsChecker.enable(Mgr);
1103bool ento::shouldRegisterObjCGenericsChecker(
const CheckerManager &) {
1115bool ento::shouldRegisterDynamicTypePropagation(
const CheckerManager &) {
Defines enum values for all the target-independent builtin functions.
static QualType getReturnTypeForMethod(const ObjCMethodDecl *Method, ArrayRef< QualType > TypeArgs, const ObjCObjectPointerType *SelfType, ASTContext &C)
Get the returned ObjCObjectPointerType by a method based on the tracked type information,...
static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, CheckerContext &C)
static const ObjCObjectPointerType * getMostInformativeDerivedClassImpl(const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, const ObjCObjectPointerType *MostInformativeCandidate, ASTContext &C)
static const ObjCMethodDecl * findMethodDecl(const ObjCMessageExpr *MessageExpr, const ObjCObjectPointerType *TrackedType, ASTContext &ASTCtxt)
A method might not be available in the interface indicated by the static type.
static bool isObjCTypeParamDependent(QualType Type)
static const Expr * stripCastsAndSugar(const Expr *E)
static const ObjCObjectPointerType * getMostInformativeDerivedClass(const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, ASTContext &C)
A downcast may loose specialization information.
static bool storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, const ObjCObjectPointerType *const *Current, const ObjCObjectPointerType *StaticLowerBound, const ObjCObjectPointerType *StaticUpperBound, ASTContext &C)
Inputs:
Result
Implement __builtin_bit_cast and related operations.
llvm::MachO::Target Target
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT)
canAssignObjCInterfaces - Return true if the two interface types are compatible for assignment from R...
const LangOptions & getLangOpts() const
CanQualType getCanonicalTagType(const TagDecl *TD) const
Represents a static or instance method of a struct/union/class.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
CastKind getCastKind() const
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
const Decl * getDecl() const
const ParentMap & getParentMap() const
Represents an ObjC class declaration.
ObjCMethodDecl * lookupClassMethod(Selector Sel) const
Lookup a class method for a given selector.
ObjCMethodDecl * lookupInstanceMethod(Selector Sel) const
Lookup an instance method for a given selector.
ObjCInterfaceDecl * getCanonicalDecl() override
Retrieves the canonical declaration of this Objective-C class.
bool isSuperClassOf(const ObjCInterfaceDecl *I) const
isSuperClassOf - Return true if this class is the specified class or is a super class of the specifie...
An expression that sends a message to the given Objective-C object or class.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Selector getSelector() const
@ SuperInstance
The receiver is the instance of the superclass object.
@ Instance
The receiver is an object instance.
@ SuperClass
The receiver is a superclass.
@ Class
The receiver is a class.
QualType getClassReceiver() const
Returns the type of a class message send, or NULL if the message is not a class message.
QualType getSuperType() const
Retrieve the type referred to by 'super'.
const ObjCMethodDecl * getMethodDecl() const
ReceiverKind getReceiverKind() const
Determine the kind of receiver that this message is being sent to.
QualType getReceiverType() const
Retrieve the receiver type to which this message is being directed.
ObjCMethodDecl - Represents an instance or class method declaration.
bool hasRelatedResultType() const
Determine whether this method has a result type that is related to the message receiver's type.
Represents a pointer to an Objective C object.
bool isSpecialized() const
Whether this type is specialized, meaning that it has type arguments.
const ObjCObjectPointerType * stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const
Strip off the Objective-C "kindof" type and (with it) any protocol qualifiers.
const ObjCObjectType * getObjectType() const
Gets the type pointed to by this ObjC pointer.
bool isUnspecialized() const
Whether this type is unspecialized, meaning that is has no type arguments.
bool isObjCIdType() const
True if this is equivalent to the 'id' type, i.e.
ObjCInterfaceDecl * getInterfaceDecl() const
If this pointer points to an Objective @interface type, gets the declaration for that interface.
Represents the declaration of an Objective-C type parameter.
Stores a list of Objective-C type parameters for a parameterized class or a category/extension thereo...
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Stmt * getParent(Stmt *) const
Represents a parameter to a function.
PointerType - C99 6.7.5.1 - Pointer Declarators.
virtual StringRef getDebugTag() const =0
The description of this program point which will be dumped for debugging purposes.
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
QualType getCanonicalType() const
QualType substObjCTypeArgs(ASTContext &ctx, ArrayRef< QualType > typeArgs, ObjCSubstitutionContext context) const
Substitute type arguments for the Objective-C type parameters used in the subject type.
The collection of all-type qualifiers we support.
Smart pointer class that efficiently represents Objective-C method names.
std::string getAsString() const
Derive the full selector name (e.g.
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
The base class of the type hierarchy.
const T * castAs() const
Member-template castAs<specific type>.
bool isObjCIdType() const
bool isObjCClassType() const
const T * getAs() const
Member-template getAs<specific type>'.
ASTContext & getASTContext() const
const SourceManager & getSourceManager() const
BugReporterVisitors are used to add custom diagnostics along a path.
Represents a call to a C++ constructor.
Represents an implicit call to a C++ destructor.
Represents an abstract call to a function or method along a particular path.
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
SVal getReturnValue() const
Returns the return value of the call.
Checker families (where a single backend class implements multiple related frontends) should derive f...
Trivial convenience class for the common case when a certain checker frontend always uses the same bu...
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
Stores the currently inferred strictest bound on the runtime type of a region in a given state along ...
QualType getType() const
Returns the currently inferred upper bound on the runtime type.
const ProgramStateRef & getState() const
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
MemRegion - The root abstract class for all memory regions.
Represents any expression that calls an Objective-C method.
const ObjCMessageExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
const MemRegion * getAsRegion() const
A class responsible for cleaning up unused symbols.
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
const char *const CoreFoundationObjectiveC
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
ProgramStateRef setClassObjectDynamicTypeInfo(ProgramStateRef State, SymbolRef Sym, DynamicTypeInfo NewTy)
Set constraint on a type contained in a class object; return the new state.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
ProgramStateRef removeDeadClassObjectTypes(ProgramStateRef State, SymbolReaper &SR)
Removes the dead Class object type informations from State.
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR)
Get dynamic type information for the region MR.
const DynamicTypeInfo * getRawDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR)
Get raw dynamic type information for the region MR.
ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR, DynamicTypeInfo NewTy)
Set dynamic type information of the region; return the new state.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR)
Removes the dead type informations from State.
DynamicTypeInfo getClassObjectDynamicTypeInfo(ProgramStateRef State, SymbolRef Sym)
Get dynamic type information stored in a class object represented by Sym.
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
@ Parameter
The parameter type of a method or function.
@ Result
The result type of a method or function.
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
@ Invariant
The parameter is invariant: must match exactly.
U cast(CodeGen::Address addr)
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.