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 167dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis#include "ClangSACheckers.h" 1755fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/AST/ASTContext.h" 180d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "clang/AST/DeclObjC.h" 190d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "clang/AST/Type.h" 2055fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 2155fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 2255fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "clang/StaticAnalyzer/Core/Checker.h" 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, 309c378f705405d37f49795d5e915989de774fe11fTed 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, 43651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const ObjCImplementationDecl *ID, 44651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const CheckerBase *Checker) { 451eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 46651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines QualType ResDerived = MethDerived->getReturnType(); 47651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines QualType ResAncestor = MethAncestor->getReturnType(); 481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 490d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) { 5013493ea1583f39d62a66e2b2a0802f08d8ec32caTed Kremenek std::string sbuf; 5113493ea1583f39d62a66e2b2a0802f08d8ec32caTed Kremenek llvm::raw_string_ostream os(sbuf); 521eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 530d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek os << "The Objective-C class '" 54b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer << *MethDerived->getClassInterface() 550d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << "', which is derived from class '" 56b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer << *MethAncestor->getClassInterface() 57651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines << "', defines the instance method '"; 58651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines MethDerived->getSelector().print(os); 59651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines os << "' whose return type is '" 600d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << ResDerived.getAsString() 61e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek << "'. A method with the same name (same selector) is also defined in " 62e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek "class '" 63b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer << *MethAncestor->getClassInterface() 64e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek << "' and has a return type of '" 650d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << ResAncestor.getAsString() 660d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek << "'. These two types are incompatible, and may result in undefined " 670d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek "behavior for clients of these classes."; 681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 69590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks PathDiagnosticLocation MethDLoc = 70590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks PathDiagnosticLocation::createBegin(MethDerived, 71590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks BR.getSourceManager()); 72590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks 73651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BR.EmitBasicReport( 74651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines MethDerived, Checker, "Incompatible instance method return type", 75651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines categories::CoreFoundationObjectiveC, os.str(), MethDLoc); 760d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 770d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek} 780d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 799c378f705405d37f49795d5e915989de774fe11fTed Kremenekstatic void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, 80651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BugReporter &BR, 81651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines const CheckerBase *Checker) { 821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 839c378f705405d37f49795d5e915989de774fe11fTed Kremenek const ObjCInterfaceDecl *D = ID->getClassInterface(); 849c378f705405d37f49795d5e915989de774fe11fTed Kremenek const ObjCInterfaceDecl *C = D->getSuperClass(); 850d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 860d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek if (!C) 870d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return; 881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 899c378f705405d37f49795d5e915989de774fe11fTed Kremenek ASTContext &Ctx = BR.getContext(); 901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 910d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // Build a DenseMap of the methods for quick querying. 920d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy; 930d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek MapTy IMeths; 940d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek unsigned NumMethods = 0; 951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 96651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines for (auto *M : ID->instance_methods()) { 970d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek IMeths[M->getSelector()] = M; 980d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek ++NumMethods; 990d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 1000d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1010d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // Now recurse the class hierarchy chain looking for methods with the 1020d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // same signatures. 1030d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek while (C && NumMethods) { 104651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines for (const auto *M : C->instance_methods()) { 1050d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek Selector S = M->getSelector(); 1061eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1070d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek MapTy::iterator MI = IMeths.find(S); 1080d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 1096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (MI == IMeths.end() || MI->second == nullptr) 1100d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek continue; 1111eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1120d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek --NumMethods; 1139c378f705405d37f49795d5e915989de774fe11fTed Kremenek ObjCMethodDecl *MethDerived = MI->second; 1146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines MI->second = nullptr; 1151eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 116651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines CompareReturnTypes(MethDerived, M, BR, Ctx, ID, Checker); 1170d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 1181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1190d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek C = C->getSuperClass(); 1200d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 1210d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek} 1227dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis 1237dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis//===----------------------------------------------------------------------===// 1247dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis// ObjCMethSigsChecker 1257dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis//===----------------------------------------------------------------------===// 1267dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis 1277dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidisnamespace { 128ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidisclass ObjCMethSigsChecker : public Checker< 1297dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis check::ASTDecl<ObjCImplementationDecl> > { 1307dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidispublic: 1317dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr, 1327dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis BugReporter &BR) const { 133651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines CheckObjCInstMethSignature(D, BR, this); 1347dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis } 1357dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis}; 1367dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis} 1377dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis 1387dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidisvoid ento::registerObjCMethSigsChecker(CheckerManager &mgr) { 1397dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis mgr.registerChecker<ObjCMethSigsChecker>(); 1407dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis} 141