[libclang] Make clang_annotateTokens use "file-targeted" deserialization and avoid
unnecessary deserializations.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144792 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Index/targeted-annotation.c b/test/Index/targeted-annotation.c
new file mode 100644
index 0000000..cfa1046
--- /dev/null
+++ b/test/Index/targeted-annotation.c
@@ -0,0 +1,99 @@
+
+#include "targeted-top.h"
+#include "targeted-preamble.h"
+
+int LocalVar1;
+int LocalVar2;
+
+// RUN: c-index-test -write-pch %t.h.pch %S/targeted-top.h
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -test-annotate-tokens=%s:1:1:7:1 %s -include %t.h \
+// RUN:    -Xclang -error-on-deserialized-decl=NestedVar1  \
+// RUN:    -Xclang -error-on-deserialized-decl=TopVar  \
+// RUN:  | FileCheck %s -check-prefix=LOCAL
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN:   c-index-test -test-annotate-tokens=%s:1:1:7:1 %s -include %t.h \
+// RUN:    -Xclang -error-on-deserialized-decl=PreambleVar  \
+// RUN:    -Xclang -error-on-deserialized-decl=NestedVar1  \
+// RUN:    -Xclang -error-on-deserialized-decl=TopVar  \
+// RUN:  | FileCheck %s -check-prefix=LOCAL
+
+// LOCAL: Punctuation: "#" [2:1 - 2:2] inclusion directive=targeted-top.h
+// LOCAL: Identifier: "include" [2:2 - 2:9] inclusion directive=targeted-top.h
+// LOCAL: Literal: ""targeted-top.h"" [2:10 - 2:26] inclusion directive=targeted-top.h
+// LOCAL: Punctuation: "#" [3:1 - 3:2] inclusion directive=targeted-preamble.h
+// LOCAL: Identifier: "include" [3:2 - 3:9] inclusion directive=targeted-preamble.h
+// LOCAL: Literal: ""targeted-preamble.h"" [3:10 - 3:31] inclusion directive=targeted-preamble.h
+// LOCAL: Keyword: "int" [5:1 - 5:4] VarDecl=LocalVar1:5:5
+// LOCAL: Identifier: "LocalVar1" [5:5 - 5:14] VarDecl=LocalVar1:5:5
+// LOCAL: Punctuation: ";" [5:14 - 5:15]
+// LOCAL: Keyword: "int" [6:1 - 6:4] VarDecl=LocalVar2:6:5
+// LOCAL: Identifier: "LocalVar2" [6:5 - 6:14] VarDecl=LocalVar2:6:5
+// LOCAL: Punctuation: ";" [6:14 - 6:15]
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -test-annotate-tokens=%S/targeted-fields.h:1:1:4:1 %s -include %t.h \
+// RUN:    -Xclang -error-on-deserialized-decl=NestedVar1  \
+// RUN:    -Xclang -error-on-deserialized-decl=TopVar  \
+// RUN:  | FileCheck %s -check-prefix=FIELD
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN:   c-index-test -test-annotate-tokens=%S/targeted-fields.h:1:1:4:1 %s -include %t.h \
+// RUN:    -Xclang -error-on-deserialized-decl=PreambleVar  \
+// RUN:    -Xclang -error-on-deserialized-decl=NestedVar1  \
+// RUN:    -Xclang -error-on-deserialized-decl=TopVar  \
+// RUN:  | FileCheck %s -check-prefix=FIELD
+
+// FIELD: Keyword: "int" [2:3 - 2:6] FieldDecl=z:2:7 (Definition)
+// FIELD: Identifier: "z" [2:7 - 2:8] FieldDecl=z:2:7 (Definition)
+// FIELD: Punctuation: ";" [2:8 - 2:9] StructDecl=:13:9 (Definition)
+// FIELD: Keyword: "int" [3:3 - 3:6] FieldDecl=w:3:7 (Definition)
+// FIELD: Identifier: "w" [3:7 - 3:8] FieldDecl=w:3:7 (Definition)
+// FIELD: Punctuation: ";" [3:8 - 3:9] StructDecl=:13:9 (Definition)
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -test-annotate-tokens=%S/targeted-nested1.h:1:1:3:1 %s -include %t.h \
+// RUN:    -Xclang -error-on-deserialized-decl=TopVar  \
+// RUN:  | FileCheck %s -check-prefix=NESTED
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN:   c-index-test -test-annotate-tokens=%S/targeted-nested1.h:1:1:3:1 %s -include %t.h \
+// RUN:    -Xclang -error-on-deserialized-decl=PreambleVar  \
+// RUN:    -Xclang -error-on-deserialized-decl=TopVar  \
+// RUN:  | FileCheck %s -check-prefix=NESTED
+
+// NESTED: Keyword: "extern" [2:1 - 2:7]
+// NESTED: Keyword: "int" [2:8 - 2:11] VarDecl=NestedVar1:2:12
+// NESTED: Identifier: "NestedVar1" [2:12 - 2:22] VarDecl=NestedVar1:2:12
+// NESTED: Punctuation: ";" [2:22 - 2:23]
+
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -test-annotate-tokens=%S/targeted-top.h:1:1:12:1 %s -include %t.h \
+// RUN:    -Xclang -error-on-deserialized-decl=NestedVar1  \
+// RUN:    -Xclang -error-on-deserialized-decl=vector_get_x  \
+// RUN:  | FileCheck %s -check-prefix=TOP
+
+// RUN: env CINDEXTEST_FAILONERROR=1 CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_NO_CACHING=1 \
+// RUN:   c-index-test -test-annotate-tokens=%S/targeted-top.h:1:1:12:1 %s -include %t.h \
+// RUN:    -Xclang -error-on-deserialized-decl=PreambleVar  \
+// RUN:    -Xclang -error-on-deserialized-decl=NestedVar1  \
+// RUN:    -Xclang -error-on-deserialized-decl=vector_get_x  \
+// RUN:  | FileCheck %s -check-prefix=TOP
+
+// TOP: Punctuation: "#" [2:1 - 2:2] preprocessing directive=
+// TOP: Identifier: "ifndef" [2:2 - 2:8] preprocessing directive=
+// TOP: Identifier: "TARGETED_TOP_H" [2:9 - 2:23] preprocessing directive=
+// TOP: Punctuation: "#" [3:1 - 3:2] preprocessing directive=
+// TOP: Identifier: "define" [3:2 - 3:8] preprocessing directive=
+// TOP: Identifier: "TARGETED_TOP_H" [3:9 - 3:23] preprocessing directive=
+// TOP: Punctuation: "#" [5:1 - 5:2] preprocessing directive=
+// TOP: Identifier: "include" [5:2 - 5:9] preprocessing directive=
+// TOP: Literal: ""targeted-nested1.h"" [5:10 - 5:30] preprocessing directive=
+// TOP: Keyword: "enum" [7:1 - 7:5] EnumDecl=:7:1 (Definition)
+// TOP: Punctuation: "{" [7:6 - 7:7] EnumDecl=:7:1 (Definition)
+// TOP: Identifier: "VALUE" [8:3 - 8:8] EnumConstantDecl=VALUE:8:3 (Definition)
+// TOP: Punctuation: "=" [8:9 - 8:10] EnumConstantDecl=VALUE:8:3 (Definition)
+// TOP: Literal: "3" [8:11 - 8:12] IntegerLiteral=
+// TOP: Punctuation: "}" [9:1 - 9:2] EnumDecl=:7:1 (Definition)
+// TOP: Punctuation: ";" [9:2 - 9:3]
+// TOP: Keyword: "extern" [11:1 - 11:7]
+// TOP: Keyword: "int" [11:8 - 11:11] VarDecl=TopVar:11:12
+// TOP: Identifier: "TopVar" [11:12 - 11:18] VarDecl=TopVar:11:12
+// TOP: Punctuation: ";" [11:18 - 11:19]
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 25d0c5b..42adfa1 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -315,6 +315,14 @@
 
     assert(CompRes == RangeOverlap);
     VisitedAtLeastOnce = true;
