forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			471 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			471 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- Analyzer.cpp - Analysis for indexing information -------*- C++ -*-===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// This file implements the Analyzer interface.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "clang/Index/Analyzer.h"
 | 
						|
#include "clang/Index/Entity.h"
 | 
						|
#include "clang/Index/TranslationUnit.h"
 | 
						|
#include "clang/Index/Handlers.h"
 | 
						|
#include "clang/Index/ASTLocation.h"
 | 
						|
#include "clang/Index/GlobalSelector.h"
 | 
						|
#include "clang/Index/DeclReferenceMap.h"
 | 
						|
#include "clang/Index/SelectorMap.h"
 | 
						|
#include "clang/Index/IndexProvider.h"
 | 
						|
#include "clang/AST/DeclObjC.h"
 | 
						|
#include "clang/AST/ExprObjC.h"
 | 
						|
#include "llvm/ADT/SmallSet.h"
 | 
						|
using namespace clang;
 | 
						|
using namespace idx;
 | 
						|
 | 
						|
namespace  {
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// DeclEntityAnalyzer Implementation
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
class DeclEntityAnalyzer : public TranslationUnitHandler {
 | 
						|
  Entity Ent;
 | 
						|
  TULocationHandler &TULocHandler;
 | 
						|
 | 
						|
public:
 | 
						|
  DeclEntityAnalyzer(Entity ent, TULocationHandler &handler)
 | 
						|
    : Ent(ent), TULocHandler(handler) { }
 | 
						|
 | 
						|
  virtual void Handle(TranslationUnit *TU) {
 | 
						|
    assert(TU && "Passed null translation unit");
 | 
						|
 | 
						|
    Decl *D = Ent.getDecl(TU->getASTContext());
 | 
						|
    assert(D && "Couldn't resolve Entity");
 | 
						|
 | 
						|
    for (Decl::redecl_iterator I = D->redecls_begin(),
 | 
						|
                               E = D->redecls_end(); I != E; ++I)
 | 
						|
      TULocHandler.Handle(TULocation(TU, ASTLocation(*I)));
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// RefEntityAnalyzer Implementation
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
class RefEntityAnalyzer : public TranslationUnitHandler {
 | 
						|
  Entity Ent;
 | 
						|
  TULocationHandler &TULocHandler;
 | 
						|
 | 
						|
public:
 | 
						|
  RefEntityAnalyzer(Entity ent, TULocationHandler &handler)
 | 
						|
    : Ent(ent), TULocHandler(handler) { }
 | 
						|
 | 
						|
  virtual void Handle(TranslationUnit *TU) {
 | 
						|
    assert(TU && "Passed null translation unit");
 | 
						|
 | 
						|
    Decl *D = Ent.getDecl(TU->getASTContext());
 | 
						|
    assert(D && "Couldn't resolve Entity");
 | 
						|
    NamedDecl *ND = dyn_cast<NamedDecl>(D);
 | 
						|
    if (!ND)
 | 
						|
      return;
 | 
						|
 | 
						|
    DeclReferenceMap &RefMap = TU->getDeclReferenceMap();
 | 
						|
    for (DeclReferenceMap::astlocation_iterator
 | 
						|
           I = RefMap.refs_begin(ND), E = RefMap.refs_end(ND); I != E; ++I)
 | 
						|
      TULocHandler.Handle(TULocation(TU, *I));
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// RefSelectorAnalyzer Implementation
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
/// \brief Accepts an ObjC method and finds all message expressions that this
 | 
						|
/// method may respond to.
 | 
						|
class RefSelectorAnalyzer : public TranslationUnitHandler {
 | 
						|
  Program &Prog;
 | 
						|
  TULocationHandler &TULocHandler;
 | 
						|
 | 
						|
  // The original ObjCInterface associated with the method.
 | 
						|
  Entity IFaceEnt;
 | 
						|
  GlobalSelector GlobSel;
 | 
						|
  bool IsInstanceMethod;
 | 
						|
 | 
						|
  /// \brief Super classes of the ObjCInterface.
 | 
						|
  typedef llvm::SmallSet<Entity, 16> EntitiesSetTy;
 | 
						|
  EntitiesSetTy HierarchyEntities;
 | 
						|
 | 
						|
public:
 | 
						|
  RefSelectorAnalyzer(ObjCMethodDecl *MD,
 | 
						|
                      Program &prog, TULocationHandler &handler)
 | 
						|
    : Prog(prog), TULocHandler(handler) {
 | 
						|
    assert(MD);
 | 
						|
 | 
						|
    // FIXME: Protocol methods.
 | 
						|
    assert(!isa<ObjCProtocolDecl>(MD->getDeclContext()) &&
 | 
						|
           "Protocol methods not supported yet");
 | 
						|
 | 
						|
    ObjCInterfaceDecl *IFD = MD->getClassInterface();
 | 
						|
    assert(IFD);
 | 
						|
    IFaceEnt = Entity::get(IFD, Prog);
 | 
						|
    GlobSel = GlobalSelector::get(MD->getSelector(), Prog);
 | 
						|
    IsInstanceMethod = MD->isInstanceMethod();
 | 
						|
 | 
						|
    for (ObjCInterfaceDecl *Cls = IFD->getSuperClass();
 | 
						|
           Cls; Cls = Cls->getSuperClass())
 | 
						|
      HierarchyEntities.insert(Entity::get(Cls, Prog));
 | 
						|
  }
 | 
						|
 | 
						|
  virtual void Handle(TranslationUnit *TU) {
 | 
						|
    assert(TU && "Passed null translation unit");
 | 
						|
 | 
						|
    ASTContext &Ctx = TU->getASTContext();
 | 
						|
    // Null means it doesn't exist in this translation unit.
 | 
						|
    ObjCInterfaceDecl *IFace =
 | 
						|
        cast_or_null<ObjCInterfaceDecl>(IFaceEnt.getDecl(Ctx));
 | 
						|
    Selector Sel = GlobSel.getSelector(Ctx);
 | 
						|
 | 
						|
    SelectorMap &SelMap = TU->getSelectorMap();
 | 
						|
    for (SelectorMap::astlocation_iterator
 | 
						|
           I = SelMap.refs_begin(Sel), E = SelMap.refs_end(Sel); I != E; ++I) {
 | 
						|
      if (ValidReference(*I, IFace))
 | 
						|
        TULocHandler.Handle(TULocation(TU, *I));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /// \brief Determines whether the given message expression is likely to end
 | 
						|
  /// up at the given interface decl.
 | 
						|
  ///
 | 
						|
  /// It returns true "eagerly", meaning it will return false only if it can
 | 
						|
  /// "prove" statically that the interface cannot accept this message.
 | 
						|
  bool ValidReference(ASTLocation ASTLoc, ObjCInterfaceDecl *IFace) {
 | 
						|
    assert(ASTLoc.isStmt());
 | 
						|
 | 
						|
    // FIXME: Finding @selector references should be through another Analyzer
 | 
						|
    // method, like FindSelectors.
 | 
						|
    if (isa<ObjCSelectorExpr>(ASTLoc.AsStmt()))
 | 
						|
      return false;
 | 
						|
 | 
						|
    ObjCInterfaceDecl *MsgD = 0;
 | 
						|
    ObjCMessageExpr *Msg = cast<ObjCMessageExpr>(ASTLoc.AsStmt());
 | 
						|
 | 
						|
    switch (Msg->getReceiverKind()) {
 | 
						|
    case ObjCMessageExpr::Instance: {
 | 
						|
      const ObjCObjectPointerType *OPT =
 | 
						|
          Msg->getInstanceReceiver()->getType()->getAsObjCInterfacePointerType();
 | 
						|
 | 
						|
      // Can be anything! Accept it as a possibility..
 | 
						|
      if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType())
 | 
						|
        return true;
 | 
						|
 | 
						|
      // Expecting class method.
 | 
						|
      if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType())
 | 
						|
        return !IsInstanceMethod;
 | 
						|
 | 
						|
      MsgD = OPT->getInterfaceDecl();
 | 
						|
      assert(MsgD);
 | 
						|
 | 
						|
      // Should be an instance method.
 | 
						|
      if (!IsInstanceMethod)
 | 
						|
        return false;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    case ObjCMessageExpr::Class: {
 | 
						|
      // Expecting class method.
 | 
						|
      if (IsInstanceMethod)
 | 
						|
        return false;
 | 
						|
 | 
						|
      MsgD = Msg->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    case ObjCMessageExpr::SuperClass:
 | 
						|
      // Expecting class method.
 | 
						|
      if (IsInstanceMethod)
 | 
						|
        return false;
 | 
						|
 | 
						|
      MsgD = Msg->getSuperType()->getAs<ObjCObjectType>()->getInterface();
 | 
						|
      break;
 | 
						|
 | 
						|
    case ObjCMessageExpr::SuperInstance:
 | 
						|
      // Expecting instance method.
 | 
						|
      if (!IsInstanceMethod)
 | 
						|
        return false;
 | 
						|
 | 
						|
      MsgD = Msg->getSuperType()->getAs<ObjCObjectPointerType>()
 | 
						|
                                                          ->getInterfaceDecl();
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    assert(MsgD);
 | 
						|
 | 
						|
    // Same interface ? We have a winner!
 | 
						|
    if (MsgD == IFace)
 | 
						|
      return true;
 | 
						|
 | 
						|
    // If the message interface is a superclass of the original interface,
 | 
						|
    // accept this message as a possibility.
 | 
						|
    if (HierarchyEntities.count(Entity::get(MsgD, Prog)))
 | 
						|
      return true;
 | 
						|
 | 
						|
    // If the message interface is a subclass of the original interface, accept
 | 
						|
    // the message unless there is a subclass in the hierarchy that will
 | 
						|
    // "steal" the message (thus the message "will go" to the subclass and not
 | 
						|
    /// the original interface).
 | 
						|
    if (IFace) {
 | 
						|
      Selector Sel = Msg->getSelector();
 | 
						|
      for (ObjCInterfaceDecl *Cls = MsgD; Cls; Cls = Cls->getSuperClass()) {
 | 
						|
        if (Cls == IFace)
 | 
						|
          return true;
 | 
						|
        if (Cls->getMethod(Sel, IsInstanceMethod))
 | 
						|
          return false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // The interfaces are unrelated, don't accept the message.
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// MessageAnalyzer Implementation
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
/// \brief Accepts an ObjC message expression and finds all methods that may
 | 
						|
/// respond to it.
 | 
						|
class MessageAnalyzer : public TranslationUnitHandler {
 | 
						|
  Program &Prog;
 | 
						|
  TULocationHandler &TULocHandler;
 | 
						|
 | 
						|
  // The ObjCInterface associated with the message. Can be null/invalid.
 | 
						|
  Entity MsgIFaceEnt;
 | 
						|
  GlobalSelector GlobSel;
 | 
						|
  bool CanBeInstanceMethod;
 | 
						|
  bool CanBeClassMethod;
 | 
						|
 | 
						|
  /// \brief Super classes of the ObjCInterface.
 | 
						|
  typedef llvm::SmallSet<Entity, 16> EntitiesSetTy;
 | 
						|
  EntitiesSetTy HierarchyEntities;
 | 
						|
 | 
						|
  /// \brief The interface in the message interface hierarchy that "intercepts"
 | 
						|
  /// the selector.
 | 
						|
  Entity ReceiverIFaceEnt;
 | 
						|
 | 
						|
public:
 | 
						|
  MessageAnalyzer(ObjCMessageExpr *Msg,
 | 
						|
                  Program &prog, TULocationHandler &handler)
 | 
						|
    : Prog(prog), TULocHandler(handler),
 | 
						|
      CanBeInstanceMethod(false),
 | 
						|
      CanBeClassMethod(false) {
 | 
						|
 | 
						|
    assert(Msg);
 | 
						|
 | 
						|
    ObjCInterfaceDecl *MsgD = 0;
 | 
						|
 | 
						|
    while (true) {
 | 
						|
      switch (Msg->getReceiverKind()) {
 | 
						|
      case ObjCMessageExpr::Instance: {
 | 
						|
        const ObjCObjectPointerType *OPT =
 | 
						|
          Msg->getInstanceReceiver()->getType()
 | 
						|
                                      ->getAsObjCInterfacePointerType();
 | 
						|
 | 
						|
        if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) {
 | 
						|
          CanBeInstanceMethod = CanBeClassMethod = true;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) {
 | 
						|
          CanBeClassMethod = true;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        MsgD = OPT->getInterfaceDecl();
 | 
						|
        assert(MsgD);
 | 
						|
        CanBeInstanceMethod = true;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
        
 | 
						|
      case ObjCMessageExpr::Class:
 | 
						|
        CanBeClassMethod = true;
 | 
						|
        MsgD = Msg->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
 | 
						|
        break;
 | 
						|
 | 
						|
      case ObjCMessageExpr::SuperClass:
 | 
						|
        CanBeClassMethod = true;
 | 
						|
        MsgD = Msg->getSuperType()->getAs<ObjCObjectType>()->getInterface();
 | 
						|
        break;
 | 
						|
 | 
						|
      case ObjCMessageExpr::SuperInstance:
 | 
						|
        CanBeInstanceMethod = true;
 | 
						|
        MsgD = Msg->getSuperType()->getAs<ObjCObjectPointerType>()
 | 
						|
                                                           ->getInterfaceDecl();
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    assert(CanBeInstanceMethod || CanBeClassMethod);
 | 
						|
 | 
						|
    Selector sel = Msg->getSelector();
 | 
						|
    assert(!sel.isNull());
 | 
						|
 | 
						|
    MsgIFaceEnt = Entity::get(MsgD, Prog);
 | 
						|
    GlobSel = GlobalSelector::get(sel, Prog);
 | 
						|
 | 
						|
    if (MsgD) {
 | 
						|
      for (ObjCInterfaceDecl *Cls = MsgD->getSuperClass();
 | 
						|
             Cls; Cls = Cls->getSuperClass())
 | 
						|
        HierarchyEntities.insert(Entity::get(Cls, Prog));
 | 
						|
 | 
						|
      // Find the interface in the hierarchy that "receives" the message.
 | 
						|
      for (ObjCInterfaceDecl *Cls = MsgD; Cls; Cls = Cls->getSuperClass()) {
 | 
						|
        bool isReceiver = false;
 | 
						|
 | 
						|
        ObjCInterfaceDecl::lookup_const_iterator Meth, MethEnd;
 | 
						|
        for (llvm::tie(Meth, MethEnd) = Cls->lookup(sel);
 | 
						|
               Meth != MethEnd; ++Meth) {
 | 
						|
          if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth))
 | 
						|
            if ((MD->isInstanceMethod() && CanBeInstanceMethod) ||
 | 
						|
                (MD->isClassMethod()    && CanBeClassMethod)) {
 | 
						|
              isReceiver = true;
 | 
						|
              break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (isReceiver) {
 | 
						|
          ReceiverIFaceEnt = Entity::get(Cls, Prog);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  virtual void Handle(TranslationUnit *TU) {
 | 
						|
    assert(TU && "Passed null translation unit");
 | 
						|
    ASTContext &Ctx = TU->getASTContext();
 | 
						|
 | 
						|
    // Null means it doesn't exist in this translation unit or there was no
 | 
						|
    // interface that was determined to receive the original message.
 | 
						|
    ObjCInterfaceDecl *ReceiverIFace =
 | 
						|
        cast_or_null<ObjCInterfaceDecl>(ReceiverIFaceEnt.getDecl(Ctx));
 | 
						|
 | 
						|
    // No subclass for the original receiver interface, so it remains the
 | 
						|
    // receiver.
 | 
						|
    if (ReceiverIFaceEnt.isValid() && ReceiverIFace == 0)
 | 
						|
      return;
 | 
						|
 | 
						|
    // Null means it doesn't exist in this translation unit or there was no
 | 
						|
    // interface associated with the message in the first place.
 | 
						|
    ObjCInterfaceDecl *MsgIFace =
 | 
						|
        cast_or_null<ObjCInterfaceDecl>(MsgIFaceEnt.getDecl(Ctx));
 | 
						|
 | 
						|
    Selector Sel = GlobSel.getSelector(Ctx);
 | 
						|
    SelectorMap &SelMap = TU->getSelectorMap();
 | 
						|
    for (SelectorMap::method_iterator
 | 
						|
           I = SelMap.methods_begin(Sel), E = SelMap.methods_end(Sel);
 | 
						|
           I != E; ++I) {
 | 
						|
      ObjCMethodDecl *D = *I;
 | 
						|
      if (ValidMethod(D, MsgIFace, ReceiverIFace)) {
 | 
						|
        for (ObjCMethodDecl::redecl_iterator
 | 
						|
               RI = D->redecls_begin(), RE = D->redecls_end(); RI != RE; ++RI)
 | 
						|
          TULocHandler.Handle(TULocation(TU, ASTLocation(*RI)));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /// \brief Determines whether the given method is likely to accept the
 | 
						|
  /// original message.
 | 
						|
  ///
 | 
						|
  /// It returns true "eagerly", meaning it will return false only if it can
 | 
						|
  /// "prove" statically that the method cannot accept the original message.
 | 
						|
  bool ValidMethod(ObjCMethodDecl *D, ObjCInterfaceDecl *MsgIFace,
 | 
						|
                   ObjCInterfaceDecl *ReceiverIFace) {
 | 
						|
    assert(D);
 | 
						|
 | 
						|
    // FIXME: Protocol methods ?
 | 
						|
    if (isa<ObjCProtocolDecl>(D->getDeclContext()))
 | 
						|
      return false;
 | 
						|
 | 
						|
    // No specific interface associated with the message. Can be anything.
 | 
						|
    if (MsgIFaceEnt.isInvalid())
 | 
						|
      return true;
 | 
						|
 | 
						|
    if ((!CanBeInstanceMethod && D->isInstanceMethod()) ||
 | 
						|
        (!CanBeClassMethod    && D->isClassMethod()))
 | 
						|
      return false;
 | 
						|
 | 
						|
    ObjCInterfaceDecl *IFace = D->getClassInterface();
 | 
						|
    assert(IFace);
 | 
						|
 | 
						|
    // If the original message interface is the same or a superclass of the
 | 
						|
    // given interface, accept the method as a possibility.
 | 
						|
    if (MsgIFace && MsgIFace->isSuperClassOf(IFace))
 | 
						|
      return true;
 | 
						|
 | 
						|
    if (ReceiverIFace) {
 | 
						|
      // The given interface, "overrides" the receiver.
 | 
						|
      if (ReceiverIFace->isSuperClassOf(IFace))
 | 
						|
        return true;
 | 
						|
    } else {
 | 
						|
      // No receiver was found for the original message.
 | 
						|
      assert(ReceiverIFaceEnt.isInvalid());
 | 
						|
 | 
						|
      // If the original message interface is a subclass of the given interface,
 | 
						|
      // accept the message.
 | 
						|
      if (HierarchyEntities.count(Entity::get(IFace, Prog)))
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // The interfaces are unrelated, or the receiver interface wasn't
 | 
						|
    // "overriden".
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
} // end anonymous namespace
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// Analyzer Implementation
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
void Analyzer::FindDeclarations(Decl *D, TULocationHandler &Handler) {
 | 
						|
  assert(D && "Passed null declaration");
 | 
						|
  Entity Ent = Entity::get(D, Prog);
 | 
						|
  if (Ent.isInvalid())
 | 
						|
    return;
 | 
						|
 | 
						|
  DeclEntityAnalyzer DEA(Ent, Handler);
 | 
						|
  Idxer.GetTranslationUnitsFor(Ent, DEA);
 | 
						|
}
 | 
						|
 | 
						|
void Analyzer::FindReferences(Decl *D, TULocationHandler &Handler) {
 | 
						|
  assert(D && "Passed null declaration");
 | 
						|
  if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
 | 
						|
    RefSelectorAnalyzer RSA(MD, Prog, Handler);
 | 
						|
    GlobalSelector Sel = GlobalSelector::get(MD->getSelector(), Prog);
 | 
						|
    Idxer.GetTranslationUnitsFor(Sel, RSA);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Entity Ent = Entity::get(D, Prog);
 | 
						|
  if (Ent.isInvalid())
 | 
						|
    return;
 | 
						|
 | 
						|
  RefEntityAnalyzer REA(Ent, Handler);
 | 
						|
  Idxer.GetTranslationUnitsFor(Ent, REA);
 | 
						|
}
 | 
						|
 | 
						|
/// \brief Find methods that may respond to the given message and pass them
 | 
						|
/// to Handler.
 | 
						|
void Analyzer::FindObjCMethods(ObjCMessageExpr *Msg,
 | 
						|
                               TULocationHandler &Handler) {
 | 
						|
  assert(Msg);
 | 
						|
  MessageAnalyzer MsgAnalyz(Msg, Prog, Handler);
 | 
						|
  GlobalSelector GlobSel = GlobalSelector::get(Msg->getSelector(), Prog);
 | 
						|
  Idxer.GetTranslationUnitsFor(GlobSel, MsgAnalyz);
 | 
						|
}
 |