123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- //===-- CheckObjCInstMethSignature.cpp - Check ObjC method signatures -----===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file defines a CheckObjCInstMethSignature, a flow-insensitive check
- // that determines if an Objective-C class interface incorrectly redefines
- // the method signature in a subclass.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
- #include "clang/Analysis/PathDiagnostic.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/DeclObjC.h"
- #include "clang/AST/Type.h"
- #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
- #include "clang/StaticAnalyzer/Core/Checker.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/Support/raw_ostream.h"
- using namespace clang;
- using namespace ento;
- static bool AreTypesCompatible(QualType Derived, QualType Ancestor,
- ASTContext &C) {
- // Right now don't compare the compatibility of pointers. That involves
- // looking at subtyping relationships. FIXME: Future patch.
- if (Derived->isAnyPointerType() && Ancestor->isAnyPointerType())
- return true;
- return C.typesAreCompatible(Derived, Ancestor);
- }
- static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
- const ObjCMethodDecl *MethAncestor,
- BugReporter &BR, ASTContext &Ctx,
- const ObjCImplementationDecl *ID,
- const CheckerBase *Checker) {
- QualType ResDerived = MethDerived->getReturnType();
- QualType ResAncestor = MethAncestor->getReturnType();
- if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) {
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- os << "The Objective-C class '"
- << *MethDerived->getClassInterface()
- << "', which is derived from class '"
- << *MethAncestor->getClassInterface()
- << "', defines the instance method '";
- MethDerived->getSelector().print(os);
- os << "' whose return type is '"
- << ResDerived.getAsString()
- << "'. A method with the same name (same selector) is also defined in "
- "class '"
- << *MethAncestor->getClassInterface()
- << "' and has a return type of '"
- << ResAncestor.getAsString()
- << "'. These two types are incompatible, and may result in undefined "
- "behavior for clients of these classes.";
- PathDiagnosticLocation MethDLoc =
- PathDiagnosticLocation::createBegin(MethDerived,
- BR.getSourceManager());
- BR.EmitBasicReport(
- MethDerived, Checker, "Incompatible instance method return type",
- categories::CoreFoundationObjectiveC, os.str(), MethDLoc);
- }
- }
- static void CheckObjCInstMethSignature(const ObjCImplementationDecl *ID,
- BugReporter &BR,
- const CheckerBase *Checker) {
- const ObjCInterfaceDecl *D = ID->getClassInterface();
- const ObjCInterfaceDecl *C = D->getSuperClass();
- if (!C)
- return;
- ASTContext &Ctx = BR.getContext();
- // Build a DenseMap of the methods for quick querying.
- typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy;
- MapTy IMeths;
- unsigned NumMethods = 0;
- for (auto *M : ID->instance_methods()) {
- IMeths[M->getSelector()] = M;
- ++NumMethods;
- }
- // Now recurse the class hierarchy chain looking for methods with the
- // same signatures.
- while (C && NumMethods) {
- for (const auto *M : C->instance_methods()) {
- Selector S = M->getSelector();
- MapTy::iterator MI = IMeths.find(S);
- if (MI == IMeths.end() || MI->second == nullptr)
- continue;
- --NumMethods;
- ObjCMethodDecl *MethDerived = MI->second;
- MI->second = nullptr;
- CompareReturnTypes(MethDerived, M, BR, Ctx, ID, Checker);
- }
- C = C->getSuperClass();
- }
- }
- //===----------------------------------------------------------------------===//
- // ObjCMethSigsChecker
- //===----------------------------------------------------------------------===//
- namespace {
- class ObjCMethSigsChecker : public Checker<
- check::ASTDecl<ObjCImplementationDecl> > {
- public:
- void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr,
- BugReporter &BR) const {
- CheckObjCInstMethSignature(D, BR, this);
- }
- };
- }
- void ento::registerObjCMethSigsChecker(CheckerManager &mgr) {
- mgr.registerChecker<ObjCMethSigsChecker>();
- }
- bool ento::shouldRegisterObjCMethSigsChecker(const CheckerManager &mgr) {
- return true;
- }
|