[cfe-commits] r77551 - in /cfe/trunk: include/clang/Index/Analyzer.h lib/Index/Analyzer.cpp test/Index/objc-decls.m test/Index/objc-message.m test/Index/objc.h test/Index/t1.m test/Index/t2.m tools/index-test/index-test.cpp

Argiris Kirtzidis akyrtzi at gmail.com
Wed Jul 29 17:03:55 PDT 2009


Author: akirtzidis
Date: Wed Jul 29 19:03:55 2009
New Revision: 77551

URL: http://llvm.org/viewvc/llvm-project?rev=77551&view=rev
Log:
Add support for ObjC message expressions, in the Analyzer:

-Accept an ObjC method and find all message expressions that this method may respond to.
-Accept an ObjC message expression and find all methods that may respond to it.

Added:
    cfe/trunk/test/Index/objc-decls.m
    cfe/trunk/test/Index/objc-message.m
    cfe/trunk/test/Index/objc.h
    cfe/trunk/test/Index/t1.m
    cfe/trunk/test/Index/t2.m
Modified:
    cfe/trunk/include/clang/Index/Analyzer.h
    cfe/trunk/lib/Index/Analyzer.cpp
    cfe/trunk/tools/index-test/index-test.cpp

Modified: cfe/trunk/include/clang/Index/Analyzer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Index/Analyzer.h?rev=77551&r1=77550&r2=77551&view=diff

==============================================================================
--- cfe/trunk/include/clang/Index/Analyzer.h (original)
+++ cfe/trunk/include/clang/Index/Analyzer.h Wed Jul 29 19:03:55 2009
@@ -16,6 +16,7 @@
 
 namespace clang {
   class Decl;
+  class ObjCMessageExpr;
 
 namespace idx {
   class Program;
@@ -42,6 +43,10 @@
   /// \brief Find all TULocations for references of the given Decl and pass
   /// them to Handler.
   void FindReferences(Decl *D, TULocationHandler &Handler);
+
+  /// \brief Find methods that may respond to the given message and pass them
+  /// to Handler.
+  void FindObjCMethods(ObjCMessageExpr *MsgE, TULocationHandler &Handler);
 };
 
 } // namespace idx

Modified: cfe/trunk/lib/Index/Analyzer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/Analyzer.cpp?rev=77551&r1=77550&r2=77551&view=diff

==============================================================================
--- cfe/trunk/lib/Index/Analyzer.cpp (original)
+++ cfe/trunk/lib/Index/Analyzer.cpp Wed Jul 29 19:03:55 2009
@@ -16,9 +16,13 @@
 #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/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprObjC.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/Support/Compiler.h"
 using namespace clang;
 using namespace idx;
@@ -73,7 +77,321 @@
     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, ASTLocation(*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 VISIBILITY_HIDDEN 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.isValid());
+    assert(ASTLoc.isStmt());
+
+    // FIXME: Finding @selector references should be through another Analyzer
+    // method, like FindSelectors.
+    if (isa<ObjCSelectorExpr>(ASTLoc.getStmt()))
+      return false;      
+
+    ObjCInterfaceDecl *MsgD = 0;
+    ObjCMessageExpr *Msg = cast<ObjCMessageExpr>(ASTLoc.getStmt());
+
+    if (Msg->getReceiver()) {
+      const ObjCObjectPointerType *OPT =
+          Msg->getReceiver()->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;
+
+    } else {
+      // Expecting class method.
+      if (IsInstanceMethod)
+        return false;
+
+      MsgD = Msg->getClassInfo().first;
+      // FIXME: Case when we only have an identifier.
+      assert(MsgD && "Identifier only"); 
+    }
+
+    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 VISIBILITY_HIDDEN 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) {
+      if (Msg->getReceiver() == 0) {
+        CanBeClassMethod = true;
+        MsgD = Msg->getClassInfo().first;
+        // FIXME: Case when we only have an identifier.
+        assert(MsgD && "Identifier only"); 
+        break;
+      }
+
+      const ObjCObjectPointerType *OPT =
+          Msg->getReceiver()->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;
+    }
+    
+    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;
   }
 };
 
@@ -95,6 +413,13 @@
 
 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;
@@ -102,3 +427,13 @@
   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);
+}

