CheckObjCInstMethSignature.cpp revision e4773eb6398acb03ad692050cb84b53ca1750b5b
10d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek//=- CheckObjCInstMethodRetTy.cpp - Check ObjC method signatures -*- C++ -*-==// 20d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// 30d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// The LLVM Compiler Infrastructure 40d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// 50d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// This file is distributed under the University of Illinois Open Source 60d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// License. See LICENSE.TXT for details. 70d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// 80d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek//===----------------------------------------------------------------------===// 90d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// 100d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// This file defines a CheckObjCInstMethSignature, a flow-insenstive check 110d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// that determines if an Objective-C class interface incorrectly redefines 120d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// the method signature in a subclass. 130d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// 140d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek//===----------------------------------------------------------------------===// 150d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 160d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "clang/Analysis/LocalCheckers.h" 170d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "clang/Analysis/PathDiagnostic.h" 180d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "clang/Analysis/PathSensitive/BugReporter.h" 190d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "clang/AST/DeclObjC.h" 200d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "clang/AST/Type.h" 210d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "clang/AST/ASTContext.h" 220d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 230d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "llvm/ADT/DenseMap.h" 240d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include <sstream> 250d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 260d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekusing namespace clang; 270d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 280d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekstatic bool AreTypesCompatible(QualType Derived, QualType Ancestor, 290d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ASTContext& C) { 300d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 310d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // Right now don't compare the compatibility of pointers. That involves 320d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // looking at subtyping relationships. FIXME: Future patch. 330d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek if ((Derived->isPointerType() || Derived->isObjCQualifiedIdType()) && 340d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek (Ancestor->isPointerType() || Ancestor->isObjCQualifiedIdType())) 350d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return true; 360d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 370d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return C.typesAreCompatible(Derived, Ancestor); 380d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek} 390d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 400d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekstatic void CompareReturnTypes(ObjCMethodDecl* MethDerived, 410d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ObjCMethodDecl* MethAncestor, 420d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek BugReporter& BR, ASTContext& Ctx, 430d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ObjCImplementationDecl* ID) { 440d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 450d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek QualType ResDerived = MethDerived->getResultType(); 460d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek QualType ResAncestor = MethAncestor->getResultType(); 470d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 480d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) { 490d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek std::ostringstream os; 500d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 510d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek os << "The Objective-C class '" 520d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << MethDerived->getClassInterface()->getName() 530d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << "', which is derived from class '" 540d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << MethAncestor->getClassInterface()->getName() 550d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << "', defines the instance method '" 560d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << MethDerived->getSelector().getName() 570d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << "' whose return type is '" 580d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << ResDerived.getAsString() 59e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek << "'. A method with the same name (same selector) is also defined in " 60e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek "class '" 61e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek << MethAncestor->getClassInterface()->getName() 62e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek << "' and has a return type of '" 630d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << ResAncestor.getAsString() 640d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << "'. These two types are incompatible, and may result in undefined " 650d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek "behavior for clients of these classes."; 660d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 670d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // Refactor. 680d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek SimpleBugType BT("incompatible instance method return type"); 690d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek DiagCollector C(BT); 700d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek Diagnostic& Diag = BR.getDiagnostic(); 710d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek Diag.Report(&C, Ctx.getFullLoc(MethDerived->getLocStart()), 720d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek Diag.getCustomDiagID(Diagnostic::Warning, os.str().c_str()), 730d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek NULL, 0, NULL, 0); 740d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 750d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek for (DiagCollector::iterator I = C.begin(), E = C.end(); I != E; ++I) 760d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek BR.EmitWarning(*I); 770d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 780d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek} 790d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 800d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekvoid clang::CheckObjCInstMethSignature(ObjCImplementationDecl* ID, 810d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek BugReporter& BR) { 820d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 830d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ObjCInterfaceDecl* D = ID->getClassInterface(); 840d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ObjCInterfaceDecl* C = D->getSuperClass(); 850d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 860d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek if (!C) 870d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return; 880d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 890d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // Build a DenseMap of the methods for quick querying. 900d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy; 910d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek MapTy IMeths; 920d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek unsigned NumMethods = 0; 930d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 940d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(), 950d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek E=ID->instmeth_end(); I!=E; ++I) { 960d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 970d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ObjCMethodDecl* M = *I; 980d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek IMeths[M->getSelector()] = M; 990d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ++NumMethods; 1000d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 1010d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1020d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // Now recurse the class hierarchy chain looking for methods with the 1030d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // same signatures. 1040d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ASTContext& Ctx = BR.getContext(); 1050d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1060d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek while (C && NumMethods) { 1070d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(), 1080d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek E=C->instmeth_end(); I!=E; ++I) { 1090d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1100d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ObjCMethodDecl* M = *I; 1110d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek Selector S = M->getSelector(); 1120d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1130d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek MapTy::iterator MI = IMeths.find(S); 1140d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1150d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek if (MI == IMeths.end() || MI->second == 0) 1160d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek continue; 1170d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1180d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek --NumMethods; 1190d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ObjCMethodDecl* MethDerived = MI->second; 1200d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek MI->second = 0; 1210d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1220d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek CompareReturnTypes(MethDerived, M, BR, Ctx, ID); 1230d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 1240d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1250d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek C = C->getSuperClass(); 1260d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 1270d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek} 128