forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			271 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			271 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
//===--- Entity.cpp - Cross-translation-unit "token" for decls ------------===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
//  Entity is a ASTContext-independent way to refer to declarations that are
 | 
						|
//  visible across translation units.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "EntityImpl.h"
 | 
						|
#include "ProgramImpl.h"
 | 
						|
#include "clang/Index/Program.h"
 | 
						|
#include "clang/Index/GlobalSelector.h"
 | 
						|
#include "clang/AST/Decl.h"
 | 
						|
#include "clang/AST/ASTContext.h"
 | 
						|
#include "clang/AST/DeclVisitor.h"
 | 
						|
using namespace clang;
 | 
						|
using namespace idx;
 | 
						|
 | 
						|
// FIXME: Entity is really really basic currently, mostly written to work
 | 
						|
// on variables and functions. Should support types and other decls eventually..
 | 
						|
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// EntityGetter
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
namespace clang {
 | 
						|
namespace idx {
 | 
						|
 | 
						|
/// \brief Gets the Entity associated with a Decl.
 | 
						|
class EntityGetter : public DeclVisitor<EntityGetter, Entity> {
 | 
						|
  Program &Prog;
 | 
						|
  ProgramImpl &ProgImpl;
 | 
						|
 | 
						|
public:
 | 
						|
  EntityGetter(Program &prog, ProgramImpl &progImpl)
 | 
						|
    : Prog(prog), ProgImpl(progImpl) { }
 | 
						|
 | 
						|
  // Get an Entity.
 | 
						|
  Entity getEntity(Entity Parent, DeclarationName Name, 
 | 
						|
                   unsigned IdNS, bool isObjCInstanceMethod);
 | 
						|
 | 
						|
  // Get an Entity associated with the name in the global namespace.
 | 
						|
  Entity getGlobalEntity(llvm::StringRef Name);
 | 
						|
 | 
						|
  Entity VisitNamedDecl(NamedDecl *D);
 | 
						|
  Entity VisitVarDecl(VarDecl *D);
 | 
						|
  Entity VisitFieldDecl(FieldDecl *D);
 | 
						|
  Entity VisitFunctionDecl(FunctionDecl *D);
 | 
						|
  Entity VisitTypeDecl(TypeDecl *D);
 | 
						|
};
 | 
						|
 | 
						|
}
 | 
						|
}
 | 
						|
 | 
						|
Entity EntityGetter::getEntity(Entity Parent, DeclarationName Name, 
 | 
						|
                               unsigned IdNS, bool isObjCInstanceMethod) {
 | 
						|
  llvm::FoldingSetNodeID ID;
 | 
						|
  EntityImpl::Profile(ID, Parent, Name, IdNS, isObjCInstanceMethod);
 | 
						|
 | 
						|
  ProgramImpl::EntitySetTy &Entities = ProgImpl.getEntities();
 | 
						|
  void *InsertPos = 0;
 | 
						|
  if (EntityImpl *Ent = Entities.FindNodeOrInsertPos(ID, InsertPos))
 | 
						|
    return Entity(Ent);
 | 
						|
 | 
						|
  void *Buf = ProgImpl.Allocate(sizeof(EntityImpl));
 | 
						|
  EntityImpl *New =
 | 
						|
      new (Buf) EntityImpl(Parent, Name, IdNS, isObjCInstanceMethod);
 | 
						|
  Entities.InsertNode(New, InsertPos);
 | 
						|
 | 
						|
  return Entity(New);
 | 
						|
}
 | 
						|
 | 
						|
Entity EntityGetter::getGlobalEntity(llvm::StringRef Name) {
 | 
						|
  IdentifierInfo *II = &ProgImpl.getIdents().get(Name);
 | 
						|
  DeclarationName GlobName(II);
 | 
						|
  unsigned IdNS = Decl::IDNS_Ordinary;
 | 
						|
  return getEntity(Entity(), GlobName, IdNS, false);
 | 
						|
}
 | 
						|
 | 
						|