Added: cfe/trunk/test/Index/objc-decls.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/objc-decls.m?rev=77551&view=auto

==============================================================================
--- cfe/trunk/test/Index/objc-decls.m (added)
+++ cfe/trunk/test/Index/objc-decls.m Wed Jul 29 19:03:55 2009
@@ -0,0 +1,16 @@
+// RUN: clang-cc -emit-pch %S/t1.m -o %t1.m.ast &&
+// RUN: clang-cc -emit-pch %S/t2.m -o %t2.m.ast &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/t1.m:12:12 -print-decls > %t &&
+// RUN: cat %t | count 2 &&
+// RUN: grep 'objc.h:2:9,' %t | count 2 && 
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/objc.h:5:13 -print-decls > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 'objc.h:5:1,' %t | count 2 &&
+// RUN: grep 't1.m:15:1,' %t | count 1 &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/objc.h:10:13 -print-decls > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 'objc.h:10:1,' %t | count 2 &&
+// RUN: grep 't2.m:11:1,' %t | count 1

Added: cfe/trunk/test/Index/objc-message.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/objc-message.m?rev=77551&view=auto

==============================================================================
--- cfe/trunk/test/Index/objc-message.m (added)
+++ cfe/trunk/test/Index/objc-message.m Wed Jul 29 19:03:55 2009
@@ -0,0 +1,38 @@
+// RUN: clang-cc -emit-pch %S/t1.m -o %t1.m.ast &&
+// RUN: clang-cc -emit-pch %S/t2.m -o %t2.m.ast &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/objc.h:5:13 -print-refs > %t &&
+// RUN: cat %t | count 1 &&
+// RUN: grep 't1.m:6:3,' %t &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/objc.h:6:13 -print-refs > %t &&
+// RUN: cat %t | count 2 &&
+// RUN: grep 't1.m:7:3,' %t &&
+// RUN: grep 't2.m:7:3,' %t &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/objc.h:10:13 -print-refs > %t &&
+// RUN: cat %t | count 2 &&
+// RUN: grep 't1.m:6:3,' %t &&
+// RUN: grep 't2.m:6:3,' %t &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/t1.m:6:15 -print-decls > %t &&
+// RUN: cat %t | count 6 &&
+// RUN: grep 'objc.h:5:1,' %t | count 2 &&
+// RUN: grep 'objc.h:10:1,' %t | count 2 &&
+// RUN: grep 't1.m:15:1,' %t &&
+// RUN: grep 't2.m:11:1,' %t &&
+
+// RUN: index-test %t1.m.ast %t2.m.ast -point-at %S/t1.m:7:15 -print-decls > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 'objc.h:6:1,' %t | count 2 &&
+// RUN: grep 't1.m:18:1,' %t &&
+
+// RUN: index-test %t2.m.ast %t1.m.ast -point-at %S/t2.m:6:15 -print-decls > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 'objc.h:10:1,' %t | count 2 &&
+// RUN: grep 't2.m:11:1,' %t &&
+
+// RUN: index-test %t2.m.ast %t1.m.ast -point-at %S/t2.m:7:15 -print-decls > %t &&
+// RUN: cat %t | count 3 &&
+// RUN: grep 'objc.h:6:1,' %t | count 2 &&
+// RUN: grep 't1.m:18:1,' %t

Added: cfe/trunk/test/Index/objc.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/objc.h?rev=77551&view=auto

==============================================================================
--- cfe/trunk/test/Index/objc.h (added)
+++ cfe/trunk/test/Index/objc.h Wed Jul 29 19:03:55 2009
@@ -0,0 +1,11 @@
+ at interface Base {
+    int my_var;
+}
+-(int) my_var;
+-(void) my_method: (int)param;
++(void) my_method: (int)param;
+ at end
+
+ at interface Sub : Base
+-(void) my_method: (int)param;
+ at end

Added: cfe/trunk/test/Index/t1.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/t1.m?rev=77551&view=auto

==============================================================================
--- cfe/trunk/test/Index/t1.m (added)
+++ cfe/trunk/test/Index/t1.m Wed Jul 29 19:03:55 2009
@@ -0,0 +1,23 @@
+#include "objc.h"
+
+static void foo() {
+  Base *base;
+  int x = [base my_var];
+  [base my_method:x];
+  [Base my_method:x];
+}
+
+ at implementation Base
+-(int) my_var {
+  return my_var;
+}
+
+-(void) my_method: (int)param {
+}
+
++(void) my_method: (int)param {
+}
+ at end
+
+// Suppress 'no run line' failure.
+// RUN: true

