34#include "llvm/ADT/STLExtras.h"
52class DynamicTypePropagation:
56 check::PostStmt<CastExpr>,
57 check::PostStmt<CXXNewExpr>,
58 check::PreObjCMessage,
59 check::PostObjCMessage > {
69 mutable std::unique_ptr<BugType> ObjCGenericsBugType;
70 void initBugType()
const {
71 if (!ObjCGenericsBugType)
72 ObjCGenericsBugType.reset(
new BugType(
78 GenericsBugVisitor(
SymbolRef S) : Sym(S) {}
80 void Profile(llvm::FoldingSetNodeID &
ID)
const override {
98 const Stmt *ReportedNode =
nullptr)
const;
110 bool CheckGenerics =
false;
116 return PointerType->getObjectType()->isObjCClass();
123 bool Precise =
false;
125 operator bool()
const {
return Type !=
nullptr; }
159 if (
const auto *ObjTy =
161 return {ObjTy->getObjectType(),
true};
172 SVal ReceiverSVal =
C.getSVal(RecE);
182 if (InferredType.
isNull()) {
183 InferredType = ReceiverSymbol->getType();
188 if (isObjCClassType(InferredType)) {
194 return {cast<ObjCObjectType>(DTI.getType()), !DTI.canBeASubClass()};
197 SVal SelfSVal = State->getSelfSVal(
C.getLocationContext());
201 if (ReceiverSVal == SelfSVal) {
205 dyn_cast<ObjCMethodDecl>(
C.getStackFrame()->getDecl()))
207 MD->getClassInterface()->getTypeForDecl()))
214 if (InferredType.
isNull()) {
220 if (
const auto *ReceiverInferredType =
221 dyn_cast<ObjCObjectPointerType>(InferredType)) {
222 return {ReceiverInferredType->getObjectType()};
230void DynamicTypePropagation::checkDeadSymbols(
SymbolReaper &SR,
235 MostSpecializedTypeArgsMapTy TyArgMap =
236 State->get<MostSpecializedTypeArgsMap>();
237 for (
SymbolRef Sym : llvm::make_first_range(TyArgMap)) {
239 State = State->remove<MostSpecializedTypeArgsMap>(Sym);
243 C.addTransition(State);
256 C.addTransition(State);
259void DynamicTypePropagation::checkPreCall(
const CallEvent &
Call,
270 switch (Ctor->getOriginExpr()->getConstructionKind()) {
271 case CXXConstructionKind::Complete:
272 case CXXConstructionKind::Delegating:
275 case CXXConstructionKind::NonVirtualBase:
276 case CXXConstructionKind::VirtualBase:
287 if (!Dtor->isBaseDestructor())
294 const Decl *
D = Dtor->getDecl();
303void DynamicTypePropagation::checkPostCall(
const CallEvent &
Call,
309 const MemRegion *RetReg =
Call.getReturnValue().getAsRegion();
316 if (
D &&
D->hasRelatedResultType()) {
317 switch (Msg->getMethodFamily()) {
327 RuntimeType ObjTy = inferReceiverType(*Msg,
C);
333 C.getASTContext().getObjCObjectPointerType(
QualType(ObjTy.Type, 0));
348 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
362 switch (Ctor->getOriginExpr()->getConstructionKind()) {
363 case CXXConstructionKind::Complete:
364 case CXXConstructionKind::Delegating:
371 case CXXConstructionKind::NonVirtualBase:
372 case CXXConstructionKind::VirtualBase:
384 if (isa_and_nonnull<InitListExpr>(
399ExplodedNode *DynamicTypePropagation::dynamicTypePropagationOnCasts(
402 const MemRegion *ToR =
C.getSVal(CE).getAsRegion();
404 return C.getPredecessor();
406 if (isa<ExplicitCastExpr>(CE))
407 return C.getPredecessor();
409 if (
const Type *NewTy = getBetterObjCType(CE,
C)) {
411 return C.addTransition(State);
413 return C.getPredecessor();
416void DynamicTypePropagation::checkPostStmt(
const CXXNewExpr *NewE,
422 const MemRegion *MR =
C.getSVal(NewE).getAsRegion();
434DynamicTypePropagation::getBetterObjCType(
const Expr *CastE,
436 const MemRegion *ToR =
C.getSVal(CastE).getAsRegion();
474 return MostInformativeCandidate;
486 const auto *SuperOfTo =
490 C.getObjCObjectPointerType(
QualType(SuperOfTo, 0));
497 MostInformativeCandidate,
C);
563 assert(!Current || (*Current)->isSpecialized());
568 State = State->set<MostSpecializedTypeArgsMap>(Sym, StaticLowerBound);
574 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
579 if (
C.canAssignObjCInterfaces(StaticLowerBound, *Current)) {
584 if (
C.canAssignObjCInterfaces(*Current, StaticUpperBound)) {
590 if (WithMostInfo == *Current)
592 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
599 if (WithMostInfo != *Current) {
600 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
610void DynamicTypePropagation::checkPostStmt(
const CastExpr *CE,
621 if (!OrigObjectPtrType || !DestObjectPtrType)
625 ExplodedNode *AfterTypeProp = dynamicTypePropagationOnCasts(CE, State,
C);
634 OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt);
637 if (OrigObjectPtrType->isUnspecialized() &&
646 State->get<MostSpecializedTypeArgsMap>(Sym);
648 if (isa<ExplicitCastExpr>(CE)) {
658 State = State->remove<MostSpecializedTypeArgsMap>(Sym);
659 C.addTransition(State, AfterTypeProp);
678 ExplodedNode *N =
C.addTransition(State, AfterTypeProp, &IllegalConv);
679 reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym,
C);
687 if (OrigToDest && !DestToOrig)
688 std::swap(LowerBound, UpperBound);
691 LowerBound = LowerBound->
isObjCIdType() ? UpperBound : LowerBound;
692 UpperBound = UpperBound->
isObjCIdType() ? LowerBound : UpperBound;
696 C.addTransition(State, AfterTypeProp);
713 class IsObjCTypeParamDependentTypeVisitor
716 IsObjCTypeParamDependentTypeVisitor() =
default;
718 if (isa<ObjCTypeParamDecl>(
Type->getDecl())) {
728 IsObjCTypeParamDependentTypeVisitor Visitor;
729 Visitor.TraverseType(
Type);
730 return Visitor.Result;
778 if (StaticResultType ==
C.getObjCInstanceType())
786 C, TypeArgs, ObjCSubstitutionContext::Result);
793void DynamicTypePropagation::checkPreObjCMessage(
const ObjCMethodCall &M,
801 State->get<MostSpecializedTypeArgsMap>(Sym);
844 if (TypeParam->getVariance() != ObjCTypeParamVariance::Invariant)
848 std::optional<ArrayRef<QualType>> TypeArgs =
855 for (
unsigned i = 0; i < Method->
param_size(); i++) {
864 ASTCtxt, *TypeArgs, ObjCSubstitutionContext::Parameter);
867 const auto *ArgObjectPtrType =
869 if (!ParamObjectPtrType || !ArgObjectPtrType)
878 State->get<MostSpecializedTypeArgsMap>(ArgSym);
879 if (TrackedArgType &&
881 ArgObjectPtrType = *TrackedArgType;
890 reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym,
C, Arg);
903void DynamicTypePropagation::checkPostObjCMessage(
const ObjCMethodCall &M,
917 if (RuntimeType ReceiverRuntimeType = inferReceiverType(M,
C)) {
919 ReceiverRuntimeType.Type->getSuperClassType();
920 QualType ReceiverClassType(ReceiverRuntimeType.Type, 0);
923 if (ReceiverRuntimeType.Type->isSpecialized() &&
924 ReceiverRuntimeType.Precise) {
926 C.getASTContext().getObjCObjectPointerType(ReceiverClassType);
927 const auto *InferredType =
929 State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType);
934 !ReceiverRuntimeType.Precise);
936 C.addTransition(State);
944 if (RuntimeType ReceiverRuntimeType = inferReceiverType(M,
C)) {
948 ReceiverRuntimeType.Type->getSuperClassType();
954 if (!ReceiversSuperClass.
isNull()) {
957 State, RetSym, ReceiversSuperClass, !ReceiverRuntimeType.Precise);
959 C.addTransition(State);
971 State->get<MostSpecializedTypeArgsMap>(RecSym);
981 std::optional<ArrayRef<QualType>> TypeArgs =
1003 Pred =
C.addTransition(State);
1008 if (!ResultPtrType || ResultPtrType->isUnspecialized())
1013 if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) {
1014 State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType);
1015 C.addTransition(State, Pred);
1019void DynamicTypePropagation::reportGenericsBug(
1022 const Stmt *ReportedNode)
const {
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>(*ObjCGenericsBugType,
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 DynamicTypePropagation *checker = mgr.
getChecker<DynamicTypePropagation>();
1101 checker->CheckGenerics =
true;
1105bool ento::shouldRegisterObjCGenericsChecker(
const CheckerManager &mgr) {
1113bool ento::shouldRegisterDynamicTypePropagation(
const CheckerManager &mgr) {
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. However it might be av...
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. E. g.: MutableMap<T, U> : Map The downcast to Mutabl...
static bool storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, const ObjCObjectPointerType *const *Current, const ObjCObjectPointerType *StaticLowerBound, const ObjCObjectPointerType *StaticUpperBound, ASTContext &C)
Inputs:
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 getRecordType(const RecordDecl *Decl) const
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
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.
DeclContext * getDeclContext()
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...
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
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.
ArrayRef< ParmVarDecl * > parameters() const
unsigned param_size() const
QualType getReturnType() const
ObjCInterfaceDecl * getClassInterface()
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 a class type in Objective C.
QualType getSuperClassType() const
Retrieve the type of the superclass of this object type.
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...
Represents a type parameter type in Objective C.
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.
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.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
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 * registerChecker(AT &&... Args)
Used to register checkers.
CheckerNameRef getCurrentCheckerName() const
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
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
ProgramStateRef setClassObjectDynamicTypeInfo(ProgramStateRef State, SymbolRef Sym, DynamicTypeInfo NewTy)
Set constraint on a type contained in a class object; return the new state.
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.
ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR)
Removes the dead type informations from State.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
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.
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.