summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-10-06 07:00:54 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-10-06 07:00:54 +0000
commitaed123ec3cc37e457fe20a6158fdadf8849ad916 (patch)
tree3c966b7fabc78150142d829f20b4be00cceb3d0a
parentb11be041e4f05519a2eabf6a99429ba6110f1ca9 (diff)
downloadclang-aed123ec3cc37e457fe20a6158fdadf8849ad916.tar.gz
[libclang] Introduce clang_findReferencesInFile which accepts a cursor, a file,
and a callback and finds all identifier references of the cursor in the file. rdar://7948304 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141277 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang-c/Index.h48
-rw-r--r--test/Index/file-refs.c57
-rw-r--r--test/Index/file-refs.cpp104
-rw-r--r--test/Index/file-refs.m87
-rw-r--r--tools/c-index-test/c-index-test.c117
-rw-r--r--tools/libclang/CIndex.cpp63
-rw-r--r--tools/libclang/CIndexHigh.cpp315
-rw-r--r--tools/libclang/CMakeLists.txt1
-rw-r--r--tools/libclang/CXCursor.cpp165
-rw-r--r--tools/libclang/CXCursor.h25
-rw-r--r--tools/libclang/Index_Internal.h43
-rw-r--r--tools/libclang/libclang.exports2
12 files changed, 965 insertions, 62 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 65d05e5094..05ac19bb23 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -1857,6 +1857,7 @@ enum CXCursorKind {
*/
typedef struct {
enum CXCursorKind kind;
+ int xdata;
void *data[3];
} CXCursor;
@@ -3779,6 +3780,53 @@ CINDEX_LINKAGE void clang_remap_dispose(CXRemapping);
* @}
*/
+/** \defgroup CINDEX_HIGH Higher level API functions
+ *
+ * @{
+ */
+
+enum CXVisitorResult {
+ CXVisit_Break,
+ CXVisit_Continue
+};
+
+typedef struct {
+ void *context;
+ enum CXVisitorResult (*visit)(void *context, CXCursor, CXSourceRange);
+} CXCursorAndRangeVisitor;
+
+/**
+ * \brief Find references of a declaration in a specific file.
+ *
+ * \param cursor pointing to a declaration or a reference of one.
+ *
+ * \param file to search for references.
+ *
+ * \param visitor callback that will receive pairs of CXCursor/CXSourceRange for
+ * each reference found.
+ * The CXSourceRange will point inside the file; if the reference is inside
+ * a macro (and not a macro argument) the CXSourceRange will be invalid.
+ */
+CINDEX_LINKAGE void clang_findReferencesInFile(CXCursor cursor, CXFile file,
+ CXCursorAndRangeVisitor visitor);
+
+#ifdef __has_feature
+# if __has_feature(blocks)
+
+typedef enum CXVisitorResult
+ (^CXCursorAndRangeVisitorBlock)(CXCursor, CXSourceRange);
+
+CINDEX_LINKAGE
+void clang_findReferencesInFileWithBlock(CXCursor, CXFile,
+ CXCursorAndRangeVisitorBlock);
+
+# endif
+#endif
+
+/**
+ * @}
+ */
+
/**
* @}
*/
diff --git a/test/Index/file-refs.c b/test/Index/file-refs.c
new file mode 100644
index 0000000000..23042ea06f
--- /dev/null
+++ b/test/Index/file-refs.c
@@ -0,0 +1,57 @@
+enum {
+ VALUE = 3
+};
+
+extern int glob_x;
+
+int f(int x) {
+ return x+glob_x+VALUE;
+}
+
+typedef struct {
+ int x;
+ int y;
+} Vector;
+
+int vector_get_x(Vector v) {
+ int x = v.x;
+ return x;
+}
+
+int f(int);
+int f(int);
+
+// RUN: c-index-test \
+
+// RUN: -file-refs-at=%s:2:5 \
+// CHECK: EnumConstantDecl=VALUE:2:3 (Definition)
+// CHECK-NEXT: EnumConstantDecl=VALUE:2:3 (Definition) =[2:3 - 2:8]
+// CHECK-NEXT: DeclRefExpr=VALUE:2:3 =[8:19 - 8:24]
+
+// RUN: -file-refs-at=%s:8:15 \
+// CHECK-NEXT: DeclRefExpr=glob_x:5:12
+// CHECK-NEXT: VarDecl=glob_x:5:12 =[5:12 - 5:18]
+// CHECK-NEXT: DeclRefExpr=glob_x:5:12 =[8:12 - 8:18]
+
+// RUN: -file-refs-at=%s:8:10 \
+// CHECK-NEXT: DeclRefExpr=x:7:11
+// CHECK-NEXT: ParmDecl=x:7:11 (Definition) =[7:11 - 7:12]
+// CHECK-NEXT: DeclRefExpr=x:7:11 =[8:10 - 8:11]
+
+// RUN: -file-refs-at=%s:12:7 \
+// CHECK-NEXT: FieldDecl=x:12:7 (Definition)
+// CHECK-NEXT: FieldDecl=x:12:7 (Definition) =[12:7 - 12:8]
+// CHECK-NEXT: MemberRefExpr=x:12:7 {{.*}} =[17:13 - 17:14]
+
+// RUN: -file-refs-at=%s:16:21 \
+// CHECK-NEXT: TypeRef=Vector:14:3
+// CHECK-NEXT: TypedefDecl=Vector:14:3 (Definition) =[14:3 - 14:9]
+// CHECK-NEXT: TypeRef=Vector:14:3 =[16:18 - 16:24]
+
+// RUN: -file-refs-at=%s:21:5 \
+// CHECK-NEXT: FunctionDecl=f:21:5
+// CHECK-NEXT: FunctionDecl=f:7:5 (Definition) =[7:5 - 7:6]
+// CHECK-NEXT: FunctionDecl=f:21:5 =[21:5 - 21:6]
+// CHECK-NEXT: FunctionDecl=f:22:5 =[22:5 - 22:6]
+
+// RUN: %s | FileCheck %s
diff --git a/test/Index/file-refs.cpp b/test/Index/file-refs.cpp
new file mode 100644
index 0000000000..a96d27c630
--- /dev/null
+++ b/test/Index/file-refs.cpp
@@ -0,0 +1,104 @@
+namespace NS {
+ class C {
+ public:
+ C() { }
+ void m();
+ };
+}
+
+void NS::C::m() {
+ C c;
+ c.m();
+}
+
+void f() {
+ NS::C c1();
+ NS::C c2 = NS::C();
+}
+
+void over(int);
+void over(float);
+
+void test_over() {
+ over(0);
+ over(0.0f);
+}
+
+template <typename T>
+T tf(T t) {
+ return t;
+}
+
+namespace Test2 {
+
+struct S {
+ S(int x, int y);
+ S();
+};
+
+typedef S Cake;
+
+void f() {
+ Cake p;
+ p = Test2::S(0,2);
+ p = Test2::Cake(0,2);
+}
+
+}
+
+// RUN: c-index-test \
+
+// RUN: -file-refs-at=%s:9:7 \
+// CHECK: NamespaceRef=NS:1:11
+// CHECK-NEXT: Namespace=NS:1:11 (Definition) =[1:11 - 1:13]
+// CHECK-NEXT: NamespaceRef=NS:1:11 =[9:6 - 9:8]
+// CHECK-NEXT: NamespaceRef=NS:1:11 =[15:3 - 15:5]
+// CHECK-NEXT: NamespaceRef=NS:1:11 =[16:3 - 16:5]
+// CHECK-NEXT: NamespaceRef=NS:1:11 =[16:14 - 16:16]
+
+// RUN: -file-refs-at=%s:2:9 \
+// CHECK-NEXT: ClassDecl=C:2:9 (Definition)
+// CHECK-NEXT: ClassDecl=C:2:9 (Definition) =[2:9 - 2:10]
+// CHECK-NEXT: CXXConstructor=C:4:5 (Definition) =[4:5 - 4:6]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[9:10 - 9:11]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[10:3 - 10:4]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[15:7 - 15:8]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[16:7 - 16:8]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[16:18 - 16:19]
+
+// RUN: -file-refs-at=%s:16:18 \
+// CHECK-NEXT: CallExpr=C:4:5
+// CHECK-NEXT: ClassDecl=C:2:9 (Definition) =[2:9 - 2:10]
+// CHECK-NEXT: CXXConstructor=C:4:5 (Definition) =[4:5 - 4:6]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[9:10 - 9:11]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[10:3 - 10:4]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[15:7 - 15:8]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[16:7 - 16:8]
+// CHECK-NEXT: TypeRef=class NS::C:2:9 =[16:18 - 16:19]
+
+// RUN: -file-refs-at=%s:20:8 \
+// CHECK-NEXT: FunctionDecl=over:20:6
+// CHECK-NEXT: FunctionDecl=over:20:6 =[20:6 - 20:10]
+// CHECK-NEXT: DeclRefExpr=over:20:6 =[24:3 - 24:7]
+
+// RUN: -file-refs-at=%s:28:1 \
+// CHECK-NEXT: TypeRef=T:27:20
+// FIXME: Missing TemplateTypeParameter=T:27:20 (Definition)
+// CHECK-NEXT: TypeRef=T:27:20 =[28:1 - 28:2]
+// CHECK-NEXT: TypeRef=T:27:20 =[28:6 - 28:7]
+
+// RUN: -file-refs-at=%s:43:14 \
+// CHECK-NEXT: CallExpr=S:35:3
+// CHECK-NEXT: StructDecl=S:34:8 (Definition) =[34:8 - 34:9]
+// CHECK-NEXT: CXXConstructor=S:35:3 =[35:3 - 35:4]
+// CHECK-NEXT: CXXConstructor=S:36:3 =[36:3 - 36:4]
+// CHECK-NEXT: TypeRef=struct Test2::S:34:8 =[39:9 - 39:10]
+// CHECK-NEXT: TypeRef=struct Test2::S:34:8 =[43:14 - 43:15]
+
+// RUN: -file-refs-at=%s:44:16 \
+// CHECK-NEXT: CallExpr=S:35:3
+// CHECK-NEXT: TypedefDecl=Cake:39:11 (Definition) =[39:11 - 39:15]
+// CHECK-NEXT: TypeRef=Cake:39:11 =[42:3 - 42:7]
+// CHECK-NEXT: TypeRef=Cake:39:11 =[44:14 - 44:18]
+
+// RUN: %s | FileCheck %s
diff --git a/test/Index/file-refs.m b/test/Index/file-refs.m
new file mode 100644
index 0000000000..2267259d58
--- /dev/null
+++ b/test/Index/file-refs.m
@@ -0,0 +1,87 @@
+@class Foo;
+
+@interface Foo
+-(id)setWithInt:(int)i andFloat:(float)f;
+@end
+
+@implementation Foo
+-(id)setWithInt:(int)i andFloat:(float)f {
+ return self;
+}
+@end
+
+void test(Foo *foo) {
+ [foo setWithInt:0 andFloat:0];
+ [foo setWithInt: 2 andFloat: 3];
+}
+
+@protocol Prot1
+-(void)protMeth;
+@end
+
+@protocol Prot2<Prot1>
+@end
+
+@interface Base<Prot2>
+@end
+
+@interface Sub : Base
+-(void)protMeth;
+@end
+
+@implementation Sub
+-(void)protMeth {}
+@end
+
+void test2(Sub *s, id<Prot1> p) {
+ [s protMeth];
+ [p protMeth];
+}
+
+
+// RUN: c-index-test \
+
+// RUN: -file-refs-at=%s:7:18 \
+// CHECK: ObjCImplementationDecl=Foo:7:17 (Definition)
+// CHECK-NEXT: ObjCClassRef=Foo:3:12 =[1:8 - 1:11]
+// CHECK-NEXT: ObjCInterfaceDecl=Foo:3:12 =[3:12 - 3:15]
+// CHECK-NEXT: ObjCImplementationDecl=Foo:7:17 (Definition) =[7:17 - 7:20]
+// CHECK-NEXT: ObjCClassRef=Foo:3:12 =[13:11 - 13:14]
+
+// RUN: -file-refs-at=%s:4:10 \
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:1
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:1 =[4:6 - 4:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::8:1 (Definition) [Overrides @4:1] =[8:6 - 8:16]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[14:8 - 14:18]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[15:8 - 15:18]
+
+// RUN: -file-refs-at=%s:15:27 \
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::4:1 =[4:24 - 4:32]
+// CHECK-NEXT: ObjCInstanceMethodDecl=setWithInt:andFloat::8:1 (Definition) [Overrides @4:1] =[8:24 - 8:32]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[14:21 - 14:29]
+// CHECK-NEXT: ObjCMessageExpr=setWithInt:andFloat::4:1 =[15:22 - 15:30]
+
+// RUN: -file-refs-at=%s:18:13 \
+// CHECK-NEXT: ObjCProtocolDecl=Prot1:18:11 (Definition)
+// CHECK-NEXT: ObjCProtocolDecl=Prot1:18:11 (Definition) =[18:11 - 18:16]
+// CHECK-NEXT: ObjCProtocolRef=Prot1:18:11 =[22:17 - 22:22]
+// CHECK-NEXT: ObjCProtocolRef=Prot1:18:11 =[36:23 - 36:28]
+
+// RUN: -file-refs-at=%s:38:10 \
+// CHECK-NEXT: ObjCMessageExpr=protMeth:19:1
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:19:1 =[19:8 - 19:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:29:1 [Overrides @19:1] =[29:8 - 29:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:1 (Definition) [Overrides @29:1] =[33:8 - 33:16]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:29:1 =[37:6 - 37:14]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:19:1 =[38:6 - 38:14]
+
+// RUN: -file-refs-at=%s:33:12 \
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:1 (Definition) [Overrides @29:1]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:19:1 =[19:8 - 19:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:29:1 [Overrides @19:1] =[29:8 - 29:16]
+// CHECK-NEXT: ObjCInstanceMethodDecl=protMeth:33:1 (Definition) [Overrides @29:1] =[33:8 - 33:16]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:29:1 =[37:6 - 37:14]
+// CHECK-NEXT: ObjCMessageExpr=protMeth:19:1 =[38:6 - 38:14]
+
+// RUN: %s | FileCheck %s
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 33044e3da7..69a179f177 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -175,7 +175,8 @@ static void PrintRange(CXSourceRange R, const char *str) {
int want_display_name = 0;
-static void PrintCursor(CXTranslationUnit TU, CXCursor Cursor) {
+static void PrintCursor(CXCursor Cursor) {
+ CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
if (clang_isInvalid(Cursor.kind)) {
CXString ks = clang_getCursorKindSpelling(Cursor.kind);
printf("Invalid Cursor => %s", clang_getCString(ks));
@@ -463,7 +464,7 @@ enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
printf("// %s: %s:%d:%d: ", FileCheckPrefix,
GetCursorSource(Cursor), line, column);
- PrintCursor(Data->TU, Cursor);
+ PrintCursor(Cursor);
PrintCursorExtent(Cursor);
printf("\n");
return CXChildVisit_Recurse;
@@ -516,7 +517,7 @@ static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
} else if (Ref.kind != CXCursor_FunctionDecl) {
printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
curLine, curColumn);
- PrintCursor(Data->TU, Ref);
+ PrintCursor(Ref);
printf("\n");
}
}
@@ -605,7 +606,7 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
}
if (linkage) {
- PrintCursor(Data->TU, cursor);
+ PrintCursor(cursor);
printf("linkage=%s\n", linkage);
}
@@ -623,7 +624,7 @@ static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
if (!clang_isInvalid(clang_getCursorKind(cursor))) {
CXType T = clang_getCursorType(cursor);
CXString S = clang_getTypeKindSpelling(T.kind);
- PrintCursor(Data->TU, cursor);
+ PrintCursor(cursor);
printf(" typekind=%s", clang_getCString(S));
if (clang_isConstQualifiedType(T))
printf(" const");
@@ -836,7 +837,7 @@ static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
printf("-%s", prefix);
PrintExtent(stdout, start_line, start_col, end_line, end_col);
printf(" ");
- PrintCursor(TU, cursor);
+ PrintCursor(cursor);
printf("\n");
}
@@ -1275,7 +1276,7 @@ typedef struct {
unsigned column;
} CursorSourceLocation;
-int inspect_cursor_at(int argc, const char **argv) {
+static int inspect_cursor_at(int argc, const char **argv) {
CXIndex CIdx;
int errorCode;
struct CXUnsavedFile *unsaved_files = 0;
@@ -1344,7 +1345,7 @@ int inspect_cursor_at(int argc, const char **argv) {
if (I + 1 == Repeats) {
CXCompletionString completionString = clang_getCursorCompletionString(
Cursor);
- PrintCursor(TU, Cursor);
+ PrintCursor(Cursor);
if (completionString != NULL) {
printf("\nCompletion string: ");
print_completion_string(completionString, stdout);
@@ -1363,6 +1364,101 @@ int inspect_cursor_at(int argc, const char **argv) {
return 0;
}
+static enum CXVisitorResult findFileRefsVisit(void *context,
+ CXCursor cursor, CXSourceRange range) {
+ if (clang_Range_isNull(range))
+ return CXVisit_Continue;
+
+ PrintCursor(cursor);
+ PrintRange(range, "");
+ printf("\n");
+ return CXVisit_Continue;
+}
+
+static int find_file_refs_at(int argc, const char **argv) {
+ CXIndex CIdx;
+ int errorCode;
+ struct CXUnsavedFile *unsaved_files = 0;
+ int num_unsaved_files = 0;
+ CXTranslationUnit TU;
+ CXCursor Cursor;
+ CursorSourceLocation *Locations = 0;
+ unsigned NumLocations = 0, Loc;
+ unsigned Repeats = 1;
+ unsigned I;
+
+ /* Count the number of locations. */
+ while (strstr(argv[NumLocations+1], "-file-refs-at=") == argv[NumLocations+1])
+ ++NumLocations;
+
+ /* Parse the locations. */
+ assert(NumLocations > 0 && "Unable to count locations?");
+ Locations = (CursorSourceLocation *)malloc(
+ NumLocations * sizeof(CursorSourceLocation));
+ for (Loc = 0; Loc < NumLocations; ++Loc) {
+ const char *input = argv[Loc + 1] + strlen("-file-refs-at=");
+ if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
+ &Locations[Loc].line,
+ &Locations[Loc].column, 0, 0)))
+ return errorCode;
+ }
+
+ if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
+ &num_unsaved_files))
+ return -1;
+
+ if (getenv("CINDEXTEST_EDITING"))
+ Repeats = 5;
+
+ /* Parse the translation unit. When we're testing clang_getCursor() after
+ reparsing, don't remap unsaved files until the second parse. */
+ CIdx = clang_createIndex(1, 1);
+ TU = clang_parseTranslationUnit(CIdx, argv[argc - 1],
+ argv + num_unsaved_files + 1 + NumLocations,
+ argc - num_unsaved_files - 2 - NumLocations,
+ unsaved_files,
+ Repeats > 1? 0 : num_unsaved_files,
+ getDefaultParsingOptions());
+
+ if (!TU) {
+ fprintf(stderr, "unable to parse input\n");
+ return -1;
+ }
+
+ for (I = 0; I != Repeats; ++I) {
+ if (Repeats > 1 &&
+ clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
+ clang_defaultReparseOptions(TU))) {
+ clang_disposeTranslationUnit(TU);
+ return 1;
+ }
+
+ for (Loc = 0; Loc < NumLocations; ++Loc) {
+ CXFile file = clang_getFile(TU, Locations[Loc].filename);
+ if (!file)
+ continue;
+
+ Cursor = clang_getCursor(TU,
+ clang_getLocation(TU, file, Locations[Loc].line,
+ Locations[Loc].column));
+ if (I + 1 == Repeats) {
+ PrintCursor(Cursor);
+ printf("\n");
+ CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
+ clang_findReferencesInFile(Cursor, file, visitor);
+ free(Locations[Loc].filename);
+ }
+ }
+ }
+
+ PrintDiagnostics(TU);
+ clang_disposeTranslationUnit(TU);
+ clang_disposeIndex(CIdx);
+ free(Locations);
+ free_remapped_files(unsaved_files, num_unsaved_files);
+ return 0;
+}
+
int perform_token_annotation(int argc, const char **argv) {
const char *input = argv[1];
char *filename = 0;
@@ -1464,7 +1560,7 @@ int perform_token_annotation(int argc, const char **argv) {
PrintExtent(stdout, start_line, start_column, end_line, end_column);
if (!clang_isInvalid(cursors[i].kind)) {
printf(" ");
- PrintCursor(TU, cursors[i]);
+ PrintCursor(cursors[i]);
}
printf("\n");
}
@@ -1730,6 +1826,7 @@ static void print_usage(void) {
"usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
" c-index-test -code-completion-timing=<site> <compiler arguments>\n"
" c-index-test -cursor-at=<site> <compiler arguments>\n"
+ " c-index-test -file-refs-at=<site> <compiler arguments>\n"
" c-index-test -test-file-scan <AST file> <source file> "
"[FileCheck prefix]\n"
" c-index-test -test-load-tu <AST file> <symbol filter> "
@@ -1776,6 +1873,8 @@ int cindextest_main(int argc, const char **argv) {
return perform_code_completion(argc, argv, 1);
if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
return inspect_cursor_at(argc, argv);
+ if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
+ return find_file_refs_at(argc, argv);
else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
CXCursorVisitor I = GetVisitor(argv[1] + 13);
if (I)
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 1349080423..71d5ea858b 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -491,7 +491,7 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(),
TLEnd = CXXUnit->top_level_end();
TL != TLEnd; ++TL) {
- if (Visit(MakeCXCursor(*TL, tu), true))
+ if (Visit(MakeCXCursor(*TL, tu, RegionOfInterest), true))
return true;
}
} else if (VisitDeclContext(
@@ -534,7 +534,7 @@ bool CursorVisitor::VisitBlockDecl(BlockDecl *B) {
return true;
if (Stmt *Body = B->getBody())
- return Visit(MakeCXCursor(Body, StmtParent, TU));
+ return Visit(MakeCXCursor(Body, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -574,7 +574,7 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
Decl *D = *I;
if (D->getLexicalDeclContext() != DC)
continue;
- CXCursor Cursor = MakeCXCursor(D, TU);
+ CXCursor Cursor = MakeCXCursor(D, TU, RegionOfInterest);
const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
if (!V.hasValue())
continue;
@@ -672,7 +672,7 @@ bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) {
if (Expr *Init = D->getInitExpr())
- return Visit(MakeCXCursor(Init, StmtParent, TU));
+ return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -767,12 +767,12 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// Visit the initializer value.
if (Expr *Initializer = Init->getInit())
- if (Visit(MakeCXCursor(Initializer, ND, TU)))
+ if (Visit(MakeCXCursor(Initializer, ND, TU, RegionOfInterest)))
return true;
}
}
- if (Visit(MakeCXCursor(ND->getBody(), StmtParent, TU)))
+ if (Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest)))
return true;
}
@@ -784,7 +784,7 @@ bool CursorVisitor::VisitFieldDecl(FieldDecl *D) {
return true;
if (Expr *BitWidth = D->getBitWidth())
- return Visit(MakeCXCursor(BitWidth, StmtParent, TU));
+ return Visit(MakeCXCursor(BitWidth, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -794,7 +794,7 @@ bool CursorVisitor::VisitVarDecl(VarDecl *D) {
return true;
if (Expr *Init = D->getInit())
- return Visit(MakeCXCursor(Init, StmtParent, TU));
+ return Visit(MakeCXCursor(Init, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -805,7 +805,7 @@ bool CursorVisitor::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
if (Expr *DefArg = D->getDefaultArgument())
- return Visit(MakeCXCursor(DefArg, StmtParent, TU));
+ return Visit(MakeCXCursor(DefArg, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -847,12 +847,12 @@ bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
for (ObjCMethodDecl::param_iterator P = ND->param_begin(),
PEnd = ND->param_end();
P != PEnd; ++P) {
- if (Visit(MakeCXCursor(*P, TU)))
+ if (Visit(MakeCXCursor(*P, TU, RegionOfInterest)))
return true;
}
if (ND->isThisDeclarationADefinition() &&
- Visit(MakeCXCursor(ND->getBody(), StmtParent, TU)))
+ Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest)))
return true;
return false;
@@ -926,7 +926,7 @@ bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
// Now visit the decls.
for (SmallVectorImpl<Decl*>::iterator I = DeclsInContainer.begin(),
E = DeclsInContainer.end(); I != E; ++I) {
- CXCursor Cursor = MakeCXCursor(*I, TU);
+ CXCursor Cursor = MakeCXCursor(*I, TU, RegionOfInterest);
const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
if (!V.hasValue())
continue;
@@ -988,12 +988,12 @@ bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) {
// the @interface.
if (ObjCMethodDecl *MD = prevDecl->getGetterMethodDecl())
if (MD->isSynthesized() && MD->getLexicalDeclContext() == CDecl)
- if (Visit(MakeCXCursor(MD, TU)))
+ if (Visit(MakeCXCursor(MD, TU, RegionOfInterest)))
return true;
if (ObjCMethodDecl *MD = prevDecl->getSetterMethodDecl())
if (MD->isSynthesized() && MD->getLexicalDeclContext() == CDecl)
- if (Visit(MakeCXCursor(MD, TU)))
+ if (Visit(MakeCXCursor(MD, TU, RegionOfInterest)))
return true;
return false;
@@ -1246,7 +1246,7 @@ bool CursorVisitor::VisitTemplateParameters(
for (TemplateParameterList::const_iterator P = Params->begin(),
PEnd = Params->end();
P != PEnd; ++P) {
- if (Visit(MakeCXCursor(*P, TU)))
+ if (Visit(MakeCXCursor(*P, TU, RegionOfInterest)))
return true;
}
@@ -1303,12 +1303,12 @@ bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
case TemplateArgument::Declaration:
if (Expr *E = TAL.getSourceDeclExpression())
- return Visit(MakeCXCursor(E, StmtParent, TU));
+ return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
return false;
case TemplateArgument::Expression:
if (Expr *E = TAL.getSourceExpression())
- return Visit(MakeCXCursor(E, StmtParent, TU));
+ return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
return false;
case TemplateArgument::Template:
@@ -1400,7 +1400,7 @@ bool CursorVisitor::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) {
bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) {
if (TL.isDefinition())
- return Visit(MakeCXCursor(TL.getDecl(), TU));
+ return Visit(MakeCXCursor(TL.getDecl(), TU, RegionOfInterest));
return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU));
}
@@ -1468,7 +1468,7 @@ bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL,
for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I)
if (Decl *D = TL.getArg(I))
- if (Visit(MakeCXCursor(D, TU)))
+ if (Visit(MakeCXCursor(D, TU, RegionOfInterest)))
return true;
return false;
@@ -1479,7 +1479,7 @@ bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) {
return true;
if (Expr *Size = TL.getSizeExpr())
- return Visit(MakeCXCursor(Size, StmtParent, TU));
+ return Visit(MakeCXCursor(Size, StmtParent, TU, RegionOfInterest));
return false;
}
@@ -2070,7 +2070,7 @@ void EnqueueVisitor::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
}
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, Stmt *S) {
- EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU)).Visit(S);
+ EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
}
bool CursorVisitor::IsInRegionOfInterest(CXCursor C) {
@@ -2098,7 +2098,8 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
continue;
// For now, perform default visitation for Decls.
- if (Visit(MakeCXCursor(D, TU, cast<DeclVisit>(&LI)->isFirst())))
+ if (Visit(MakeCXCursor(D, TU, RegionOfInterest,
+ cast<DeclVisit>(&LI)->isFirst())))
return true;
continue;
@@ -2156,7 +2157,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
continue;
// Update the current cursor.
- CXCursor Cursor = MakeCXCursor(S, StmtParent, TU);
+ CXCursor Cursor = MakeCXCursor(S, StmtParent, TU, RegionOfInterest);
if (!IsInRegionOfInterest(Cursor))
continue;
switch (Visitor(Cursor, Parent, ClientData)) {
@@ -2674,7 +2675,7 @@ CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
}
CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
- CXCursor Result = { CXCursor_TranslationUnit, { 0, 0, TU } };
+ CXCursor Result = { CXCursor_TranslationUnit, 0, { 0, 0, TU } };
return Result;
}
@@ -3616,8 +3617,12 @@ static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
// clang_getCursor() to point at the constructor.
if (clang_isExpression(BestCursor->kind) &&
isa<CXXTemporaryObjectExpr>(getCursorExpr(*BestCursor)) &&
- cursor.kind == CXCursor_TypeRef)
+ cursor.kind == CXCursor_TypeRef) {
+ // Keep the cursor pointing at CXXTemporaryObjectExpr but also mark it
+ // as having the actual point on the type reference.
+ *BestCursor = getTypeRefedCallExprCursor(*BestCursor);
return CXChildVisit_Recurse;
+ }
*BestCursor = cursor;
return CXChildVisit_Recurse;
@@ -4055,8 +4060,12 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
if (clang_isExpression(C.kind)) {
Expr *E = getCursorExpr(C);
Decl *D = getDeclFromExpr(E);
- if (D)
- return MakeCXCursor(D, tu);
+ if (D) {
+ CXCursor declCursor = MakeCXCursor(D, tu);
+ declCursor = getSelectorIdentifierCursor(getSelectorIdentifierIndex(C),
+ declCursor);
+ return declCursor;
+ }
if (OverloadExpr *Ovl = dyn_cast_or_null<OverloadExpr>(E))
return MakeCursorOverloadedDeclRef(Ovl, tu);
diff --git a/tools/libclang/CIndexHigh.cpp b/tools/libclang/CIndexHigh.cpp
new file mode 100644
index 0000000000..b5a05eaafc
--- /dev/null
+++ b/tools/libclang/CIndexHigh.cpp
@@ -0,0 +1,315 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Index_Internal.h"
+#include "CXCursor.h"
+#include "CXSourceLocation.h"
+#include "CXTranslationUnit.h"
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/AST/DeclObjC.h"
+
+using namespace clang;
+
+static void getTopOverriddenMethods(CXTranslationUnit TU,
+ Decl *D,
+ SmallVectorImpl<Decl *> &Methods) {
+ if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D))
+ return;
+
+ SmallVector<CXCursor, 8> Overridden;
+ cxcursor::getOverriddenCursors(cxcursor::MakeCXCursor(D, TU), Overridden);
+
+ if (Overridden.empty()) {
+ Methods.push_back(D->getCanonicalDecl());
+ return;
+ }
+
+ for (SmallVector<CXCursor, 8>::iterator
+ I = Overridden.begin(), E = Overridden.end(); I != E; ++I)
+ getTopOverriddenMethods(TU, cxcursor::getCursorDecl(*I), Methods);
+}
+
+namespace {
+
+struct FindFileIdRefVisitData {
+ CXTranslationUnit TU;
+ FileID FID;
+ Decl *Dcl;
+ int SelectorIdIdx;
+ CXCursorAndRangeVisitor visitor;
+
+ typedef SmallVector<Decl *, 8> TopMethodsTy;
+ TopMethodsTy TopMethods;
+
+ FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID,
+ Decl *D, int selectorIdIdx,
+ CXCursorAndRangeVisitor visitor)
+ : TU(TU), FID(FID), SelectorIdIdx(selectorIdIdx), visitor(visitor) {
+ Dcl = getCanonical(D);
+ getTopOverriddenMethods(TU, Dcl, TopMethods);
+ }
+
+ ASTContext &getASTContext() const {
+ return static_cast<ASTUnit *>(TU->TUData)->getASTContext();
+ }
+
+ /// \brief We are looking to find all semantically relevant identifiers,
+ /// so the definition of "canonical" here is different than in the AST, e.g.
+ ///
+ /// \code
+ /// class C {
+ /// C() {}
+ /// };
+ /// \endcode
+ ///
+ /// we consider the canonical decl of the constructor decl to be the class
+ /// itself, so both 'C' can be highlighted.
+ Decl *getCanonical(Decl *D) const {
+ D = D->getCanonicalDecl();
+
+ if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
+ return getCanonical(ImplD->getClassInterface());
+ if (CXXConstructorDecl *CXXCtorD = dyn_cast<CXXConstructorDecl>(D))
+ return getCanonical(CXXCtorD->getParent());
+
+ return D;
+ }
+
+ bool isHit(Decl *D) const {
+ D = getCanonical(D);
+ if (D == Dcl)
+ return true;
+
+ if (isa<ObjCMethodDecl>(D) || isa<CXXMethodDecl>(D))
+ return isOverriddingMethod(D);
+
+ return false;
+ }
+
+private:
+ bool isOverriddingMethod(Decl *D) const {
+ if (std::find(TopMethods.begin(), TopMethods.end(), D) !=
+ TopMethods.end())
+ return true;
+
+ TopMethodsTy methods;
+ getTopOverriddenMethods(TU, D, methods);
+ for (TopMethodsTy::iterator
+ I = methods.begin(), E = methods.end(); I != E; ++I) {
+ if (std::find(TopMethods.begin(), TopMethods.end(), *I) !=
+ TopMethods.end())
+ return true;
+ }
+
+ return false;
+ }
+};
+
+} // end anonymous namespace.
+
+/// \brief For a macro \arg Loc, returns the file spelling location and sets
+/// to \arg isMacroArg whether the spelling resides inside a macro definition or
+/// a macro argument.
+static SourceLocation getFileSpellingLoc(SourceManager &SM,
+ SourceLocation Loc,
+ bool &isMacroArg) {
+ assert(Loc.isMacroID());
+ SourceLocation SpellLoc = SM.getImmediateSpellingLoc(Loc);
+ if (SpellLoc.isMacroID())
+ return getFileSpellingLoc(SM, SpellLoc, isMacroArg);
+
+ isMacroArg = SM.isMacroArgExpansion(Loc);
+ return SpellLoc;
+}
+
+static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
+ CXCursor declCursor = clang_getCursorReferenced(cursor);
+ if (!clang_isDeclaration(declCursor.kind))
+ return CXChildVisit_Recurse;
+
+ Decl *D = cxcursor::getCursorDecl(declCursor);
+ FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data;
+ if (data->isHit(D)) {
+ cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor);
+
+ // We are looking for identifiers to highlight so for objc methods (and
+ // not a parameter) we can only highlight the selector identifiers.
+ if ((cursor.kind == CXCursor_ObjCClassMethodDecl ||
+ cursor.kind == CXCursor_ObjCInstanceMethodDecl) &&
+ cxcursor::getSelectorIdentifierIndex(cursor) == -1)
+ return CXChildVisit_Recurse;
+
+ if (clang_isExpression(cursor.kind)) {
+ if (cursor.kind == CXCursor_DeclRefExpr ||
+ cursor.kind == CXCursor_MemberRefExpr) {
+ // continue..
+
+ } else if (cursor.kind == CXCursor_ObjCMessageExpr &&
+ cxcursor::getSelectorIdentifierIndex(cursor) != -1) {
+ // continue..
+
+ } else
+ return CXChildVisit_Recurse;
+ }
+
+ SourceLocation
+ Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
+ SourceLocation SelIdLoc = cxcursor::getSelectorIdentifierLoc(cursor);
+ if (SelIdLoc.isValid())
+ Loc = SelIdLoc;
+
+ SourceManager &SM = data->getASTContext().getSourceManager();
+ bool isInMacroDef = false;
+ if (Loc.isMacroID()) {
+ bool isMacroArg;
+ Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
+ isInMacroDef = !isMacroArg;
+ }
+
+ // We are looking for identifiers in a specific file.
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ if (LocInfo.first != data->FID)
+ return CXChildVisit_Recurse;
+
+ if (isInMacroDef) {
+ // FIXME: For a macro definition make sure that all expansions
+ // of it expand to the same reference before allowing to point to it.
+ Loc = SourceLocation();
+ }
+
+ data->visitor.visit(data->visitor.context, cursor,
+ cxloc::translateSourceRange(D->getASTContext(), Loc));
+ }
+ return CXChildVisit_Recurse;
+}
+
+static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
+ const FileEntry *File,
+ CXCursorAndRangeVisitor Visitor) {
+ assert(clang_isDeclaration(declCursor.kind));
+ ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
+ ASTContext &Ctx = Unit->getASTContext();
+ SourceManager &SM = Unit->getSourceManager();
+
+ FileID FID = SM.translateFile(File);
+ Decl *Dcl = cxcursor::getCursorDecl(declCursor);
+ FindFileIdRefVisitData data(TU, FID, Dcl,
+ cxcursor::getSelectorIdentifierIndex(declCursor),
+ Visitor);
+
+ if (DeclContext *DC = Dcl->getParentFunctionOrMethod()) {
+ clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
+ findFileIdRefVisit, &data);
+ return;
+ }
+
+ if (FID == SM.getMainFileID() && !Unit->isMainFileAST()) {
+ SourceLocation FileLoc = SM.getLocForStartOfFile(FID);
+ TranslationUnitDecl *TUD = Ctx.getTranslationUnitDecl();
+ CXCursor TUCursor = clang_getTranslationUnitCursor(TU);
+ for (DeclContext::decl_iterator
+ I = TUD->noload_decls_begin(), E = TUD->noload_decls_end();
+ I != E; ++I) {
+ Decl *D = *I;
+
+ SourceRange R = D->getSourceRange();
+ if (R.isInvalid())
+ continue;
+ if (SM.isBeforeInTranslationUnit(R.getEnd(), FileLoc))
+ continue;
+
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
+ if (!TD->isFreeStanding())
+ continue;
+
+ CXCursor CurCursor = cxcursor::MakeCXCursor(D, TU);
+ findFileIdRefVisit(CurCursor, TUCursor, &data);
+ clang_visitChildren(CurCursor, findFileIdRefVisit, &data);
+ }
+ return;
+ }
+
+ clang_visitChildren(clang_getTranslationUnitCursor(TU),
+ findFileIdRefVisit, &data);
+}
+
+
+//===----------------------------------------------------------------------===//
+// libclang public APIs.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+void clang_findReferencesInFile(CXCursor cursor, CXFile file,
+ CXCursorAndRangeVisitor visitor) {
+ bool Logging = ::getenv("LIBCLANG_LOGGING");
+
+ if (clang_Cursor_isNull(cursor)) {
+ if (Logging)
+ llvm::errs() << "clang_findReferencesInFile: Null cursor\n";
+ return;
+ }
+ if (!file) {
+ if (Logging)
+ llvm::errs() << "clang_findReferencesInFile: Null file\n";
+ return;
+ }
+ if (!visitor.visit) {
+ if (Logging)
+ llvm::errs() << "clang_findReferencesInFile: Null visitor\n";
+ return;
+ }
+
+ // We are interested in semantics of identifiers so for C++ constructor exprs
+ // prefer type references, e.g.:
+ //
+ // return MyStruct();
+ //
+ // for 'MyStruct' we'll have a cursor pointing at the constructor decl but
+ // we are actually interested in the type declaration.
+ cursor = cxcursor::getTypeRefCursor(cursor);
+
+ CXCursor refCursor = clang_getCursorReferenced(cursor);
+
+ if (!clang_isDeclaration(refCursor.kind)) {
+ if (Logging)
+ llvm::errs() << "clang_findReferencesInFile: cursor is not referencing a "
+ "declaration\n";
+ return;
+ }
+
+ ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ findIdRefsInFile(cxcursor::getCursorTU(cursor),
+ refCursor,
+ static_cast<const FileEntry *>(file),
+ visitor);
+}
+
+static enum CXVisitorResult _visitCursorAndRange(void *context,
+ CXCursor cursor,
+ CXSourceRange range) {
+ CXCursorAndRangeVisitorBlock block = (CXCursorAndRangeVisitorBlock)context;
+ return INVOKE_BLOCK2(block, cursor, range);
+}
+
+void clang_findReferencesInFileWithBlock(CXCursor cursor,
+ CXFile file,
+ CXCursorAndRangeVisitorBlock block) {
+ CXCursorAndRangeVisitor visitor = { block,
+ block ? _visitCursorAndRange : 0 };
+ return clang_findReferencesInFile(cursor, file, visitor);
+}
+
+} // end: extern "C"
+
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index f45389f0b9..f754e980b9 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -21,6 +21,7 @@ set(SOURCES
CIndexCXX.cpp
CIndexCodeCompletion.cpp
CIndexDiagnostic.cpp
+ CIndexHigh.cpp
CIndexInclusionStack.cpp
CIndexUSRs.cpp
CIndexer.cpp
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 3aec4a2ea9..16aea6f713 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -20,8 +20,10 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
#include "clang-c/Index.h"
#include "llvm/Support/ErrorHandling.h"
@@ -30,7 +32,7 @@ using namespace cxcursor;
CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) {
assert(K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid);
- CXCursor C = { K, { 0, 0, 0 } };
+ CXCursor C = { K, 0, { 0, 0, 0 } };
return C;
}
@@ -51,21 +53,41 @@ static CXCursorKind GetCursorKind(const Attr *A) {
CXCursor cxcursor::MakeCXCursor(const Attr *A, Decl *Parent,
CXTranslationUnit TU) {
assert(A && Parent && TU && "Invalid arguments!");
- CXCursor C = { GetCursorKind(A), { Parent, (void*)A, TU } };
+ CXCursor C = { GetCursorKind(A), 0, { Parent, (void*)A, TU } };
return C;
}
CXCursor cxcursor::MakeCXCursor(Decl *D, CXTranslationUnit TU,
+ SourceRange RegionOfInterest,
bool FirstInDeclGroup) {
assert(D && TU && "Invalid arguments!");
- CXCursor C = { getCursorKindForDecl(D),
- { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU }
- };
+
+ CXCursorKind K = getCursorKindForDecl(D);
+
+ if (K == CXCursor_ObjCClassMethodDecl ||
+ K == CXCursor_ObjCInstanceMethodDecl) {
+ int SelectorIdIndex = -1;
+ // Check if cursor points to a selector id.
+ if (RegionOfInterest.isValid() &&
+ RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) {
+ SmallVector<SourceLocation, 16> SelLocs;
+ cast<ObjCMethodDecl>(D)->getSelectorLocs(SelLocs);
+ SmallVector<SourceLocation, 16>::iterator
+ I=std::find(SelLocs.begin(), SelLocs.end(),RegionOfInterest.getBegin());
+ if (I != SelLocs.end())
+ SelectorIdIndex = I - SelLocs.begin();
+ }
+ CXCursor C = { K, SelectorIdIndex,
+ { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU }};
+ return C;
+ }
+
+ CXCursor C = { K, 0, { D, (void*)(intptr_t) (FirstInDeclGroup ? 1 : 0), TU }};
return C;
}
-CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
- CXTranslationUnit TU) {
+CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
+ SourceRange RegionOfInterest) {
assert(S && TU && "Invalid arguments!");
CXCursorKind K = CXCursor_NotImplemented;
@@ -408,10 +430,22 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::ObjCMessageExprClass:
K = CXCursor_ObjCMessageExpr;
- break;
+ int SelectorIdIndex = -1;
+ // Check if cursor points to a selector id.
+ if (RegionOfInterest.isValid() &&
+ RegionOfInterest.getBegin() == RegionOfInterest.getEnd()) {
+ SmallVector<SourceLocation, 16> SelLocs;
+ cast<ObjCMessageExpr>(S)->getSelectorLocs(SelLocs);
+ SmallVector<SourceLocation, 16>::iterator
+ I=std::find(SelLocs.begin(), SelLocs.end(),RegionOfInterest.getBegin());
+ if (I != SelLocs.end())
+ SelectorIdIndex = I - SelLocs.begin();
+ }
+ CXCursor C = { K, 0, { Parent, S, TU } };
+ return getSelectorIdentifierCursor(SelectorIdIndex, C);
}
- CXCursor C = { K, { Parent, S, TU } };
+ CXCursor C = { K, 0, { Parent, S, TU } };
return C;
}
@@ -420,7 +454,7 @@ CXCursor cxcursor::MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super,
CXTranslationUnit TU) {
assert(Super && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCSuperClassRef, { Super, RawLoc, TU } };
+ CXCursor C = { CXCursor_ObjCSuperClassRef, 0, { Super, RawLoc, TU } };
return C;
}
@@ -437,7 +471,7 @@ CXCursor cxcursor::MakeCursorObjCProtocolRef(ObjCProtocolDecl *Super,
CXTranslationUnit TU) {
assert(Super && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCProtocolRef, { Super, RawLoc, TU } };
+ CXCursor C = { CXCursor_ObjCProtocolRef, 0, { Super, RawLoc, TU } };
return C;
}
@@ -457,7 +491,7 @@ CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class,
return MakeCXCursorInvalid(CXCursor_InvalidCode);
assert(TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCClassRef, { Class, RawLoc, TU } };
+ CXCursor C = { CXCursor_ObjCClassRef, 0, { Class, RawLoc, TU } };
return C;
}
@@ -473,7 +507,7 @@ CXCursor cxcursor::MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc,
CXTranslationUnit TU) {
assert(Type && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_TypeRef, { Type, RawLoc, TU } };
+ CXCursor C = { CXCursor_TypeRef, 0, { Type, RawLoc, TU } };
return C;
}
@@ -490,7 +524,7 @@ CXCursor cxcursor::MakeCursorTemplateRef(TemplateDecl *Template,
CXTranslationUnit TU) {
assert(Template && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_TemplateRef, { Template, RawLoc, TU } };
+ CXCursor C = { CXCursor_TemplateRef, 0, { Template, RawLoc, TU } };
return C;
}
@@ -508,7 +542,7 @@ CXCursor cxcursor::MakeCursorNamespaceRef(NamedDecl *NS, SourceLocation Loc,
assert(NS && (isa<NamespaceDecl>(NS) || isa<NamespaceAliasDecl>(NS)) && TU &&
"Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_NamespaceRef, { NS, RawLoc, TU } };
+ CXCursor C = { CXCursor_NamespaceRef, 0, { NS, RawLoc, TU } };
return C;
}
@@ -525,7 +559,7 @@ CXCursor cxcursor::MakeCursorMemberRef(FieldDecl *Field, SourceLocation Loc,
assert(Field && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_MemberRef, { Field, RawLoc, TU } };
+ CXCursor C = { CXCursor_MemberRef, 0, { Field, RawLoc, TU } };
return C;
}
@@ -539,7 +573,7 @@ cxcursor::getCursorMemberRef(CXCursor C) {
CXCursor cxcursor::MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B,
CXTranslationUnit TU){
- CXCursor C = { CXCursor_CXXBaseSpecifier, { B, 0, TU } };
+ CXCursor C = { CXCursor_CXXBaseSpecifier, 0, { B, 0, TU } };
return C;
}
@@ -550,7 +584,7 @@ CXXBaseSpecifier *cxcursor::getCursorCXXBaseSpecifier(CXCursor C) {
CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range,
CXTranslationUnit TU) {
- CXCursor C = { CXCursor_PreprocessingDirective,
+ CXCursor C = { CXCursor_PreprocessingDirective, 0,
{ reinterpret_cast<void *>(Range.getBegin().getRawEncoding()),
reinterpret_cast<void *>(Range.getEnd().getRawEncoding()),
TU }
@@ -570,7 +604,7 @@ SourceRange cxcursor::getCursorPreprocessingDirective(CXCursor C) {
CXCursor cxcursor::MakeMacroDefinitionCursor(MacroDefinition *MI,
CXTranslationUnit TU) {
- CXCursor C = { CXCursor_MacroDefinition, { MI, 0, TU } };
+ CXCursor C = { CXCursor_MacroDefinition, 0, { MI, 0, TU } };
return C;
}
@@ -581,7 +615,7 @@ MacroDefinition *cxcursor::getCursorMacroDefinition(CXCursor C) {
CXCursor cxcursor::MakeMacroExpansionCursor(MacroExpansion *MI,
CXTranslationUnit TU) {
- CXCursor C = { CXCursor_MacroExpansion, { MI, 0, TU } };
+ CXCursor C = { CXCursor_MacroExpansion, 0, { MI, 0, TU } };
return C;
}
@@ -592,7 +626,7 @@ MacroExpansion *cxcursor::getCursorMacroExpansion(CXCursor C) {
CXCursor cxcursor::MakeInclusionDirectiveCursor(InclusionDirective *ID,
CXTranslationUnit TU) {
- CXCursor C = { CXCursor_InclusionDirective, { ID, 0, TU } };
+ CXCursor C = { CXCursor_InclusionDirective, 0, { ID, 0, TU } };
return C;
}
@@ -606,7 +640,7 @@ CXCursor cxcursor::MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc,
assert(Label && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_LabelRef, { Label, RawLoc, TU } };
+ CXCursor C = { CXCursor_LabelRef, 0, { Label, RawLoc, TU } };
return C;
}
@@ -624,7 +658,7 @@ CXCursor cxcursor::MakeCursorOverloadedDeclRef(OverloadExpr *E,
OverloadedDeclRefStorage Storage(E);
void *RawLoc = reinterpret_cast<void *>(E->getNameLoc().getRawEncoding());
CXCursor C = {
- CXCursor_OverloadedDeclRef,
+ CXCursor_OverloadedDeclRef, 0,
{ Storage.getOpaqueValue(), RawLoc, TU }
};
return C;
@@ -637,7 +671,7 @@ CXCursor cxcursor::MakeCursorOverloadedDeclRef(Decl *D,
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
OverloadedDeclRefStorage Storage(D);
CXCursor C = {
- CXCursor_OverloadedDeclRef,
+ CXCursor_OverloadedDeclRef, 0,
{ Storage.getOpaqueValue(), RawLoc, TU }
};
return C;
@@ -650,7 +684,7 @@ CXCursor cxcursor::MakeCursorOverloadedDeclRef(TemplateName Name,
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
OverloadedDeclRefStorage Storage(Name.getAsOverloadedTemplate());
CXCursor C = {
- CXCursor_OverloadedDeclRef,
+ CXCursor_OverloadedDeclRef, 0,
{ Storage.getOpaqueValue(), RawLoc, TU }
};
return C;
@@ -788,6 +822,87 @@ void cxcursor::getOverriddenCursors(CXCursor cursor,
CollectOverriddenMethods(TU, Method->getDeclContext(), Method, overridden);
}
+std::pair<int, SourceLocation>
+cxcursor::getSelectorIdentifierIndexAndLoc(CXCursor cursor) {
+ if (cursor.kind == CXCursor_ObjCMessageExpr) {
+ if (cursor.xdata != -1)
+ return std::make_pair(cursor.xdata,
+ cast<ObjCMessageExpr>(getCursorExpr(cursor))
+ ->getSelectorLoc(cursor.xdata));
+ } else if (cursor.kind == CXCursor_ObjCClassMethodDecl ||
+ cursor.kind == CXCursor_ObjCInstanceMethodDecl) {
+ if (cursor.xdata != -1)
+ return std::make_pair(cursor.xdata,
+ cast<ObjCMethodDecl>(getCursorDecl(cursor))
+ ->getSelectorLoc(cursor.xdata));
+ }
+
+ return std::make_pair(-1, SourceLocation());
+}
+
+CXCursor cxcursor::getSelectorIdentifierCursor(int SelIdx, CXCursor cursor) {
+ CXCursor newCursor = cursor;
+
+ if (cursor.kind == CXCursor_ObjCMessageExpr) {
+ if (SelIdx == -1 ||
+ unsigned(SelIdx) >= cast<ObjCMessageExpr>(getCursorExpr(cursor))
+ ->getNumSelectorLocs())
+ newCursor.xdata = -1;
+ else
+ newCursor.xdata = SelIdx;
+ } else if (cursor.kind == CXCursor_ObjCClassMethodDecl ||
+ cursor.kind == CXCursor_ObjCInstanceMethodDecl) {
+ if (SelIdx == -1 ||
+ unsigned(SelIdx) >= cast<ObjCMethodDecl>(getCursorDecl(cursor))
+ ->getNumSelectorLocs())
+ newCursor.xdata = -1;
+ else
+ newCursor.xdata = SelIdx;
+ }
+
+ return newCursor;
+}
+
+CXCursor cxcursor::getTypeRefCursor(CXCursor cursor) {
+ if (cursor.kind != CXCursor_CallExpr)
+ return cursor;
+
+ if (cursor.xdata == 0)
+ return cursor;
+
+ Expr *E = getCursorExpr(cursor);
+ TypeSourceInfo *Type = 0;
+ if (CXXUnresolvedConstructExpr *
+ UnCtor = dyn_cast<CXXUnresolvedConstructExpr>(E)) {
+ Type = UnCtor->getTypeSourceInfo();
+ } else if (CXXTemporaryObjectExpr *Tmp = dyn_cast<CXXTemporaryObjectExpr>(E)){
+ Type = Tmp->getTypeSourceInfo();
+ }
+
+ if (!Type)
+ return cursor;
+
+ CXTranslationUnit TU = getCursorTU(cursor);
+ QualType Ty = Type->getType();
+ TypeLoc TL = Type->getTypeLoc();
+ SourceLocation Loc = TL.getBeginLoc();
+
+ if (const ElaboratedType *ElabT = Ty->getAs<ElaboratedType>()) {
+ Ty = ElabT->getNamedType();
+ ElaboratedTypeLoc ElabTL = cast<ElaboratedTypeLoc>(TL);
+ Loc = ElabTL.getNamedTypeLoc().getBeginLoc();
+ }
+
+ if (const TypedefType *Typedef = Ty->getAs<TypedefType>())
+ return MakeCursorTypeRef(Typedef->getDecl(), Loc, TU);
+ if (const TagType *Tag = Ty->getAs<TagType>())
+ return MakeCursorTypeRef(Tag->getDecl(), Loc, TU);
+ if (const TemplateTypeParmType *TemplP = Ty->getAs<TemplateTypeParmType>())
+ return MakeCursorTypeRef(TemplP->getDecl(), Loc, TU);
+
+ return cursor;
+}
+
bool cxcursor::operator==(CXCursor X, CXCursor Y) {
return X.kind == Y.kind && X.data[0] == Y.data[0] && X.data[1] == Y.data[1] &&
X.data[2] == Y.data[2];
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index 5d9d5683c4..e3ca2680f1 100644
--- a/tools/libclang/CXCursor.h
+++ b/tools/libclang/CXCursor.h
@@ -49,9 +49,11 @@ CXCursor getCursor(CXTranslationUnit, SourceLocation);
CXCursor MakeCXCursor(const clang::Attr *A, clang::Decl *Parent,
CXTranslationUnit TU);
CXCursor MakeCXCursor(clang::Decl *D, CXTranslationUnit TU,
+ SourceRange RegionOfInterest = SourceRange(),
bool FirstInDeclGroup = true);
CXCursor MakeCXCursor(clang::Stmt *S, clang::Decl *Parent,
- CXTranslationUnit TU);
+ CXTranslationUnit TU,
+ SourceRange RegionOfInterest = SourceRange());
CXCursor MakeCXCursorInvalid(CXCursorKind K);
/// \brief Create an Objective-C superclass reference at the given location.
@@ -195,6 +197,27 @@ CXTranslationUnit getCursorTU(CXCursor Cursor);
void getOverriddenCursors(CXCursor cursor,
SmallVectorImpl<CXCursor> &overridden);
+/// \brief Returns a index/location pair for a selector identifier if the cursor
+/// points to one.
+std::pair<int, SourceLocation> getSelectorIdentifierIndexAndLoc(CXCursor);
+static inline int getSelectorIdentifierIndex(CXCursor cursor) {
+ return getSelectorIdentifierIndexAndLoc(cursor).first;
+}
+static inline SourceLocation getSelectorIdentifierLoc(CXCursor cursor) {
+ return getSelectorIdentifierIndexAndLoc(cursor).second;
+}
+
+CXCursor getSelectorIdentifierCursor(int SelIdx, CXCursor cursor);
+
+static inline CXCursor getTypeRefedCallExprCursor(CXCursor cursor) {
+ CXCursor newCursor = cursor;
+ if (cursor.kind == CXCursor_CallExpr)
+ newCursor.xdata = 1;
+ return newCursor;
+}
+
+CXCursor getTypeRefCursor(CXCursor cursor);
+
bool operator==(CXCursor X, CXCursor Y);
inline bool operator!=(CXCursor X, CXCursor Y) {
diff --git a/tools/libclang/Index_Internal.h b/tools/libclang/Index_Internal.h
new file mode 100644
index 0000000000..df54d7c879
--- /dev/null
+++ b/tools/libclang/Index_Internal.h
@@ -0,0 +1,43 @@
+//===- CXString.h - Routines for manipulating CXStrings -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines routines for manipulating CXStrings.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBCLANG_INDEX_INTERNAL_H
+#define LLVM_LIBCLANG_INDEX_INTERNAL_H
+
+#include "clang-c/Index.h"
+
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+#if __has_feature(blocks)
+
+#define INVOKE_BLOCK2(block, arg1, arg2) block(arg1, arg2)
+
+#else
+// If we are compiled with a compiler that doesn't have native blocks support,
+// define and call the block manually.
+
+#define INVOKE_BLOCK2(block, arg1, arg2) block->invoke(block, arg1, arg2)
+
+typedef struct _CXCursorAndRangeVisitorBlock {
+ void *isa;
+ int flags;
+ int reserved;
+ enum CXVisitorResult (*invoke)(_CXCursorAndRangeVisitorBlock *,
+ CXCursor, CXSourceRange);
+} *CXCursorAndRangeVisitorBlock;
+
+#endif // !__has_feature(blocks)
+
+#endif
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 89d41318d9..68c0ad5c27 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -42,6 +42,8 @@ clang_equalLocations
clang_equalRanges
clang_equalTypes
clang_executeOnThread
+clang_findReferencesInFile
+clang_findReferencesInFileWithBlock
clang_formatDiagnostic
clang_getArrayElementType
clang_getArraySize