+
+    if (isa<ObjCContainerDecl>(D)) {
+      FileDI_current = &DIt;
+      FileDE_current = DE;
+    } else {
+      FileDI_current = 0;
+    }
+
     if (Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true))
       break;
   }
@@ -838,6 +846,27 @@
   return false;
 }
 
+template <typename DeclIt>
+static void addRangedDeclsInContainer(DeclIt *DI_current, DeclIt DE_current,
+                                      SourceManager &SM, SourceLocation EndLoc,
+                                      SmallVectorImpl<Decl *> &Decls) {
+  DeclIt next = *DI_current;
+  while (++next != DE_current) {
+    Decl *D_next = *next;
+    if (!D_next)
+      break;
+    SourceLocation L = D_next->getLocStart();
+    if (!L.isValid())
+      break;
+    if (SM.isBeforeInTranslationUnit(L, EndLoc)) {
+      *DI_current = next;
+      Decls.push_back(D_next);
+      continue;
+    }
+    break;
+  }
+}
+
 namespace {
   struct ContainerDeclsSort {
     SourceManager &SM;
@@ -856,7 +885,7 @@
   // an @implementation can lexically contain Decls that are not properly
   // nested in the AST.  When we identify such cases, we need to retrofit
   // this nesting here.
-  if (!DI_current)
+  if (!DI_current && !FileDI_current)
     return VisitDeclContext(D);
 
   // Scan the Decls that immediately come after the container
@@ -867,20 +896,12 @@
   SourceLocation EndLoc = D->getSourceRange().getEnd();
   SourceManager &SM = AU->getSourceManager();
   if (EndLoc.isValid()) {
-    DeclContext::decl_iterator next = *DI_current;
-    while (++next != DE_current) {
-      Decl *D_next = *next;
-      if (!D_next)
-        break;
-      SourceLocation L = D_next->getLocStart();
-      if (!L.isValid())
-        break;
-      if (SM.isBeforeInTranslationUnit(L, EndLoc)) {
-        *DI_current = next;
-        DeclsInContainer.push_back(D_next);
-        continue;
-      }
-      break;
+    if (DI_current) {
+      addRangedDeclsInContainer(DI_current, DE_current, SM, EndLoc,
+                                DeclsInContainer);
+    } else {
+      addRangedDeclsInContainer(FileDI_current, FileDE_current, SM, EndLoc,
+                                DeclsInContainer);
     }
   }
 
@@ -4517,10 +4538,7 @@
 
   void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); }
   enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent);
