CheckObjCInstMethSignature.cpp revision 9ef6537a894c33003359b1f9b9676e9178e028b7
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 1698cabbad47a4d9db6b7e95c950d3302c110d1b02Argyrios Kyrtzidis#include "clang/GR/Checkers/LocalCheckers.h" 1798cabbad47a4d9db6b7e95c950d3302c110d1b02Argyrios Kyrtzidis#include "clang/GR/BugReporter/PathDiagnostic.h" 1898cabbad47a4d9db6b7e95c950d3302c110d1b02Argyrios Kyrtzidis#include "clang/GR/BugReporter/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" 2413493ea1583f39d62a66e2b2a0802f08d8ec32caTed Kremenek#include "llvm/Support/raw_ostream.h" 250d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 260d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekusing namespace clang; 279ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekusing namespace ento; 280d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 290d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekstatic bool AreTypesCompatible(QualType Derived, QualType Ancestor, 300d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ASTContext& C) { 310d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 320d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // Right now don't compare the compatibility of pointers. That involves 330d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // looking at subtyping relationships. FIXME: Future patch. 3458f9f2c884af6b72d036b746a016d8031d31cb7aSteve Naroff if (Derived->isAnyPointerType() && Ancestor->isAnyPointerType()) 350d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return true; 360d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 370d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return C.typesAreCompatible(Derived, Ancestor); 380d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek} 390d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 402376002038c8b904acd20be754aedd1a7471be71Ted Kremenekstatic void CompareReturnTypes(const ObjCMethodDecl *MethDerived, 412376002038c8b904acd20be754aedd1a7471be71Ted Kremenek const ObjCMethodDecl *MethAncestor, 422376002038c8b904acd20be754aedd1a7471be71Ted Kremenek BugReporter &BR, ASTContext &Ctx, 432376002038c8b904acd20be754aedd1a7471be71Ted Kremenek const ObjCImplementationDecl *ID) { 441eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 450d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek QualType ResDerived = MethDerived->getResultType(); 461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump QualType ResAncestor = MethAncestor->getResultType(); 471eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 480d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) { 4913493ea1583f39d62a66e2b2a0802f08d8ec32caTed Kremenek std::string sbuf; 5013493ea1583f39d62a66e2b2a0802f08d8ec32caTed Kremenek llvm::raw_string_ostream os(sbuf); 511eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 520d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek os << "The Objective-C class '" 53900fc6388e803868a34b9483510c345e9b49d7ebBenjamin Kramer << MethDerived->getClassInterface() 540d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << "', which is derived from class '" 55900fc6388e803868a34b9483510c345e9b49d7ebBenjamin Kramer << MethAncestor->getClassInterface() 560d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << "', defines the instance method '" 57077bf5e2f48acfa9e7d69429b6e4ba86ea14896dChris Lattner << MethDerived->getSelector().getAsString() 580d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << "' whose return type is '" 590d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << ResDerived.getAsString() 60e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek << "'. A method with the same name (same selector) is also defined in " 61e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek "class '" 62900fc6388e803868a34b9483510c345e9b49d7ebBenjamin Kramer << MethAncestor->getClassInterface() 63e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek << "' and has a return type of '" 640d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << ResAncestor.getAsString() 650d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << "'. These two types are incompatible, and may result in undefined " 660d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek "behavior for clients of these classes."; 671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 6813493ea1583f39d62a66e2b2a0802f08d8ec32caTed Kremenek BR.EmitBasicReport("Incompatible instance method return type", 69f0171732efb4647772ad2a45c0f31978b0e34f71Benjamin Kramer os.str(), MethDerived->getLocStart()); 700d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 710d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek} 720d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 739ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenekvoid ento::CheckObjCInstMethSignature(const ObjCImplementationDecl* ID, 745a4f98ff943e6a501b0fe47ade007c9bbf96cb88Argyrios Kyrtzidis BugReporter& BR) { 751eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 762376002038c8b904acd20be754aedd1a7471be71Ted Kremenek const ObjCInterfaceDecl* D = ID->getClassInterface(); 772376002038c8b904acd20be754aedd1a7471be71Ted Kremenek const ObjCInterfaceDecl* C = D->getSuperClass(); 780d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 790d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek if (!C) 800d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return; 811eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 82653f1b1bf293a9bd96fd4dd6372e779cc7af1597Douglas Gregor ASTContext& Ctx = BR.getContext(); 831eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 840d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // Build a DenseMap of the methods for quick querying. 850d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy; 860d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek MapTy IMeths; 870d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek unsigned NumMethods = 0; 881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 8917945a0f64fe03ff6ec0c2146005a87636e3ac12Argyrios Kyrtzidis for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(), 901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump E=ID->instmeth_end(); I!=E; ++I) { 911eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 920d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ObjCMethodDecl* M = *I; 930d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek IMeths[M->getSelector()] = M; 940d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ++NumMethods; 950d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 960d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 970d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // Now recurse the class hierarchy chain looking for methods with the 980d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // same signatures. 990d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek while (C && NumMethods) { 10017945a0f64fe03ff6ec0c2146005a87636e3ac12Argyrios Kyrtzidis for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(), 10117945a0f64fe03ff6ec0c2146005a87636e3ac12Argyrios Kyrtzidis E=C->instmeth_end(); I!=E; ++I) { 1020d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1030d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ObjCMethodDecl* M = *I; 1040d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek Selector S = M->getSelector(); 1051eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1060d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek MapTy::iterator MI = IMeths.find(S); 1070d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1080d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek if (MI == IMeths.end() || MI->second == 0) 1090d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek continue; 1101eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1110d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek --NumMethods; 1120d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ObjCMethodDecl* MethDerived = MI->second; 1130d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek MI->second = 0; 1141eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1150d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek CompareReturnTypes(MethDerived, M, BR, Ctx, ID); 1160d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 1171eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1180d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek C = C->getSuperClass(); 1190d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 1200d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek} 121