Shih-wei Liao | f8fd82b | 2010-02-10 11:10:31 -0800 | [diff] [blame^] | 1 | //===--- Entity.cpp - Cross-translation-unit "token" for decls ------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // Entity is a ASTContext-independent way to refer to declarations that are |
| 11 | // visible across translation units. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "EntityImpl.h" |
| 16 | #include "ProgramImpl.h" |
| 17 | #include "clang/Index/Program.h" |
| 18 | #include "clang/Index/GlobalSelector.h" |
| 19 | #include "clang/AST/Decl.h" |
| 20 | #include "clang/AST/ASTContext.h" |
| 21 | #include "clang/AST/DeclVisitor.h" |
| 22 | using namespace clang; |
| 23 | using namespace idx; |
| 24 | |
| 25 | // FIXME: Entity is really really basic currently, mostly written to work |
| 26 | // on variables and functions. Should support types and other decls eventually.. |
| 27 | |
| 28 | |
| 29 | //===----------------------------------------------------------------------===// |
| 30 | // EntityGetter |
| 31 | //===----------------------------------------------------------------------===// |
| 32 | |
| 33 | namespace clang { |
| 34 | namespace idx { |
| 35 | |
| 36 | /// \brief Gets the Entity associated with a Decl. |
| 37 | class EntityGetter : public DeclVisitor<EntityGetter, Entity> { |
| 38 | Program &Prog; |
| 39 | ProgramImpl &ProgImpl; |
| 40 | |
| 41 | public: |
| 42 | EntityGetter(Program &prog, ProgramImpl &progImpl) |
| 43 | : Prog(prog), ProgImpl(progImpl) { } |
| 44 | |
| 45 | Entity VisitNamedDecl(NamedDecl *D); |
| 46 | Entity VisitVarDecl(VarDecl *D); |
| 47 | Entity VisitFunctionDecl(FunctionDecl *D); |
| 48 | }; |
| 49 | |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | Entity EntityGetter::VisitNamedDecl(NamedDecl *D) { |
| 54 | Entity Parent; |
| 55 | if (!D->getDeclContext()->isTranslationUnit()) { |
| 56 | Parent = Visit(cast<Decl>(D->getDeclContext())); |
| 57 | // FIXME: Anonymous structs ? |
| 58 | if (Parent.isInvalid()) |
| 59 | return Entity(); |
| 60 | } |
| 61 | if (Parent.isValid() && Parent.isInternalToTU()) |
| 62 | return Entity(D); |
| 63 | |
| 64 | // FIXME: Only works for DeclarationNames that are identifiers and selectors. |
| 65 | // Treats other DeclarationNames as internal Decls for now.. |
| 66 | |
| 67 | DeclarationName LocalName = D->getDeclName(); |
| 68 | if (!LocalName) |
| 69 | return Entity(D); |
| 70 | |
| 71 | DeclarationName GlobName; |
| 72 | |
| 73 | if (IdentifierInfo *II = LocalName.getAsIdentifierInfo()) { |
| 74 | IdentifierInfo *GlobII = |
| 75 | &ProgImpl.getIdents().get(II->getNameStart(), |
| 76 | II->getNameStart() + II->getLength()); |
| 77 | GlobName = DeclarationName(GlobII); |
| 78 | } else { |
| 79 | Selector LocalSel = LocalName.getObjCSelector(); |
| 80 | |
| 81 | // Treats other DeclarationNames as internal Decls for now.. |
| 82 | if (LocalSel.isNull()) |
| 83 | return Entity(D); |
| 84 | |
| 85 | Selector GlobSel = |
| 86 | (uintptr_t)GlobalSelector::get(LocalSel, Prog).getAsOpaquePtr(); |
| 87 | GlobName = DeclarationName(GlobSel); |
| 88 | } |
| 89 | |
| 90 | assert(GlobName); |
| 91 | |
| 92 | unsigned IdNS = D->getIdentifierNamespace(); |
| 93 | |
| 94 | ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D); |
| 95 | bool isObjCInstanceMethod = MD && MD->isInstanceMethod(); |
| 96 | |
| 97 | llvm::FoldingSetNodeID ID; |
| 98 | EntityImpl::Profile(ID, Parent, GlobName, IdNS, isObjCInstanceMethod); |
| 99 | |
| 100 | ProgramImpl::EntitySetTy &Entities = ProgImpl.getEntities(); |
| 101 | void *InsertPos = 0; |
| 102 | if (EntityImpl *Ent = Entities.FindNodeOrInsertPos(ID, InsertPos)) |
| 103 | return Entity(Ent); |
| 104 | |
| 105 | void *Buf = ProgImpl.Allocate(sizeof(EntityImpl)); |
| 106 | EntityImpl *New = |
| 107 | new (Buf) EntityImpl(Parent, GlobName, IdNS, isObjCInstanceMethod); |
| 108 | Entities.InsertNode(New, InsertPos); |
| 109 | |
| 110 | return Entity(New); |
| 111 | } |
| 112 | |
| 113 | Entity EntityGetter::VisitVarDecl(VarDecl *D) { |
| 114 | // If it's static it cannot be referred to by another translation unit. |
| 115 | if (D->getStorageClass() == VarDecl::Static) |
| 116 | return Entity(D); |
| 117 | |
| 118 | return VisitNamedDecl(D); |
| 119 | } |
| 120 | |
| 121 | Entity EntityGetter::VisitFunctionDecl(FunctionDecl *D) { |
| 122 | // If it's static it cannot be refered to by another translation unit. |
| 123 | if (D->getStorageClass() == FunctionDecl::Static) |
| 124 | return Entity(D); |
| 125 | |
| 126 | return VisitNamedDecl(D); |
| 127 | } |
| 128 | |
| 129 | //===----------------------------------------------------------------------===// |
| 130 | // EntityImpl Implementation |
| 131 | //===----------------------------------------------------------------------===// |
| 132 | |
| 133 | Decl *EntityImpl::getDecl(ASTContext &AST) { |
| 134 | DeclContext *DC = |
| 135 | Parent.isInvalid() ? AST.getTranslationUnitDecl() |
| 136 | : cast<DeclContext>(Parent.getDecl(AST)); |
| 137 | if (!DC) |
| 138 | return 0; // Couldn't get the parent context. |
| 139 | |
| 140 | DeclarationName LocalName; |
| 141 | |
| 142 | if (IdentifierInfo *GlobII = Name.getAsIdentifierInfo()) { |
| 143 | IdentifierInfo &II = |
| 144 | AST.Idents.get(GlobII->getNameStart(), |
| 145 | GlobII->getNameStart() + GlobII->getLength()); |
| 146 | LocalName = DeclarationName(&II); |
| 147 | } else { |
| 148 | Selector GlobSel = Name.getObjCSelector(); |
| 149 | assert(!GlobSel.isNull() && "A not handled yet declaration name"); |
| 150 | GlobalSelector GSel = |
| 151 | GlobalSelector::getFromOpaquePtr(GlobSel.getAsOpaquePtr()); |
| 152 | LocalName = GSel.getSelector(AST); |
| 153 | } |
| 154 | |
| 155 | assert(LocalName); |
| 156 | |
| 157 | DeclContext::lookup_result Res = DC->lookup(LocalName); |
| 158 | for (DeclContext::lookup_iterator I = Res.first, E = Res.second; I!=E; ++I) { |
| 159 | Decl *D = *I; |
| 160 | if (D->getIdentifierNamespace() == IdNS) { |
| 161 | if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { |
| 162 | if (MD->isInstanceMethod() == IsObjCInstanceMethod) |
| 163 | return MD; |
| 164 | } else |
| 165 | return D; |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | return 0; // Failed to find a decl using this Entity. |
| 170 | } |
| 171 | |
| 172 | /// \brief Get an Entity associated with the given Decl. |
| 173 | /// \returns Null if an Entity cannot refer to this Decl. |
| 174 | Entity EntityImpl::get(Decl *D, Program &Prog, ProgramImpl &ProgImpl) { |
| 175 | assert(D && "Passed null Decl"); |
| 176 | return EntityGetter(Prog, ProgImpl).Visit(D); |
| 177 | } |
| 178 | |
| 179 | std::string EntityImpl::getPrintableName() { |
| 180 | return Name.getAsString(); |
| 181 | } |
| 182 | |
| 183 | //===----------------------------------------------------------------------===// |
| 184 | // Entity Implementation |
| 185 | //===----------------------------------------------------------------------===// |
| 186 | |
| 187 | Entity::Entity(Decl *D) : Val(D->getCanonicalDecl()) { } |
| 188 | |
| 189 | /// \brief Find the Decl that can be referred to by this entity. |
| 190 | Decl *Entity::getDecl(ASTContext &AST) const { |
| 191 | if (isInvalid()) |
| 192 | return 0; |
| 193 | |
| 194 | if (Decl *D = Val.dyn_cast<Decl *>()) |
| 195 | // Check that the passed AST is actually the one that this Decl belongs to. |
| 196 | return (&D->getASTContext() == &AST) ? D : 0; |
| 197 | |
| 198 | return Val.get<EntityImpl *>()->getDecl(AST); |
| 199 | } |
| 200 | |
| 201 | std::string Entity::getPrintableName() const { |
| 202 | if (isInvalid()) |
| 203 | return "<< Invalid >>"; |
| 204 | |
| 205 | if (Decl *D = Val.dyn_cast<Decl *>()) { |
| 206 | if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) |
| 207 | return ND->getNameAsString(); |
| 208 | else |
| 209 | return std::string(); |
| 210 | } |
| 211 | |
| 212 | return Val.get<EntityImpl *>()->getPrintableName(); |
| 213 | } |
| 214 | |
| 215 | /// \brief Get an Entity associated with the given Decl. |
| 216 | /// \returns Null if an Entity cannot refer to this Decl. |
| 217 | Entity Entity::get(Decl *D, Program &Prog) { |
| 218 | if (D == 0) |
| 219 | return Entity(); |
| 220 | ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl); |
| 221 | return EntityImpl::get(D, Prog, ProgImpl); |
| 222 | } |
| 223 | |
| 224 | unsigned |
| 225 | llvm::DenseMapInfo<Entity>::getHashValue(Entity E) { |
| 226 | return DenseMapInfo<void*>::getHashValue(E.getAsOpaquePtr()); |
| 227 | } |