[llvm-branch-commits] [cfe-branch] r118544 - in /cfe/branches/Apple/whitney: test/Index/annotate-tokens.m tools/libclang/CIndex.cpp
Daniel Dunbar
daniel at zuster.org
Tue Nov 9 09:30:52 PST 2010
Author: ddunbar
Date: Tue Nov 9 11:30:52 2010
New Revision: 118544
URL: http://llvm.org/viewvc/llvm-project?rev=118544&view=rev
Log:
Merge r118109:
--
Author: Ted Kremenek <kremenek at apple.com>
Date: Tue Nov 2 23:10:24 2010 +0000
Hack to workaround deficiency in ObjC ASTs. Functions and variables may be declared
within an @implementation, but we have no way to record that information in the AST.
This may cause CursorVisitor to miss these Decls when doing a AST walk.
Fixes <rdar://problem/8595462>.
Modified:
cfe/branches/Apple/whitney/test/Index/annotate-tokens.m
cfe/branches/Apple/whitney/tools/libclang/CIndex.cpp
Modified: cfe/branches/Apple/whitney/test/Index/annotate-tokens.m
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/Apple/whitney/test/Index/annotate-tokens.m?rev=118544&r1=118543&r2=118544&view=diff
==============================================================================
--- cfe/branches/Apple/whitney/test/Index/annotate-tokens.m (original)
+++ cfe/branches/Apple/whitney/test/Index/annotate-tokens.m Tue Nov 9 11:30:52 2010
@@ -88,7 +88,21 @@
(void)@protocol(Proto);
}
-// RUN: c-index-test -test-annotate-tokens=%s:1:1:89:2 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s
+// <rdar://problem/8595462> - Properly annotate functions and variables
+// declared within an @implementation.
+ at class Rdar8595462_A;
+ at interface Rdar8595462_B
+ at end
+
+ at implementation Rdar8595462_B
+Rdar8595462_A * Rdar8595462_aFunction() {
+ Rdar8595462_A * localVar = 0;
+ return localVar;
+}
+static Rdar8595462_A * Rdar8595462_staticVar;
+ at end
+
+// RUN: c-index-test -test-annotate-tokens=%s:1:1:104:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s
// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=Foo:1:12
// CHECK: Keyword: "interface" [1:2 - 1:11] ObjCInterfaceDecl=Foo:1:12
// CHECK: Identifier: "Foo" [1:12 - 1:15] ObjCInterfaceDecl=Foo:1:12
@@ -397,3 +411,39 @@
// CHECK: Punctuation: ")" [88:24 - 88:25] UnexposedExpr=Proto:85:1
// CHECK: Punctuation: ";" [88:25 - 88:26] UnexposedStmt=
// CHECK: Punctuation: "}" [89:1 - 89:2] UnexposedStmt=
+// CHECK: Punctuation: "@" [93:1 - 93:2] UnexposedDecl=[93:8]
+// CHECK: Keyword: "class" [93:2 - 93:7] UnexposedDecl=[93:8]
+// CHECK: Identifier: "Rdar8595462_A" [93:8 - 93:21] ObjCClassRef=Rdar8595462_A:93:8
+// CHECK: Punctuation: ";" [93:21 - 93:22]
+// CHECK: Punctuation: "@" [94:1 - 94:2] ObjCInterfaceDecl=Rdar8595462_B:94:12
+// CHECK: Keyword: "interface" [94:2 - 94:11] ObjCInterfaceDecl=Rdar8595462_B:94:12
+// CHECK: Identifier: "Rdar8595462_B" [94:12 - 94:25] ObjCInterfaceDecl=Rdar8595462_B:94:12
+// CHECK: Punctuation: "@" [95:1 - 95:2] ObjCInterfaceDecl=Rdar8595462_B:94:12
+// CHECK: Keyword: "end" [95:2 - 95:5] ObjCInterfaceDecl=Rdar8595462_B:94:12
+// CHECK: Punctuation: "@" [97:1 - 97:2] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
+// CHECK: Keyword: "implementation" [97:2 - 97:16] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
+// CHECK: Identifier: "Rdar8595462_B" [97:17 - 97:30] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
+// CHECK: Identifier: "Rdar8595462_A" [98:1 - 98:14] ObjCClassRef=Rdar8595462_A:93:8
+// CHECK: Punctuation: "*" [98:15 - 98:16] FunctionDecl=Rdar8595462_aFunction:98:17 (Definition)
+// CHECK: Identifier: "Rdar8595462_aFunction" [98:17 - 98:38] FunctionDecl=Rdar8595462_aFunction:98:17 (Definition)
+// CHECK: Punctuation: "(" [98:38 - 98:39] FunctionDecl=Rdar8595462_aFunction:98:17 (Definition)
+// CHECK: Punctuation: ")" [98:39 - 98:40] FunctionDecl=Rdar8595462_aFunction:98:17 (Definition)
+// CHECK: Punctuation: "{" [98:41 - 98:42] UnexposedStmt=
+// CHECK: Identifier: "Rdar8595462_A" [99:3 - 99:16] ObjCClassRef=Rdar8595462_A:93:8
+// CHECK: Punctuation: "*" [99:17 - 99:18] VarDecl=localVar:99:19 (Definition)
+// CHECK: Identifier: "localVar" [99:19 - 99:27] VarDecl=localVar:99:19 (Definition)
+// CHECK: Punctuation: "=" [99:28 - 99:29] VarDecl=localVar:99:19 (Definition)
+// CHECK: Literal: "0" [99:30 - 99:31] UnexposedExpr=
+// CHECK: Punctuation: ";" [99:31 - 99:32] UnexposedStmt=
+// CHECK: Keyword: "return" [100:3 - 100:9] UnexposedStmt=
+// CHECK: Identifier: "localVar" [100:10 - 100:18] DeclRefExpr=localVar:99:19
+// CHECK: Punctuation: ";" [100:18 - 100:19] UnexposedStmt=
+// CHECK: Punctuation: "}" [101:1 - 101:2] UnexposedStmt=
+// CHECK: Keyword: "static" [102:1 - 102:7] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
+// CHECK: Identifier: "Rdar8595462_A" [102:8 - 102:21] ObjCClassRef=Rdar8595462_A:93:8
+// CHECK: Punctuation: "*" [102:22 - 102:23] VarDecl=Rdar8595462_staticVar:102:24
+// CHECK: Identifier: "Rdar8595462_staticVar" [102:24 - 102:45] VarDecl=Rdar8595462_staticVar:102:24
+// CHECK: Punctuation: ";" [102:45 - 102:46] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
+// CHECK: Punctuation: "@" [103:1 - 103:2] ObjCImplementationDecl=Rdar8595462_B:97:1 (Definition)
+// CHECK: Keyword: "end" [103:2 - 103:5]
+
Modified: cfe/branches/Apple/whitney/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/branches/Apple/whitney/tools/libclang/CIndex.cpp?rev=118544&r1=118543&r2=118544&view=diff
==============================================================================
--- cfe/branches/Apple/whitney/tools/libclang/CIndex.cpp (original)
+++ cfe/branches/Apple/whitney/tools/libclang/CIndex.cpp Tue Nov 9 11:30:52 2010
@@ -31,6 +31,8 @@
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Optional.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -151,6 +153,11 @@
/// its search.
SourceRange RegionOfInterest;
+ // FIXME: Eventually remove. This part of a hack to support proper
+ // iteration over all Decls contained lexically within an ObjC container.
+ DeclContext::decl_iterator *DI_current;
+ DeclContext::decl_iterator DE_current;
+
using DeclVisitor<CursorVisitor, bool>::Visit;
using TypeLocVisitor<CursorVisitor, bool>::Visit;
using StmtVisitor<CursorVisitor, bool>::Visit;
@@ -187,7 +194,8 @@
unsigned MaxPCHLevel,
SourceRange RegionOfInterest = SourceRange())
: TU(TU), Visitor(Visitor), ClientData(ClientData),
- MaxPCHLevel(MaxPCHLevel), RegionOfInterest(RegionOfInterest)
+ MaxPCHLevel(MaxPCHLevel), RegionOfInterest(RegionOfInterest),
+ DI_current(0)
{
Parent.kind = CXCursor_NoDeclFound;
Parent.data[0] = 0;
@@ -207,6 +215,7 @@
bool VisitAttributes(Decl *D);
bool VisitBlockDecl(BlockDecl *B);
bool VisitCXXRecordDecl(CXXRecordDecl *D);
+ llvm::Optional<bool> shouldVisitCursor(CXCursor C);
bool VisitDeclContext(DeclContext *DC);
bool VisitTranslationUnitDecl(TranslationUnitDecl *D);
bool VisitTypedefDecl(TypedefDecl *D);
@@ -497,40 +506,50 @@
return false;
}
-bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
- for (DeclContext::decl_iterator
- I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
-
- Decl *D = *I;
- if (D->getLexicalDeclContext() != DC)
- continue;
+llvm::Optional<bool> CursorVisitor::shouldVisitCursor(CXCursor Cursor) {
+ if (RegionOfInterest.isValid()) {
+ SourceRange Range = getRawCursorExtent(Cursor);
+ if (Range.isInvalid())
+ return llvm::Optional<bool>();
- CXCursor Cursor = MakeCXCursor(D, TU);
+ switch (CompareRegionOfInterest(Range)) {
+ case RangeBefore:
+ // This declaration comes before the region of interest; skip it.
+ return llvm::Optional<bool>();
- if (RegionOfInterest.isValid()) {
- SourceRange Range = getRawCursorExtent(Cursor);
- if (Range.isInvalid())
- continue;
+ case RangeAfter:
+ // This declaration comes after the region of interest; we're done.
+ return false;
- switch (CompareRegionOfInterest(Range)) {
- case RangeBefore:
- // This declaration comes before the region of interest; skip it.
- continue;
+ case RangeOverlap:
+ // This declaration overlaps the region of interest; visit it.
+ break;
+ }
+ }
+ return true;
+}
- case RangeAfter:
- // This declaration comes after the region of interest; we're done.
- return false;
+bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
+ DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
- case RangeOverlap:
- // This declaration overlaps the region of interest; visit it.
- break;
- }
- }
+ // FIXME: Eventually remove. This part of a hack to support proper
+ // iteration over all Decls contained lexically within an ObjC container.
+ SaveAndRestore<DeclContext::decl_iterator*> DI_saved(DI_current, &I);
+ SaveAndRestore<DeclContext::decl_iterator> DE_saved(DE_current, E);
+ for ( ; I != E; ++I) {
+ Decl *D = *I;
+ if (D->getLexicalDeclContext() != DC)
+ continue;
+ CXCursor Cursor = MakeCXCursor(D, TU);
+ const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
+ if (!V.hasValue())
+ continue;
+ if (!V.getValue())
+ return false;
if (Visit(Cursor, true))
return true;
}
-
return false;
}
@@ -794,8 +813,83 @@
return false;
}
+namespace {
+ struct ContainerDeclsSort {
+ SourceManager &SM;
+ ContainerDeclsSort(SourceManager &sm) : SM(sm) {}
+ bool operator()(Decl *A, Decl *B) {
+ SourceLocation L_A = A->getLocStart();
+ SourceLocation L_B = B->getLocStart();
+ assert(L_A.isValid() && L_B.isValid());
+ return SM.isBeforeInTranslationUnit(L_A, L_B);
+ }
+ };
+}
+
bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
- return VisitDeclContext(D);
+ // FIXME: Eventually convert back to just 'VisitDeclContext()'. Essentially
+ // 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)
+ return VisitDeclContext(D);
+
+ // Scan the Decls that immediately come after the container
+ // in the current DeclContext. If any fall within the
+ // container's lexical region, stash them into a vector
+ // for later processing.
+ llvm::SmallVector<Decl *, 24> DeclsInContainer;
+ SourceLocation EndLoc = D->getSourceRange().getEnd();
+ SourceManager &SM = TU->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;
+ }
+ }
+
+ // The common case.
+ if (DeclsInContainer.empty())
+ return VisitDeclContext(D);
+
+ // Get all the Decls in the DeclContext, and sort them with the
+ // additional ones we've collected. Then visit them.
+ for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
+ I!=E; ++I) {
+ Decl *subDecl = *I;
+ if (!subDecl || subDecl->getLexicalDeclContext() != D)
+ continue;
+ DeclsInContainer.push_back(subDecl);
+ }
+
+ // Now sort the Decls so that they appear in lexical order.
+ std::sort(DeclsInContainer.begin(), DeclsInContainer.end(),
+ ContainerDeclsSort(SM));
+
+ // Now visit the decls.
+ for (llvm::SmallVectorImpl<Decl*>::iterator I = DeclsInContainer.begin(),
+ E = DeclsInContainer.end(); I != E; ++I) {
+ CXCursor Cursor = MakeCXCursor(*I, TU);
+ const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
+ if (!V.hasValue())
+ continue;
+ if (!V.getValue())
+ return false;
+ if (Visit(Cursor, true))
+ return true;
+ }
+ return false;
}
bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
More information about the llvm-branch-commits
mailing list