Entity EntityGetter::VisitNamedDecl(NamedDecl *D) {
 | 
						|
  Entity Parent;
 | 
						|
  if (!D->getDeclContext()->isTranslationUnit()) {
 | 
						|
    Parent = Visit(cast<Decl>(D->getDeclContext()));
 | 
						|
    // FIXME: Anonymous structs ?
 | 
						|
    if (Parent.isInvalid())
 | 
						|
      return Entity();
 | 
						|
  }
 | 
						|
  if (Parent.isValid() && Parent.isInternalToTU())
 | 
						|
    return Entity(D);
 | 
						|
 | 
						|
  // FIXME: Only works for DeclarationNames that are identifiers and selectors.
 | 
						|
  // Treats other DeclarationNames as internal Decls for now..
 | 
						|
 | 
						|
  DeclarationName LocalName = D->getDeclName();
 | 
						|
  if (!LocalName)
 | 
						|
    return Entity(D);
 | 
						|
 | 
						|
  DeclarationName GlobName;
 | 
						|
 | 
						|
  if (IdentifierInfo *II = LocalName.getAsIdentifierInfo()) {
 | 
						|
    IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName());
 | 
						|
    GlobName = DeclarationName(GlobII);
 | 
						|
  } else {
 | 
						|
    Selector LocalSel = LocalName.getObjCSelector();
 | 
						|
 | 
						|
    // Treats other DeclarationNames as internal Decls for now..
 | 
						|
    if (LocalSel.isNull())
 | 
						|
      return Entity(D);
 | 
						|
 | 
						|
    Selector GlobSel =
 | 
						|
        (uintptr_t)GlobalSelector::get(LocalSel, Prog).getAsOpaquePtr();
 | 
						|
    GlobName = DeclarationName(GlobSel);
 | 
						|
  }
 | 
						|
 | 
						|
  assert(GlobName);
 | 
						|
 | 
						|
  unsigned IdNS = D->getIdentifierNamespace();
 | 
						|
 | 
						|
  ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D);
 | 
						|
  bool isObjCInstanceMethod = MD && MD->isInstanceMethod();
 | 
						|
  return getEntity(Parent, GlobName, IdNS, isObjCInstanceMethod);
 | 
						|
}
 | 
						|
 | 
						|
Entity EntityGetter::VisitVarDecl(VarDecl *D) {
 | 
						|
  // Local variables have no linkage, make invalid Entities.
 | 
						|
  if (D->hasLocalStorage())
 | 
						|
    return Entity();
 | 
						|
 | 
						|
  // If it's static it cannot be referred to by another translation unit.
 | 
						|
  if (D->getStorageClass() == SC_Static)
 | 
						|
    return Entity(D);
 | 
						|
 | 
						|
  return VisitNamedDecl(D);
 | 
						|
}
 | 
						|
 | 
						|
Entity EntityGetter::VisitFunctionDecl(FunctionDecl *D) {
 | 
						|
  // If it's static it cannot be referred to by another translation unit.
 | 
						|
  if (D->getStorageClass() == SC_Static)
 | 
						|
    return Entity(D);
 | 
						|
 | 
						|
  return VisitNamedDecl(D);
 | 
						|
}
 | 
						|
 | 
						|
Entity EntityGetter::VisitFieldDecl(FieldDecl *D) {
 | 
						|
  // Make FieldDecl an invalid Entity since it has no linkage.
 | 
						|
  return Entity();
 | 
						|
}
 | 
						|
 | 
						|
