clang API Documentation
00001 //=- CheckObjCInstMethodRetTy.cpp - Check ObjC method signatures -*- C++ -*-==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines a CheckObjCInstMethSignature, a flow-insenstive check 00011 // that determines if an Objective-C class interface incorrectly redefines 00012 // the method signature in a subclass. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "ClangSACheckers.h" 00017 #include "clang/AST/ASTContext.h" 00018 #include "clang/AST/DeclObjC.h" 00019 #include "clang/AST/Type.h" 00020 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 00021 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 00022 #include "clang/StaticAnalyzer/Core/Checker.h" 00023 #include "llvm/ADT/DenseMap.h" 00024 #include "llvm/Support/raw_ostream.h" 00025 00026 using namespace clang; 00027 using namespace ento; 00028 00029 static bool AreTypesCompatible(QualType Derived, QualType Ancestor, 00030 ASTContext &C) { 00031 00032 // Right now don't compare the compatibility of pointers. That involves 00033 // looking at subtyping relationships. FIXME: Future patch. 00034 if (Derived->isAnyPointerType() && Ancestor->isAnyPointerType()) 00035 return true; 00036 00037 return C.typesAreCompatible(Derived, Ancestor); 00038 } 00039 00040 static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, 00041 const ObjCMethodDecl *MethAncestor, 00042 BugReporter &BR, ASTContext &Ctx, 00043 const ObjCImplementationDecl *ID, 00044 const CheckerBase *Checker) { 00045 00046 QualType ResDerived = MethDerived->getReturnType(); 00047 QualType ResAncestor = MethAncestor->getReturnType(); 00048 00049 if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) { 00050 std::string sbuf; 00051 llvm::raw_string_ostream os(sbuf); 00052 00053 os << "The Objective-C class '" 00054 << *MethDerived->getClassInterface() 00055 << "', which is derived from class '" 00056 << *MethAncestor->getClassInterface() 00057 << "', defines the instance method '"; 00058 MethDerived->getSelector().print(os); 00059 os << "' whose return type is '" 00060 << ResDerived.getAsString() 00061 << "'. A method with the same name (same selector) is also defined in " 00062 "class '" 00063 << *MethAncestor->getClassInterface() 00064 << "' and has a return type of '" 00065 << ResAncestor.getAsString() 00066 << "'. These two types are incompatible, and may result in undefined " 00067 "behavior for clients of these classes."; 00068 00069 PathDiagnosticLocation MethDLoc = 00070 PathDiagnosticLocation::createBegin(MethDerived, 00071 BR.getSourceManager()); 00072 00073 BR.EmitBasicReport( 00074 MethDerived, Checker, "Incompatible instance method return type", 00075 categories::CoreFoundationObjectiveC, os.str(), MethDLoc); 00076 } 00077 } 00078 00079 static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID, 00080 BugReporter &BR, 00081 const CheckerBase *Checker) { 00082 00083 const ObjCInterfaceDecl *D = ID->getClassInterface(); 00084 const ObjCInterfaceDecl *C = D->getSuperClass(); 00085 00086 if (!C) 00087 return; 00088 00089 ASTContext &Ctx = BR.getContext(); 00090 00091 // Build a DenseMap of the methods for quick querying. 00092 typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy; 00093 MapTy IMeths; 00094 unsigned NumMethods = 0; 00095 00096 for (auto *M : ID->instance_methods()) { 00097 IMeths[M->getSelector()] = M; 00098 ++NumMethods; 00099 } 00100 00101 // Now recurse the class hierarchy chain looking for methods with the 00102 // same signatures. 00103 while (C && NumMethods) { 00104 for (const auto *M : C->instance_methods()) { 00105 Selector S = M->getSelector(); 00106 00107 MapTy::iterator MI = IMeths.find(S); 00108 00109 if (MI == IMeths.end() || MI->second == nullptr) 00110 continue; 00111 00112 --NumMethods; 00113 ObjCMethodDecl *MethDerived = MI->second; 00114 MI->second = nullptr; 00115 00116 CompareReturnTypes(MethDerived, M, BR, Ctx, ID, Checker); 00117 } 00118 00119 C = C->getSuperClass(); 00120 } 00121 } 00122 00123 //===----------------------------------------------------------------------===// 00124 // ObjCMethSigsChecker 00125 //===----------------------------------------------------------------------===// 00126 00127 namespace { 00128 class ObjCMethSigsChecker : public Checker< 00129 check::ASTDecl<ObjCImplementationDecl> > { 00130 public: 00131 void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr, 00132 BugReporter &BR) const { 00133 CheckObjCInstMethSignature(D, BR, this); 00134 } 00135 }; 00136 } 00137 00138 void ento::registerObjCMethSigsChecker(CheckerManager &mgr) { 00139 mgr.registerChecker<ObjCMethSigsChecker>(); 00140 }