-  void AnnotateTokens(CXCursor parent);
-  void AnnotateTokens() {
-    AnnotateTokens(clang_getTranslationUnitCursor(AnnotateVis.getTU()));
-  }
+  void AnnotateTokens();
   
   /// \brief Determine whether the annotator saw any cursors that have 
   /// context-sensitive keywords.
@@ -4530,10 +4548,10 @@
 };
 }
 
-void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) {
+void AnnotateTokensWorker::AnnotateTokens() {
   // Walk the AST within the region of interest, annotating tokens
   // along the way.
-  VisitChildren(parent);
+  AnnotateVis.visitFileRegion();
 
   for (unsigned I = 0 ; I < TokIdx ; ++I) {
     AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
@@ -4549,6 +4567,9 @@
 
   const CXCursor &C = clang_getNullCursor();
   for (unsigned I = TokIdx ; I < NumTokens ; ++I) {
+    if (I < PreprocessingTokIdx && clang_isPreprocessing(Cursors[I].kind))
+      continue;
+
     AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
     Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second;
   }
diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h
index eaefd83..d3fa70d 100644
--- a/tools/libclang/CursorVisitor.h
+++ b/tools/libclang/CursorVisitor.h
@@ -87,6 +87,8 @@
   // iteration over all Decls contained lexically within an ObjC container.
   DeclContext::decl_iterator *DI_current;
   DeclContext::decl_iterator DE_current;
+  SmallVectorImpl<Decl *>::iterator *FileDI_current;
+  SmallVectorImpl<Decl *>::iterator FileDE_current;
 
   // Cache of pre-allocated worklists for data-recursion walk of Stmts.
   SmallVector<VisitorWorkList*, 5> WorkListFreeList;
@@ -134,7 +136,7 @@
       Visitor(Visitor), ClientData(ClientData),
       VisitPreprocessorLast(VisitPreprocessorLast),
       VisitIncludedEntities(VisitIncludedPreprocessingEntries),
-      RegionOfInterest(RegionOfInterest), DI_current(0)
+      RegionOfInterest(RegionOfInterest), DI_current(0), FileDI_current(0)
   {
     Parent.kind = CXCursor_NoDeclFound;
     Parent.data[0] = 0;