diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Index')
17 files changed, 2316 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Index/ASTLocation.cpp b/contrib/llvm/tools/clang/lib/Index/ASTLocation.cpp new file mode 100644 index 0000000..bd3b5ee --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/ASTLocation.cpp @@ -0,0 +1,117 @@ +//===--- ASTLocation.cpp - A <Decl, Stmt> pair ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ASTLocation is Decl or a Stmt and its immediate Decl parent. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/ASTLocation.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprObjC.h" +using namespace clang; +using namespace idx; + +static Decl *getDeclFromExpr(Stmt *E) { + if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E)) + return RefExpr->getDecl(); + if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) + return ME->getMemberDecl(); + if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E)) + return RE->getDecl(); + + if (CallExpr *CE = dyn_cast<CallExpr>(E)) + return getDeclFromExpr(CE->getCallee()); + if (CastExpr *CE = dyn_cast<CastExpr>(E)) + return getDeclFromExpr(CE->getSubExpr()); + + return 0; +} + +Decl *ASTLocation::getReferencedDecl() { + if (isInvalid()) + return 0; + + switch (getKind()) { + default: assert(0 && "Invalid Kind"); + case N_Type: + return 0; + case N_Decl: + return D; + case N_NamedRef: + return NDRef.ND; + case N_Stmt: + return getDeclFromExpr(Stm); + } + + return 0; +} + +SourceRange ASTLocation::getSourceRange() const { + if (isInvalid()) + return SourceRange(); + + switch (getKind()) { + default: assert(0 && "Invalid Kind"); + return SourceRange(); + case N_Decl: + return D->getSourceRange(); + case N_Stmt: + return Stm->getSourceRange(); + case N_NamedRef: + return SourceRange(AsNamedRef().Loc, AsNamedRef().Loc); + case N_Type: + return AsTypeLoc().getLocalSourceRange(); + } + + return SourceRange(); +} + +void ASTLocation::print(llvm::raw_ostream &OS) const { + if (isInvalid()) { + OS << "<< Invalid ASTLocation >>\n"; + return; + } + + ASTContext &Ctx = getParentDecl()->getASTContext(); + + switch (getKind()) { + case N_Decl: + OS << "[Decl: " << AsDecl()->getDeclKindName() << " "; + if (const NamedDecl *ND = dyn_cast<NamedDecl>(AsDecl())) + OS << ND; + break; + + case N_Stmt: + OS << "[Stmt: " << AsStmt()->getStmtClassName() << " "; + AsStmt()->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions())); + break; + + case N_NamedRef: + OS << "[NamedRef: " << AsNamedRef().ND->getDeclKindName() << " "; + OS << AsNamedRef().ND; + break; + + case N_Type: { + QualType T = AsTypeLoc().getType(); + OS << "[Type: " << T->getTypeClassName() << " " << T.getAsString(); + } + } + + OS << "] <"; + + SourceRange Range = getSourceRange(); + SourceManager &SourceMgr = Ctx.getSourceManager(); + Range.getBegin().print(OS, SourceMgr); + OS << ", "; + Range.getEnd().print(OS, SourceMgr); + OS << ">\n"; +} diff --git a/contrib/llvm/tools/clang/lib/Index/ASTVisitor.h b/contrib/llvm/tools/clang/lib/Index/ASTVisitor.h new file mode 100644 index 0000000..943c720 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/ASTVisitor.h @@ -0,0 +1,144 @@ +//===--- ASTVisitor.h - Visitor for an ASTContext ---------------*- 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 the ASTVisitor interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_ASTVISITOR_H +#define LLVM_CLANG_INDEX_ASTVISITOR_H + +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeLocVisitor.h" + +namespace clang { + +namespace idx { + +/// \brief Traverses the full AST, both Decls and Stmts. +template<typename ImplClass> +class ASTVisitor : public DeclVisitor<ImplClass>, + public StmtVisitor<ImplClass>, + public TypeLocVisitor<ImplClass> { +public: + ASTVisitor() : CurrentDecl(0) { } + + Decl *CurrentDecl; + + typedef ASTVisitor<ImplClass> Base; + typedef DeclVisitor<ImplClass> BaseDeclVisitor; + typedef StmtVisitor<ImplClass> BaseStmtVisitor; + typedef TypeLocVisitor<ImplClass> BaseTypeLocVisitor; + + using BaseStmtVisitor::Visit; + + //===--------------------------------------------------------------------===// + // DeclVisitor + //===--------------------------------------------------------------------===// + + void Visit(Decl *D) { + Decl *PrevDecl = CurrentDecl; + CurrentDecl = D; + BaseDeclVisitor::Visit(D); + CurrentDecl = PrevDecl; + } + + void VisitDeclaratorDecl(DeclaratorDecl *D) { + BaseDeclVisitor::VisitDeclaratorDecl(D); + if (TypeSourceInfo *TInfo = D->getTypeSourceInfo()) + Visit(TInfo->getTypeLoc()); + } + + void VisitFunctionDecl(FunctionDecl *D) { + BaseDeclVisitor::VisitFunctionDecl(D); + if (D->isThisDeclarationADefinition()) + Visit(D->getBody()); + } + + void VisitObjCMethodDecl(ObjCMethodDecl *D) { + BaseDeclVisitor::VisitObjCMethodDecl(D); + if (D->getBody()) + Visit(D->getBody()); + } + + void VisitBlockDecl(BlockDecl *D) { + BaseDeclVisitor::VisitBlockDecl(D); + Visit(D->getBody()); + } + + void VisitVarDecl(VarDecl *D) { + BaseDeclVisitor::VisitVarDecl(D); + if (Expr *Init = D->getInit()) + Visit(Init); + } + + void VisitDecl(Decl *D) { + if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D)) + return; + + if (DeclContext *DC = dyn_cast<DeclContext>(D)) + static_cast<ImplClass*>(this)->VisitDeclContext(DC); + } + + void VisitDeclContext(DeclContext *DC) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) + Visit(*I); + } + + //===--------------------------------------------------------------------===// + // StmtVisitor + //===--------------------------------------------------------------------===// + + void VisitDeclStmt(DeclStmt *Node) { + for (DeclStmt::decl_iterator + I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) + Visit(*I); + } + + void VisitBlockExpr(BlockExpr *Node) { + // The BlockDecl is also visited by 'VisitDeclContext()'. No need to visit it twice. + } + + void VisitStmt(Stmt *Node) { + for (Stmt::child_iterator + I = Node->child_begin(), E = Node->child_end(); I != E; ++I) + if (*I) + Visit(*I); + } + + //===--------------------------------------------------------------------===// + // TypeLocVisitor + //===--------------------------------------------------------------------===// + + void Visit(TypeLoc TL) { + for (; TL; TL = TL.getNextTypeLoc()) + BaseTypeLocVisitor::Visit(TL); + } + + void VisitArrayLoc(ArrayTypeLoc TL) { + BaseTypeLocVisitor::VisitArrayTypeLoc(TL); + if (TL.getSizeExpr()) + Visit(TL.getSizeExpr()); + } + + void VisitFunctionTypeLoc(FunctionTypeLoc TL) { + BaseTypeLocVisitor::VisitFunctionTypeLoc(TL); + for (unsigned i = 0; i != TL.getNumArgs(); ++i) + Visit(TL.getArg(i)); + } + +}; + +} // namespace idx + +} // namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/lib/Index/Analyzer.cpp b/contrib/llvm/tools/clang/lib/Index/Analyzer.cpp new file mode 100644 index 0000000..6be35ab --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/Analyzer.cpp @@ -0,0 +1,470 @@ +//===--- 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); +} diff --git a/contrib/llvm/tools/clang/lib/Index/CMakeLists.txt b/contrib/llvm/tools/clang/lib/Index/CMakeLists.txt new file mode 100644 index 0000000..4d67035 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/CMakeLists.txt @@ -0,0 +1,16 @@ +set(LLVM_NO_RTTI 1) + +add_clang_library(clangIndex + ASTLocation.cpp + Analyzer.cpp + CallGraph.cpp + DeclReferenceMap.cpp + Entity.cpp + GlobalSelector.cpp + Handlers.cpp + IndexProvider.cpp + Indexer.cpp + Program.cpp + ResolveLocation.cpp + SelectorMap.cpp + ) diff --git a/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp b/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp new file mode 100644 index 0000000..6403319 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp @@ -0,0 +1,150 @@ +//== CallGraph.cpp - Call graph building ------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the CallGraph and CGBuilder classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/CallGraph.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/StmtVisitor.h" + +#include "llvm/Support/GraphWriter.h" + +using namespace clang; +using namespace idx; + +namespace { +class CGBuilder : public StmtVisitor<CGBuilder> { + + CallGraph &G; + FunctionDecl *FD; + + Entity CallerEnt; + + CallGraphNode *CallerNode; + +public: + CGBuilder(CallGraph &g, FunctionDecl *fd, Entity E, CallGraphNode *N) + : G(g), FD(fd), CallerEnt(E), CallerNode(N) {} + + void VisitStmt(Stmt *S) { VisitChildren(S); } + + void VisitCallExpr(CallExpr *CE); + + void VisitChildren(Stmt *S) { + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I != E;++I) + if (*I) + static_cast<CGBuilder*>(this)->Visit(*I); + } +}; +} + +void CGBuilder::VisitCallExpr(CallExpr *CE) { + if (FunctionDecl *CalleeDecl = CE->getDirectCallee()) { + Entity Ent = Entity::get(CalleeDecl, G.getProgram()); + CallGraphNode *CalleeNode = G.getOrInsertFunction(Ent); + CallerNode->addCallee(ASTLocation(FD, CE), CalleeNode); + } +} + +CallGraph::CallGraph() : Root(0) { + ExternalCallingNode = getOrInsertFunction(Entity()); +} + +CallGraph::~CallGraph() { + if (!FunctionMap.empty()) { + for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end(); + I != E; ++I) + delete I->second; + FunctionMap.clear(); + } +} + +void CallGraph::addTU(ASTContext& Ctx) { + DeclContext *DC = Ctx.getTranslationUnitDecl(); + for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); + I != E; ++I) { + + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { + if (FD->isThisDeclarationADefinition()) { + // Set caller's ASTContext. + Entity Ent = Entity::get(FD, Prog); + CallGraphNode *Node = getOrInsertFunction(Ent); + CallerCtx[Node] = &Ctx; + + // If this function has external linkage, anything could call it. + if (FD->isGlobal()) + ExternalCallingNode->addCallee(idx::ASTLocation(), Node); + + // Set root node to 'main' function. + if (FD->getNameAsString() == "main") + Root = Node; + + CGBuilder builder(*this, FD, Ent, Node); + builder.Visit(FD->getBody()); + } + } + } +} + +CallGraphNode *CallGraph::getOrInsertFunction(Entity F) { + CallGraphNode *&Node = FunctionMap[F]; + if (Node) + return Node; + + return Node = new CallGraphNode(F); +} + +Decl *CallGraph::getDecl(CallGraphNode *Node) { + // Get the function's context. + ASTContext *Ctx = CallerCtx[Node]; + + return Node->getDecl(*Ctx); +} + +void CallGraph::print(llvm::raw_ostream &os) { + for (iterator I = begin(), E = end(); I != E; ++I) { + if (I->second->hasCallee()) { + os << "function: " << I->first.getPrintableName() + << " calls:\n"; + for (CallGraphNode::iterator CI = I->second->begin(), + CE = I->second->end(); CI != CE; ++CI) { + os << " " << CI->second->getName(); + } + os << '\n'; + } + } +} + +void CallGraph::dump() { + print(llvm::errs()); +} + +void CallGraph::ViewCallGraph() const { + llvm::ViewGraph(*this, "CallGraph"); +} + +namespace llvm { + +template <> +struct DOTGraphTraits<CallGraph> : public DefaultDOTGraphTraits { + + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + + static std::string getNodeLabel(const CallGraphNode *Node, + const CallGraph &CG) { + return Node->getName(); + + } + +}; + +} diff --git a/contrib/llvm/tools/clang/lib/Index/DeclReferenceMap.cpp b/contrib/llvm/tools/clang/lib/Index/DeclReferenceMap.cpp new file mode 100644 index 0000000..d6e30ab --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/DeclReferenceMap.cpp @@ -0,0 +1,90 @@ +//===--- DeclReferenceMap.cpp - Map Decls to their references -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// DeclReferenceMap creates a mapping from Decls to the ASTLocations that +// reference them. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/DeclReferenceMap.h" +#include "clang/Index/ASTLocation.h" +#include "ASTVisitor.h" +using namespace clang; +using namespace idx; + +namespace { + +class RefMapper : public ASTVisitor<RefMapper> { + DeclReferenceMap::MapTy ⤅ + +public: + RefMapper(DeclReferenceMap::MapTy &map) : Map(map) { } + + void VisitDeclRefExpr(DeclRefExpr *Node); + void VisitMemberExpr(MemberExpr *Node); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); + + void VisitTypedefTypeLoc(TypedefTypeLoc TL); + void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); +}; + +} // anonymous namespace + +//===----------------------------------------------------------------------===// +// RefMapper Implementation +//===----------------------------------------------------------------------===// + +void RefMapper::VisitDeclRefExpr(DeclRefExpr *Node) { + NamedDecl *PrimD = cast<NamedDecl>(Node->getDecl()->getCanonicalDecl()); + Map.insert(std::make_pair(PrimD, ASTLocation(CurrentDecl, Node))); +} + +void RefMapper::VisitMemberExpr(MemberExpr *Node) { + NamedDecl *PrimD = cast<NamedDecl>(Node->getMemberDecl()->getCanonicalDecl()); + Map.insert(std::make_pair(PrimD, ASTLocation(CurrentDecl, Node))); +} + +void RefMapper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { + Map.insert(std::make_pair(Node->getDecl(), ASTLocation(CurrentDecl, Node))); +} + +void RefMapper::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + NamedDecl *ND = TL.getTypedefDecl(); + Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc()))); +} + +void RefMapper::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + NamedDecl *ND = TL.getIFaceDecl(); + Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc()))); +} + +//===----------------------------------------------------------------------===// +// DeclReferenceMap Implementation +//===----------------------------------------------------------------------===// + +DeclReferenceMap::DeclReferenceMap(ASTContext &Ctx) { + RefMapper(Map).Visit(Ctx.getTranslationUnitDecl()); +} + +DeclReferenceMap::astlocation_iterator +DeclReferenceMap::refs_begin(NamedDecl *D) const { + NamedDecl *Prim = cast<NamedDecl>(D->getCanonicalDecl()); + return astlocation_iterator(Map.lower_bound(Prim)); +} + +DeclReferenceMap::astlocation_iterator +DeclReferenceMap::refs_end(NamedDecl *D) const { + NamedDecl *Prim = cast<NamedDecl>(D->getCanonicalDecl()); + return astlocation_iterator(Map.upper_bound(Prim)); +} + +bool DeclReferenceMap::refs_empty(NamedDecl *D) const { + NamedDecl *Prim = cast<NamedDecl>(D->getCanonicalDecl()); + return refs_begin(Prim) == refs_end(Prim); +} diff --git a/contrib/llvm/tools/clang/lib/Index/Entity.cpp b/contrib/llvm/tools/clang/lib/Index/Entity.cpp new file mode 100644 index 0000000..cd9d277 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/Entity.cpp @@ -0,0 +1,223 @@ +//===--- 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) { } + + Entity VisitNamedDecl(NamedDecl *D); + Entity VisitVarDecl(VarDecl *D); + Entity VisitFunctionDecl(FunctionDecl *D); +}; + +} +} + +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(); + + llvm::FoldingSetNodeID ID; + EntityImpl::Profile(ID, Parent, GlobName, 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, GlobName, IdNS, isObjCInstanceMethod); + Entities.InsertNode(New, InsertPos); + + return Entity(New); +} + +Entity EntityGetter::VisitVarDecl(VarDecl *D) { + // If it's static it cannot be referred to by another translation unit. + if (D->getStorageClass() == VarDecl::Static) + return Entity(D); + + return VisitNamedDecl(D); +} + +Entity EntityGetter::VisitFunctionDecl(FunctionDecl *D) { + // If it's static it cannot be refered to by another translation unit. + if (D->getStorageClass() == FunctionDecl::Static) + return Entity(D); + + return VisitNamedDecl(D); +} + +//===----------------------------------------------------------------------===// +// 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); +} + +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); +} + +unsigned +llvm::DenseMapInfo<Entity>::getHashValue(Entity E) { + return DenseMapInfo<void*>::getHashValue(E.getAsOpaquePtr()); +} diff --git a/contrib/llvm/tools/clang/lib/Index/EntityImpl.h b/contrib/llvm/tools/clang/lib/Index/EntityImpl.h new file mode 100644 index 0000000..cbce934 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/EntityImpl.h @@ -0,0 +1,70 @@ +//===--- EntityImpl.h - Internal Entity implementation---------*- C++ -*-=====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Internal implementation for the Entity class +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_ENTITYIMPL_H +#define LLVM_CLANG_INDEX_ENTITYIMPL_H + +#include "clang/Index/Entity.h" +#include "clang/AST/DeclarationName.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/StringSet.h" + +namespace clang { + +namespace idx { + class ProgramImpl; + +class EntityImpl : public llvm::FoldingSetNode { + Entity Parent; + DeclarationName Name; + + /// \brief Identifier namespace. + unsigned IdNS; + + /// \brief If Name is a selector, this keeps track whether it's for an + /// instance method. + bool IsObjCInstanceMethod; + +public: + EntityImpl(Entity parent, DeclarationName name, unsigned idNS, + bool isObjCInstanceMethod) + : Parent(parent), Name(name), IdNS(idNS), + IsObjCInstanceMethod(isObjCInstanceMethod) { } + + /// \brief Find the Decl that can be referred to by this entity. + Decl *getDecl(ASTContext &AST); + + /// \brief Get an Entity associated with the given Decl. + /// \returns Null if an Entity cannot refer to this Decl. + static Entity get(Decl *D, Program &Prog, ProgramImpl &ProgImpl); + + std::string getPrintableName(); + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, Parent, Name, IdNS, IsObjCInstanceMethod); + } + static void Profile(llvm::FoldingSetNodeID &ID, Entity Parent, + DeclarationName Name, unsigned IdNS, + bool isObjCInstanceMethod) { + ID.AddPointer(Parent.getAsOpaquePtr()); + ID.AddPointer(Name.getAsOpaquePtr()); + ID.AddInteger(IdNS); + ID.AddBoolean(isObjCInstanceMethod); + } +}; + +} // namespace idx + +} // namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/lib/Index/GlobalSelector.cpp b/contrib/llvm/tools/clang/lib/Index/GlobalSelector.cpp new file mode 100644 index 0000000..3467918 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/GlobalSelector.cpp @@ -0,0 +1,71 @@ +//===-- GlobalSelector.cpp - Cross-translation-unit "token" for selectors -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// GlobalSelector is a ASTContext-independent way to refer to selectors. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/GlobalSelector.h" +#include "ProgramImpl.h" +#include "clang/Index/Program.h" +#include "clang/AST/ASTContext.h" +using namespace clang; +using namespace idx; + +/// \brief Get the ASTContext-specific selector. +Selector GlobalSelector::getSelector(ASTContext &AST) const { + if (isInvalid()) + return Selector(); + + Selector GlobSel = Selector(reinterpret_cast<uintptr_t>(Val)); + + llvm::SmallVector<IdentifierInfo *, 8> Ids; + for (unsigned i = 0, e = GlobSel.isUnarySelector() ? 1 : GlobSel.getNumArgs(); + i != e; ++i) { + IdentifierInfo *GlobII = GlobSel.getIdentifierInfoForSlot(i); + IdentifierInfo *II = &AST.Idents.get(GlobII->getName()); + Ids.push_back(II); + } + + return AST.Selectors.getSelector(GlobSel.getNumArgs(), Ids.data()); +} + +/// \brief Get a printable name for debugging purpose. +std::string GlobalSelector::getPrintableName() const { + if (isInvalid()) + return "<< Invalid >>"; + + Selector GlobSel = Selector(reinterpret_cast<uintptr_t>(Val)); + return GlobSel.getAsString(); +} + +/// \brief Get a GlobalSelector for the ASTContext-specific selector. +GlobalSelector GlobalSelector::get(Selector Sel, Program &Prog) { + if (Sel.isNull()) + return GlobalSelector(); + + ProgramImpl &ProgImpl = *static_cast<ProgramImpl*>(Prog.Impl); + + llvm::SmallVector<IdentifierInfo *, 8> Ids; + for (unsigned i = 0, e = Sel.isUnarySelector() ? 1 : Sel.getNumArgs(); + i != e; ++i) { + IdentifierInfo *II = Sel.getIdentifierInfoForSlot(i); + IdentifierInfo *GlobII = &ProgImpl.getIdents().get(II->getName()); + Ids.push_back(GlobII); + } + + Selector GlobSel = ProgImpl.getSelectors().getSelector(Sel.getNumArgs(), + Ids.data()); + return GlobalSelector(GlobSel.getAsOpaquePtr()); +} + +unsigned +llvm::DenseMapInfo<GlobalSelector>::getHashValue(GlobalSelector Sel) { + return DenseMapInfo<void*>::getHashValue(Sel.getAsOpaquePtr()); +} diff --git a/contrib/llvm/tools/clang/lib/Index/Handlers.cpp b/contrib/llvm/tools/clang/lib/Index/Handlers.cpp new file mode 100644 index 0000000..1e9a27d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/Handlers.cpp @@ -0,0 +1,22 @@ +//===--- Handlers.cpp - Interfaces for receiving information ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Abstract interfaces for receiving information. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/Handlers.h" +#include "clang/Index/Entity.h" +using namespace clang; +using namespace idx; + +// Out-of-line to give the virtual tables a home. +EntityHandler::~EntityHandler() { } +TranslationUnitHandler::~TranslationUnitHandler() { } +TULocationHandler::~TULocationHandler() { } diff --git a/contrib/llvm/tools/clang/lib/Index/IndexProvider.cpp b/contrib/llvm/tools/clang/lib/Index/IndexProvider.cpp new file mode 100644 index 0000000..eea0988 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/IndexProvider.cpp @@ -0,0 +1,20 @@ +//===- IndexProvider.cpp - Maps information to translation units -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Maps information to TranslationUnits. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/IndexProvider.h" +#include "clang/Index/Entity.h" +using namespace clang; +using namespace idx; + +// Out-of-line to give the virtual table a home. +IndexProvider::~IndexProvider() { } diff --git a/contrib/llvm/tools/clang/lib/Index/Indexer.cpp b/contrib/llvm/tools/clang/lib/Index/Indexer.cpp new file mode 100644 index 0000000..57bfc5b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/Indexer.cpp @@ -0,0 +1,104 @@ +//===--- Indexer.cpp - IndexProvider implementation -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// IndexProvider implementation. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/Indexer.h" +#include "clang/Index/Program.h" +#include "clang/Index/Handlers.h" +#include "clang/Index/TranslationUnit.h" +#include "ASTVisitor.h" +#include "clang/AST/DeclBase.h" +using namespace clang; +using namespace idx; + +namespace { + +class EntityIndexer : public EntityHandler { + TranslationUnit *TU; + Indexer::MapTy ⤅ + +public: + EntityIndexer(TranslationUnit *tu, Indexer::MapTy &map) : TU(tu), Map(map) { } + + virtual void Handle(Entity Ent) { + if (Ent.isInternalToTU()) + return; + Map[Ent].insert(TU); + } +}; + +class SelectorIndexer : public ASTVisitor<SelectorIndexer> { + Program &Prog; + TranslationUnit *TU; + Indexer::SelMapTy ⤅ + +public: + SelectorIndexer(Program &prog, TranslationUnit *tu, Indexer::SelMapTy &map) + : Prog(prog), TU(tu), Map(map) { } + + void VisitObjCMethodDecl(ObjCMethodDecl *D) { + Map[GlobalSelector::get(D->getSelector(), Prog)].insert(TU); + Base::VisitObjCMethodDecl(D); + } + + void VisitObjCMessageExpr(ObjCMessageExpr *Node) { + Map[GlobalSelector::get(Node->getSelector(), Prog)].insert(TU); + Base::VisitObjCMessageExpr(Node); + } +}; + +} // anonymous namespace + +void Indexer::IndexAST(TranslationUnit *TU) { + assert(TU && "Passed null TranslationUnit"); + ASTContext &Ctx = TU->getASTContext(); + CtxTUMap[&Ctx] = TU; + EntityIndexer Idx(TU, Map); + Prog.FindEntities(Ctx, Idx); + + SelectorIndexer SelIdx(Prog, TU, SelMap); + SelIdx.Visit(Ctx.getTranslationUnitDecl()); +} + +void Indexer::GetTranslationUnitsFor(Entity Ent, + TranslationUnitHandler &Handler) { + assert(Ent.isValid() && "Expected valid Entity"); + + if (Ent.isInternalToTU()) { + Decl *D = Ent.getInternalDecl(); + CtxTUMapTy::iterator I = CtxTUMap.find(&D->getASTContext()); + if (I != CtxTUMap.end()) + Handler.Handle(I->second); + return; + } + + MapTy::iterator I = Map.find(Ent); + if (I == Map.end()) + return; + + TUSetTy &Set = I->second; + for (TUSetTy::iterator I = Set.begin(), E = Set.end(); I != E; ++I) + Handler.Handle(*I); +} + +void Indexer::GetTranslationUnitsFor(GlobalSelector Sel, + TranslationUnitHandler &Handler) { + assert(Sel.isValid() && "Expected valid GlobalSelector"); + + SelMapTy::iterator I = SelMap.find(Sel); + if (I == SelMap.end()) + return; + + TUSetTy &Set = I->second; + for (TUSetTy::iterator I = Set.begin(), E = Set.end(); I != E; ++I) + Handler.Handle(*I); +} diff --git a/contrib/llvm/tools/clang/lib/Index/Makefile b/contrib/llvm/tools/clang/lib/Index/Makefile new file mode 100644 index 0000000..4d86713 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/Makefile @@ -0,0 +1,27 @@ +##===- clang/lib/Index/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the Indexer library for the C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +include $(LEVEL)/Makefile.config + +LIBRARYNAME := clangIndex +BUILD_ARCHIVE = 1 + +ifeq ($(ARCH),PowerPC) +CXX.Flags += -maltivec +endif + +CPP.Flags += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/contrib/llvm/tools/clang/lib/Index/Program.cpp b/contrib/llvm/tools/clang/lib/Index/Program.cpp new file mode 100644 index 0000000..4efad2c --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/Program.cpp @@ -0,0 +1,50 @@ +//===--- Program.cpp - Entity originator and misc -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Storage for Entities and utility functions +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/Program.h" +#include "ProgramImpl.h" +#include "clang/Index/Handlers.h" +#include "clang/Index/TranslationUnit.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/ASTContext.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; +using namespace idx; + +// Out-of-line to give the virtual tables a home. +TranslationUnit::~TranslationUnit() { } + +Program::Program() : Impl(new ProgramImpl()) { } + +Program::~Program() { + delete static_cast<ProgramImpl *>(Impl); +} + +static void FindEntitiesInDC(DeclContext *DC, Program &Prog, + EntityHandler &Handler) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { + if (I->getLocation().isInvalid()) + continue; + Entity Ent = Entity::get(*I, Prog); + if (Ent.isValid()) + Handler.Handle(Ent); + if (DeclContext *SubDC = dyn_cast<DeclContext>(*I)) + FindEntitiesInDC(SubDC, Prog, Handler); + } +} + +/// \brief Traverses the AST and passes all the entities to the Handler. +void Program::FindEntities(ASTContext &Ctx, EntityHandler &Handler) { + FindEntitiesInDC(Ctx.getTranslationUnitDecl(), *this, Handler); +} diff --git a/contrib/llvm/tools/clang/lib/Index/ProgramImpl.h b/contrib/llvm/tools/clang/lib/Index/ProgramImpl.h new file mode 100644 index 0000000..57b9ce3 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/ProgramImpl.h @@ -0,0 +1,56 @@ +//===--- ProgramImpl.h - Internal Program implementation---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Internal implementation for the Program class +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_PROGRAMIMPL_H +#define LLVM_CLANG_INDEX_PROGRAMIMPL_H + +#include "EntityImpl.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" + +namespace clang { + +namespace idx { + class EntityListener; + +class ProgramImpl { +public: + typedef llvm::FoldingSet<EntityImpl> EntitySetTy; + +private: + EntitySetTy Entities; + llvm::BumpPtrAllocator BumpAlloc; + + IdentifierTable Identifiers; + SelectorTable Selectors; + + ProgramImpl(const ProgramImpl&); // do not implement + ProgramImpl &operator=(const ProgramImpl &); // do not implement + +public: + ProgramImpl() : Identifiers(LangOptions()) { } + + EntitySetTy &getEntities() { return Entities; } + IdentifierTable &getIdents() { return Identifiers; } + SelectorTable &getSelectors() { return Selectors; } + + void *Allocate(unsigned Size, unsigned Align = 8) { + return BumpAlloc.Allocate(Size, Align); + } +}; + +} // namespace idx + +} // namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/lib/Index/ResolveLocation.cpp b/contrib/llvm/tools/clang/lib/Index/ResolveLocation.cpp new file mode 100644 index 0000000..ccd7a12 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/ResolveLocation.cpp @@ -0,0 +1,602 @@ +//===--- ResolveLocation.cpp - Source location resolver ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines the ResolveLocationInAST function, which resolves a +// source location into a ASTLocation. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/Utils.h" +#include "clang/Index/ASTLocation.h" +#include "clang/AST/TypeLocVisitor.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Lex/Lexer.h" +#include "clang/Basic/SourceManager.h" +using namespace clang; +using namespace idx; + +namespace { + +/// \brief Base for the LocResolver classes. Mostly does source range checking. +class LocResolverBase { +protected: + ASTContext &Ctx; + SourceLocation Loc; + + ASTLocation ResolveInDeclarator(Decl *D, Stmt *Stm, TypeSourceInfo *TInfo); + + enum RangePos { + BeforeLoc, + ContainsLoc, + AfterLoc + }; + + RangePos CheckRange(SourceRange Range); + RangePos CheckRange(TypeSourceInfo *TInfo); + RangePos CheckRange(Decl *D) { + if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) + if (ContainsLocation(DD->getTypeSourceInfo())) + return ContainsLoc; + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) + if (ContainsLocation(TD->getTypeSourceInfo())) + return ContainsLoc; + + return CheckRange(D->getSourceRange()); + } + RangePos CheckRange(Stmt *Node) { return CheckRange(Node->getSourceRange()); } + RangePos CheckRange(TypeLoc TL) { return CheckRange(TL.getLocalSourceRange()); } + + template <typename T> + bool isBeforeLocation(T Node) { + return CheckRange(Node) == BeforeLoc; + } + + template <typename T> + bool isAfterLocation(T Node) { + return CheckRange(Node) == AfterLoc; + } + +public: + LocResolverBase(ASTContext &ctx, SourceLocation loc) + : Ctx(ctx), Loc(loc) {} + + template <typename T> + bool ContainsLocation(T Node) { + return CheckRange(Node) == ContainsLoc; + } + +#ifndef NDEBUG + /// \brief Debugging output. + void print(Decl *D); + /// \brief Debugging output. + void print(Stmt *Node); +#endif +}; + +/// \brief Searches a statement for the ASTLocation that corresponds to a source +/// location. +class StmtLocResolver : public LocResolverBase, + public StmtVisitor<StmtLocResolver, + ASTLocation > { + Decl * const Parent; + +public: + StmtLocResolver(ASTContext &ctx, SourceLocation loc, Decl *parent) + : LocResolverBase(ctx, loc), Parent(parent) {} + + ASTLocation VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node); + ASTLocation VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node); + ASTLocation VisitDeclStmt(DeclStmt *Node); + ASTLocation VisitStmt(Stmt *Node); +}; + +/// \brief Searches a declaration for the ASTLocation that corresponds to a +/// source location. +class DeclLocResolver : public LocResolverBase, + public DeclVisitor<DeclLocResolver, + ASTLocation > { +public: + DeclLocResolver(ASTContext &ctx, SourceLocation loc) + : LocResolverBase(ctx, loc) {} + + ASTLocation VisitDeclContext(DeclContext *DC); + ASTLocation VisitTranslationUnitDecl(TranslationUnitDecl *TU); + ASTLocation VisitDeclaratorDecl(DeclaratorDecl *D); + ASTLocation VisitVarDecl(VarDecl *D); + ASTLocation VisitFunctionDecl(FunctionDecl *D); + ASTLocation VisitObjCClassDecl(ObjCClassDecl *D); + ASTLocation VisitObjCMethodDecl(ObjCMethodDecl *D); + ASTLocation VisitTypedefDecl(TypedefDecl *D); + ASTLocation VisitDecl(Decl *D); +}; + +class TypeLocResolver : public LocResolverBase, + public TypeLocVisitor<TypeLocResolver, ASTLocation> { + Decl * const ParentDecl; + +public: + TypeLocResolver(ASTContext &ctx, SourceLocation loc, Decl *pd) + : LocResolverBase(ctx, loc), ParentDecl(pd) { } + + ASTLocation VisitBuiltinTypeLoc(BuiltinTypeLoc TL); + ASTLocation VisitTypedefTypeLoc(TypedefTypeLoc TL); + ASTLocation VisitFunctionTypeLoc(FunctionTypeLoc TL); + ASTLocation VisitArrayTypeLoc(ArrayTypeLoc TL); + ASTLocation VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); + ASTLocation VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL); + ASTLocation VisitTypeLoc(TypeLoc TL); +}; + +} // anonymous namespace + +ASTLocation +StmtLocResolver::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { + assert(ContainsLocation(Node) && + "Should visit only after verifying that loc is in range"); + + if (Node->isArgumentType()) { + TypeSourceInfo *TInfo = Node->getArgumentTypeInfo(); + if (ContainsLocation(TInfo)) + return ResolveInDeclarator(Parent, Node, TInfo); + } else { + Expr *SubNode = Node->getArgumentExpr(); + if (ContainsLocation(SubNode)) + return Visit(SubNode); + } + + return ASTLocation(Parent, Node); +} + + +ASTLocation +StmtLocResolver::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { + assert(ContainsLocation(Node) && + "Should visit only after verifying that loc is in range"); + + if (Node->getNumArgs() == 1) + // Unary operator. Let normal child traversal handle it. + return VisitCallExpr(Node); + + assert(Node->getNumArgs() == 2 && + "Wrong args for the C++ operator call expr ?"); + + llvm::SmallVector<Expr *, 3> Nodes; + // Binary operator. Check in order of 1-left arg, 2-callee, 3-right arg. + Nodes.push_back(Node->getArg(0)); + Nodes.push_back(Node->getCallee()); + Nodes.push_back(Node->getArg(1)); + + for (unsigned i = 0, e = Nodes.size(); i != e; ++i) { + RangePos RP = CheckRange(Nodes[i]); + if (RP == AfterLoc) + break; + if (RP == ContainsLoc) + return Visit(Nodes[i]); + } + + return ASTLocation(Parent, Node); +} + +ASTLocation StmtLocResolver::VisitDeclStmt(DeclStmt *Node) { + assert(ContainsLocation(Node) && + "Should visit only after verifying that loc is in range"); + + // Search all declarations of this DeclStmt. + for (DeclStmt::decl_iterator + I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) { + RangePos RP = CheckRange(*I); + if (RP == AfterLoc) + break; + if (RP == ContainsLoc) + return DeclLocResolver(Ctx, Loc).Visit(*I); + } + + return ASTLocation(Parent, Node); +} + +ASTLocation StmtLocResolver::VisitStmt(Stmt *Node) { + assert(ContainsLocation(Node) && + "Should visit only after verifying that loc is in range"); + + // Search the child statements. + for (Stmt::child_iterator + I = Node->child_begin(), E = Node->child_end(); I != E; ++I) { + if (*I == NULL) + continue; + + RangePos RP = CheckRange(*I); + if (RP == AfterLoc) + break; + if (RP == ContainsLoc) + return Visit(*I); + } + + return ASTLocation(Parent, Node); +} + +ASTLocation DeclLocResolver::VisitDeclContext(DeclContext *DC) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { + RangePos RP = CheckRange(*I); + if (RP == AfterLoc) + break; + if (RP == ContainsLoc) + return Visit(*I); + } + + return ASTLocation(cast<Decl>(DC)); +} + +ASTLocation DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { + ASTLocation ASTLoc = VisitDeclContext(TU); + if (ASTLoc.getParentDecl() == TU) + return ASTLocation(); + return ASTLoc; +} + +ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) { + assert(ContainsLocation(D) && + "Should visit only after verifying that loc is in range"); + + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, 0, D->getTypeSourceInfo()); + + // First, search through the parameters of the function. + for (FunctionDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) { + RangePos RP = CheckRange(*I); + if (RP == AfterLoc) + return ASTLocation(D); + if (RP == ContainsLoc) + return Visit(*I); + } + + // We didn't find the location in the parameters and we didn't get passed it. + + if (!D->isThisDeclarationADefinition()) + return ASTLocation(D); + + // Second, search through the declarations that are part of the function. + // If we find the location there, we won't have to search through its body. + + for (DeclContext::decl_iterator + I = D->decls_begin(), E = D->decls_end(); I != E; ++I) { + if (isa<ParmVarDecl>(*I)) + continue; // We already searched through the parameters. + + RangePos RP = CheckRange(*I); + if (RP == AfterLoc) + break; + if (RP == ContainsLoc) + return Visit(*I); + } + + // We didn't find a declaration that corresponds to the source location. + + // Finally, search through the body of the function. + Stmt *Body = D->getBody(); + assert(Body && "Expected definition"); + assert(!isBeforeLocation(Body) && + "This function is supposed to contain the loc"); + if (isAfterLocation(Body)) + return ASTLocation(D); + + // The body contains the location. + assert(ContainsLocation(Body)); + return StmtLocResolver(Ctx, Loc, D).Visit(Body); +} + +ASTLocation DeclLocResolver::VisitDeclaratorDecl(DeclaratorDecl *D) { + assert(ContainsLocation(D) && + "Should visit only after verifying that loc is in range"); + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeSourceInfo()); + + return ASTLocation(D); +} + +ASTLocation DeclLocResolver::VisitTypedefDecl(TypedefDecl *D) { + assert(ContainsLocation(D) && + "Should visit only after verifying that loc is in range"); + + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeSourceInfo()); + + return ASTLocation(D); +} + +ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) { + assert(ContainsLocation(D) && + "Should visit only after verifying that loc is in range"); + + // Check whether the location points to the init expression. + Expr *Init = D->getInit(); + if (Init && ContainsLocation(Init)) + return StmtLocResolver(Ctx, Loc, D).Visit(Init); + + if (ContainsLocation(D->getTypeSourceInfo())) + return ResolveInDeclarator(D, 0, D->getTypeSourceInfo()); + + return ASTLocation(D); +} + +ASTLocation DeclLocResolver::VisitObjCClassDecl(ObjCClassDecl *D) { + assert(ContainsLocation(D) && + "Should visit only after verifying that loc is in range"); + + for (ObjCClassDecl::iterator I = D->begin(), E = D->end() ; I != E; ++I) { + if (CheckRange(I->getLocation()) == ContainsLoc) + return ASTLocation(D, I->getInterface(), I->getLocation()); + } + return ASTLocation(D); +} + +ASTLocation DeclLocResolver::VisitObjCMethodDecl(ObjCMethodDecl *D) { + assert(ContainsLocation(D) && + "Should visit only after verifying that loc is in range"); + + // First, search through the parameters of the method. + for (ObjCMethodDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) { + RangePos RP = CheckRange(*I); + if (RP == AfterLoc) + return ASTLocation(D); + if (RP == ContainsLoc) + return Visit(*I); + } + + // We didn't find the location in the parameters and we didn't get passed it. + + if (!D->getBody()) + return ASTLocation(D); + + // Second, search through the declarations that are part of the method. + // If we find he location there, we won't have to search through its body. + + for (DeclContext::decl_iterator + I = D->decls_begin(), E = D->decls_end(); I != E; ++I) { + if (isa<ParmVarDecl>(*I)) + continue; // We already searched through the parameters. + + RangePos RP = CheckRange(*I); + if (RP == AfterLoc) + break; + if (RP == ContainsLoc) + return Visit(*I); + } + + // We didn't find a declaration that corresponds to the source location. + + // Finally, search through the body of the method. + Stmt *Body = D->getBody(); + assert(Body && "Expected definition"); + assert(!isBeforeLocation(Body) && + "This method is supposed to contain the loc"); + if (isAfterLocation(Body)) + return ASTLocation(D); + + // The body contains the location. + assert(ContainsLocation(Body)); + return StmtLocResolver(Ctx, Loc, D).Visit(Body); +} + +ASTLocation DeclLocResolver::VisitDecl(Decl *D) { + assert(ContainsLocation(D) && + "Should visit only after verifying that loc is in range"); + if (DeclContext *DC = dyn_cast<DeclContext>(D)) + return VisitDeclContext(DC); + return ASTLocation(D); +} + +ASTLocation TypeLocResolver::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + // Continue the 'id' magic by making the builtin type (which cannot + // actually be spelled) map to the typedef. + BuiltinType *T = TL.getTypePtr(); + if (T->getKind() == BuiltinType::ObjCId) { + TypedefDecl *D = Ctx.getObjCIdType()->getAs<TypedefType>()->getDecl(); + return ASTLocation(ParentDecl, D, TL.getNameLoc()); + } + + // Same thing with 'Class'. + if (T->getKind() == BuiltinType::ObjCClass) { + TypedefDecl *D = Ctx.getObjCClassType()->getAs<TypedefType>()->getDecl(); + return ASTLocation(ParentDecl, D, TL.getNameLoc()); + } + + return ASTLocation(ParentDecl, TL); +} + +ASTLocation TypeLocResolver::VisitTypedefTypeLoc(TypedefTypeLoc TL) { + assert(ContainsLocation(TL) && + "Should visit only after verifying that loc is in range"); + if (ContainsLocation(TL.getNameLoc())) + return ASTLocation(ParentDecl, TL.getTypedefDecl(), TL.getNameLoc()); + return ASTLocation(ParentDecl, TL); +} + +ASTLocation TypeLocResolver::VisitFunctionTypeLoc(FunctionTypeLoc TL) { + assert(ContainsLocation(TL) && + "Should visit only after verifying that loc is in range"); + + for (unsigned i = 0; i != TL.getNumArgs(); ++i) { + ParmVarDecl *Parm = TL.getArg(i); + RangePos RP = CheckRange(Parm); + if (RP == AfterLoc) + break; + if (RP == ContainsLoc) + return DeclLocResolver(Ctx, Loc).Visit(Parm); + } + + return ASTLocation(ParentDecl, TL); +} + +ASTLocation TypeLocResolver::VisitArrayTypeLoc(ArrayTypeLoc TL) { + assert(ContainsLocation(TL) && + "Should visit only after verifying that loc is in range"); + + Expr *E = TL.getSizeExpr(); + if (E && ContainsLocation(E)) + return StmtLocResolver(Ctx, Loc, ParentDecl).Visit(E); + + return ASTLocation(ParentDecl, TL); +} + +ASTLocation TypeLocResolver::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + assert(ContainsLocation(TL) && + "Should visit only after verifying that loc is in range"); + if (ContainsLocation(TL.getNameLoc())) + return ASTLocation(ParentDecl, TL.getIFaceDecl(), TL.getNameLoc()); + + return ASTLocation(ParentDecl, TL); +} + +ASTLocation TypeLocResolver::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + assert(ContainsLocation(TL) && + "Should visit only after verifying that loc is in range"); + + for (unsigned i = 0; i != TL.getNumProtocols(); ++i) { + SourceLocation L = TL.getProtocolLoc(i); + RangePos RP = CheckRange(L); + if (RP == AfterLoc) + break; + if (RP == ContainsLoc) + return ASTLocation(ParentDecl, TL.getProtocol(i), L); + } + + return ASTLocation(ParentDecl, TL); +} + +ASTLocation TypeLocResolver::VisitTypeLoc(TypeLoc TL) { + assert(ContainsLocation(TL) && + "Should visit only after verifying that loc is in range"); + return ASTLocation(ParentDecl, TL); +} + +ASTLocation LocResolverBase::ResolveInDeclarator(Decl *D, Stmt *Stm, + TypeSourceInfo *TInfo) { + assert(ContainsLocation(TInfo) && + "Should visit only after verifying that loc is in range"); + + (void)TypeLocResolver(Ctx, Loc, D); + for (TypeLoc TL = TInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) + if (ContainsLocation(TL)) + return TypeLocResolver(Ctx, Loc, D).Visit(TL); + + assert(0 && "Should have found the loc in a typeloc"); + return ASTLocation(D, Stm); +} + +LocResolverBase::RangePos LocResolverBase::CheckRange(TypeSourceInfo *TInfo) { + if (!TInfo) + return BeforeLoc; // Keep looking. + + for (TypeLoc TL = TInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) + if (ContainsLocation(TL)) + return ContainsLoc; + + return BeforeLoc; // Keep looking. +} + +LocResolverBase::RangePos LocResolverBase::CheckRange(SourceRange Range) { + if (!Range.isValid()) + return BeforeLoc; // Keep looking. + + // Update the end source range to cover the full length of the token + // positioned at the end of the source range. + // + // e.g., + // int foo + // ^ ^ + // + // will be updated to + // int foo + // ^ ^ + unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(), + Ctx.getSourceManager(), + Ctx.getLangOptions()); + Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1)); + + SourceManager &SourceMgr = Ctx.getSourceManager(); + if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc)) + return BeforeLoc; + + if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin())) + return AfterLoc; + + return ContainsLoc; +} + +#ifndef NDEBUG +void LocResolverBase::print(Decl *D) { + llvm::raw_ostream &OS = llvm::outs(); + OS << "#### DECL " << D->getDeclKindName() << " ####\n"; + D->print(OS); + OS << " <"; + D->getLocStart().print(OS, Ctx.getSourceManager()); + OS << " > - <"; + D->getLocEnd().print(OS, Ctx.getSourceManager()); + OS << ">\n\n"; + OS.flush(); +} + +void LocResolverBase::print(Stmt *Node) { + llvm::raw_ostream &OS = llvm::outs(); + OS << "#### STMT " << Node->getStmtClassName() << " ####\n"; + Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions())); + OS << " <"; + Node->getLocStart().print(OS, Ctx.getSourceManager()); + OS << " > - <"; + Node->getLocEnd().print(OS, Ctx.getSourceManager()); + OS << ">\n\n"; + OS.flush(); +} +#endif + + +/// \brief Returns the AST node that a source location points to. +/// +ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc, + ASTLocation *LastLoc) { + if (Loc.isInvalid()) + return ASTLocation(); + + if (LastLoc && LastLoc->isValid()) { + DeclContext *DC = 0; + + if (Decl *Dcl = LastLoc->dyn_AsDecl()) { + DC = Dcl->getDeclContext(); + } else if (LastLoc->isStmt()) { + Decl *Parent = LastLoc->getParentDecl(); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Parent)) + DC = FD; + else { + // This is needed to handle statements within an initializer. + // Example: + // void func() { long double fabsf = __builtin_fabsl(__x); } + // In this case, the 'parent' of __builtin_fabsl is fabsf. + DC = Parent->getDeclContext(); + } + } else { // We have 'N_NamedRef' or 'N_Type' + DC = LastLoc->getParentDecl()->getDeclContext(); + } + assert(DC && "Missing DeclContext"); + + FunctionDecl *FD = dyn_cast<FunctionDecl>(DC); + DeclLocResolver DLocResolver(Ctx, Loc); + + if (FD && FD->isThisDeclarationADefinition() && + DLocResolver.ContainsLocation(FD)) { + return DLocResolver.VisitFunctionDecl(FD); + } + // Fall through and try the slow path... + // FIXME: Optimize more cases. + } + return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl()); +} diff --git a/contrib/llvm/tools/clang/lib/Index/SelectorMap.cpp b/contrib/llvm/tools/clang/lib/Index/SelectorMap.cpp new file mode 100644 index 0000000..0f11e31 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Index/SelectorMap.cpp @@ -0,0 +1,84 @@ +//===- SelectorMap.cpp - Maps selectors to methods and messages -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// SelectorMap creates a mapping from selectors to ObjC method declarations +// and ObjC message expressions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/SelectorMap.h" +#include "ASTVisitor.h" +using namespace clang; +using namespace idx; + +namespace { + +class SelMapper : public ASTVisitor<SelMapper> { + SelectorMap::SelMethMapTy &SelMethMap; + SelectorMap::SelRefMapTy &SelRefMap; + +public: + SelMapper(SelectorMap::SelMethMapTy &MethMap, + SelectorMap::SelRefMapTy &RefMap) + : SelMethMap(MethMap), SelRefMap(RefMap) { } + + void VisitObjCMethodDecl(ObjCMethodDecl *D); + void VisitObjCMessageExpr(ObjCMessageExpr *Node); + void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); +}; + +} // anonymous namespace + +//===----------------------------------------------------------------------===// +// SelMapper Implementation +//===----------------------------------------------------------------------===// + +void SelMapper::VisitObjCMethodDecl(ObjCMethodDecl *D) { + if (D->getCanonicalDecl() == D) + SelMethMap.insert(std::make_pair(D->getSelector(), D)); + Base::VisitObjCMethodDecl(D); +} + +void SelMapper::VisitObjCMessageExpr(ObjCMessageExpr *Node) { + ASTLocation ASTLoc(CurrentDecl, Node); + SelRefMap.insert(std::make_pair(Node->getSelector(), ASTLoc)); +} + +void SelMapper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { + ASTLocation ASTLoc(CurrentDecl, Node); + SelRefMap.insert(std::make_pair(Node->getSelector(), ASTLoc)); +} + +//===----------------------------------------------------------------------===// +// SelectorMap Implementation +//===----------------------------------------------------------------------===// + +SelectorMap::SelectorMap(ASTContext &Ctx) { + SelMapper(SelMethMap, SelRefMap).Visit(Ctx.getTranslationUnitDecl()); +} + +SelectorMap::method_iterator +SelectorMap::methods_begin(Selector Sel) const { + return method_iterator(SelMethMap.lower_bound(Sel)); +} + +SelectorMap::method_iterator +SelectorMap::methods_end(Selector Sel) const { + return method_iterator(SelMethMap.upper_bound(Sel)); +} + +SelectorMap::astlocation_iterator +SelectorMap::refs_begin(Selector Sel) const { + return astlocation_iterator(SelRefMap.lower_bound(Sel)); +} + +SelectorMap::astlocation_iterator +SelectorMap::refs_end(Selector Sel) const { + return astlocation_iterator(SelRefMap.upper_bound(Sel)); +} |