Teach CIndex's cursor visitor to restrict its traversal to a specific
region of interest (if provided). Implement clang_getCursor() in terms
of this traversal rather than using the Index library; the unified
cursor visitor is more complete, and will be The Way Forward.

Minor other tweaks needed to make this work:
  - Extend Preprocessor::getLocForEndOfToken() to accept an offset
  from the end, making it easy to move to the last character in the
  token (rather than just past the end of the token).
  - In Lexer::MeasureTokenLength(), the length of whitespace is zero.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94200 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/CIndex/CIndex.cpp b/tools/CIndex/CIndex.cpp
index e84d15c..3447553 100644
--- a/tools/CIndex/CIndex.cpp
+++ b/tools/CIndex/CIndex.cpp
@@ -19,6 +19,7 @@
 #include "clang/AST/StmtVisitor.h"
 #include "clang/AST/TypeLocVisitor.h"
 #include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/System/Program.h"
 
@@ -133,9 +134,40 @@
   return Result;
 }
 
+static SourceRange translateSourceRange(CXSourceRange R) {
+  return SourceRange(SourceLocation::getFromRawEncoding(R.begin_int_data),
+                     SourceLocation::getFromRawEncoding(R.end_int_data));
+}
+
+/// \brief The result of comparing two source ranges.
+enum RangeComparisonResult {
+  /// \brief Either the ranges overlap or one of the ranges is invalid.
+  RangeOverlap,
+  
+  /// \brief The first range ends before the second range starts.
+  RangeBefore,
+  
+  /// \brief The first range starts after the second range ends.
+  RangeAfter
+};
+
+/// \brief Compare two source ranges to determine their relative position in 
+/// the translation unit.
+static RangeComparisonResult RangeCompare(SourceManager &SM, 
+                                          SourceRange R1, 
+                                          SourceRange R2) {
+  assert(R1.isValid() && "First range is invalid?");
+  assert(R2.isValid() && "Second range is invalid?");
+  if (SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin()))
+    return RangeBefore;
+  if (SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin()))
+    return RangeAfter;
+  return RangeOverlap;
+}
+
 
 //===----------------------------------------------------------------------===//
-// Visitors.
+// Cursor visitor.
 //===----------------------------------------------------------------------===//
 
 namespace {
@@ -145,25 +177,53 @@
                       public TypeLocVisitor<CursorVisitor, bool>,
                       public StmtVisitor<CursorVisitor, bool>
 {
+  /// \brief The translation unit we are traversing.
   ASTUnit *TU;
+  
+  /// \brief The parent cursor whose children we are traversing.
   CXCursor Parent;
+  
+  /// \brief The declaration that serves at the parent of any statement or
+  /// expression nodes.
   Decl *StmtParent;
+  
+  /// \brief The visitor function.
   CXCursorVisitor Visitor;
+  
+  /// \brief The opaque client data, to be passed along to the visitor.
   CXClientData ClientData;
-
+  
   // MaxPCHLevel - the maximum PCH level of declarations that we will pass on
   // to the visitor. Declarations with a PCH level greater than this value will
   // be suppressed.
   unsigned MaxPCHLevel;
-  
+
+  /// \brief When valid, a source range to which the cursor should restrict
+  /// its search.
+  SourceRange RegionOfInterest;
+    
   using DeclVisitor<CursorVisitor, bool>::Visit;
   using TypeLocVisitor<CursorVisitor, bool>::Visit;
   using StmtVisitor<CursorVisitor, bool>::Visit;
+    
+  /// \brief Determine whether this particular source range comes before, comes 
+  /// after, or overlaps the region of interest. 
+  ///
+  /// \param R a source range retrieved from the abstract syntax tree.
+  RangeComparisonResult CompareRegionOfInterest(SourceRange R); 
+  
+  /// \brief Determine whether this particular source range comes before, comes 
+  /// after, or overlaps the region of interest. 
+  ///
+  /// \param CXR a source range retrieved from a cursor.
+  RangeComparisonResult CompareRegionOfInterest(CXSourceRange CXR); 
   
 public:
   CursorVisitor(ASTUnit *TU, CXCursorVisitor Visitor, CXClientData ClientData, 
-                unsigned MaxPCHLevel)
-    : TU(TU), Visitor(Visitor), ClientData(ClientData), MaxPCHLevel(MaxPCHLevel)
+                unsigned MaxPCHLevel, 
+                SourceRange RegionOfInterest = SourceRange())
+    : TU(TU), Visitor(Visitor), ClientData(ClientData), 
+      MaxPCHLevel(MaxPCHLevel), RegionOfInterest(RegionOfInterest)
   {
     Parent.kind = CXCursor_NoDeclFound;
     Parent.data[0] = 0;
@@ -172,7 +232,7 @@
     StmtParent = 0;
   }
   
-  bool Visit(CXCursor Cursor);
+  bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false);
   bool VisitChildren(CXCursor Parent);
   
   // Declaration visitors
@@ -231,12 +291,32 @@
   
 } // end anonymous namespace
 
+RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) {
+  assert(RegionOfInterest.isValid() && "RangeCompare called with invalid range");
+  if (R.isInvalid())
+    return RangeOverlap;
+
+  // Move the end of the input range to the end of the last token in that
+  // range.
+  R.setEnd(TU->getPreprocessor().getLocForEndOfToken(R.getEnd(), 1));
+  return RangeCompare(TU->getSourceManager(), R, RegionOfInterest);
+}
+
+RangeComparisonResult CursorVisitor::CompareRegionOfInterest(CXSourceRange CXR) {
+  return CompareRegionOfInterest(translateSourceRange(CXR));
+}
+
 /// \brief Visit the given cursor and, if requested by the visitor,
 /// its children.
 ///
