From: Argyrios Kyrtzidis Date: Mon, 17 Oct 2011 19:48:19 +0000 (+0000) Subject: [libclang] Introduce a new high level API for indexing clients that assumes X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4e7064fa7e344e8f87a5b8457e96dfdd252c4a9e;p=clang [libclang] Introduce a new high level API for indexing clients that assumes more of the work involved in indexing a translation unit and simplifies client implementations. Only C/ObjC for now, C++ (and comments) to come. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142233 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 1320145a89..d45830ef91 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -3855,6 +3855,329 @@ void clang_findReferencesInFileWithBlock(CXCursor, CXFile, # endif #endif +typedef void *CXIdxFile; +typedef void *CXIdxEntity; +typedef void *CXIdxContainer; +typedef void *CXIdxMacro; +typedef void *CXIdxASTFile; + +typedef struct { + void *ptr_data[2]; + unsigned int_data; +} CXIdxLoc; + +typedef struct { + CXIdxLoc hashLoc; + const char *filename; + CXIdxFile file; + int isImport; + int isAngled; +} CXIdxIncludedFileInfo; + +typedef struct { + CXFile file; + CXIdxLoc loc; + int isModule; +} CXIdxImportedASTFileInfo; + +typedef struct { + CXIdxLoc loc; + const char *name; +} CXIdxMacroInfo; + +typedef struct { + CXIdxMacroInfo *macroInfo; + CXIdxLoc defBegin; + unsigned defLength; +} CXIdxMacroDefinedInfo; + +typedef struct { + CXIdxLoc loc; + const char *name; + CXIdxMacro macro; +} CXIdxMacroUndefinedInfo; + +typedef struct { + CXIdxLoc loc; + const char *name; + CXIdxMacro macro; +} CXIdxMacroExpandedInfo; + +typedef struct { + const char *name; + const char *USR; +} CXIdxEntityInfo; + +typedef struct { + CXCursor cursor; + CXIdxLoc loc; + CXIdxContainer container; +} CXIdxIndexedDeclInfo; + +typedef struct { + CXIdxEntityInfo *entityInfo; + CXCursor cursor; + CXIdxLoc loc; + CXIdxASTFile ASTFile; +} CXIdxImportedEntityInfo; + +typedef struct { + CXIdxMacroInfo *macroInfo; + CXIdxASTFile ASTFile; +} CXIdxImportedMacroInfo; + +typedef struct { + CXIdxEntityInfo *entityInfo; + CXIdxIndexedDeclInfo *declInfo; +} CXIdxIndexedEntityInfo; + +typedef struct { + CXIdxIndexedDeclInfo *declInfo; + CXIdxEntity entity; +} CXIdxIndexedRedeclInfo; + +typedef struct { + CXCursor cursor; + CXIdxLoc loc; + CXIdxEntity entity; +} CXIdxContainerInfo; + +typedef struct { + CXIdxIndexedEntityInfo *indexedEntityInfo; +} CXIdxTypedefInfo; + +typedef struct { + CXIdxIndexedEntityInfo *indexedEntityInfo; + int isDefinition; +} CXIdxFunctionInfo; + +typedef struct { + CXIdxIndexedRedeclInfo *indexedRedeclInfo; + int isDefinition; +} CXIdxFunctionRedeclInfo; + +typedef struct { + CXIdxIndexedEntityInfo *indexedEntityInfo; + int isDefinition; +} CXIdxVariableInfo; + +typedef struct { + CXIdxIndexedRedeclInfo *indexedRedeclInfo; + int isDefinition; +} CXIdxVariableRedeclInfo; + +typedef struct { + CXIdxIndexedEntityInfo *indexedEntityInfo; + int isDefinition; + int isAnonymous; +} CXIdxTagTypeInfo; + +typedef struct { + CXIdxIndexedRedeclInfo *indexedRedeclInfo; + int isDefinition; +} CXIdxTagTypeRedeclInfo; + +typedef struct { + CXIdxContainerInfo *containerInfo; +} CXIdxTagTypeDefinitionInfo; + +typedef struct { + CXIdxIndexedEntityInfo *indexedEntityInfo; +} CXIdxFieldInfo; + +typedef struct { + CXIdxIndexedEntityInfo *indexedEntityInfo; +} CXIdxEnumeratorInfo; + +typedef struct { + CXIdxIndexedEntityInfo *indexedEntityInfo; + int isForwardRef; +} CXIdxObjCClassInfo; + +typedef struct { + CXIdxIndexedEntityInfo *indexedEntityInfo; + int isForwardRef; +} CXIdxObjCProtocolInfo; + +typedef struct { + CXIdxIndexedEntityInfo *indexedEntityInfo; + CXIdxEntity objcClass; +} CXIdxObjCCategoryInfo; + +typedef struct { + CXIdxIndexedEntityInfo *indexedEntityInfo; + int isDefinition; +} CXIdxObjCMethodInfo; + +typedef struct { + CXIdxIndexedEntityInfo *indexedEntityInfo; +} CXIdxObjCPropertyInfo; + +typedef struct { + CXIdxIndexedRedeclInfo *indexedRedeclInfo; + int isDefinition; +} CXIdxObjCMethodRedeclInfo; + +typedef struct { + CXIdxContainerInfo *containerInfo; + CXIdxLoc bodyBegin; +} CXIdxStmtBodyInfo; + +typedef struct { + CXIdxContainerInfo *containerInfo; +} CXIdxObjCContainerInfo; + +typedef struct { + CXIdxEntity objcClass; + CXIdxLoc loc; +} CXIdxObjCBaseClassInfo; + +typedef struct { + CXIdxEntity protocol; + CXIdxLoc loc; +} CXIdxObjCProtocolRefInfo; + +typedef struct { + CXCursor cursor; + CXIdxEntity objcClass; + CXIdxContainer container; + CXIdxObjCBaseClassInfo *baseInfo; + CXIdxObjCProtocolRefInfo **protocols; + unsigned numProtocols; +} CXIdxObjCClassDefineInfo; + +typedef struct { + CXIdxContainer container; + CXIdxLoc endLoc; +} CXIdxEndContainerInfo; + +typedef struct { + CXCursor cursor; + CXIdxLoc loc; + CXIdxEntity referencedEntity; + CXIdxEntity parentEntity; + CXIdxContainer container; +} CXIdxEntityRefInfo; + +typedef struct { + void (*diagnostic)(CXClientData client_data, + CXDiagnostic, void *reserved); + + CXIdxFile (*recordFile)(CXClientData client_data, + CXFile file, void *reserved); + + void (*ppIncludedFile)(CXClientData client_data, + CXIdxIncludedFileInfo *); + + CXIdxMacro (*ppMacroDefined)(CXClientData client_data, + CXIdxMacroDefinedInfo *); + + void (*ppMacroUndefined)(CXClientData client_data, + CXIdxMacroUndefinedInfo *); + + void (*ppMacroExpanded)(CXClientData client_data, + CXIdxMacroExpandedInfo *); + + CXIdxASTFile (*importedASTFile)(CXClientData client_data, + CXIdxImportedASTFileInfo *); + + CXIdxEntity (*importedEntity)(CXClientData client_data, + CXIdxImportedEntityInfo *); + + CXIdxEntity (*importedMacro)(CXClientData client_data, + CXIdxImportedMacroInfo *); + + CXIdxContainer (*startedTranslationUnit)(CXClientData client_data, + void *reserved); + + CXIdxEntity (*indexTypedef)(CXClientData client_data, + CXIdxTypedefInfo *); + + CXIdxEntity (*indexFunction)(CXClientData client_data, + CXIdxFunctionInfo *); + + void (*indexFunctionRedeclaration)(CXClientData client_data, + CXIdxFunctionRedeclInfo *); + + CXIdxEntity (*indexVariable)(CXClientData client_data, + CXIdxVariableInfo *); + + void (*indexVariableRedeclaration)(CXClientData client_data, + CXIdxVariableRedeclInfo *); + + CXIdxEntity (*indexTagType)(CXClientData client_data, + CXIdxTagTypeInfo *); + + void (*indexTagTypeRedeclaration)(CXClientData client_data, + CXIdxTagTypeRedeclInfo *); + + CXIdxEntity (*indexField)(CXClientData client_data, + CXIdxFieldInfo *); + + CXIdxEntity (*indexEnumerator)(CXClientData client_data, + CXIdxEnumeratorInfo *); + + CXIdxContainer (*startedTagTypeDefinition)(CXClientData client_data, + CXIdxTagTypeDefinitionInfo *); + + CXIdxEntity (*indexObjCClass)(CXClientData client_data, + CXIdxObjCClassInfo *); + + CXIdxEntity (*indexObjCProtocol)(CXClientData client_data, + CXIdxObjCProtocolInfo *); + + CXIdxEntity (*indexObjCCategory)(CXClientData client_data, + CXIdxObjCCategoryInfo *); + + CXIdxEntity (*indexObjCMethod)(CXClientData client_data, + CXIdxObjCMethodInfo *); + + CXIdxEntity (*indexObjCProperty)(CXClientData client_data, + CXIdxObjCPropertyInfo *); + + void (*indexObjCMethodRedeclaration)(CXClientData client_data, + CXIdxObjCMethodRedeclInfo *); + + CXIdxContainer (*startedStatementBody)(CXClientData client_data, + CXIdxStmtBodyInfo *); + + CXIdxContainer (*startedObjCContainer)(CXClientData client_data, + CXIdxObjCContainerInfo *); + + void (*defineObjCClass)(CXClientData client_data, + CXIdxObjCClassDefineInfo *); + + void (*endedContainer)(CXClientData client_data, + CXIdxEndContainerInfo *); + + void (*indexEntityReference)(CXClientData client_data, + CXIdxEntityRefInfo *); + +} IndexerCallbacks; + +CINDEX_LINKAGE int clang_indexTranslationUnit(CXIndex CIdx, + CXClientData client_data, + IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, + unsigned index_options, + const char *source_filename, + const char * const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + CXTranslationUnit *out_TU, + unsigned TU_options); + +CINDEX_LINKAGE void clang_indexLoc_getFileLocation(CXIdxLoc loc, + CXIdxFile *indexFile, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset); + +CINDEX_LINKAGE +CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc loc); + /** * @} */ diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 2a3584b892..97c78dbeb0 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -1480,6 +1480,504 @@ static int find_file_refs_at(int argc, const char **argv) { return 0; } +typedef struct { + const char *check_prefix; + int first_check_printed; +} IndexData; + +static void printCheck(IndexData *data) { + if (data->check_prefix) { + if (data->first_check_printed) { + printf("// %s-NEXT: ", data->check_prefix); + } else { + printf("// %s : ", data->check_prefix); + data->first_check_printed = 1; + } + } +} + +static void printCXIndexFile(CXIdxFile file) { + CXString filename = clang_getFileName((CXFile)file); + printf("%s", clang_getCString(filename)); + clang_disposeString(filename); +} + +static void printCXIndexLoc(CXIdxLoc loc) { + CXString filename; + const char *cname, *end; + CXIdxFile file; + unsigned line, column; + + clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0); + if (line == 0) { + printf(""); + return; + } + filename = clang_getFileName((CXFile)file); + cname = clang_getCString(filename); + end = cname + strlen(cname); + int isHeader = (end[-2] == '.' && end[-1] == 'h'); + + if (isHeader) { + printCXIndexFile(file); + printf(":"); + } + printf("%d:%d", line, column); +} + +static CXIdxEntity makeCXIndexEntity(CXIdxIndexedEntityInfo *info) { + const char *name; + CXIdxLoc loc; + char *newStr; + CXIdxFile file; + unsigned line, column; + + name = info->entityInfo->name; + if (!name) + name = ""; + + loc = info->declInfo->loc; + clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0); + // FIXME: free these. + newStr = (char *)malloc(strlen(name) + 10); + sprintf(newStr, "%s:%d:%d", name, line, column); + return (CXIdxEntity)newStr; +} + +static CXIdxContainer makeCXIndexContainer(CXIdxEntity entity) { + return (CXIdxContainer)entity; +} + +static void printCXIndexEntity(CXIdxEntity entity) { + printf("{%s}", (const char *)entity); +} + +static void printCXIndexContainer(CXIdxContainer container) { + printf("[%s]", (const char *)container); +} + +static void printIndexedDeclInfo(CXIdxIndexedDeclInfo *info) { + printf(" | cursor: "); + PrintCursor(info->cursor); + printf(" | loc: "); + printCXIndexLoc(info->loc); + printf(" | container: "); + printCXIndexContainer(info->container); +} + +static void printIndexedEntityInfo(const char *cb, + CXClientData client_data, + CXIdxIndexedEntityInfo *info) { + const char *name; + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + name = info->entityInfo->name; + if (!name) + name = ""; + + printf("%s: %s", cb, info->entityInfo->name); + printIndexedDeclInfo(info->declInfo); + printf(" | USR: %s", info->entityInfo->USR); +} + +static void printIndexedRedeclInfo(const char *cb, + CXClientData client_data, + CXIdxIndexedRedeclInfo *info) { + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + printf("%s redeclaration: ", cb); + printCXIndexEntity(info->entity); + printIndexedDeclInfo(info->declInfo); +} + +static void printStartedContainerInfo(const char *cb, + CXClientData client_data, + CXIdxContainerInfo *info) { + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + printf("started %s: ", cb); + printCXIndexEntity(info->entity); + printf(" | cursor: "); + PrintCursor(info->cursor); + printf(" | loc: "); + printCXIndexLoc(info->loc); +} + +static void index_diagnostic(CXClientData client_data, + CXDiagnostic diag, void *reserved) { + CXString str; + const char *cstr; + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + str = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions()); + cstr = clang_getCString(str); + printf("diagnostic: %s", cstr); + clang_disposeString(str); +} + +static CXIdxFile index_recordFile(CXClientData client_data, + CXFile file, void *reserved) { + return (CXIdxFile)file; +} + +static void index_ppIncludedFile(CXClientData client_data, + CXIdxIncludedFileInfo *info) { + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + printf("included file: "); + printCXIndexFile(info->file); + printf(" | name: \"%s\"", info->filename); + printf(" | hash loc: "); + printCXIndexLoc(info->hashLoc); + printf(" | isImport: %d | isAngled: %d\n", info->isImport, info->isAngled); +} + +static CXIdxMacro index_ppMacroDefined(CXClientData client_data, + CXIdxMacroDefinedInfo *info) { + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + printf("macro defined: %s", info->macroInfo->name); + printf(" | loc: "); + printCXIndexLoc(info->macroInfo->loc); + printf(" | defBegin: "); + printCXIndexLoc(info->defBegin); + printf(" | length: %d\n", info->defLength); + + return (CXIdxMacro)info->macroInfo->name; +} + +static void index_ppMacroUndefined(CXClientData client_data, + CXIdxMacroUndefinedInfo *info) { + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + printf("macro undefined: %s", info->name); + printf(" | loc: "); + printCXIndexLoc(info->loc); + printf("\n"); +} + +static void index_ppMacroExpanded(CXClientData client_data, + CXIdxMacroExpandedInfo *info) { + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + printf("macro expanded: %s", info->name); + printf(" | loc: "); + printCXIndexLoc(info->loc); + printf("\n"); +} + +static CXIdxEntity index_importedEntity(CXClientData client_data, + CXIdxImportedEntityInfo *info) { + IndexData *index_data; + CXIdxIndexedDeclInfo DeclInfo = { info->cursor, info->loc, 0 }; + CXIdxIndexedEntityInfo EntityInfo = { info->entityInfo, &DeclInfo }; + const char *name; + index_data = (IndexData *)client_data; + printCheck(index_data); + + name = info->entityInfo->name; + if (!name) + name = ""; + + printf("imported entity: %s", name); + printf(" | cursor: "); + PrintCursor(info->cursor); + printf(" | loc: "); + printCXIndexLoc(info->loc); + printf("\n"); + + return makeCXIndexEntity(&EntityInfo); +} + +static CXIdxContainer index_startedTranslationUnit(CXClientData client_data, + void *reserved) { + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + printf("started TU\n"); + return (CXIdxContainer)"TU"; +} + +static CXIdxEntity index_indexTypedef(CXClientData client_data, + CXIdxTypedefInfo *info) { + printIndexedEntityInfo("typedef", client_data, info->indexedEntityInfo); + printf("\n"); + + return makeCXIndexEntity(info->indexedEntityInfo); +} + +static CXIdxEntity index_indexFunction(CXClientData client_data, + CXIdxFunctionInfo *info) { + printIndexedEntityInfo("function", client_data, info->indexedEntityInfo); + printf(" | isDefinition: %d\n", info->isDefinition); + + return makeCXIndexEntity(info->indexedEntityInfo); +} + +static void index_indexFunctionRedeclaration(CXClientData client_data, + CXIdxFunctionRedeclInfo *info) { + printIndexedRedeclInfo("function", client_data, info->indexedRedeclInfo); + printf(" | isDefinition: %d\n", info->isDefinition); +} + +static CXIdxEntity index_indexVariable(CXClientData client_data, + CXIdxVariableInfo *info) { + printIndexedEntityInfo("variable", client_data, info->indexedEntityInfo); + printf(" | isDefinition: %d\n", info->isDefinition); + + return makeCXIndexEntity(info->indexedEntityInfo); +} + +static void index_indexVariableRedeclaration(CXClientData client_data, + CXIdxVariableRedeclInfo *info) { + printIndexedRedeclInfo("variable", client_data, info->indexedRedeclInfo); + printf(" | isDefinition: %d\n", info->isDefinition); +} + +static CXIdxEntity index_indexTagType(CXClientData client_data, + CXIdxTagTypeInfo *info) { + printIndexedEntityInfo("tag type", client_data, info->indexedEntityInfo); + printf(" | isDefinition: %d | anon: %d\n", + info->isDefinition, info->isAnonymous); + + return makeCXIndexEntity(info->indexedEntityInfo); +} + +static void index_indexTagTypeRedeclaration(CXClientData client_data, + CXIdxTagTypeRedeclInfo *info) { + printIndexedRedeclInfo("tag type", client_data, info->indexedRedeclInfo); + printf(" | isDefinition: %d\n", info->isDefinition); +} + +static CXIdxEntity index_indexField(CXClientData client_data, + CXIdxFieldInfo *info) { + printIndexedEntityInfo("field", client_data, info->indexedEntityInfo); + printf("\n"); + + return makeCXIndexEntity(info->indexedEntityInfo); +} + +static CXIdxEntity index_indexEnumerator(CXClientData client_data, + CXIdxEnumeratorInfo *info) { + printIndexedEntityInfo("enumerator", client_data, info->indexedEntityInfo); + printf("\n"); + + return makeCXIndexEntity(info->indexedEntityInfo); +} + +static CXIdxContainer +index_startedTagTypeDefinition(CXClientData client_data, + CXIdxTagTypeDefinitionInfo *info) { + printStartedContainerInfo("tag type definition", client_data, + info->containerInfo); + printf("\n"); + + return makeCXIndexContainer(info->containerInfo->entity); +} + +static CXIdxEntity index_indexObjCClass(CXClientData client_data, + CXIdxObjCClassInfo *info) { + printIndexedEntityInfo("ObjC class", client_data, info->indexedEntityInfo); + printf(" | forward ref: %d\n", info->isForwardRef); + + return makeCXIndexEntity(info->indexedEntityInfo); +} + +static CXIdxEntity index_indexObjCProtocol(CXClientData client_data, + CXIdxObjCProtocolInfo *info) { + printIndexedEntityInfo("ObjC protocol", client_data, + info->indexedEntityInfo); + printf(" | forward ref: %d\n", info->isForwardRef); + + return makeCXIndexEntity(info->indexedEntityInfo); +} + +static CXIdxEntity index_indexObjCCategory(CXClientData client_data, + CXIdxObjCCategoryInfo *info) { + printIndexedEntityInfo("ObjC category", client_data, + info->indexedEntityInfo); + printf(" | class: "); + printCXIndexEntity(info->objcClass); + printf("\n"); + + return makeCXIndexEntity(info->indexedEntityInfo); +} + +static CXIdxEntity index_indexObjCMethod(CXClientData client_data, + CXIdxObjCMethodInfo *info) { + printIndexedEntityInfo("ObjC Method", client_data, info->indexedEntityInfo); + printf(" | isDefinition: %d\n", info->isDefinition); + + return makeCXIndexEntity(info->indexedEntityInfo); +} + +static CXIdxEntity index_indexObjCProperty(CXClientData client_data, + CXIdxObjCPropertyInfo *info) { + printIndexedEntityInfo("ObjC property", client_data, info->indexedEntityInfo); + printf("\n"); + + return makeCXIndexEntity(info->indexedEntityInfo); +} + +static void index_indexObjCMethodRedeclaration(CXClientData client_data, + CXIdxObjCMethodRedeclInfo *info) { + printIndexedRedeclInfo("ObjC Method", client_data, info->indexedRedeclInfo); + printf(" | isDefinition: %d\n", info->isDefinition); +} + +static CXIdxContainer +index_startedStatementBody(CXClientData client_data, + CXIdxStmtBodyInfo *info) { + printStartedContainerInfo("body", client_data, info->containerInfo); + printf(" | body: "); + printCXIndexLoc(info->bodyBegin); + printf("\n"); + + return makeCXIndexContainer(info->containerInfo->entity); +} + +static CXIdxContainer +index_startedObjCContainer(CXClientData client_data, + CXIdxObjCContainerInfo *info) { + printStartedContainerInfo("ObjC container", client_data, info->containerInfo); + printf("\n"); + + return makeCXIndexContainer(info->containerInfo->entity); +} + +static void index_defineObjCClass(CXClientData client_data, + CXIdxObjCClassDefineInfo *info) { + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + printf("define objc class: "); + printCXIndexEntity(info->objcClass); + printf(" | cursor: "); + PrintCursor(info->cursor); + printf(" | container: "); + printCXIndexContainer(info->container); + + if (info->baseInfo) { + printf(" | base: "); + printCXIndexEntity(info->baseInfo->objcClass); + printf(" | base loc: "); + printCXIndexLoc(info->baseInfo->loc); + } + + printf("\n"); +} + +static void index_endedContainer(CXClientData client_data, + CXIdxEndContainerInfo *info) { + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + printf("ended container: "); + printCXIndexContainer(info->container); + printf(" | end: "); + printCXIndexLoc(info->endLoc); + printf("\n"); +} + +static void index_indexEntityReference(CXClientData client_data, + CXIdxEntityRefInfo *info) { + IndexData *index_data; + index_data = (IndexData *)client_data; + printCheck(index_data); + + printf("reference: "); + printCXIndexEntity(info->referencedEntity); + printf(" | cursor: "); + PrintCursor(info->cursor); + printf(" | loc: "); + printCXIndexLoc(info->loc); + printf(" | parent: "); + printCXIndexEntity(info->parentEntity); + printf(" | container: "); + printCXIndexContainer(info->container); + printf("\n"); +} + +static IndexerCallbacks IndexCB = { + index_diagnostic, + index_recordFile, + index_ppIncludedFile, + index_ppMacroDefined, + index_ppMacroUndefined, + index_ppMacroExpanded, + 0, //importedASTFile + index_importedEntity, + 0,//index_importedMacro, + index_startedTranslationUnit, + index_indexTypedef, + index_indexFunction, + index_indexFunctionRedeclaration, + index_indexVariable, + index_indexVariableRedeclaration, + index_indexTagType, + index_indexTagTypeRedeclaration, + index_indexField, + index_indexEnumerator, + index_startedTagTypeDefinition, + index_indexObjCClass, + index_indexObjCProtocol, + index_indexObjCCategory, + index_indexObjCMethod, + index_indexObjCProperty, + index_indexObjCMethodRedeclaration, + index_startedStatementBody, + index_startedObjCContainer, + index_defineObjCClass, + index_endedContainer, + index_indexEntityReference +}; + +static int index_file(int argc, const char **argv) { + const char *check_prefix; + CXIndex CIdx; + IndexData index_data; + + check_prefix = 0; + if (argc > 0) { + if (strstr(argv[0], "-check-prefix=") == argv[0]) { + check_prefix = argv[0] + strlen("-check-prefix="); + ++argv; + --argc; + } + } + + if (argc == 0) { + fprintf(stderr, "no compiler arguments\n"); + return -1; + } + + CIdx = clang_createIndex(0, 1); + index_data.check_prefix = check_prefix; + index_data.first_check_printed = 0; + + return clang_indexTranslationUnit(CIdx, &index_data, &IndexCB,sizeof(IndexCB), + 0, 0, argv, argc, 0, 0, 0, 0); +} + int perform_token_annotation(int argc, const char **argv) { const char *input = argv[1]; char *filename = 0; @@ -1848,6 +2346,7 @@ static void print_usage(void) { " c-index-test -code-completion-timing= \n" " c-index-test -cursor-at= \n" " c-index-test -file-refs-at= \n" + " c-index-test -index-file [-check-prefix=] \n" " c-index-test -test-file-scan " "[FileCheck prefix]\n"); fprintf(stderr, @@ -1897,6 +2396,8 @@ int cindextest_main(int argc, const char **argv) { return inspect_cursor_at(argc, argv); if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1]) return find_file_refs_at(argc, argv); + if (argc > 2 && strcmp(argv[1], "-index-file") == 0) + return index_file(argc - 2, argv + 2); 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 bb232eb567..46f8965902 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -62,6 +62,11 @@ CXTranslationUnit cxtu::MakeCXTranslationUnit(ASTUnit *TU) { return D; } +cxtu::CXTUOwner::~CXTUOwner() { + if (TU) + clang_disposeTranslationUnit(TU); +} + /// \brief The result of comparing two source ranges. enum RangeComparisonResult { /// \brief Either the ranges overlap or one of the ranges is invalid. diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index 91ceb7c78b..195463cbe2 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -790,7 +790,7 @@ static inline StringRef extractUSRSuffix(StringRef s) { return s.startswith("c:") ? s.substr(2) : ""; } -bool cxcursor::getDeclCursorUSR(Decl *D, SmallVectorImpl &Buf) { +bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl &Buf) { // Don't generate USRs for things with invalid locations. if (!D || D->getLocStart().isInvalid()) return true; @@ -820,7 +820,7 @@ bool cxcursor::getDeclCursorUSR(Decl *D, SmallVectorImpl &Buf) { { USRGenerator UG(&D->getASTContext(), &Buf); - UG->Visit(D); + UG->Visit((Decl*)D); if (UG->ignoreResults()) return true; diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index f754e980b9..00b4692ebc 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -28,6 +28,11 @@ set(SOURCES CXCursor.cpp CXString.cpp CXType.cpp + IndexBody.cpp + IndexDecl.cpp + IndexTypeSourceInfo.cpp + Indexing.cpp + IndexingContext.cpp ../../include/clang-c/Index.h ) diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index db27500143..586d9beba3 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -468,12 +468,12 @@ cxcursor::getCursorObjCSuperClassRef(CXCursor C) { reinterpret_cast(C.data[1]))); } -CXCursor cxcursor::MakeCursorObjCProtocolRef(ObjCProtocolDecl *Super, +CXCursor cxcursor::MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto, SourceLocation Loc, CXTranslationUnit TU) { - assert(Super && TU && "Invalid arguments!"); + assert(Proto && TU && "Invalid arguments!"); void *RawLoc = reinterpret_cast(Loc.getRawEncoding()); - CXCursor C = { CXCursor_ObjCProtocolRef, 0, { Super, RawLoc, TU } }; + CXCursor C = { CXCursor_ObjCProtocolRef, 0, { (void*)Proto, RawLoc, TU } }; return C; } @@ -485,7 +485,7 @@ cxcursor::getCursorObjCProtocolRef(CXCursor C) { reinterpret_cast(C.data[1]))); } -CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class, +CXCursor cxcursor::MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class, SourceLocation Loc, CXTranslationUnit TU) { // 'Class' can be null for invalid code. @@ -493,7 +493,7 @@ CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class, return MakeCXCursorInvalid(CXCursor_InvalidCode); assert(TU && "Invalid arguments!"); void *RawLoc = reinterpret_cast(Loc.getRawEncoding()); - CXCursor C = { CXCursor_ObjCClassRef, 0, { Class, RawLoc, TU } }; + CXCursor C = { CXCursor_ObjCClassRef, 0, { (void*)Class, RawLoc, TU } }; return C; } @@ -505,11 +505,11 @@ cxcursor::getCursorObjCClassRef(CXCursor C) { reinterpret_cast(C.data[1]))); } -CXCursor cxcursor::MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, +CXCursor cxcursor::MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc, CXTranslationUnit TU) { assert(Type && TU && "Invalid arguments!"); void *RawLoc = reinterpret_cast(Loc.getRawEncoding()); - CXCursor C = { CXCursor_TypeRef, 0, { Type, RawLoc, TU } }; + CXCursor C = { CXCursor_TypeRef, 0, { (void*)Type, RawLoc, TU } }; return C; } diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h index e402d7f970..8209cf4948 100644 --- a/tools/libclang/CXCursor.h +++ b/tools/libclang/CXCursor.h @@ -67,7 +67,8 @@ std::pair getCursorObjCSuperClassRef(CXCursor C); /// \brief Create an Objective-C protocol reference at the given location. -CXCursor MakeCursorObjCProtocolRef(ObjCProtocolDecl *Proto, SourceLocation Loc, +CXCursor MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto, + SourceLocation Loc, CXTranslationUnit TU); /// \brief Unpack an ObjCProtocolRef cursor into the protocol it references @@ -76,7 +77,8 @@ std::pair getCursorObjCProtocolRef(CXCursor C); /// \brief Create an Objective-C class reference at the given location. -CXCursor MakeCursorObjCClassRef(ObjCInterfaceDecl *Class, SourceLocation Loc, +CXCursor MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class, + SourceLocation Loc, CXTranslationUnit TU); /// \brief Unpack an ObjCClassRef cursor into the class it references @@ -85,7 +87,7 @@ std::pair getCursorObjCClassRef(CXCursor C); /// \brief Create a type reference at the given location. -CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, +CXCursor MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc, CXTranslationUnit TU); /// \brief Unpack a TypeRef cursor into the class it references @@ -221,7 +223,7 @@ CXCursor getTypeRefCursor(CXCursor cursor); /// \brief Generate a USR for \arg D and put it in \arg Buf. /// \returns true if no USR was computed or the result should be ignored, /// false otherwise. -bool getDeclCursorUSR(Decl *D, SmallVectorImpl &Buf); +bool getDeclCursorUSR(const Decl *D, SmallVectorImpl &Buf); bool operator==(CXCursor X, CXCursor Y); diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h index 2b8f977539..47d7146116 100644 --- a/tools/libclang/CXTranslationUnit.h +++ b/tools/libclang/CXTranslationUnit.h @@ -28,6 +28,23 @@ namespace cxtu { CXTranslationUnitImpl *MakeCXTranslationUnit(ASTUnit *TU); +class CXTUOwner { + CXTranslationUnitImpl *TU; + +public: + CXTUOwner(CXTranslationUnitImpl *tu) : TU(tu) { } + ~CXTUOwner(); + + CXTranslationUnitImpl *getTU() const { return TU; } + + CXTranslationUnitImpl *takeTU() { + CXTranslationUnitImpl *retTU = TU; + TU = 0; + return retTU; + } +}; + + }} // end namespace clang::cxtu #endif diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp new file mode 100644 index 0000000000..e02a4fa81a --- /dev/null +++ b/tools/libclang/IndexBody.cpp @@ -0,0 +1,72 @@ +//===- 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 "IndexingContext.h" + +#include "clang/AST/RecursiveASTVisitor.h" + +using namespace clang; +using namespace cxindex; + +namespace { + +class BodyIndexer : public RecursiveASTVisitor { + IndexingContext &IndexCtx; + const DeclContext *ParentDC; + +public: + BodyIndexer(IndexingContext &indexCtx, const DeclContext *DC) + : IndexCtx(indexCtx), ParentDC(DC) { } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool TraverseTypeLoc(TypeLoc TL) { + IndexCtx.indexTypeLoc(TL, 0, ParentDC); + return true; + } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + const NamedDecl *D = E->getDecl(); + if (!D) + return true; + if (D->getParentFunctionOrMethod()) + return true; + + IndexCtx.handleReference(D, E->getLocation(), 0, ParentDC, E); + return true; + } + + bool VisitMemberExpr(MemberExpr *E) { + const NamedDecl *D = E->getMemberDecl(); + if (!D) + return true; + if (D->getParentFunctionOrMethod()) + return true; + + IndexCtx.handleReference(D, E->getMemberLoc(), 0, ParentDC, E); + return true; + } + + bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { + const NamedDecl *D = E->getDecl(); + if (!D) + return true; + if (D->getParentFunctionOrMethod()) + return true; + + IndexCtx.handleReference(D, E->getLocation(), 0, ParentDC, E); + return true; + } +}; + +} // anonymous namespace + +void IndexingContext::indexBody(const Stmt *S, const DeclContext *DC) { + BodyIndexer(*this, DC).TraverseStmt(const_cast(S)); +} diff --git a/tools/libclang/IndexDecl.cpp b/tools/libclang/IndexDecl.cpp new file mode 100644 index 0000000000..5cf9f80263 --- /dev/null +++ b/tools/libclang/IndexDecl.cpp @@ -0,0 +1,218 @@ +//===- 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 "IndexingContext.h" + +#include "clang/AST/DeclVisitor.h" + +using namespace clang; +using namespace cxindex; + +namespace { + +class IndexingDeclVisitor : public DeclVisitor { + IndexingContext &IndexCtx; + +public: + explicit IndexingDeclVisitor(IndexingContext &indexCtx) + : IndexCtx(indexCtx) { } + + bool VisitFunctionDecl(FunctionDecl *D) { + IndexCtx.handleFunction(D); + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); + if (D->isThisDeclarationADefinition()) { + const Stmt *Body = D->getBody(); + if (Body) { + IndexCtx.invokeStartedStatementBody(D, D); + IndexCtx.indexBody(Body, D); + IndexCtx.invokeEndedContainer(D); + } + } + return true; + } + + bool VisitVarDecl(VarDecl *D) { + IndexCtx.handleVar(D); + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); + return true; + } + + bool VisitFieldDecl(FieldDecl *D) { + IndexCtx.handleField(D); + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); + return true; + } + + bool VisitEnumConstantDecl(EnumConstantDecl *D) { + IndexCtx.handleEnumerator(D); + return true; + } + + bool VisitTypedefDecl(TypedefDecl *D) { + IndexCtx.handleTypedef(D); + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); + return true; + } + + bool VisitTagDecl(TagDecl *D) { + // Non-free standing tags are handled in indexTypeSourceInfo. + if (D->isFreeStanding()) + IndexCtx.indexTagDecl(D); + return true; + } + + bool VisitObjCClassDecl(ObjCClassDecl *D) { + ObjCClassDecl::ObjCClassRef *Ref = D->getForwardDecl(); + if (Ref->getInterface()->getLocation() == Ref->getLocation()) { + IndexCtx.handleObjCInterface(Ref->getInterface()); + } else { + IndexCtx.handleReference(Ref->getInterface(), + Ref->getLocation(), + 0, + Ref->getInterface()->getDeclContext()); + } + return true; + } + + bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { + ObjCForwardProtocolDecl::protocol_loc_iterator LI = D->protocol_loc_begin(); + for (ObjCForwardProtocolDecl::protocol_iterator + I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I, ++LI) { + SourceLocation Loc = *LI; + ObjCProtocolDecl *PD = *I; + + if (PD->getLocation() == Loc) { + IndexCtx.handleObjCProtocol(PD); + } else { + IndexCtx.handleReference(PD, Loc, 0, PD->getDeclContext()); + } + } + return true; + } + + bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + // Only definitions are handled here. + if (D->isForwardDecl()) + return true; + + if (!D->isInitiallyForwardDecl()) + IndexCtx.handleObjCInterface(D); + + IndexCtx.indexTUDeclsInObjCContainer(); + IndexCtx.invokeStartedObjCContainer(D); + IndexCtx.defineObjCInterface(D); + IndexCtx.indexDeclContext(D); + IndexCtx.invokeEndedContainer(D); + return true; + } + + bool VisitObjCProtocolDecl(ObjCProtocolDecl *D) { + // Only definitions are handled here. + if (D->isForwardDecl()) + return true; + + if (!D->isInitiallyForwardDecl()) + IndexCtx.handleObjCProtocol(D); + + IndexCtx.indexTUDeclsInObjCContainer(); + IndexCtx.invokeStartedObjCContainer(D); + IndexCtx.indexDeclContext(D); + IndexCtx.invokeEndedContainer(D); + return true; + } + + bool VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + ObjCInterfaceDecl *Class = D->getClassInterface(); + if (Class->isImplicitInterfaceDecl()) + IndexCtx.handleObjCInterface(Class); + + IndexCtx.indexTUDeclsInObjCContainer(); + IndexCtx.invokeStartedObjCContainer(D); + IndexCtx.indexDeclContext(D); + IndexCtx.invokeEndedContainer(D); + return true; + } + + bool VisitObjCCategoryDecl(ObjCCategoryDecl *D) { + if (!D->IsClassExtension()) + IndexCtx.handleObjCCategory(D); + + IndexCtx.indexTUDeclsInObjCContainer(); + IndexCtx.invokeStartedObjCContainer(D); + IndexCtx.indexDeclContext(D); + IndexCtx.invokeEndedContainer(D); + return true; + } + + bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + IndexCtx.indexTUDeclsInObjCContainer(); + IndexCtx.invokeStartedObjCContainer(D); + IndexCtx.indexDeclContext(D); + IndexCtx.invokeEndedContainer(D); + return true; + } + + bool VisitObjCMethodDecl(ObjCMethodDecl *D) { + IndexCtx.handleObjCMethod(D); + IndexCtx.indexTypeSourceInfo(D->getResultTypeSourceInfo(), D); + for (ObjCMethodDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) + IndexCtx.indexTypeSourceInfo((*I)->getTypeSourceInfo(), D); + + if (D->isThisDeclarationADefinition()) { + const Stmt *Body = D->getBody(); + if (Body) { + IndexCtx.invokeStartedStatementBody(D, D); + IndexCtx.indexBody(Body, D); + IndexCtx.invokeEndedContainer(D); + } + } + return true; + } + + bool VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + IndexCtx.handleObjCProperty(D); + IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); + return true; + } +}; + +} // anonymous namespace + +void IndexingContext::indexDecl(const Decl *D) { + bool Handled = IndexingDeclVisitor(*this).Visit(const_cast(D)); + if (!Handled && isa(D)) + indexDeclContext(cast(D)); +} + +void IndexingContext::indexDeclContext(const DeclContext *DC) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { + indexDecl(*I); + } +} + +void IndexingContext::indexDeclGroupRef(DeclGroupRef DG) { + for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) { + Decl *D = *I; + if (isNotFromSourceFile(D->getLocation())) + return; + + if (isa(D)) + continue; // Wait for the objc container. + + indexDecl(D); + } +} + +void IndexingContext::indexTUDeclsInObjCContainer() { + for (unsigned i = 0, e = TUDeclsInObjCContainer.size(); i != e; ++i) + indexDeclGroupRef(TUDeclsInObjCContainer[i]); + TUDeclsInObjCContainer.clear(); +} diff --git a/tools/libclang/IndexTypeSourceInfo.cpp b/tools/libclang/IndexTypeSourceInfo.cpp new file mode 100644 index 0000000000..63446450f3 --- /dev/null +++ b/tools/libclang/IndexTypeSourceInfo.cpp @@ -0,0 +1,94 @@ +//===- 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 "IndexingContext.h" + +#include "clang/AST/RecursiveASTVisitor.h" + +using namespace clang; +using namespace cxindex; + +namespace { + +class TypeIndexer : public RecursiveASTVisitor { + IndexingContext &IndexCtx; + const NamedDecl *Parent; + const DeclContext *ParentDC; + +public: + TypeIndexer(IndexingContext &indexCtx, const NamedDecl *parent, + const DeclContext *DC) + : IndexCtx(indexCtx), Parent(parent), ParentDC(DC) { } + + bool shouldWalkTypesOfTypeLocs() const { return false; } + + bool VisitTypedefTypeLoc(TypedefTypeLoc TL) { + IndexCtx.handleReference(TL.getTypedefNameDecl(), TL.getNameLoc(), + Parent, ParentDC); + return true; + } + + bool VisitTagTypeLoc(TagTypeLoc TL) { + TagDecl *D = TL.getDecl(); + + if (TL.isDefinition()) { + IndexCtx.indexTagDecl(D); + return true; + } + + if (D->getLocation() == TL.getNameLoc()) + IndexCtx.handleTagDecl(D); + else + IndexCtx.handleReference(D, TL.getNameLoc(), + Parent, ParentDC); + return true; + } + + bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { + IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(), + Parent, ParentDC); + return true; + } + + bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { + for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) { + IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i), + Parent, ParentDC); + } + return true; + } +}; + +} // anonymous namespace + +void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo, + const NamedDecl *Parent, + const DeclContext *DC) { + if (!TInfo || TInfo->getTypeLoc().isNull()) + return; + + if (DC == 0) + DC = Parent->getDeclContext(); + indexTypeLoc(TInfo->getTypeLoc(), Parent, DC); +} + +void IndexingContext::indexTypeLoc(TypeLoc TL, + const NamedDecl *Parent, + const DeclContext *DC) { + TypeIndexer(*this, Parent, DC).TraverseTypeLoc(TL); +} + +void IndexingContext::indexTagDecl(const TagDecl *D) { + handleTagDecl(D); + if (D->isThisDeclarationADefinition()) { + invokeStartedTagTypeDefinition(D); + indexDeclContext(D); + invokeEndedContainer(D); + } +} diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp new file mode 100644 index 0000000000..d05995ce0d --- /dev/null +++ b/tools/libclang/Indexing.cpp @@ -0,0 +1,479 @@ +//===- 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 "IndexingContext.h" +#include "CXCursor.h" +#include "CXSourceLocation.h" +#include "CXTranslationUnit.h" +#include "CXString.h" +#include "CIndexer.h" + +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/Utils.h" +#include "clang/Sema/SemaConsumer.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PPCallbacks.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/CrashRecoveryContext.h" + +using namespace clang; +using namespace cxstring; +using namespace cxtu; +using namespace cxindex; + +namespace { + +//===----------------------------------------------------------------------===// +// IndexPPCallbacks +//===----------------------------------------------------------------------===// + +class IndexPPCallbacks : public PPCallbacks { + Preprocessor &PP; + IndexingContext &IndexCtx; + +public: + IndexPPCallbacks(Preprocessor &PP, IndexingContext &indexCtx) + : PP(PP), IndexCtx(indexCtx) { } + + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + const FileEntry *File, + SourceLocation EndLoc, + StringRef SearchPath, + StringRef RelativePath) { + bool isImport = (IncludeTok.is(tok::identifier) && + IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import); + IndexCtx.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled); + } + + /// MacroDefined - This hook is called whenever a macro definition is seen. + virtual void MacroDefined(const Token &Id, const MacroInfo *MI) { + if (MI->isBuiltinMacro()) + return; + if (IndexCtx.isNotFromSourceFile(MI->getDefinitionLoc())) + return; + + SourceLocation Loc = MI->getDefinitionLoc(); + SourceLocation DefBegin = MI->tokens_empty() ? Loc + : MI->getReplacementToken(0).getLocation(); + IndexCtx.ppMacroDefined(Loc, + Id.getIdentifierInfo()->getName(), + DefBegin, + MI->getDefinitionLength(PP.getSourceManager()), + MI); + } + + /// MacroUndefined - This hook is called whenever a macro #undef is seen. + /// MI is released immediately following this callback. + virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) { + if (MI->isBuiltinMacro()) + return; + if (IndexCtx.isNotFromSourceFile(MI->getDefinitionLoc())) + return; + + SourceLocation Loc = MacroNameTok.getLocation(); + IndexCtx.ppMacroUndefined(Loc, + MacroNameTok.getIdentifierInfo()->getName(), + MI); + } + + /// MacroExpands - This is called by when a macro invocation is found. + virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI, + SourceRange Range) { + if (MI->isBuiltinMacro()) + return; + if (IndexCtx.isNotFromSourceFile(MI->getDefinitionLoc())) + return; + + SourceLocation Loc = MacroNameTok.getLocation(); + IndexCtx.ppMacroExpanded(Loc, + MacroNameTok.getIdentifierInfo()->getName(), + MI); + } + + /// SourceRangeSkipped - This hook is called when a source range is skipped. + /// \param Range The SourceRange that was skipped. The range begins at the + /// #if/#else directive and ends after the #endif/#else directive. + virtual void SourceRangeSkipped(SourceRange Range) { + } +}; + +//===----------------------------------------------------------------------===// +// IndexingConsumer +//===----------------------------------------------------------------------===// + +class IndexingConsumer : public ASTConsumer { + IndexingContext &IndexCtx; + +public: + explicit IndexingConsumer(IndexingContext &indexCtx) + : IndexCtx(indexCtx) { } + + // ASTConsumer Implementation + + virtual void Initialize(ASTContext &Context) { + IndexCtx.setASTContext(Context); + IndexCtx.invokeStartedTranslationUnit(); + } + + virtual void HandleTranslationUnit(ASTContext &Ctx) { + IndexCtx.invokeFinishedTranslationUnit(); + } + + virtual void HandleTopLevelDecl(DeclGroupRef DG) { + IndexCtx.indexDeclGroupRef(DG); + } + + /// \brief Handle the specified top-level declaration that occurred inside + /// and ObjC container. + virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) { + // They will be handled after the interface is seen first. + IndexCtx.addTUDeclInObjCContainer(D); + } + + /// \brief This is called by the AST reader when deserializing things. + /// The default implementation forwards to HandleTopLevelDecl but we don't + /// care about them when indexing, so have an empty definition. + virtual void HandleInterestingDecl(DeclGroupRef D) {} +}; + +//===----------------------------------------------------------------------===// +// IndexingDiagnosticConsumer +//===----------------------------------------------------------------------===// + +class IndexingDiagnosticConsumer : public DiagnosticConsumer { + IndexingContext &IndexCtx; + +public: + explicit IndexingDiagnosticConsumer(IndexingContext &indexCtx) + : IndexCtx(indexCtx) {} + + virtual void HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) { + // Default implementation (Warnings/errors count). + DiagnosticConsumer::HandleDiagnostic(Level, Info); + + IndexCtx.handleDiagnostic(StoredDiagnostic(Level, Info)); + } + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + return new IgnoringDiagConsumer(); + } +}; + +class CaptureDiagnosticConsumer : public DiagnosticConsumer { + SmallVector Errors; +public: + + virtual void HandleDiagnostic(DiagnosticsEngine::Level level, + const Diagnostic &Info) { + if (level >= DiagnosticsEngine::Error) + Errors.push_back(StoredDiagnostic(level, Info)); + } + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + return new IgnoringDiagConsumer(); + } +}; + +//===----------------------------------------------------------------------===// +// IndexingFrontendAction +//===----------------------------------------------------------------------===// + +class IndexingFrontendAction : public ASTFrontendAction { + IndexingContext IndexCtx; + +public: + IndexingFrontendAction(CXClientData clientData, + IndexerCallbacks &indexCallbacks, + unsigned indexOptions, + CXTranslationUnit cxTU) + : IndexCtx(clientData, indexCallbacks, indexOptions, cxTU) { } + + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + CI.getDiagnostics().setClient(new IndexingDiagnosticConsumer(IndexCtx), + /*own=*/true); + IndexCtx.setASTContext(CI.getASTContext()); + Preprocessor &PP = CI.getPreprocessor(); + PP.addPPCallbacks(new IndexPPCallbacks(PP, IndexCtx)); + return new IndexingConsumer(IndexCtx); + } + + virtual TranslationUnitKind getTranslationUnitKind() { return TU_Prefix; } + virtual bool hasCodeCompletionSupport() const { return false; } +}; + +//===----------------------------------------------------------------------===// +// clang_indexTranslationUnit Implementation +//===----------------------------------------------------------------------===// + +struct IndexTranslationUnitInfo { + CXIndex CIdx; + CXClientData client_data; + IndexerCallbacks *index_callbacks; + unsigned index_callbacks_size; + unsigned index_options; + const char *source_filename; + const char *const *command_line_args; + int num_command_line_args; + struct CXUnsavedFile *unsaved_files; + unsigned num_unsaved_files; + CXTranslationUnit *out_TU; + unsigned TU_options; + int result; +}; + +struct MemBufferOwner { + SmallVector Buffers; + + ~MemBufferOwner() { + for (SmallVectorImpl::iterator + I = Buffers.begin(), E = Buffers.end(); I != E; ++I) + delete *I; + } +}; + +} // anonymous namespace + +static void clang_indexTranslationUnit_Impl(void *UserData) { + IndexTranslationUnitInfo *ITUI = + static_cast(UserData); + CXIndex CIdx = ITUI->CIdx; + CXClientData client_data = ITUI->client_data; + IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks; + unsigned index_callbacks_size = ITUI->index_callbacks_size; + unsigned index_options = ITUI->index_options; + const char *source_filename = ITUI->source_filename; + const char * const *command_line_args = ITUI->command_line_args; + int num_command_line_args = ITUI->num_command_line_args; + struct CXUnsavedFile *unsaved_files = ITUI->unsaved_files; + unsigned num_unsaved_files = ITUI->num_unsaved_files; + CXTranslationUnit *out_TU = ITUI->out_TU; + unsigned TU_options = ITUI->TU_options; + ITUI->result = 1; // init as error. + + if (out_TU) + *out_TU = 0; + bool requestedToGetTU = (out_TU != 0); + + if (!CIdx) + return; + if (!client_index_callbacks || index_callbacks_size == 0) + return; + + IndexerCallbacks CB; + memset(&CB, 0, sizeof(CB)); + unsigned ClientCBSize = index_callbacks_size < sizeof(CB) + ? index_callbacks_size : sizeof(CB); + memcpy(&CB, client_index_callbacks, ClientCBSize); + + CIndexer *CXXIdx = static_cast(CIdx); + + (void)CXXIdx; + (void)TU_options; + + CaptureDiagnosticConsumer *CaptureDiag = new CaptureDiagnosticConsumer(); + + // Configure the diagnostics. + DiagnosticOptions DiagOpts; + llvm::IntrusiveRefCntPtr + Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args, + command_line_args, + CaptureDiag, + /*ShouldOwnClient=*/true)); + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar > + DiagCleanup(Diags.getPtr()); + + llvm::OwningPtr > + Args(new std::vector()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar > + ArgsCleanup(Args.get()); + + Args->insert(Args->end(), command_line_args, + command_line_args + num_command_line_args); + + // The 'source_filename' argument is optional. If the caller does not + // specify it then it is assumed that the source file is specified + // in the actual argument list. + // Put the source file after command_line_args otherwise if '-x' flag is + // present it will be unused. + if (source_filename) + Args->push_back(source_filename); + + llvm::IntrusiveRefCntPtr + CInvok(createInvocationFromCommandLine(*Args, Diags)); + + if (!CInvok) + return; + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar > + CInvokCleanup(CInvok.getPtr()); + + if (CInvok->getFrontendOpts().Inputs.empty()) + return; + + llvm::OwningPtr BufOwner(new MemBufferOwner()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + BufOwnerCleanup(BufOwner.get()); + + for (unsigned I = 0; I != num_unsaved_files; ++I) { + StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); + CInvok->getPreprocessorOpts().addRemappedFile(unsaved_files[I].Filename, Buffer); + BufOwner->Buffers.push_back(Buffer); + } + + // Since libclang is primarily used by batch tools dealing with + // (often very broken) source code, where spell-checking can have a + // significant negative impact on performance (particularly when + // precompiled headers are involved), we disable it. + CInvok->getLangOpts().SpellChecking = false; + + if (!requestedToGetTU) + CInvok->getPreprocessorOpts().DetailedRecord = false; + + ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags); + llvm::OwningPtr CXTU(new CXTUOwner(MakeCXTranslationUnit(Unit))); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + CXTUCleanup(CXTU.get()); + + llvm::OwningPtr IndexAction; + IndexAction.reset(new IndexingFrontendAction(client_data, CB, + index_options, CXTU->getTU())); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + IndexActionCleanup(IndexAction.get()); + + Unit = ASTUnit::LoadFromCompilerInvocationAction(CInvok.getPtr(), Diags, + IndexAction.get(), + Unit); + if (!Unit) + return; + + // FIXME: Set state of the ASTUnit according to the TU_options. + if (out_TU) + *out_TU = CXTU->takeTU(); + + ITUI->result = 0; // success. +} + +//===----------------------------------------------------------------------===// +// libclang public APIs. +//===----------------------------------------------------------------------===// + +extern "C" { + +int clang_indexTranslationUnit(CXIndex CIdx, + CXClientData client_data, + IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, + unsigned index_options, + const char *source_filename, + const char * const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + CXTranslationUnit *out_TU, + unsigned TU_options) { + IndexTranslationUnitInfo ITUI = { CIdx, client_data, index_callbacks, + index_callbacks_size, index_options, + source_filename, command_line_args, + num_command_line_args, unsaved_files, + num_unsaved_files, out_TU, TU_options, 0 }; + + if (getenv("CINDEXTEST_NOTHREADS")) { + clang_indexTranslationUnit_Impl(&ITUI); + return ITUI.result; + } + + llvm::CrashRecoveryContext CRC; + + if (!RunSafely(CRC, clang_indexTranslationUnit_Impl, &ITUI)) { + fprintf(stderr, "libclang: crash detected during parsing: {\n"); + fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); + fprintf(stderr, " 'command_line_args' : ["); + for (int i = 0; i != num_command_line_args; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "'%s'", command_line_args[i]); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'unsaved_files' : ["); + for (unsigned i = 0; i != num_unsaved_files; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename, + unsaved_files[i].Length); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'options' : %d,\n", TU_options); + fprintf(stderr, "}\n"); + + return 1; + } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { + if (out_TU) + PrintLibclangResourceUsage(*out_TU); + } + + return ITUI.result; +} + +void clang_indexLoc_getFileLocation(CXIdxLoc location, + CXIdxFile *indexFile, + CXFile *file, + unsigned *line, + unsigned *column, + unsigned *offset) { + if (indexFile) *indexFile = 0; + if (file) *file = 0; + if (line) *line = 0; + if (column) *column = 0; + if (offset) *offset = 0; + + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + if (!location.ptr_data[0] || Loc.isInvalid()) + return; + + IndexingContext &IndexCtx = + *static_cast(location.ptr_data[0]); + IndexCtx.translateLoc(Loc, indexFile, file, line, column, offset); +} + +CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc location) { + SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data); + if (!location.ptr_data[0] || Loc.isInvalid()) + return clang_getNullLocation(); + + IndexingContext &IndexCtx = + *static_cast(location.ptr_data[0]); + return cxloc::translateSourceLocation(IndexCtx.getASTContext(), Loc); +} + +} // end: extern "C" + diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp new file mode 100644 index 0000000000..7c0ceaf152 --- /dev/null +++ b/tools/libclang/IndexingContext.cpp @@ -0,0 +1,695 @@ +//===- 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 "IndexingContext.h" +#include "CXTranslationUnit.h" +#include "CIndexDiagnostic.h" + +#include "clang/Frontend/ASTUnit.h" +#include "clang/AST/DeclObjC.h" + +using namespace clang; +using namespace cxindex; +using namespace cxcursor; + +const char *IndexingContext::StrAdapter::toCStr(StringRef Str) { + if (Str.empty()) + return ""; + if (Str.data()[Str.size()] == '\0') + return Str.data(); + Scratch += Str; + Scratch.push_back('\0'); + return Scratch.data() + (Scratch.size() - Str.size() - 1); +} + +void IndexingContext::setASTContext(ASTContext &ctx) { + Ctx = &ctx; + static_cast(CXTU->TUData)->setASTContext(&ctx); +} + +void IndexingContext::ppIncludedFile(SourceLocation hashLoc, + StringRef filename, + const FileEntry *File, + bool isImport, bool isAngled) { + if (!CB.ppIncludedFile) + return; + + StrAdapter SA(this); + CXIdxIncludedFileInfo Info = { getIndexLoc(hashLoc), + SA.toCStr(filename), + getIndexFile(File), + isImport, isAngled }; + CB.ppIncludedFile(ClientData, &Info); +} + +void IndexingContext::ppMacroDefined(SourceLocation Loc, StringRef Name, + SourceLocation DefBegin, unsigned Length, + const void *OpaqueMacro) { + if (!CB.ppMacroDefined) + return; + + StrAdapter SA(this); + CXIdxMacroInfo MacroInfo = { getIndexLoc(Loc), SA.toCStr(Name) }; + CXIdxMacroDefinedInfo Info = { &MacroInfo, + getIndexLoc(DefBegin), Length }; + CXIdxMacro idxMacro = CB.ppMacroDefined(ClientData, &Info); + MacroMap[OpaqueMacro] = idxMacro; +} + +void IndexingContext::ppMacroUndefined(SourceLocation Loc, StringRef Name, + const void *OpaqueMacro) { + if (!CB.ppMacroUndefined) + return; + + StrAdapter SA(this); + CXIdxMacroUndefinedInfo Info = { getIndexLoc(Loc), + SA.toCStr(Name), 0 }; + CB.ppMacroUndefined(ClientData, &Info); +} + +void IndexingContext::ppMacroExpanded(SourceLocation Loc, StringRef Name, + const void *OpaqueMacro) { + if (!CB.ppMacroExpanded) + return; + + StrAdapter SA(this); + CXIdxMacroExpandedInfo Info = { getIndexLoc(Loc), + SA.toCStr(Name), 0 }; + CB.ppMacroExpanded(ClientData, &Info); +} + +void IndexingContext::invokeStartedTranslationUnit() { + CXIdxContainer idxCont = 0; + if (CB.startedTranslationUnit) + idxCont = CB.startedTranslationUnit(ClientData, 0); + addContainerInMap(Ctx->getTranslationUnitDecl(), idxCont); +} + +void IndexingContext::invokeFinishedTranslationUnit() { + invokeEndedContainer(Ctx->getTranslationUnitDecl()); +} + +void IndexingContext::handleDiagnostic(const StoredDiagnostic &StoredDiag) { + if (!CB.diagnostic) + return; + + CXStoredDiagnostic CXDiag(StoredDiag, Ctx->getLangOptions()); + CB.diagnostic(ClientData, &CXDiag, 0); +} + +void IndexingContext::handleFunction(const FunctionDecl *D) { + StrAdapter SA(this); + + if (D->isFirstDeclaration()) { + CXIdxEntity idxEntity = 0; + if (CB.indexFunction) { + CXIdxEntityInfo EntityInfo; + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedEntityInfo IdxEntityInfo; + getIndexedEntityInfo(D, IdxEntityInfo, EntityInfo, DeclInfo, SA); + CXIdxFunctionInfo Info = { &IdxEntityInfo, + D->isThisDeclarationADefinition() }; + + idxEntity = CB.indexFunction(ClientData, &Info); + } + + addEntityInMap(D, idxEntity); + + } else { + if (CB.indexFunctionRedeclaration) { + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedRedeclInfo RedeclInfo; + getIndexedRedeclInfo(D, RedeclInfo, DeclInfo); + CXIdxFunctionRedeclInfo Info = { &RedeclInfo, + D->isThisDeclarationADefinition() }; + + CB.indexFunctionRedeclaration(ClientData, &Info); + } + } +} + +void IndexingContext::handleVar(const VarDecl *D) { + StrAdapter SA(this); + + if (D->isFirstDeclaration()) { + CXIdxEntity idxEntity = 0; + if (CB.indexVariable) { + CXIdxEntityInfo EntityInfo; + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedEntityInfo IdxEntityInfo; + getIndexedEntityInfo(D, IdxEntityInfo, EntityInfo, DeclInfo, SA); + CXIdxVariableInfo Info = { &IdxEntityInfo, + D->isThisDeclarationADefinition() }; + + idxEntity = CB.indexVariable(ClientData, &Info); + } + + addEntityInMap(D, idxEntity); + + } else { + if (CB.indexVariableRedeclaration) { + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedRedeclInfo RedeclInfo; + getIndexedRedeclInfo(D, RedeclInfo, DeclInfo); + CXIdxVariableRedeclInfo Info = { &RedeclInfo, + D->isThisDeclarationADefinition() }; + + CB.indexVariableRedeclaration(ClientData, &Info); + } + } +} + +void IndexingContext::handleField(const FieldDecl *D) { + StrAdapter SA(this); + + CXIdxEntity idxEntity = 0; + if (CB.indexTypedef) { + CXIdxEntityInfo EntityInfo; + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedEntityInfo IdxEntityInfo; + getIndexedEntityInfo(D, IdxEntityInfo, EntityInfo, DeclInfo, SA); + CXIdxFieldInfo Info = { &IdxEntityInfo }; + + idxEntity = CB.indexField(ClientData, &Info); + } + + addEntityInMap(D, idxEntity); +} + +void IndexingContext::handleEnumerator(const EnumConstantDecl *D) { + StrAdapter SA(this); + + CXIdxEntity idxEntity = 0; + if (CB.indexTypedef) { + CXIdxEntityInfo EntityInfo; + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedEntityInfo IdxEntityInfo; + getIndexedEntityInfo(D, IdxEntityInfo, EntityInfo, DeclInfo, SA); + CXIdxEnumeratorInfo Info = { &IdxEntityInfo }; + + idxEntity = CB.indexEnumerator(ClientData, &Info); + } + + addEntityInMap(D, idxEntity); +} + +void IndexingContext::handleTagDecl(const TagDecl *D) { + StrAdapter SA(this); + + if (D->isFirstDeclaration()) { + CXIdxEntity idxEntity = 0; + if (CB.indexTagType) { + CXIdxEntityInfo EntityInfo; + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedEntityInfo IdxEntityInfo; + getIndexedEntityInfo(D, IdxEntityInfo, EntityInfo, DeclInfo, SA); + CXIdxTagTypeInfo Info = { &IdxEntityInfo, + D->isThisDeclarationADefinition(), + D->getIdentifier() == 0}; + + idxEntity = CB.indexTagType(ClientData, &Info); + } + + addEntityInMap(D, idxEntity); + + } else { + if (CB.indexTagTypeRedeclaration) { + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedRedeclInfo RedeclInfo; + getIndexedRedeclInfo(D, RedeclInfo, DeclInfo); + CXIdxTagTypeRedeclInfo Info = { &RedeclInfo, + D->isThisDeclarationADefinition() }; + + CB.indexTagTypeRedeclaration(ClientData, &Info); + } + } +} + +void IndexingContext::handleTypedef(const TypedefDecl *D) { + StrAdapter SA(this); + + CXIdxEntity idxEntity = 0; + if (CB.indexTypedef) { + CXIdxEntityInfo EntityInfo; + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedEntityInfo IdxEntityInfo; + getIndexedEntityInfo(D, IdxEntityInfo, EntityInfo, DeclInfo, SA); + CXIdxTypedefInfo Info = { &IdxEntityInfo }; + + idxEntity = CB.indexTypedef(ClientData, &Info); + } + + addEntityInMap(D, idxEntity); +} + +void IndexingContext::handleObjCInterface(const ObjCInterfaceDecl *D) { + StrAdapter SA(this); + + CXIdxEntity idxEntity = 0; + if (CB.indexObjCClass) { + CXIdxEntityInfo EntityInfo; + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedEntityInfo IdxEntityInfo; + getIndexedEntityInfo(D, IdxEntityInfo, EntityInfo, DeclInfo, SA); + CXIdxObjCClassInfo Info = { &IdxEntityInfo, + D->isForwardDecl() }; + + idxEntity = CB.indexObjCClass(ClientData, &Info); + } + + addEntityInMap(D, idxEntity); +} + +void IndexingContext::defineObjCInterface(const ObjCInterfaceDecl *D) { + if (!CB.defineObjCClass) + return; + + CXIdxObjCBaseClassInfo BaseClass = { getIndexEntity(D->getSuperClass()), + getIndexLoc(D->getSuperClassLoc()) }; + if (D->getSuperClass()) { + BaseClass.objcClass = getIndexEntity(D->getSuperClass()); + BaseClass.loc = getIndexLoc(D->getSuperClassLoc()); + } + + SmallVector ProtInfos; + ObjCInterfaceDecl::protocol_loc_iterator LI = D->protocol_loc_begin(); + for (ObjCInterfaceDecl::protocol_iterator + I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I, ++LI) { + SourceLocation Loc = *LI; + ObjCProtocolDecl *PD = *I; + CXIdxObjCProtocolRefInfo ProtInfo = { getIndexEntity(PD), + getIndexLoc(Loc) }; + ProtInfos.push_back(ProtInfo); + } + + SmallVector Prots; + for (unsigned i = 0, e = Prots.size(); i != e; ++i) + Prots.push_back(&ProtInfos[i]); + + CXIdxObjCClassDefineInfo Info = { getCursor(D), + getIndexEntity(D), + getIndexContainerForDC(D), + D->getSuperClass() ? &BaseClass : 0, + Prots.data(), + Prots.size() }; + CB.defineObjCClass(ClientData, &Info); +} + +void IndexingContext::handleObjCProtocol(const ObjCProtocolDecl *D) { + StrAdapter SA(this); + + CXIdxEntity idxEntity = 0; + if (CB.indexObjCProtocol) { + CXIdxEntityInfo EntityInfo; + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedEntityInfo IdxEntityInfo; + getIndexedEntityInfo(D, IdxEntityInfo, EntityInfo, DeclInfo, SA); + CXIdxObjCProtocolInfo Info = { &IdxEntityInfo, + D->isForwardDecl() }; + + idxEntity = CB.indexObjCProtocol(ClientData, &Info); + } + + addEntityInMap(D, idxEntity); +} + +void IndexingContext::handleObjCCategory(const ObjCCategoryDecl *D) { + StrAdapter SA(this); + + CXIdxEntity idxEntity = 0; + if (CB.indexObjCCategory) { + CXIdxEntityInfo EntityInfo; + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedEntityInfo IdxEntityInfo; + getIndexedEntityInfo(D, IdxEntityInfo, EntityInfo, DeclInfo, SA); + CXIdxObjCCategoryInfo Info = { &IdxEntityInfo, + getIndexEntity(D->getClassInterface()) }; + + idxEntity = CB.indexObjCCategory(ClientData, &Info); + } + + addEntityInMap(D, idxEntity); +} + +void IndexingContext::handleObjCMethod(const ObjCMethodDecl *D) { + StrAdapter SA(this); + + if (D->isCanonicalDecl()) { + CXIdxEntity idxEntity = 0; + if (CB.indexObjCMethod) { + CXIdxEntityInfo EntityInfo; + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedEntityInfo IdxEntityInfo; + getIndexedEntityInfo(D, IdxEntityInfo, EntityInfo, DeclInfo, SA); + CXIdxObjCMethodInfo Info = { &IdxEntityInfo, + D->isThisDeclarationADefinition() }; + + idxEntity = CB.indexObjCMethod(ClientData, &Info); + } + + addEntityInMap(D, idxEntity); + + } else { + if (CB.indexObjCMethodRedeclaration) { + CXIdxIndexedRedeclInfo RedeclInfo; + CXIdxIndexedDeclInfo DeclInfo; + getIndexedRedeclInfo(D, RedeclInfo, DeclInfo); + CXIdxObjCMethodRedeclInfo Info = { &RedeclInfo, + D->isThisDeclarationADefinition() }; + + CB.indexObjCMethodRedeclaration(ClientData, &Info); + } + } +} + +void IndexingContext::handleObjCProperty(const ObjCPropertyDecl *D) { + StrAdapter SA(this); + + CXIdxEntity idxEntity = 0; + if (CB.indexObjCProperty) { + CXIdxEntityInfo EntityInfo; + CXIdxIndexedDeclInfo DeclInfo; + CXIdxIndexedEntityInfo IdxEntityInfo; + getIndexedEntityInfo(D, IdxEntityInfo, EntityInfo, DeclInfo, SA); + CXIdxObjCPropertyInfo Info = { &IdxEntityInfo }; + + idxEntity = CB.indexObjCProperty(ClientData, &Info); + } + + addEntityInMap(D, idxEntity); +} + +void IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc, + const NamedDecl *Parent, + const DeclContext *DC, + const Expr *E) { + if (Loc.isInvalid()) + return; + if (!CB.indexEntityReference) + return; + if (isNotFromSourceFile(D->getLocation())) + return; + + CXIdxEntityRefInfo Info = { E ? MakeCXCursor((Stmt*)E, + (Decl*)cast(DC), CXTU) + : getRefCursor(D, Loc), + getIndexLoc(Loc), + getIndexEntity(D), + getIndexEntity(Parent), + getIndexContainerForDC(DC) }; + CB.indexEntityReference(ClientData, &Info); +} + +void IndexingContext::invokeStartedStatementBody(const NamedDecl *D, + const DeclContext *DC) { + const Stmt *Body = cast(DC)->getBody(); + assert(Body); + + CXIdxContainer idxCont = 0; + if (CB.startedStatementBody) { + CXIdxContainerInfo ContainerInfo; + getContainerInfo(D, ContainerInfo); + CXIdxStmtBodyInfo Info = { &ContainerInfo, + getIndexLoc(Body->getLocStart()) }; + + idxCont = CB.startedStatementBody(ClientData, &Info); + } + addContainerInMap(DC, idxCont); +} + +void IndexingContext::invokeStartedTagTypeDefinition(const TagDecl *D) { + CXIdxContainer idxCont = 0; + if (CB.startedTagTypeDefinition) { + CXIdxContainerInfo ContainerInfo; + getContainerInfo(D, ContainerInfo); + CXIdxTagTypeDefinitionInfo Info = { &ContainerInfo }; + + idxCont = CB.startedTagTypeDefinition(ClientData, &Info); + } + addContainerInMap(D, idxCont); +} + +void IndexingContext::invokeStartedObjCContainer(const ObjCContainerDecl *D) { + CXIdxContainer idxCont = 0; + if (CB.startedObjCContainer) { + CXIdxContainerInfo ContainerInfo; + getContainerInfo(D, ContainerInfo); + CXIdxObjCContainerInfo Info = { &ContainerInfo }; + + idxCont = CB.startedObjCContainer(ClientData, &Info); + } + addContainerInMap(D, idxCont); +} + +void IndexingContext::invokeEndedContainer(const DeclContext *DC) { + if (CB.endedContainer) { + CXIdxEndContainerInfo Info = { getIndexContainerForDC(DC), + getIndexLoc(cast(DC)->getLocEnd()) }; + CB.endedContainer(ClientData, &Info); + } +} + +bool IndexingContext::isNotFromSourceFile(SourceLocation Loc) const { + if (Loc.isInvalid()) + return true; + SourceManager &SM = Ctx->getSourceManager(); + SourceLocation FileLoc = SM.getFileLoc(Loc); + FileID FID = SM.getFileID(FileLoc); + return SM.getFileEntryForID(FID) == 0; +} + +void IndexingContext::addContainerInMap(const DeclContext *DC, + CXIdxContainer container) { + assert(getScopedContext(DC) == DC); + ContainerMapTy::iterator I = ContainerMap.find(DC); + if (I == ContainerMap.end()) { + if (container) + ContainerMap[DC] = container; + return; + } + // Allow changing the container of a previously seen DeclContext so we + // can handle invalid user code, like a function re-definition. + if (container) + I->second = container; + else + ContainerMap.erase(I); +} + +void IndexingContext::addEntityInMap(const NamedDecl *D, CXIdxEntity entity) { + assert(getEntityDecl(D) == D && + "Tried to add a non-entity (canonical) decl"); + assert(EntityMap.find(D) == EntityMap.end()); + if (entity || D->isFromASTFile()) + EntityMap[D] = entity; +} + +CXIdxEntity IndexingContext::getIndexEntity(const NamedDecl *D) { + if (!D) + return 0; + D = getEntityDecl(D); + EntityMapTy::const_iterator I = EntityMap.find(D); + if (I != EntityMap.end()) + return I->second; + + if (!D->isFromASTFile()) { + //assert(0 && "Entity not in map"); + return 0; + } + + StrAdapter SA(this); + + CXIdxEntity idxEntity = 0; + if (CB.importedEntity) { + CXIdxEntityInfo EntityInfo; + getEntityInfo(D, EntityInfo, SA); + CXIdxImportedEntityInfo Info = { &EntityInfo, + getCursor(D), + getIndexLoc(D->getLocation()), + /*CXIdxASTFile*/0 }; + idxEntity = CB.importedEntity(ClientData, &Info); + } + addEntityInMap(D, idxEntity); + return idxEntity; +} + +const NamedDecl *IndexingContext::getEntityDecl(const NamedDecl *D) const { + assert(D); + D = cast(D->getCanonicalDecl()); + + if (const ObjCCategoryDecl *Cat = dyn_cast(D)) { + if (Cat->IsClassExtension()) + return getEntityDecl(Cat->getClassInterface()); + + } else if (const ObjCImplementationDecl * + ImplD = dyn_cast(D)) { + return getEntityDecl(ImplD->getClassInterface()); + + } else if (const ObjCCategoryImplDecl * + CatImplD = dyn_cast(D)) { + return getEntityDecl(CatImplD->getCategoryDecl()); + } + + return D; +} + +const DeclContext * +IndexingContext::getScopedContext(const DeclContext *DC) const { + // Local contexts are ignored for indexing. + const DeclContext *FuncCtx = cast(DC)->getParentFunctionOrMethod(); + if (FuncCtx) + return FuncCtx; + + // We consider enums always scoped for indexing. + if (isa(DC)) + return DC; + + if (const NamespaceDecl *NS = dyn_cast(DC)) { + if (NS->isAnonymousNamespace()) + return getScopedContext(NS->getParent()); + return NS; + } + + return DC->getRedeclContext(); +} + +CXIdxContainer +IndexingContext::getIndexContainerForDC(const DeclContext *DC) const { + DC = getScopedContext(DC); + ContainerMapTy::const_iterator I = ContainerMap.find(DC); +// assert(I != ContainerMap.end() && +// "Failed to include a scoped context in the container map"); + return I->second; +} + +CXIdxFile IndexingContext::getIndexFile(const FileEntry *File) { + if (!File) + return 0; + if (!CB.recordFile) + return 0; + + FileMapTy::iterator FI = FileMap.find(File); + if (FI != FileMap.end()) + return FI->second; + + CXIdxFile idxFile = CB.recordFile(ClientData, (CXFile)File, 0); + FileMap[File] = idxFile; + return idxFile; +} + +CXIdxLoc IndexingContext::getIndexLoc(SourceLocation Loc) const { + CXIdxLoc idxLoc = { {0, 0}, 0 }; + if (Loc.isInvalid()) + return idxLoc; + + idxLoc.ptr_data[0] = (void*)this; + idxLoc.int_data = Loc.getRawEncoding(); + return idxLoc; +} + +void IndexingContext::translateLoc(SourceLocation Loc, + CXIdxFile *indexFile, CXFile *file, + unsigned *line, unsigned *column, + unsigned *offset) { + if (Loc.isInvalid()) + return; + + SourceManager &SM = Ctx->getSourceManager(); + Loc = SM.getFileLoc(Loc); + + std::pair LocInfo = SM.getDecomposedLoc(Loc); + FileID FID = LocInfo.first; + unsigned FileOffset = LocInfo.second; + + if (FID.isInvalid()) + return; + + const FileEntry *FE = SM.getFileEntryForID(FID); + if (indexFile) + *indexFile = getIndexFile(FE); + if (file) + *file = (void *)FE; + if (line) + *line = SM.getLineNumber(FID, FileOffset); + if (column) + *column = SM.getColumnNumber(FID, FileOffset); + if (offset) + *offset = FileOffset; +} + +void IndexingContext::getIndexedEntityInfo(const NamedDecl *D, + CXIdxIndexedEntityInfo &IdxEntityInfo, + CXIdxEntityInfo &EntityInfo, + CXIdxIndexedDeclInfo &IdxDeclInfo, + StrAdapter &SA) { + getEntityInfo(D, EntityInfo, SA); + getIndexedDeclInfo(D, IdxDeclInfo); + IdxEntityInfo.entityInfo = &EntityInfo; + IdxEntityInfo.declInfo = &IdxDeclInfo; +} + +void IndexingContext::getIndexedDeclInfo(const NamedDecl *D, + CXIdxIndexedDeclInfo &IdxDeclInfo) { + IdxDeclInfo.cursor = getCursor(D); + IdxDeclInfo.loc = getIndexLoc(D->getLocation()); + IdxDeclInfo.container = getIndexContainer(D); +} + +void IndexingContext::getIndexedRedeclInfo(const NamedDecl *D, + CXIdxIndexedRedeclInfo &RedeclInfo, + CXIdxIndexedDeclInfo &IdxDeclInfo) { + getIndexedDeclInfo(D, IdxDeclInfo); + RedeclInfo.declInfo = &IdxDeclInfo; + RedeclInfo.entity = getIndexEntity(D); +} + +void IndexingContext::getContainerInfo(const NamedDecl *D, + CXIdxContainerInfo &ContainerInfo) { + ContainerInfo.cursor = getCursor(D); + ContainerInfo.loc = getIndexLoc(D->getLocation()); + ContainerInfo.entity = getIndexEntity(D); +} + +void IndexingContext::getEntityInfo(const NamedDecl *D, + CXIdxEntityInfo &EntityInfo, + StrAdapter &SA) { + if (IdentifierInfo *II = D->getIdentifier()) { + EntityInfo.name = SA.toCStr(II->getName()); + + } else if (isa(D) || isa(D)) { + EntityInfo.name = 0; + + } else { + unsigned Begin = SA.getCurSize(); + { + llvm::raw_svector_ostream OS(SA.getBuffer()); + D->printName(OS); + } + EntityInfo.name = SA.getCStr(Begin); + } + + unsigned Begin = SA.getCurSize(); + bool Ignore = getDeclCursorUSR(D, SA.getBuffer()); + if (Ignore) { + EntityInfo.USR = ""; + } else { + EntityInfo.USR = SA.getCStr(Begin); + } +} + +CXCursor IndexingContext::getRefCursor(const NamedDecl *D, SourceLocation Loc) { + if (const TypeDecl *TD = dyn_cast(D)) + return MakeCursorTypeRef(TD, Loc, CXTU); + if (const ObjCInterfaceDecl *ID = dyn_cast(D)) + return MakeCursorObjCClassRef(ID, Loc, CXTU); + if (const ObjCProtocolDecl *PD = dyn_cast(D)) + return MakeCursorObjCProtocolRef(PD, Loc, CXTU); + + //assert(0 && "not yet"); + return clang_getNullCursor(); +} diff --git a/tools/libclang/IndexingContext.h b/tools/libclang/IndexingContext.h new file mode 100644 index 0000000000..710568058f --- /dev/null +++ b/tools/libclang/IndexingContext.h @@ -0,0 +1,204 @@ +//===- IndexingContext.h - 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 "clang/AST/Decl.h" +#include "clang/AST/DeclGroup.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + class FileEntry; + class ObjCPropertyDecl; + +namespace cxindex { + class IndexingContext; + +class IndexingContext { + ASTContext *Ctx; + CXClientData ClientData; + IndexerCallbacks &CB; + unsigned IndexOptions; + CXTranslationUnit CXTU; + + typedef llvm::DenseMap FileMapTy; + typedef llvm::DenseMap EntityMapTy; + typedef llvm::DenseMap MacroMapTy; + typedef llvm::DenseMap ContainerMapTy; + FileMapTy FileMap; + EntityMapTy EntityMap; + MacroMapTy MacroMap; + ContainerMapTy ContainerMap; + + SmallVector TUDeclsInObjCContainer; + + llvm::SmallString<256> StrScratch; + + class StrAdapter { + llvm::SmallString<256> &Scratch; + + public: + StrAdapter(IndexingContext *indexCtx) + : Scratch(indexCtx->StrScratch) {} + ~StrAdapter() { Scratch.clear(); } + + const char *toCStr(StringRef Str); + + unsigned getCurSize() const { return Scratch.size(); } + + const char *getCStr(unsigned CharIndex) { + Scratch.push_back('\0'); + return Scratch.data() + CharIndex; + } + + SmallVectorImpl &getBuffer() { return Scratch; } + }; + +public: + IndexingContext(CXClientData clientData, IndexerCallbacks &indexCallbacks, + unsigned indexOptions, CXTranslationUnit cxTU) + : Ctx(0), ClientData(clientData), CB(indexCallbacks), + IndexOptions(indexOptions), CXTU(cxTU) { } + + ASTContext &getASTContext() const { return *Ctx; } + + void setASTContext(ASTContext &ctx); + + void ppIncludedFile(SourceLocation hashLoc, + StringRef filename, const FileEntry *File, + bool isImport, bool isAngled); + + void ppMacroDefined(SourceLocation Loc, StringRef Name, + SourceLocation DefBegin, unsigned Length, + const void *OpaqueMacro); + + void ppMacroUndefined(SourceLocation Loc, StringRef Name, + const void *OpaqueMacro); + + void ppMacroExpanded(SourceLocation Loc, StringRef Name, + const void *OpaqueMacro); + + void invokeStartedTranslationUnit(); + + void invokeFinishedTranslationUnit(); + + void indexDecl(const Decl *D); + + void indexTagDecl(const TagDecl *D); + + void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent, + const DeclContext *DC = 0); + + void indexTypeLoc(TypeLoc TL, const NamedDecl *Parent, + const DeclContext *DC); + + void indexDeclContext(const DeclContext *DC); + + void indexBody(const Stmt *S, const DeclContext *DC); + + void handleDiagnostic(const StoredDiagnostic &StoredDiag); + + void handleFunction(const FunctionDecl *FD); + + void handleVar(const VarDecl *D); + + void handleField(const FieldDecl *D); + + void handleEnumerator(const EnumConstantDecl *D); + + void handleTagDecl(const TagDecl *D); + + void handleTypedef(const TypedefDecl *D); + + void handleObjCInterface(const ObjCInterfaceDecl *D); + + void defineObjCInterface(const ObjCInterfaceDecl *D); + + void handleObjCProtocol(const ObjCProtocolDecl *D); + + void handleObjCCategory(const ObjCCategoryDecl *D); + + void handleObjCMethod(const ObjCMethodDecl *D); + + void handleObjCProperty(const ObjCPropertyDecl *D); + + void handleReference(const NamedDecl *D, SourceLocation Loc, + const NamedDecl *Parent, + const DeclContext *DC, + const Expr *E = 0); + + void invokeStartedTagTypeDefinition(const TagDecl *D); + + void invokeStartedStatementBody(const NamedDecl *D, const DeclContext *DC); + + void invokeStartedObjCContainer(const ObjCContainerDecl *D); + + void invokeEndedContainer(const DeclContext *DC); + + bool isNotFromSourceFile(SourceLocation Loc) const; + + void indexTUDeclsInObjCContainer(); + void indexDeclGroupRef(DeclGroupRef DG); + + void addTUDeclInObjCContainer(DeclGroupRef DG) { + TUDeclsInObjCContainer.push_back(DG); + } + + void translateLoc(SourceLocation Loc, CXIdxFile *indexFile, CXFile *file, + unsigned *line, unsigned *column, unsigned *offset); + +private: + void addEntityInMap(const NamedDecl *D, CXIdxEntity entity); + + void addContainerInMap(const DeclContext *DC, CXIdxContainer container); + + CXIdxEntity getIndexEntity(const NamedDecl *D); + + const NamedDecl *getEntityDecl(const NamedDecl *D) const; + + CXIdxContainer getIndexContainer(const NamedDecl *D) const { + return getIndexContainerForDC(D->getDeclContext()); + } + + const DeclContext *getScopedContext(const DeclContext *DC) const; + CXIdxContainer getIndexContainerForDC(const DeclContext *DC) const; + + CXIdxFile getIndexFile(const FileEntry *File); + + CXIdxLoc getIndexLoc(SourceLocation Loc) const; + + void getIndexedEntityInfo(const NamedDecl *D, + CXIdxIndexedEntityInfo &IdxEntityInfo, + CXIdxEntityInfo &EntityInfo, + CXIdxIndexedDeclInfo &IdxDeclInfo, + StrAdapter &SA); + + void getIndexedDeclInfo(const NamedDecl *D, + CXIdxIndexedDeclInfo &IdxDeclInfo); + + void getIndexedRedeclInfo(const NamedDecl *D, + CXIdxIndexedRedeclInfo &RedeclInfo, + CXIdxIndexedDeclInfo &IdxDeclInfo); + + void getContainerInfo(const NamedDecl *D, + CXIdxContainerInfo &ContainerInfo); + + void getEntityInfo(const NamedDecl *D, + CXIdxEntityInfo &EntityInfo, + StrAdapter &SA); + + CXCursor getCursor(const NamedDecl *D) { + return cxcursor::MakeCXCursor(const_cast(D), CXTU); + } + + CXCursor getRefCursor(const NamedDecl *D, SourceLocation Loc); +}; + +}} // end clang::cxindex diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 989ed837ea..b452483129 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -129,6 +129,9 @@ clang_getTranslationUnitSpelling clang_getTypeDeclaration clang_getTypeKindSpelling clang_hashCursor +clang_indexLoc_getCXSourceLocation +clang_indexLoc_getFileLocation +clang_indexTranslationUnit clang_isAttribute clang_isConstQualifiedType clang_isCursorDefinition