[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
This commit is contained in:
Argyrios Kyrtzidis 2011-10-06 07:00:54 +00:00
parent b11be041e4
commit aed123ec3c
12 changed files with 965 additions and 62 deletions

View File

@ -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
/**
* @}
*/

57
test/Index/file-refs.c Normal file
View File

@ -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

104
test/Index/file-refs.cpp Normal file
View File

@ -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

87
test/Index/file-refs.m Normal file
View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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"

View File

@ -21,6 +21,7 @@ set(SOURCES
CIndexCXX.cpp
CIndexCodeCompletion.cpp
CIndexDiagnostic.cpp
CIndexHigh.cpp
CIndexInclusionStack.cpp
CIndexUSRs.cpp
CIndexer.cpp

View File

@ -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];

View File

@ -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) {

View File

@ -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

View File

@ -42,6 +42,8 @@ clang_equalLocations
clang_equalRanges
clang_equalTypes
clang_executeOnThread
clang_findReferencesInFile
clang_findReferencesInFileWithBlock
clang_formatDiagnostic
clang_getArrayElementType
clang_getArraySize