+/// \param Cursor the cursor to visit.
+///
+/// \param CheckRegionOfInterest if true, then the caller already checked that
+/// this cursor is within the region of interest.
+///
 /// \returns true if the visitation should be aborted, false if it
 /// should continue.
-bool CursorVisitor::Visit(CXCursor Cursor) {
+bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
   if (clang_isInvalid(Cursor.kind))
     return false;
   
@@ -250,6 +330,15 @@
       return false;
   }
 
+  // If we have a range of interest, and this cursor doesn't intersect with it,
+  // we're done.
+  if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) {
+    CXSourceRange Range = clang_getCursorExtent(Cursor);
+    if (translateSourceRange(Range).isInvalid() || 
+        CompareRegionOfInterest(Range))
+      return false;
+  }
+  
   switch (Visitor(Cursor, Parent, ClientData)) {
   case CXChildVisit_Break:
     return true;
@@ -310,11 +399,12 @@
   
   if (clang_isTranslationUnit(Cursor.kind)) {
     ASTUnit *CXXUnit = getCursorASTUnit(Cursor);
-    if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls()) {
+    if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() &&
+        RegionOfInterest.isInvalid()) {
       const std::vector<Decl*> &TLDs = CXXUnit->getTopLevelDecls();
       for (std::vector<Decl*>::const_iterator it = TLDs.begin(),
            ie = TLDs.end(); it != ie; ++it) {
-        if (Visit(MakeCXCursor(*it, CXXUnit)))
+        if (Visit(MakeCXCursor(*it, CXXUnit), true))
           return true;
       }
     } else {
@@ -332,7 +422,27 @@
 bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
   for (DeclContext::decl_iterator
        I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
-    if (Visit(MakeCXCursor(*I, TU)))
+    if (RegionOfInterest.isValid()) {
+      SourceRange R = (*I)->getSourceRange();
+      if (R.isInvalid())
+        continue;
+      
+      switch (CompareRegionOfInterest(R)) {
+      case RangeBefore:
+        // This declaration comes before the region of interest; skip it.
+        continue;
+      
+      case RangeAfter:
+        // This declaration comes after the region of interest; we're done.
+        return false;
+      
+      case RangeOverlap:
+        // This declaration overlaps the region of interest; visit it.
+        break;
+      }      
+    }
+    
+    if (Visit(MakeCXCursor(*I, TU), true))
       return true;
   }
   
@@ -1131,6 +1241,14 @@
   return NULL;
 }
 
+enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, 
+                                         CXCursor parent, 
+                                         CXClientData client_data) {
+  CXCursor *BestCursor = static_cast<CXCursor *>(client_data);
+  *BestCursor = cursor;
+  return CXChildVisit_Recurse;
+}
+  
 CXCursor clang_getCursor(CXTranslationUnit CTUnit, const char *source_name,
                          unsigned line, unsigned column) {
   assert(CTUnit && "Passed null CXTranslationUnit");
@@ -1144,32 +1262,21 @@
 
   SourceLocation SLoc =
     CXXUnit->getSourceManager().getLocation(File, line, column);
-
-  ASTLocation LastLoc = CXXUnit->getLastASTLocation();
-  ASTLocation ALoc = ResolveLocationInAST(CXXUnit->getASTContext(), SLoc,
-                                          &LastLoc);
   
-  // FIXME: This doesn't look thread-safe.
-  if (ALoc.isValid())
-    CXXUnit->setLastASTLocation(ALoc);
-
-  Decl *Dcl = ALoc.getParentDecl();
-  if (ALoc.isNamedRef())
-    Dcl = ALoc.AsNamedRef().ND;
-  Stmt *Stm = ALoc.dyn_AsStmt();
-  if (Dcl) {
-    if (Stm)
-      return MakeCXCursor(Stm, Dcl, CXXUnit);
-
-    if (ALoc.isNamedRef()) {
-      if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(Dcl))
-        return MakeCursorObjCClassRef(Class, ALoc.AsNamedRef().Loc, CXXUnit);
-      if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(Dcl))
-        return MakeCursorObjCProtocolRef(Proto, ALoc.AsNamedRef().Loc, CXXUnit);
-    }
-    return MakeCXCursor(Dcl, CXXUnit);
+  CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound);
+  if (SLoc.isValid()) {
+    SourceRange RegionOfInterest(SLoc, 
+                       CXXUnit->getPreprocessor().getLocForEndOfToken(SLoc, 1));
+    
+    // FIXME: Would be great to have a "hint" cursor, then walk from that
+    // hint cursor upward until we find a cursor whose source range encloses
+    // the region of interest, rather than starting from the translation unit.
+    CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit);
+    CursorVisitor CursorVis(CXXUnit, GetCursorVisitor, &Result, 
+                            Decl::MaxPCHLevel, RegionOfInterest);
+    CursorVis.VisitChildren(Parent);
   }
-  return MakeCXCursorInvalid(CXCursor_NoDeclFound);
+  return Result;  
 }
 
 CXCursor clang_getNullCursor(void) {
@@ -1304,6 +1411,10 @@
   if (clang_isExpression(C.kind))
     return translateSourceRange(getCursorContext(C), 
                                 getCursorExpr(C)->getSourceRange());
+
+  if (clang_isStatement(C.kind))
+    return translateSourceRange(getCursorContext(C), 
+                                getCursorStmt(C)->getSourceRange());
   
   if (!getCursorDecl(C)) {
     CXSourceRange empty = { 0, 0, 0 };