From aed123ec3cc37e457fe20a6158fdadf8849ad916 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Thu, 6 Oct 2011 07:00:54 +0000 Subject: [PATCH] [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 --- include/clang-c/Index.h | 48 +++++ test/Index/file-refs.c | 57 ++++++ test/Index/file-refs.cpp | 104 ++++++++++ test/Index/file-refs.m | 87 +++++++++ tools/c-index-test/c-index-test.c | 117 ++++++++++- tools/libclang/CIndex.cpp | 63 +++--- tools/libclang/CIndexHigh.cpp | 315 ++++++++++++++++++++++++++++++ tools/libclang/CMakeLists.txt | 1 + tools/libclang/CXCursor.cpp | 165 +++++++++++++--- tools/libclang/CXCursor.h | 25 ++- tools/libclang/Index_Internal.h | 43 ++++ tools/libclang/libclang.exports | 2 + 12 files changed, 965 insertions(+), 62 deletions(-) create mode 100644 test/Index/file-refs.c create mode 100644 test/Index/file-refs.cpp create mode 100644 test/Index/file-refs.m create mode 100644 tools/libclang/CIndexHigh.cpp create mode 100644 tools/libclang/Index_Internal.h 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; @@ -3775,6 +3776,53 @@ CINDEX_LINKAGE void clang_remap_getFilenames(CXRemapping, unsigned index, */ 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 +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 +@end + +@interface Base +@end + +@interface Sub : Base +-(void)protMeth; +@end + +@implementation Sub +-(void)protMeth {} +@end + +void test2(Sub *s, id 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= \n" " c-index-test -code-completion-timing= \n" " c-index-test -cursor-at= \n" + " c-index-test -file-refs-at= \n" " c-index-test -test-file-scan " "[FileCheck prefix]\n" " c-index-test -test-load-tu " @@ -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 &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::iterator I = DeclsInContainer.begin(), E = DeclsInContainer.end(); I != E; ++I) { - CXCursor Cursor = MakeCXCursor(*I, TU); + CXCursor Cursor = MakeCXCursor(*I, TU, RegionOfInterest); const llvm::Optional &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(&LI)->isFirst()))) + if (Visit(MakeCXCursor(D, TU, RegionOfInterest, + cast(&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(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(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 &Methods) { + if (!isa(D) && !isa(D)) + return; + + SmallVector Overridden; + cxcursor::getOverriddenCursors(cxcursor::MakeCXCursor(D, TU), Overridden); + + if (Overridden.empty()) { + Methods.push_back(D->getCanonicalDecl()); + return; + } + + for (SmallVector::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 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(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(D)) + return getCanonical(ImplD->getClassInterface()); + if (CXXConstructorDecl *CXXCtorD = dyn_cast(D)) + return getCanonical(CXXCtorD->getParent()); + + return D; + } + + bool isHit(Decl *D) const { + D = getCanonical(D); + if (D == Dcl) + return true; + + if (isa(D) || isa(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 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(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(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(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(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 SelLocs; + cast(D)->getSelectorLocs(SelLocs); + SmallVector::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 SelLocs; + cast(S)->getSelectorLocs(SelLocs); + SmallVector::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(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(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(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(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(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(NS) || isa(NS)) && TU && "Invalid arguments!"); void *RawLoc = reinterpret_cast(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(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(Range.getBegin().getRawEncoding()), reinterpret_cast(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(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(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(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(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 +cxcursor::getSelectorIdentifierIndexAndLoc(CXCursor cursor) { + if (cursor.kind == CXCursor_ObjCMessageExpr) { + if (cursor.xdata != -1) + return std::make_pair(cursor.xdata, + cast(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(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(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(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(E)) { + Type = UnCtor->getTypeSourceInfo(); + } else if (CXXTemporaryObjectExpr *Tmp = dyn_cast(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()) { + Ty = ElabT->getNamedType(); + ElaboratedTypeLoc ElabTL = cast(TL); + Loc = ElabTL.getNamedTypeLoc().getBeginLoc(); + } + + if (const TypedefType *Typedef = Ty->getAs()) + return MakeCursorTypeRef(Typedef->getDecl(), Loc, TU); + if (const TagType *Tag = Ty->getAs()) + return MakeCursorTypeRef(Tag->getDecl(), Loc, TU); + if (const TemplateTypeParmType *TemplP = Ty->getAs()) + 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 &overridden); +/// \brief Returns a index/location pair for a selector identifier if the cursor +/// points to one. +std::pair 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 -- 2.40.0