diff options
author | Ted Kremenek <kremenek@apple.com> | 2008-07-11 22:40:47 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2008-07-11 22:40:47 +0000 |
commit | 0d8019e55c0f465bafc11b04aed691de95b9131d (patch) | |
tree | 67854def92c93e2096a354c201a6de323e349ee8 /lib/Analysis/CheckObjCInstMethSignature.cpp | |
parent | 75a4881047deeb3a300ff9293dc6ba8570048bb5 (diff) |
Add new check: -check-objc-methodsigs. This check scans methods in
ObjCImplementationDecls and sees if a ancestor class defines a method with the
same selector but with a different type signature. Right now it just compares
return types, and mainly looks at differences in primitive values. The checking
will be expanded in the future.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@53482 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/CheckObjCInstMethSignature.cpp')
-rw-r--r-- | lib/Analysis/CheckObjCInstMethSignature.cpp | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Analysis/CheckObjCInstMethSignature.cpp new file mode 100644 index 0000000000..2572edbc12 --- /dev/null +++ b/lib/Analysis/CheckObjCInstMethSignature.cpp @@ -0,0 +1,125 @@ +//=- CheckObjCInstMethodRetTy.cpp - Check ObjC method signatures -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a CheckObjCInstMethSignature, a flow-insenstive check +// that determines if an Objective-C class interface incorrectly redefines +// the method signature in a subclass. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/LocalCheckers.h" +#include "clang/Analysis/PathDiagnostic.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Type.h" +#include "clang/AST/ASTContext.h" + +#include "llvm/ADT/DenseMap.h" +#include <sstream> + +using namespace clang; + +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->isPointerType() || Derived->isObjCQualifiedIdType()) && + (Ancestor->isPointerType() || Ancestor->isObjCQualifiedIdType())) + return true; + + return C.typesAreCompatible(Derived, Ancestor); +} + +static void CompareReturnTypes(ObjCMethodDecl* MethDerived, + ObjCMethodDecl* MethAncestor, + BugReporter& BR, ASTContext& Ctx, + ObjCImplementationDecl* ID) { + + QualType ResDerived = MethDerived->getResultType(); + QualType ResAncestor = MethAncestor->getResultType(); + + if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) { + std::ostringstream os; + + os << "The Objective-C class '" + << MethDerived->getClassInterface()->getName() + << "', which is derived from class '" + << MethAncestor->getClassInterface()->getName() + << "', defines the instance method '" + << MethDerived->getSelector().getName() + << "' whose return type is '" + << ResDerived.getAsString() + << "'. The same method (same selector) is defined in class 'B' and has " + "a return type of '" + << ResAncestor.getAsString() + << "'. These two types are incompatible, and may result in undefined " + "behavior for clients of these classes."; + + // Refactor. + SimpleBugType BT("incompatible instance method return type"); + DiagCollector C(BT); + Diagnostic& Diag = BR.getDiagnostic(); + Diag.Report(&C, Ctx.getFullLoc(MethDerived->getLocStart()), + Diag.getCustomDiagID(Diagnostic::Warning, os.str().c_str()), + NULL, 0, NULL, 0); + + for (DiagCollector::iterator I = C.begin(), E = C.end(); I != E; ++I) + BR.EmitWarning(*I); + } +} + +void clang::CheckObjCInstMethSignature(ObjCImplementationDecl* ID, + BugReporter& BR) { + + ObjCInterfaceDecl* D = ID->getClassInterface(); + ObjCInterfaceDecl* C = D->getSuperClass(); + + if (!C) + return; + + // Build a DenseMap of the methods for quick querying. + typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy; + MapTy IMeths; + unsigned NumMethods = 0; + + for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(), + E=ID->instmeth_end(); I!=E; ++I) { + + ObjCMethodDecl* M = *I; + IMeths[M->getSelector()] = M; + ++NumMethods; + } + + // Now recurse the class hierarchy chain looking for methods with the + // same signatures. + ASTContext& Ctx = BR.getContext(); + + while (C && NumMethods) { + for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(), + E=C->instmeth_end(); I!=E; ++I) { + + ObjCMethodDecl* M = *I; + Selector S = M->getSelector(); + + MapTy::iterator MI = IMeths.find(S); + + if (MI == IMeths.end() || MI->second == 0) + continue; + + --NumMethods; + ObjCMethodDecl* MethDerived = MI->second; + MI->second = 0; + + CompareReturnTypes(MethDerived, M, BR, Ctx, ID); + } + + C = C->getSuperClass(); + } +} |