Added: cfe/trunk/test/Index/t2.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/t2.m?rev=77551&view=auto

==============================================================================
--- cfe/trunk/test/Index/t2.m (added)
+++ cfe/trunk/test/Index/t2.m Wed Jul 29 19:03:55 2009
@@ -0,0 +1,16 @@
+#include "objc.h"
+
+static void foo() {
+  Sub *sub;
+  int x = [sub my_var];
+  [sub my_method:x];
+  [Sub my_method:x];
+}
+
+ at implementation Sub
+-(void) my_method: (int)param {
+}
+ at end
+
+// Suppress 'no run line' failure.
+// RUN: true

Modified: cfe/trunk/tools/index-test/index-test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/index-test/index-test.cpp?rev=77551&r1=77550&r2=77551&view=diff

==============================================================================
--- cfe/trunk/tools/index-test/index-test.cpp (original)
+++ cfe/trunk/tools/index-test/index-test.cpp Wed Jul 29 19:03:55 2009
@@ -44,8 +44,8 @@
 #include "clang/Index/Utils.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CommandLineSourceLoc.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/Expr.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExprObjC.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/Support/CommandLine.h"
@@ -106,8 +106,48 @@
 
 static bool HadErrors = false;
 
+static void ProcessObjCMessage(ObjCMessageExpr *Msg, Indexer &Idxer) {
+  llvm::raw_ostream &OS = llvm::outs();
+  typedef Storing<TULocationHandler> ResultsTy;
+  ResultsTy Results;
+
+  Analyzer Analyz(Idxer.getProgram(), Idxer);
+
+  switch (ProgAction) {
+  default: assert(0);
+  case PrintRefs:
+    llvm::errs() << "Error: Cannot -print-refs on a ObjC message expression\n";
+    HadErrors = true;
+    return;
+    
+  case PrintDecls: {
+    Analyz.FindObjCMethods(Msg, Results);
+    for (ResultsTy::iterator
+           I = Results.begin(), E = Results.end(); I != E; ++I)
+      I->print(OS);
+    break;
+  }
+
+  case PrintDefs: {
+    Analyz.FindObjCMethods(Msg, Results);
+    for (ResultsTy::iterator
+           I = Results.begin(), E = Results.end(); I != E; ++I) {
+      const ObjCMethodDecl *D = cast<ObjCMethodDecl>(I->getDecl());
+      if (D->isThisDeclarationADefinition())
+        I->print(OS);
+    }
+    break;
+  }
+
+  }
+}
+
 static void ProcessASTLocation(ASTLocation ASTLoc, Indexer &Idxer) {
   assert(ASTLoc.isValid());
+  
+  if (ObjCMessageExpr *Msg =
+        dyn_cast_or_null<ObjCMessageExpr>(ASTLoc.getStmt()))
+    return ProcessObjCMessage(Msg, Idxer);
 
   Decl *D = ASTLoc.getReferencedDecl();
   if (D == 0) {
@@ -140,7 +180,7 @@
     break;
   }
 
-  case PrintDefs:{
+  case PrintDefs: {
     Analyz.FindDeclarations(D, Results);
     for (ResultsTy::iterator
            I = Results.begin(), E = Results.end(); I != E; ++I) {
@@ -206,6 +246,10 @@
   if (!PointAtLocation.empty()) {
     const std::string &Filename = PointAtLocation[0].FileName;
     const FileEntry *File = FileMgr.getFile(Filename);
+    if (File == 0) {
+      llvm::errs() << "File '" << Filename << "' does not exist\n";
+      return 1;
+    }
 
     // Safety check. Using an out-of-date AST file will only lead to crashes
     // or incorrect results.
@@ -218,10 +262,6 @@
       return 1;
     }
 
-    if (File == 0) {
-      llvm::errs() << "File '" << Filename << "' does not exist\n";
-      return 1;
-    }
     unsigned Line = PointAtLocation[0].Line;
     unsigned Col = PointAtLocation[0].Column;
 





More information about the cfe-commits mailing list