Entity EntityGetter::VisitTypeDecl(TypeDecl *D) {
 | 
						|
  // Although in C++ class name has external linkage, usually the definition of
 | 
						|
  // the class is available in the same translation unit when it's needed. So we
 | 
						|
  // make all of them invalid Entity.
 | 
						|
  return Entity();
 | 
						|
}
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// EntityImpl Implementation
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
Decl *EntityImpl::getDecl(ASTContext &AST) {
 | 
						|
  DeclContext *DC =
 | 
						|
    Parent.isInvalid() ? AST.getTranslationUnitDecl()
 | 
						|
                       : cast<DeclContext>(Parent.getDecl(AST));
 | 
						|
  if (!DC)
 | 
						|
    return 0; // Couldn't get the parent context.
 | 
						|
 | 
						|
  DeclarationName LocalName;
 | 
						|
 | 
						|
  if (IdentifierInfo *GlobII = Name.getAsIdentifierInfo()) {
 | 
						|
    IdentifierInfo &II = AST.Idents.get(GlobII->getName());
 | 
						|
    LocalName = DeclarationName(&II);
 | 
						|
  } else {
 | 
						|
    Selector GlobSel = Name.getObjCSelector();
 | 
						|
    assert(!GlobSel.isNull() && "A not handled yet declaration name");
 | 
						|
    GlobalSelector GSel =
 | 
						|
        GlobalSelector::getFromOpaquePtr(GlobSel.getAsOpaquePtr());
 | 
						|
    LocalName = GSel.getSelector(AST);
 | 
						|
  }
 | 
						|
 | 
						|
  assert(LocalName);
 | 
						|
 | 
						|
  DeclContext::lookup_result Res = DC->lookup(LocalName);
 | 
						|
  for (DeclContext::lookup_iterator I = Res.first, E = Res.second; I!=E; ++I) {
 | 
						|
    Decl *D = *I;
 | 
						|
    if (D->getIdentifierNamespace() == IdNS) {
 | 
						|
      if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
 | 
						|
        if (MD->isInstanceMethod() == IsObjCInstanceMethod)
 | 
						|
          return MD;
 | 
						|
      } else
 | 
						|
        return D;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return 0; // Failed to find a decl using this Entity.
 | 
						|
}
 | 
						|
 | 
						|
/// \brief Get an Entity associated with the given Decl.
 | 
						|
/// \returns Null if an Entity cannot refer to this Decl.
 | 
						|
Entity EntityImpl::get(Decl *D, Program &Prog, ProgramImpl &ProgImpl) {
 | 
						|
  assert(D && "Passed null Decl");
 | 
						|
  return EntityGetter(Prog, ProgImpl).Visit(D);
 | 
						|
}
 | 
						|
 | 
						|
/// \brief Get an Entity associated with a global name.
 | 
						|
Entity EntityImpl::get(llvm::StringRef Name, Program &Prog, 
 | 
						|
                       ProgramImpl &ProgImpl) {
 | 
						|
  return EntityGetter(Prog, ProgImpl).getGlobalEntity(Name);
 | 
						|
}
 | 
						|
 | 
						|
std::string EntityImpl::getPrintableName() {
 | 
						|
  return Name.getAsString();
 | 
						|
}
 | 
						|
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
// Entity Implementation
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
Entity::Entity(Decl *D) : Val(D->getCanonicalDecl()) { }
 | 
						|
 | 
						|
/// \brief Find the Decl that can be referred to by this entity.
 | 
						|
Decl *Entity::getDecl(ASTContext &AST) const {
 | 
						|
  if (isInvalid())
 | 
						|
    return 0;
 | 
						|
 | 
						|
  if (Decl *D = Val.dyn_cast<Decl *>())
 | 
						|
    // Check that the passed AST is actually the one that this Decl belongs to.
 | 
						|
    return (&D->getASTContext() == &AST) ? D : 0;
 | 
						|
 | 
						|
  return Val.get<EntityImpl *>()->getDecl(AST);
 | 
						|
}
 | 
						|
 | 
						|
std::string Entity::getPrintableName() const {
 | 
						|
  if (isInvalid())
 | 
						|
    return "<< Invalid >>";
 | 
						|
 | 
						|
  if (Decl *D = Val.dyn_cast<Decl *>()) {
 | 
						|
    if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
 | 
						|
      return ND->getNameAsString();
 | 
						|
    else
 | 
						|
      return std::string();
 | 
						|
  }
 | 
						|
 | 
						|
  return Val.get<EntityImpl *>()->getPrintableName();
 | 
						|
}
 | 
						|
 | 
						|
/// \brief Get an Entity associated with the given Decl.
 | 
						|
/// \returns Null if an Entity cannot refer to this Decl.
 | 
						|
Entity Entity::get(Decl *D, Program &Prog) {
 | 
						|
  if (D == 0)
 | 
						|
    return Entity();
 | 
						|
  ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl);
 | 
						|
  return EntityImpl::get(D, Prog, ProgImpl);
 | 
						|
}
 | 
						|
 | 
						|
Entity Entity::get(llvm::StringRef Name, Program &Prog) {
 | 
						|
  ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl);
 | 
						|
  return EntityImpl::get(Name, Prog, ProgImpl);
 | 
						|
}
 | 
						|
 | 
						|
unsigned
 | 
						|
llvm::DenseMapInfo<Entity>::getHashValue(Entity E) {
 | 
						|
  return DenseMapInfo<void*>::getHashValue(E.getAsOpaquePtr());
 | 
						|
}
 |