//===--- 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(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 EntitiesSetTy; EntitiesSetTy HierarchyEntities; public: RefSelectorAnalyzer(ObjCMethodDecl *MD, Program &prog, TULocationHandler &handler) : Prog(prog), TULocHandler(handler) { assert(MD); // FIXME: Protocol methods. assert(!isa(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(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(ASTLoc.AsStmt())) return false; ObjCInterfaceDecl *MsgD = 0; ObjCMessageExpr *Msg = cast(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()->getInterface(); break; } case ObjCMessageExpr::SuperClass: // Expecting class method. if (IsInstanceMethod) return false; MsgD = Msg->getSuperType()->getAs()->getInterface(); break; case ObjCMessageExpr::SuperInstance: // Expecting instance method. if (!IsInstanceMethod) return false; MsgD = Msg->getSuperType()->getAs() ->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 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()->getInterface(); break; case ObjCMessageExpr::SuperClass: CanBeClassMethod = true; MsgD = Msg->getSuperType()->getAs()->getInterface(); break; case ObjCMessageExpr::SuperInstance: CanBeInstanceMethod = true; MsgD = Msg->getSuperType()->getAs() ->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(*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(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(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(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(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); }