CheckObjCInstMethSignature.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. //=- CheckObjCInstMethodRetTy.cpp - Check ObjC method signatures -*- C++ -*-==//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This file defines a CheckObjCInstMethSignature, a flow-insenstive check
  11. // that determines if an Objective-C class interface incorrectly redefines
  12. // the method signature in a subclass.
  13. //
  14. //===----------------------------------------------------------------------===//
  15. #include "ClangSACheckers.h"
  16. #include "clang/AST/ASTContext.h"
  17. #include "clang/AST/DeclObjC.h"
  18. #include "clang/AST/Type.h"
  19. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  20. #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
  21. #include "clang/StaticAnalyzer/Core/Checker.h"
  22. #include "llvm/ADT/DenseMap.h"
  23. #include "llvm/Support/raw_ostream.h"
  24. using namespace clang;
  25. using namespace ento;
  26. static bool AreTypesCompatible(QualType Derived, QualType Ancestor,
  27. ASTContext &C) {
  28. // Right now don't compare the compatibility of pointers. That involves
  29. // looking at subtyping relationships. FIXME: Future patch.
  30. if (Derived->isAnyPointerType() && Ancestor->isAnyPointerType())
  31. return true;
  32. return C.typesAreCompatible(Derived, Ancestor);
  33. }
  34. static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
  35. const ObjCMethodDecl *MethAncestor,
  36. BugReporter &BR, ASTContext &Ctx,
  37. const ObjCImplementationDecl *ID,
  38. const CheckerBase *Checker) {
  39. QualType ResDerived = MethDerived->getReturnType();
  40. QualType ResAncestor = MethAncestor->getReturnType();
  41. if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) {
  42. std::string sbuf;
  43. llvm::raw_string_ostream os(sbuf);
  44. os << "The Objective-C class '"
  45. << *MethDerived->getClassInterface()
  46. << "', which is derived from class '"
  47. << *MethAncestor->getClassInterface()
  48. << "', defines the instance method '";
  49. MethDerived->getSelector().print(os);
  50. os << "' whose return type is '"
  51. << ResDerived.getAsString()
  52. << "'. A method with the same name (same selector) is also defined in "
  53. "class '"
  54. << *MethAncestor->getClassInterface()
  55. << "' and has a return type of '"
  56. << ResAncestor.getAsString()
  57. << "'. These two types are incompatible, and may result in undefined "
  58. "behavior for clients of these classes.";
  59. PathDiagnosticLocation MethDLoc =
  60. PathDiagnosticLocation::createBegin(MethDerived,
  61. BR.getSourceManager());
  62. BR.EmitBasicReport(
  63. MethDerived, Checker, "Incompatible instance method return type",
  64. categories::CoreFoundationObjectiveC, os.str(), MethDLoc);
  65. }
  66. }
  67. static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID,
  68. BugReporter &BR,
  69. const CheckerBase *Checker) {
  70. const ObjCInterfaceDecl *D = ID->getClassInterface();
  71. const ObjCInterfaceDecl *C = D->getSuperClass();
  72. if (!C)
  73. return;
  74. ASTContext &Ctx = BR.getContext();
  75. // Build a DenseMap of the methods for quick querying.
  76. typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy;
  77. MapTy IMeths;
  78. unsigned NumMethods = 0;
  79. for (auto *M : ID->instance_methods()) {
  80. IMeths[M->getSelector()] = M;
  81. ++NumMethods;
  82. }
  83. // Now recurse the class hierarchy chain looking for methods with the
  84. // same signatures.
  85. while (C && NumMethods) {
  86. for (const auto *M : C->instance_methods()) {
  87. Selector S = M->getSelector();
  88. MapTy::iterator MI = IMeths.find(S);
  89. if (MI == IMeths.end() || MI->second == nullptr)
  90. continue;
  91. --NumMethods;
  92. ObjCMethodDecl *MethDerived = MI->second;
  93. MI->second = nullptr;
  94. CompareReturnTypes(MethDerived, M, BR, Ctx, ID, Checker);
  95. }
  96. C = C->getSuperClass();
  97. }
  98. }
  99. //===----------------------------------------------------------------------===//
  100. // ObjCMethSigsChecker
  101. //===----------------------------------------------------------------------===//
  102. namespace {
  103. class ObjCMethSigsChecker : public Checker<
  104. check::ASTDecl<ObjCImplementationDecl> > {
  105. public:
  106. void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
  107. BugReporter &BR) const {
  108. CheckObjCInstMethSignature(D, BR, this);
  109. }
  110. };
  111. }
  112. void ento::registerObjCMethSigsChecker(CheckerManager &mgr) {
  113. mgr.registerChecker<ObjCMethSigsChecker>();
  114. }