121 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C++
		
	
	
	
//=- 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 "llvm/Support/raw_ostream.h"
 | 
						|
 | 
						|
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::string sbuf;
 | 
						|
    llvm::raw_string_ostream os(sbuf);
 | 
						|
    
 | 
						|
    os << "The Objective-C class '"
 | 
						|
       << MethDerived->getClassInterface()->getNameAsString()
 | 
						|
       << "', which is derived from class '"
 | 
						|
       << MethAncestor->getClassInterface()->getNameAsString()
 | 
						|
       << "', defines the instance method '"
 | 
						|
       << MethDerived->getSelector().getAsString()
 | 
						|
       << "' whose return type is '"
 | 
						|
       << ResDerived.getAsString()
 | 
						|
       << "'.  A method with the same name (same selector) is also defined in "
 | 
						|
          "class '"
 | 
						|
       << MethAncestor->getClassInterface()->getNameAsString()
 | 
						|
       << "' and has a return type of '"
 | 
						|
       << ResAncestor.getAsString()
 | 
						|
       << "'.  These two types are incompatible, and may result in undefined "
 | 
						|
          "behavior for clients of these classes.";
 | 
						|
    
 | 
						|
    BR.EmitBasicReport("Incompatible instance method return type",
 | 
						|
                       os.str().c_str(), MethDerived->getLocStart());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
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();
 | 
						|
  }
 | 
						|
}
 |