You've already forked linux-packaging-mono
							
							
		
			
	
	
		
			141 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			141 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | //=- CheckObjCInstMethodRetTy.cpp - Check ObjC method signatures -*- C++ -*-==//
 | ||
|  | //
 | ||
|  | //                     The LLVM Compiler Infrastructure
 | ||
|  | //
 | ||
|  | // This file is distributed under the University of Illinois Open Source
 | ||
|  | // License. See LICENSE.TXT for details.
 | ||
|  | //
 | ||
|  | //===----------------------------------------------------------------------===//
 | ||
|  | //
 | ||
|  | //  This file defines a CheckObjCInstMethSignature, a flow-insenstive check
 | ||
|  | //  that determines if an Objective-C class interface incorrectly redefines
 | ||
|  | //  the method signature in a subclass.
 | ||
|  | //
 | ||
|  | //===----------------------------------------------------------------------===//
 | ||
|  | 
 | ||
|  | #include "ClangSACheckers.h"
 | ||
|  | #include "clang/AST/ASTContext.h"
 | ||
|  | #include "clang/AST/DeclObjC.h"
 | ||
|  | #include "clang/AST/Type.h"
 | ||
|  | #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 | ||
|  | #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
 | ||
|  | #include "clang/StaticAnalyzer/Core/Checker.h"
 | ||
|  | #include "llvm/ADT/DenseMap.h"
 | ||
|  | #include "llvm/Support/raw_ostream.h"
 | ||
|  | 
 | ||
|  | using namespace clang; | ||
|  | using namespace ento; | ||
|  | 
 | ||
|  | static bool AreTypesCompatible(QualType Derived, QualType Ancestor, | ||
|  |                                ASTContext &C) { | ||
|  | 
 | ||
|  |   // Right now don't compare the compatibility of pointers.  That involves
 | ||
|  |   // looking at subtyping relationships.  FIXME: Future patch.
 | ||
|  |   if (Derived->isAnyPointerType() &&  Ancestor->isAnyPointerType()) | ||
|  |     return true; | ||
|  | 
 | ||
|  |   return C.typesAreCompatible(Derived, Ancestor); | ||
|  | } | ||
|  | 
 | ||
|  | static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, | ||
|  |                                const ObjCMethodDecl *MethAncestor, | ||
|  |                                BugReporter &BR, ASTContext &Ctx, | ||
|  |                                const ObjCImplementationDecl *ID, | ||
|  |                                const CheckerBase *Checker) { | ||
|  | 
 | ||
|  |   QualType ResDerived = MethDerived->getReturnType(); | ||
|  |   QualType ResAncestor = MethAncestor->getReturnType(); | ||
|  | 
 | ||
|  |   if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) { | ||
|  |     std::string sbuf; | ||
|  |     llvm::raw_string_ostream os(sbuf); | ||
|  | 
 | ||
|  |     os << "The Objective-C class '" | ||
|  |        << *MethDerived->getClassInterface() | ||
|  |        << "', which is derived from class '" | ||
|  |        << *MethAncestor->getClassInterface() | ||
|  |        << "', defines the instance method '"; | ||
|  |     MethDerived->getSelector().print(os); | ||
|  |     os << "' whose return type is '" | ||
|  |        << ResDerived.getAsString() | ||
|  |        << "'.  A method with the same name (same selector) is also defined in " | ||
|  |           "class '" | ||
|  |        << *MethAncestor->getClassInterface() | ||
|  |        << "' and has a return type of '" | ||
|  |        << ResAncestor.getAsString() | ||
|  |        << "'.  These two types are incompatible, and may result in undefined " | ||
|  |           "behavior for clients of these classes."; | ||
|  | 
 | ||
|  |     PathDiagnosticLocation MethDLoc = | ||
|  |       PathDiagnosticLocation::createBegin(MethDerived, | ||
|  |                                           BR.getSourceManager()); | ||
|  | 
 | ||
|  |     BR.EmitBasicReport( | ||
|  |         MethDerived, Checker, "Incompatible instance method return type", | ||
|  |         categories::CoreFoundationObjectiveC, os.str(), MethDLoc); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, | ||
|  |                                        BugReporter &BR, | ||
|  |                                        const CheckerBase *Checker) { | ||
|  | 
 | ||
|  |   const ObjCInterfaceDecl *D = ID->getClassInterface(); | ||
|  |   const ObjCInterfaceDecl *C = D->getSuperClass(); | ||
|  | 
 | ||
|  |   if (!C) | ||
|  |     return; | ||
|  | 
 | ||
|  |   ASTContext &Ctx = BR.getContext(); | ||
|  | 
 | ||
|  |   // Build a DenseMap of the methods for quick querying.
 | ||
|  |   typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy; | ||
|  |   MapTy IMeths; | ||
|  |   unsigned NumMethods = 0; | ||
|  | 
 | ||
|  |   for (auto *M : ID->instance_methods()) { | ||
|  |     IMeths[M->getSelector()] = M; | ||
|  |     ++NumMethods; | ||
|  |   } | ||
|  | 
 | ||
|  |   // Now recurse the class hierarchy chain looking for methods with the
 | ||
|  |   // same signatures.
 | ||
|  |   while (C && NumMethods) { | ||
|  |     for (const auto *M : C->instance_methods()) { | ||
|  |       Selector S = M->getSelector(); | ||
|  | 
 | ||
|  |       MapTy::iterator MI = IMeths.find(S); | ||
|  | 
 | ||
|  |       if (MI == IMeths.end() || MI->second == nullptr) | ||
|  |         continue; | ||
|  | 
 | ||
|  |       --NumMethods; | ||
|  |       ObjCMethodDecl *MethDerived = MI->second; | ||
|  |       MI->second = nullptr; | ||
|  | 
 | ||
|  |       CompareReturnTypes(MethDerived, M, BR, Ctx, ID, Checker); | ||
|  |     } | ||
|  | 
 | ||
|  |     C = C->getSuperClass(); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | //===----------------------------------------------------------------------===//
 | ||
|  | // ObjCMethSigsChecker
 | ||
|  | //===----------------------------------------------------------------------===//
 | ||
|  | 
 | ||
|  | namespace { | ||
|  | class ObjCMethSigsChecker : public Checker< | ||
|  |                                       check::ASTDecl<ObjCImplementationDecl> > { | ||
|  | public: | ||
|  |   void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr, | ||
|  |                     BugReporter &BR) const { | ||
|  |     CheckObjCInstMethSignature(D, BR, this); | ||
|  |   } | ||
|  | }; | ||
|  | } | ||
|  | 
 | ||
|  | void ento::registerObjCMethSigsChecker(CheckerManager &mgr) { | ||
|  |   mgr.registerChecker<ObjCMethSigsChecker>(); | ||
|  | } |