From c96d2e1beeac55d7ae4a839c5a32e1bad0b1197e Mon Sep 17 00:00:00 2001 From: Gabor Horvath Date: Sun, 13 Sep 2015 23:03:11 +0000 Subject: [PATCH] [Static Analyzer] Remove a redundant file. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247533 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Checkers/ObjCGenericsChecker.cpp | 623 ------------------ 1 file changed, 623 deletions(-) delete mode 100644 lib/StaticAnalyzer/Checkers/ObjCGenericsChecker.cpp diff --git a/lib/StaticAnalyzer/Checkers/ObjCGenericsChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCGenericsChecker.cpp deleted file mode 100644 index a8cf646390..0000000000 --- a/lib/StaticAnalyzer/Checkers/ObjCGenericsChecker.cpp +++ /dev/null @@ -1,623 +0,0 @@ -//=== ObjCGenericsChecker.cpp - Path sensitive checker for Generics *- C++ -*=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This checker tries to find type errors that the compiler is not able to catch -// due to the implicit conversions that were introduced for backward -// compatibility. -// -//===----------------------------------------------------------------------===// - -#include "ClangSACheckers.h" -#include "clang/AST/ParentMap.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" - -using namespace clang; -using namespace ento; - -// ProgramState trait - a map from symbol to its specialized type. -REGISTER_MAP_WITH_PROGRAMSTATE(TypeParamMap, SymbolRef, - const ObjCObjectPointerType *) - -namespace { -class ObjCGenericsChecker - : public Checker> { -public: - void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; - void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; - void checkPostStmt(const CastExpr *CE, CheckerContext &C) const; - void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; - -private: - mutable std::unique_ptr ObjCGenericsBugType; - void initBugType() const { - if (!ObjCGenericsBugType) - ObjCGenericsBugType.reset( - new BugType(this, "Generics", categories::CoreFoundationObjectiveC)); - } - - class GenericsBugVisitor : public BugReporterVisitorImpl { - public: - GenericsBugVisitor(SymbolRef S) : Sym(S) {} - - void Profile(llvm::FoldingSetNodeID &ID) const override { - static int X = 0; - ID.AddPointer(&X); - ID.AddPointer(Sym); - } - - PathDiagnosticPiece *VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext &BRC, - BugReport &BR) override; - - private: - // The tracked symbol. - SymbolRef Sym; - }; - - void reportGenericsBug(const ObjCObjectPointerType *From, - const ObjCObjectPointerType *To, ExplodedNode *N, - SymbolRef Sym, CheckerContext &C, - const Stmt *ReportedNode = nullptr) const; - - void checkReturnType(const ObjCMessageExpr *MessageExpr, - const ObjCObjectPointerType *TrackedType, SymbolRef Sym, - const ObjCMethodDecl *Method, - ArrayRef TypeArgs, bool SubscriptOrProperty, - CheckerContext &C) const; -}; -} // end anonymous namespace - -void ObjCGenericsChecker::reportGenericsBug(const ObjCObjectPointerType *From, - const ObjCObjectPointerType *To, - ExplodedNode *N, SymbolRef Sym, - CheckerContext &C, - const Stmt *ReportedNode) const { - initBugType(); - SmallString<192> Buf; - llvm::raw_svector_ostream OS(Buf); - OS << "Conversion from value of type '"; - QualType::print(From, Qualifiers(), OS, C.getLangOpts(), llvm::Twine()); - OS << "' to incompatible type '"; - QualType::print(To, Qualifiers(), OS, C.getLangOpts(), llvm::Twine()); - OS << "'"; - std::unique_ptr R( - new BugReport(*ObjCGenericsBugType, OS.str(), N)); - R->markInteresting(Sym); - R->addVisitor(llvm::make_unique(Sym)); - if (ReportedNode) - R->addRange(ReportedNode->getSourceRange()); - C.emitReport(std::move(R)); -} - -PathDiagnosticPiece *ObjCGenericsChecker::GenericsBugVisitor::VisitNode( - const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, - BugReport &BR) { - ProgramStateRef state = N->getState(); - ProgramStateRef statePrev = PrevN->getState(); - - const ObjCObjectPointerType *const *TrackedType = - state->get(Sym); - const ObjCObjectPointerType *const *TrackedTypePrev = - statePrev->get(Sym); - if (!TrackedType) - return nullptr; - - if (TrackedTypePrev && *TrackedTypePrev == *TrackedType) - return nullptr; - - // Retrieve the associated statement. - const Stmt *S = nullptr; - ProgramPoint ProgLoc = N->getLocation(); - if (Optional SP = ProgLoc.getAs()) { - S = SP->getStmt(); - } - - if (!S) - return nullptr; - - const LangOptions &LangOpts = BRC.getASTContext().getLangOpts(); - - SmallString<256> Buf; - llvm::raw_svector_ostream OS(Buf); - OS << "Type '"; - QualType::print(*TrackedType, Qualifiers(), OS, LangOpts, llvm::Twine()); - OS << "' is inferred from "; - - if (const auto *ExplicitCast = dyn_cast(S)) { - OS << "explicit cast (from '"; - QualType::print(ExplicitCast->getSubExpr()->getType().getTypePtr(), - Qualifiers(), OS, LangOpts, llvm::Twine()); - OS << "' to '"; - QualType::print(ExplicitCast->getType().getTypePtr(), Qualifiers(), OS, - LangOpts, llvm::Twine()); - OS << "')"; - } else if (const auto *ImplicitCast = dyn_cast(S)) { - OS << "implicit cast (from '"; - QualType::print(ImplicitCast->getSubExpr()->getType().getTypePtr(), - Qualifiers(), OS, LangOpts, llvm::Twine()); - OS << "' to '"; - QualType::print(ImplicitCast->getType().getTypePtr(), Qualifiers(), OS, - LangOpts, llvm::Twine()); - OS << "')"; - } else { - OS << "this context"; - } - - // Generate the extra diagnostic. - PathDiagnosticLocation Pos(S, BRC.getSourceManager(), - N->getLocationContext()); - return new PathDiagnosticEventPiece(Pos, OS.str(), true, nullptr); -} - -/// Clean up the states stored by the checker. -void ObjCGenericsChecker::checkDeadSymbols(SymbolReaper &SR, - CheckerContext &C) const { - if (!SR.hasDeadSymbols()) - return; - - ProgramStateRef State = C.getState(); - TypeParamMapTy TyParMap = State->get(); - for (TypeParamMapTy::iterator I = TyParMap.begin(), E = TyParMap.end(); - I != E; ++I) { - if (SR.isDead(I->first)) { - State = State->remove(I->first); - } - } -} - -static const ObjCObjectPointerType *getMostInformativeDerivedClassImpl( - const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, - const ObjCObjectPointerType *MostInformativeCandidate, ASTContext &C) { - // Checking if from and to are the same classes modulo specialization. - if (From->getInterfaceDecl()->getCanonicalDecl() == - To->getInterfaceDecl()->getCanonicalDecl()) { - if (To->isSpecialized()) { - assert(MostInformativeCandidate->isSpecialized()); - return MostInformativeCandidate; - } - return From; - } - const auto *SuperOfTo = - To->getObjectType()->getSuperClassType()->getAs(); - assert(SuperOfTo); - QualType SuperPtrOfToQual = - C.getObjCObjectPointerType(QualType(SuperOfTo, 0)); - const auto *SuperPtrOfTo = SuperPtrOfToQual->getAs(); - if (To->isUnspecialized()) - return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, SuperPtrOfTo, - C); - else - return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, - MostInformativeCandidate, C); -} - -/// A downcast may loose specialization information. E. g.: -/// MutableMap : Map -/// The downcast to MutableMap looses the information about the types of the -/// Map (due to the type parameters are not being forwarded to Map), and in -/// general there is no way to recover that information from the -/// declaration. In order to have to most information, lets find the most -/// derived type that has all the type parameters forwarded. -/// -/// Get the a subclass of \p From (which has a lower bound \p To) that do not -/// loose information about type parameters. \p To has to be a subclass of -/// \p From. From has to be specialized. -static const ObjCObjectPointerType * -getMostInformativeDerivedClass(const ObjCObjectPointerType *From, - const ObjCObjectPointerType *To, ASTContext &C) { - return getMostInformativeDerivedClassImpl(From, To, To, C); -} - -/// Inputs: -/// \param StaticLowerBound Static lower bound for a symbol. The dynamic lower -/// bound might be the subclass of this type. -/// \param StaticUpperBound A static upper bound for a symbol. -/// \p StaticLowerBound expected to be the subclass of \p StaticUpperBound. -/// \param Current The type that was inferred for a symbol in a previous -/// context. Might be null when this is the first time that inference happens. -/// Precondition: -/// \p StaticLowerBound or \p StaticUpperBound is specialized. If \p Current -/// is not null, it is specialized. -/// Possible cases: -/// (1) The \p Current is null and \p StaticLowerBound <: \p StaticUpperBound -/// (2) \p StaticLowerBound <: \p Current <: \p StaticUpperBound -/// (3) \p Current <: \p StaticLowerBound <: \p StaticUpperBound -/// (4) \p StaticLowerBound <: \p StaticUpperBound <: \p Current -/// Effect: -/// Use getMostInformativeDerivedClass with the upper and lower bound of the -/// set {\p StaticLowerBound, \p Current, \p StaticUpperBound}. The computed -/// lower bound must be specialized. If the result differs from \p Current or -/// \p Current is null, store the result. -static bool -storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, - const ObjCObjectPointerType *const *Current, - const ObjCObjectPointerType *StaticLowerBound, - const ObjCObjectPointerType *StaticUpperBound, - ASTContext &C) { - // Precondition - assert(StaticUpperBound->isSpecialized() || - StaticLowerBound->isSpecialized()); - assert(!Current || (*Current)->isSpecialized()); - - // Case (1) - if (!Current) { - if (StaticUpperBound->isUnspecialized()) { - State = State->set(Sym, StaticLowerBound); - return true; - } - // Upper bound is specialized. - const ObjCObjectPointerType *WithMostInfo = - getMostInformativeDerivedClass(StaticUpperBound, StaticLowerBound, C); - State = State->set(Sym, WithMostInfo); - return true; - } - - // Case (3) - if (C.canAssignObjCInterfaces(StaticLowerBound, *Current)) { - return false; - } - - // Case (4) - if (C.canAssignObjCInterfaces(*Current, StaticUpperBound)) { - // The type arguments might not be forwarded at any point of inheritance. - const ObjCObjectPointerType *WithMostInfo = - getMostInformativeDerivedClass(*Current, StaticUpperBound, C); - WithMostInfo = - getMostInformativeDerivedClass(WithMostInfo, StaticLowerBound, C); - if (WithMostInfo == *Current) - return false; - State = State->set(Sym, WithMostInfo); - return true; - } - - // Case (2) - const ObjCObjectPointerType *WithMostInfo = - getMostInformativeDerivedClass(*Current, StaticLowerBound, C); - if (WithMostInfo != *Current) { - State = State->set(Sym, WithMostInfo); - return true; - } - - return false; -} - -/// Type inference based on static type information that is available for the -/// cast and the tracked type information for the given symbol. When the tracked -/// symbol and the destination type of the cast are unrelated, report an error. -void ObjCGenericsChecker::checkPostStmt(const CastExpr *CE, - CheckerContext &C) const { - if (CE->getCastKind() != CK_BitCast) - return; - - QualType OriginType = CE->getSubExpr()->getType(); - QualType DestType = CE->getType(); - - const auto *OrigObjectPtrType = OriginType->getAs(); - const auto *DestObjectPtrType = DestType->getAs(); - - if (!OrigObjectPtrType || !DestObjectPtrType) - return; - - ASTContext &ASTCtxt = C.getASTContext(); - - // This checker detects the subtyping relationships using the assignment - // rules. In order to be able to do this the kindofness must be stripped - // first. The checker treats every type as kindof type anyways: when the - // tracked type is the subtype of the static type it tries to look up the - // methods in the tracked type first. - OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt); - DestObjectPtrType = DestObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt); - - // TODO: erase tracked information when there is a cast to unrelated type - // and everything is unspecialized statically. - if (OrigObjectPtrType->isUnspecialized() && - DestObjectPtrType->isUnspecialized()) - return; - - ProgramStateRef State = C.getState(); - SymbolRef Sym = State->getSVal(CE, C.getLocationContext()).getAsSymbol(); - if (!Sym) - return; - - // Check which assignments are legal. - bool OrigToDest = - ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, OrigObjectPtrType); - bool DestToOrig = - ASTCtxt.canAssignObjCInterfaces(OrigObjectPtrType, DestObjectPtrType); - const ObjCObjectPointerType *const *TrackedType = - State->get(Sym); - - // Downcasts and upcasts handled in an uniform way regardless of being - // explicit. Explicit casts however can happen between mismatched types. - if (isa(CE) && !OrigToDest && !DestToOrig) { - // Mismatched types. If the DestType specialized, store it. Forget the - // tracked type otherwise. - if (DestObjectPtrType->isSpecialized()) { - State = State->set(Sym, DestObjectPtrType); - C.addTransition(State); - } else if (TrackedType) { - State = State->remove(Sym); - C.addTransition(State); - } - return; - } - - // The tracked type should be the sub or super class of the static destination - // type. When an (implicit) upcast or a downcast happens according to static - // types, and there is no subtyping relationship between the tracked and the - // static destination types, it indicates an error. - if (TrackedType && - !ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, *TrackedType) && - !ASTCtxt.canAssignObjCInterfaces(*TrackedType, DestObjectPtrType)) { - static CheckerProgramPointTag IllegalConv(this, "IllegalConversion"); - ExplodedNode *N = C.addTransition(State, &IllegalConv); - reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym, C); - return; - } - - // Handle downcasts and upcasts. - - const ObjCObjectPointerType *LowerBound = DestObjectPtrType; - const ObjCObjectPointerType *UpperBound = OrigObjectPtrType; - if (OrigToDest && !DestToOrig) - std::swap(LowerBound, UpperBound); - - // The id type is not a real bound. Eliminate it. - LowerBound = LowerBound->isObjCIdType() ? UpperBound : LowerBound; - UpperBound = UpperBound->isObjCIdType() ? LowerBound : UpperBound; - - if (storeWhenMoreInformative(State, Sym, TrackedType, LowerBound, UpperBound, - ASTCtxt)) { - C.addTransition(State); - } -} - -static const Expr *stripCastsAndSugar(const Expr *E) { - E = E->IgnoreParenImpCasts(); - if (const PseudoObjectExpr *POE = dyn_cast(E)) - E = POE->getSyntacticForm()->IgnoreParenImpCasts(); - if (const OpaqueValueExpr *OVE = dyn_cast(E)) - E = OVE->getSourceExpr()->IgnoreParenImpCasts(); - return E; -} - -/// This callback is used to infer the types for Class variables. This info is -/// used later to validate messages that sent to classes. Class variables are -/// initialized with by invoking the 'class' method on a class. -void ObjCGenericsChecker::checkPostObjCMessage(const ObjCMethodCall &M, - CheckerContext &C) const { - const ObjCMessageExpr *MessageExpr = M.getOriginExpr(); - - SymbolRef Sym = M.getReturnValue().getAsSymbol(); - if (!Sym) - return; - - Selector Sel = MessageExpr->getSelector(); - // We are only interested in cases where the class method is invoked on a - // class. This method is provided by the runtime and available on all classes. - if (MessageExpr->getReceiverKind() != ObjCMessageExpr::Class || - Sel.getAsString() != "class") - return; - - QualType ReceiverType = MessageExpr->getClassReceiver(); - const auto *ReceiverClassType = ReceiverType->getAs(); - QualType ReceiverClassPointerType = - C.getASTContext().getObjCObjectPointerType( - QualType(ReceiverClassType, 0)); - - if (!ReceiverClassType->isSpecialized()) - return; - const auto *InferredType = - ReceiverClassPointerType->getAs(); - assert(InferredType); - - ProgramStateRef State = C.getState(); - State = State->set(Sym, InferredType); - C.addTransition(State); -} - -static bool isObjCTypeParamDependent(QualType Type) { - // It is illegal to typedef parameterized types inside an interface. Therfore - // an Objective-C type can only be dependent on a type parameter when the type - // parameter structurally present in the type itself. - class IsObjCTypeParamDependentTypeVisitor - : public RecursiveASTVisitor { - public: - IsObjCTypeParamDependentTypeVisitor() : Result(false) {} - bool VisitTypedefType(const TypedefType *Type) { - if (isa(Type->getDecl())) { - Result = true; - return false; - } - return true; - } - - bool Result; - }; - - IsObjCTypeParamDependentTypeVisitor Visitor; - Visitor.TraverseType(Type); - return Visitor.Result; -} - -/// A method might not be available in the interface indicated by the static -/// type. However it might be available in the tracked type. In order to -/// properly substitute the type parameters we need the declaration context of -/// the method. The more specialized the enclosing class of the method is, the -/// more likely that the parameter substitution will be successful. -static const ObjCMethodDecl * -findMethodDecl(const ObjCMessageExpr *MessageExpr, - const ObjCObjectPointerType *TrackedType, ASTContext &ASTCtxt) { - const ObjCMethodDecl *Method = nullptr; - - QualType ReceiverType = MessageExpr->getReceiverType(); - const auto *ReceiverObjectPtrType = - ReceiverType->getAs(); - - // Do this "devirtualization" on instance and class methods only. Trust the - // static type on super and super class calls. - if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Instance || - MessageExpr->getReceiverKind() == ObjCMessageExpr::Class) { - // When the receiver type is id, Class, or some super class of the tracked - // type, look up the method in the tracked type, not in the receiver type. - // This way we preserve more information. - if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType() || - ASTCtxt.canAssignObjCInterfaces(ReceiverObjectPtrType, TrackedType)) { - const ObjCInterfaceDecl *InterfaceDecl = TrackedType->getInterfaceDecl(); - // The method might not be found. - Selector Sel = MessageExpr->getSelector(); - Method = InterfaceDecl->lookupInstanceMethod(Sel); - if (!Method) - Method = InterfaceDecl->lookupClassMethod(Sel); - } - } - - // Fallback to statick method lookup when the one based on the tracked type - // failed. - return Method ? Method : MessageExpr->getMethodDecl(); -} - -/// Validate that the return type of a message expression is used correctly. -void ObjCGenericsChecker::checkReturnType( - const ObjCMessageExpr *MessageExpr, - const ObjCObjectPointerType *TrackedType, SymbolRef Sym, - const ObjCMethodDecl *Method, ArrayRef TypeArgs, - bool SubscriptOrProperty, CheckerContext &C) const { - QualType StaticResultType = Method->getReturnType(); - ASTContext &ASTCtxt = C.getASTContext(); - // Check whether the result type was a type parameter. - bool IsDeclaredAsInstanceType = - StaticResultType == ASTCtxt.getObjCInstanceType(); - if (!isObjCTypeParamDependent(StaticResultType) && !IsDeclaredAsInstanceType) - return; - - QualType ResultType = Method->getReturnType().substObjCTypeArgs( - ASTCtxt, TypeArgs, ObjCSubstitutionContext::Result); - if (IsDeclaredAsInstanceType) - ResultType = QualType(TrackedType, 0); - - const Stmt *Parent = - C.getCurrentAnalysisDeclContext()->getParentMap().getParent(MessageExpr); - if (SubscriptOrProperty) { - // Properties and subscripts are not direct parents. - Parent = - C.getCurrentAnalysisDeclContext()->getParentMap().getParent(Parent); - } - - const auto *ImplicitCast = dyn_cast_or_null(Parent); - if (!ImplicitCast || ImplicitCast->getCastKind() != CK_BitCast) - return; - - const auto *ExprTypeAboveCast = - ImplicitCast->getType()->getAs(); - const auto *ResultPtrType = ResultType->getAs(); - - if (!ExprTypeAboveCast || !ResultPtrType) - return; - - // Only warn on unrelated types to avoid too many false positives on - // downcasts. - if (!ASTCtxt.canAssignObjCInterfaces(ExprTypeAboveCast, ResultPtrType) && - !ASTCtxt.canAssignObjCInterfaces(ResultPtrType, ExprTypeAboveCast)) { - static CheckerProgramPointTag Tag(this, "ReturnTypeMismatch"); - ExplodedNode *N = C.addTransition(C.getState(), &Tag); - reportGenericsBug(ResultPtrType, ExprTypeAboveCast, N, Sym, C); - return; - } -} - -/// When the receiver has a tracked type, use that type to validate the -/// argumments of the message expression and the return value. -void ObjCGenericsChecker::checkPreObjCMessage(const ObjCMethodCall &M, - CheckerContext &C) const { - ProgramStateRef State = C.getState(); - SymbolRef Sym = M.getReceiverSVal().getAsSymbol(); - if (!Sym) - return; - - const ObjCObjectPointerType *const *TrackedType = - State->get(Sym); - if (!TrackedType) - return; - - // Get the type arguments from tracked type and substitute type arguments - // before do the semantic check. - - ASTContext &ASTCtxt = C.getASTContext(); - const ObjCMessageExpr *MessageExpr = M.getOriginExpr(); - const ObjCMethodDecl *Method = - findMethodDecl(MessageExpr, *TrackedType, ASTCtxt); - - // It is possible to call non-existent methods in Obj-C. - if (!Method) - return; - - Optional> TypeArgs = - (*TrackedType)->getObjCSubstitutions(Method->getDeclContext()); - // This case might happen when there is an unspecialized override of a - // specialized method. - if (!TypeArgs) - return; - - for (unsigned i = 0; i < Method->param_size(); i++) { - const Expr *Arg = MessageExpr->getArg(i); - const ParmVarDecl *Param = Method->parameters()[i]; - - QualType OrigParamType = Param->getType(); - if (!isObjCTypeParamDependent(OrigParamType)) - continue; - - QualType ParamType = OrigParamType.substObjCTypeArgs( - ASTCtxt, *TypeArgs, ObjCSubstitutionContext::Parameter); - // Check if it can be assigned - const auto *ParamObjectPtrType = ParamType->getAs(); - const auto *ArgObjectPtrType = - stripCastsAndSugar(Arg)->getType()->getAs(); - if (!ParamObjectPtrType || !ArgObjectPtrType) - continue; - - // Check if we have more concrete tracked type that is not a super type of - // the static argument type. - SVal ArgSVal = M.getArgSVal(i); - SymbolRef ArgSym = ArgSVal.getAsSymbol(); - if (ArgSym) { - const ObjCObjectPointerType *const *TrackedArgType = - State->get(ArgSym); - if (TrackedArgType && - ASTCtxt.canAssignObjCInterfaces(ArgObjectPtrType, *TrackedArgType)) { - ArgObjectPtrType = *TrackedArgType; - } - } - - // Warn when argument is incompatible with the parameter. - if (!ASTCtxt.canAssignObjCInterfaces(ParamObjectPtrType, - ArgObjectPtrType)) { - static CheckerProgramPointTag Tag(this, "ArgTypeMismatch"); - ExplodedNode *N = C.addTransition(State, &Tag); - reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, Arg); - return; - } - } - - checkReturnType(MessageExpr, *TrackedType, Sym, Method, *TypeArgs, - M.getMessageKind() != OCM_Message, C); -} - -/// Register checker. -void ento::registerObjCGenericsChecker(CheckerManager &mgr) { - mgr.registerChecker(); -} -- 2.40.0