51class DynamicTypePropagation:
55 check::PostStmt<CastExpr>,
56 check::PostStmt<CXXNewExpr>,
57 check::PreObjCMessage,
58 check::PostObjCMessage > {
68 mutable std::unique_ptr<BugType> ObjCGenericsBugType;
69 void initBugType()
const {
70 if (!ObjCGenericsBugType)
71 ObjCGenericsBugType.reset(
new BugType(
77 GenericsBugVisitor(
SymbolRef S) : Sym(S) {}
79 void Profile(llvm::FoldingSetNodeID &ID)
const override {
97 const Stmt *ReportedNode =
nullptr)
const;
109 bool CheckGenerics =
false;
115 return PointerType->getObjectType()->isObjCClass();
122 bool Precise =
false;
124 operator bool()
const {
return Type !=
nullptr; }
158 if (
const auto *ObjTy =
160 return {ObjTy->getObjectType(),
true};
171 SVal ReceiverSVal =
C.getSVal(RecE);
181 if (InferredType.
isNull()) {
182 InferredType = ReceiverSymbol->getType();
187 if (isObjCClassType(InferredType)) {
193 return {cast<ObjCObjectType>(DTI.getType()), !DTI.canBeASubClass()};
196 SVal SelfSVal = State->getSelfSVal(
C.getLocationContext());
200 if (ReceiverSVal == SelfSVal) {
204 dyn_cast<ObjCMethodDecl>(
C.getStackFrame()->getDecl()))
206 MD->getClassInterface()->getTypeForDecl()))
213 if (InferredType.
isNull()) {
219 if (
const auto *ReceiverInferredType =
220 dyn_cast<ObjCObjectPointerType>(InferredType)) {
221 return {ReceiverInferredType->getObjectType()};
229void DynamicTypePropagation::checkDeadSymbols(
SymbolReaper &SR,
234 MostSpecializedTypeArgsMapTy TyArgMap =
235 State->get<MostSpecializedTypeArgsMap>();
236 for (MostSpecializedTypeArgsMapTy::iterator I = TyArgMap.begin(),
239 if (SR.
isDead(I->first)) {
240 State = State->remove<MostSpecializedTypeArgsMap>(I->first);
244 C.addTransition(State);
257 C.addTransition(State);
260void DynamicTypePropagation::checkPreCall(
const CallEvent &Call,
271 switch (Ctor->getOriginExpr()->getConstructionKind()) {
278 if (
const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion())
288 if (!Dtor->isBaseDestructor())
295 const Decl *D = Dtor->getDecl();
304void DynamicTypePropagation::checkPostCall(
const CallEvent &Call,
307 if (
const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
310 const MemRegion *RetReg =
Call.getReturnValue().getAsRegion();
318 switch (Msg->getMethodFamily()) {
328 RuntimeType ObjTy = inferReceiverType(*Msg,
C);
334 C.getASTContext().getObjCObjectPointerType(
QualType(ObjTy.Type, 0));
349 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
363 switch (Ctor->getOriginExpr()->getConstructionKind()) {
374 if (
const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) {
385 if (isa_and_nonnull<InitListExpr>(
400ExplodedNode *DynamicTypePropagation::dynamicTypePropagationOnCasts(
403 const MemRegion *ToR =
C.getSVal(CE).getAsRegion();
405 return C.getPredecessor();
407 if (isa<ExplicitCastExpr>(CE))
408 return C.getPredecessor();
410 if (
const Type *NewTy = getBetterObjCType(CE,
C)) {
412 return C.addTransition(State);
414 return C.getPredecessor();
417void DynamicTypePropagation::checkPostStmt(
const CXXNewExpr *NewE,
423 const MemRegion *MR =
C.getSVal(NewE).getAsRegion();
435DynamicTypePropagation::getBetterObjCType(
const Expr *CastE,
437 const MemRegion *ToR =
C.getSVal(CastE).getAsRegion();
475 return MostInformativeCandidate;
487 const auto *SuperOfTo =
491 C.getObjCObjectPointerType(
QualType(SuperOfTo, 0));
498 MostInformativeCandidate,
C);
564 assert(!Current || (*Current)->isSpecialized());
569 State = State->set<MostSpecializedTypeArgsMap>(Sym, StaticLowerBound);
575 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
580 if (
C.canAssignObjCInterfaces(StaticLowerBound, *Current)) {
585 if (
C.canAssignObjCInterfaces(*Current, StaticUpperBound)) {
591 if (WithMostInfo == *Current)
593 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
600 if (WithMostInfo != *Current) {
601 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo);
611void DynamicTypePropagation::checkPostStmt(
const CastExpr *CE,
622 if (!OrigObjectPtrType || !DestObjectPtrType)
626 ExplodedNode *AfterTypeProp = dynamicTypePropagationOnCasts(CE, State,
C);
635 OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt);
638 if (OrigObjectPtrType->isUnspecialized() &&
647 State->get<MostSpecializedTypeArgsMap>(Sym);
649 if (isa<ExplicitCastExpr>(CE)) {
659 State = State->remove<MostSpecializedTypeArgsMap>(Sym);
660 C.addTransition(State, AfterTypeProp);
679 ExplodedNode *N =
C.addTransition(State, AfterTypeProp, &IllegalConv);
680 reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym,
C);
688 if (OrigToDest && !DestToOrig)
689 std::swap(LowerBound, UpperBound);
692 LowerBound = LowerBound->
isObjCIdType() ? UpperBound : LowerBound;
693 UpperBound = UpperBound->
isObjCIdType() ? LowerBound : UpperBound;
697 C.addTransition(State, AfterTypeProp);
714 class IsObjCTypeParamDependentTypeVisitor
717 IsObjCTypeParamDependentTypeVisitor() :
Result(
false) {}
719 if (isa<ObjCTypeParamDecl>(
Type->getDecl())) {
729 IsObjCTypeParamDependentTypeVisitor Visitor;
730 Visitor.TraverseType(
Type);
731 return Visitor.Result;
745 const auto *ReceiverObjectPtrType =
780 if (StaticResultType ==
C.getObjCInstanceType())
788 C, TypeArgs, ObjCSubstitutionContext::Result);
795void DynamicTypePropagation::checkPreObjCMessage(
const ObjCMethodCall &M,
803 State->get<MostSpecializedTypeArgsMap>(Sym);
846 if (TypeParam->getVariance() != ObjCTypeParamVariance::Invariant)
850 std::optional<ArrayRef<QualType>> TypeArgs =
857 for (
unsigned i = 0; i < Method->
param_size(); i++) {
866 ASTCtxt, *TypeArgs, ObjCSubstitutionContext::Parameter);
869 const auto *ArgObjectPtrType =
871 if (!ParamObjectPtrType || !ArgObjectPtrType)
880 State->get<MostSpecializedTypeArgsMap>(ArgSym);
881 if (TrackedArgType &&
883 ArgObjectPtrType = *TrackedArgType;
892 reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym,
C, Arg);
905void DynamicTypePropagation::checkPostObjCMessage(
const ObjCMethodCall &M,
919 if (RuntimeType ReceiverRuntimeType = inferReceiverType(M,
C)) {
921 ReceiverRuntimeType.Type->getSuperClassType();
922 QualType ReceiverClassType(ReceiverRuntimeType.Type, 0);
925 if (ReceiverRuntimeType.Type->isSpecialized() &&
926 ReceiverRuntimeType.Precise) {
928 C.getASTContext().getObjCObjectPointerType(ReceiverClassType);
929 const auto *InferredType =
931 State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType);
936 !ReceiverRuntimeType.Precise);
938 C.addTransition(State);
946 if (RuntimeType ReceiverRuntimeType = inferReceiverType(M,
C)) {
950 ReceiverRuntimeType.Type->getSuperClassType();
956 if (!ReceiversSuperClass.
isNull()) {
959 State, RetSym, ReceiversSuperClass, !ReceiverRuntimeType.Precise);
961 C.addTransition(State);
973 State->get<MostSpecializedTypeArgsMap>(RecSym);
983 std::optional<ArrayRef<QualType>> TypeArgs =
1005 Pred =
C.addTransition(State);
1010 if (!ResultPtrType || ResultPtrType->isUnspecialized())
1015 if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) {
1016 State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType);
1017 C.addTransition(State, Pred);
1021void DynamicTypePropagation::reportGenericsBug(
1024 const Stmt *ReportedNode)
const {
1030 llvm::raw_svector_ostream
OS(Buf);
1031 OS <<
"Conversion from value of type '";
1033 OS <<
"' to incompatible type '";
1036 auto R = std::make_unique<PathSensitiveBugReport>(*ObjCGenericsBugType,
1038 R->markInteresting(Sym);
1039 R->addVisitor(std::make_unique<GenericsBugVisitor>(Sym));
1042 C.emitReport(std::move(R));
1052 state->get<MostSpecializedTypeArgsMap>(Sym);
1054 statePrev->get<MostSpecializedTypeArgsMap>(Sym);
1058 if (TrackedTypePrev && *TrackedTypePrev == *TrackedType)
1069 llvm::raw_svector_ostream
OS(Buf);
1072 OS <<
"' is inferred from ";
1074 if (
const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) {
1075 OS <<
"explicit cast (from '";
1080 LangOpts, llvm::Twine());
1082 }
else if (
const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) {
1083 OS <<
"implicit cast (from '";
1088 LangOpts, llvm::Twine());
1091 OS <<
"this context";
1097 return std::make_shared<PathDiagnosticEventPiece>(Pos,
OS.str(),
true);
1102 DynamicTypePropagation *checker = mgr.
getChecker<DynamicTypePropagation>();
1103 checker->CheckGenerics =
true;
1107bool ento::shouldRegisterObjCGenericsChecker(
const CheckerManager &mgr) {
1115bool ento::shouldRegisterDynamicTypePropagation(
const CheckerManager &mgr) {
Defines enum values for all the target-independent builtin functions.
static CompilationDatabasePluginRegistry::Add< FixedCompilationDatabasePlugin > X("fixed-compilation-database", "Reads plain-text flags file")
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:
#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.
ObjCTypeParamList * getTypeParamList() const
Retrieve the type parameters of this class.
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
bool hasRelatedResultType() const
Determine whether this method has a result type that is related to the message receiver's type.
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.
bool Call(InterpState &S, CodePtr &PC, const Function *Func)
@ C
Languages that the frontend can parse and compile.
@ Result
The result type of a method or function.