From b670b9b849e8528e77dc65f67652c8513708f4f0 Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Wed, 12 Feb 2014 19:12:37 +0000 Subject: [PATCH] libclang: report error code for bad PCH files This commit improves libclang to report the error condition when CXTranslationUnit can not be created because of a stale PCH file. This allows the caller, for example, to rebuild the PCH file and retry the request. There two are APIs in libclang that return a CXTranslationUnit and don't support reporting detailed errors (the only error condition is a NULL result). For these APIs, a second, superior, version is introduced -- clang_createTranslationUnit2 and clang_parseTranslationUnit2. These functions return a CXTranslationUnit indirectly and also return an error code. Old functions are still supported and are nothing more than convenience wrappers that ignore extended error codes. As a cleanup, this commit also categorizes some libclang errors in the functions I had to modify anyway. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201249 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang-c/Index.h | 125 ++++++++-- .../Basic/DiagnosticSerializationKinds.td | 5 +- test/Index/pch-depending-on-deleted-module.c | 14 ++ test/Modules/fatal-module-loader-error.m | 2 +- tools/c-index-test/c-index-test.c | 236 +++++++++++------- tools/libclang/CIndex.cpp | 141 ++++++++--- tools/libclang/CXTranslationUnit.h | 4 + tools/libclang/Indexing.cpp | 38 ++- tools/libclang/libclang.exports | 2 + 9 files changed, 410 insertions(+), 157 deletions(-) create mode 100644 test/Index/pch-depending-on-deleted-module.c diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 0f15216900..ca34a8190a 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -30,7 +30,7 @@ * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. */ #define CINDEX_VERSION_MAJOR 0 -#define CINDEX_VERSION_MINOR 22 +#define CINDEX_VERSION_MINOR 23 #define CINDEX_VERSION_ENCODE(major, minor) ( \ ((major) * 10000) \ @@ -72,6 +72,43 @@ extern "C" { * @{ */ +/** + * \brief Error codes returned by libclang routines. + * + * Zero (\c CXError_Success) is the only error code indicating success. Other + * error codes, including not yet assigned non-zero values, indicate errors. + */ +enum CXErrorCode { + /** + * \brief No error. + */ + CXError_Success = 0, + + /** + * \brief A generic error code, no further details are available. + * + * Errors of this kind can get their own specific error codes in future + * libclang versions. + */ + CXError_Failure = 1, + + /** + * \brief libclang crashed while performing the requested operation. + */ + CXError_Crashed = 2, + + /** + * \brief The function detected that the arguments violate the function + * contract. + */ + CXError_InvalidArguments = 3, + + /** + * \brief An AST deserialization error has occurred. + */ + CXError_ASTReadError = 4 +}; + /** * \brief An "index" that consists of a set of translation units that would * typically be linked together into an executable or library. @@ -1076,10 +1113,27 @@ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( struct CXUnsavedFile *unsaved_files); /** - * \brief Create a translation unit from an AST file (-emit-ast). + * \brief Same as \c clang_createTranslationUnit2, but returns + * the \c CXTranslationUnit instead of an error code. In case of an error this + * routine returns a \c NULL \c CXTranslationUnit, without further detailed + * error codes. */ -CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit(CXIndex, - const char *ast_filename); +CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit( + CXIndex CIdx, + const char *ast_filename); + +/** + * \brief Create a translation unit from an AST file (\c -emit-ast). + * + * \param[out] out_TU A non-NULL pointer to store the created + * \c CXTranslationUnit. + * + * \returns Zero on success, otherwise returns an error code. + */ +CINDEX_LINKAGE enum CXErrorCode clang_createTranslationUnit2( + CXIndex CIdx, + const char *ast_filename, + CXTranslationUnit *out_TU); /** * \brief Flags that control the creation of translation units. @@ -1193,7 +1247,22 @@ enum CXTranslationUnit_Flags { * set of optimizations enabled may change from one version to the next. */ CINDEX_LINKAGE unsigned clang_defaultEditingTranslationUnitOptions(void); - + +/** + * \brief Same as \c clang_parseTranslationUnit2, but returns + * the \c CXTranslationUnit instead of an error code. In case of an error this + * routine returns a \c NULL \c CXTranslationUnit, without further detailed + * error codes. + */ +CINDEX_LINKAGE CXTranslationUnit +clang_parseTranslationUnit(CXIndex CIdx, + const char *source_filename, + const char *const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options); + /** * \brief Parse the given source file and the translation unit corresponding * to that file. @@ -1208,7 +1277,7 @@ CINDEX_LINKAGE unsigned clang_defaultEditingTranslationUnitOptions(void); * associated. * * \param source_filename The name of the source file to load, or NULL if the - * source file is included in \p command_line_args. + * source file is included in \c command_line_args. * * \param command_line_args The command-line arguments that would be * passed to the \c clang executable if it were being invoked out-of-process. @@ -1217,7 +1286,7 @@ CINDEX_LINKAGE unsigned clang_defaultEditingTranslationUnitOptions(void); * '-emit-ast', '-fsyntax-only' (which is the default), and '-o \'. * * \param num_command_line_args The number of command-line arguments in - * \p command_line_args. + * \c command_line_args. * * \param unsaved_files the files that have not yet been saved to disk * but may be required for parsing, including the contents of @@ -1232,18 +1301,22 @@ CINDEX_LINKAGE unsigned clang_defaultEditingTranslationUnitOptions(void); * is managed but not its compilation. This should be a bitwise OR of the * CXTranslationUnit_XXX flags. * - * \returns A new translation unit describing the parsed code and containing - * any diagnostics produced by the compiler. If there is a failure from which - * the compiler cannot recover, returns NULL. + * \param[out] out_TU A non-NULL pointer to store the created + * \c CXTranslationUnit, describing the parsed code and containing any + * diagnostics produced by the compiler. + * + * \returns Zero on success, otherwise returns an error code. */ -CINDEX_LINKAGE CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx, - const char *source_filename, - const char * const *command_line_args, - int num_command_line_args, - struct CXUnsavedFile *unsaved_files, - unsigned num_unsaved_files, - unsigned options); - +CINDEX_LINKAGE enum CXErrorCode +clang_parseTranslationUnit2(CXIndex CIdx, + const char *source_filename, + const char *const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options, + CXTranslationUnit *out_TU); + /** * \brief Flags that control how translation units are saved. * @@ -1395,10 +1468,11 @@ CINDEX_LINKAGE unsigned clang_defaultReparseOptions(CXTranslationUnit TU); * The function \c clang_defaultReparseOptions() produces a default set of * options recommended for most uses, based on the translation unit. * - * \returns 0 if the sources could be reparsed. A non-zero value will be + * \returns 0 if the sources could be reparsed. A non-zero error code will be * returned if reparsing was impossible, such that the translation unit is - * invalid. In such cases, the only valid call for \p TU is - * \c clang_disposeTranslationUnit(TU). + * invalid. In such cases, the only valid call for \c TU is + * \c clang_disposeTranslationUnit(TU). The error codes returned by this + * routine are described by the \c CXErrorCode enum. */ CINDEX_LINKAGE int clang_reparseTranslationUnit(CXTranslationUnit TU, unsigned num_unsaved_files, @@ -5789,11 +5863,12 @@ typedef enum { * \param index_options A bitmask of options that affects how indexing is * performed. This should be a bitwise OR of the CXIndexOpt_XXX flags. * - * \param out_TU [out] pointer to store a CXTranslationUnit that can be reused - * after indexing is finished. Set to NULL if you do not require it. + * \param[out] out_TU pointer to store a \c CXTranslationUnit that can be + * reused after indexing is finished. Set to \c NULL if you do not require it. * - * \returns If there is a failure from which the there is no recovery, returns - * non-zero, otherwise returns 0. + * \returns 0 on success or if there were errors from which the compiler could + * recover. If there is a failure from which the there is no recovery, returns + * a non-zero \c CXErrorCode. * * The rest of the parameters are the same as #clang_parseTranslationUnit. */ diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td index 2c58b61683..57ba0a4bcb 100644 --- a/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/include/clang/Basic/DiagnosticSerializationKinds.td @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// let Component = "Serialization" in { +let CategoryName = "AST Deserialization Issue" in { def err_fe_unable_to_read_pch_file : Error< "unable to read PCH file %0: '%1'">; @@ -78,4 +79,6 @@ def note_module_odr_violation_no_possible_decls : Note< def note_module_odr_violation_possible_decl : Note< "declaration of %0 does not match">; -} +} // let CategoryName +} // let Component + diff --git a/test/Index/pch-depending-on-deleted-module.c b/test/Index/pch-depending-on-deleted-module.c new file mode 100644 index 0000000000..223b6361a8 --- /dev/null +++ b/test/Index/pch-depending-on-deleted-module.c @@ -0,0 +1,14 @@ +#include "a.h" + +// RUN: rm -rf %t +// RUN: mkdir %t + +// RUN: %clang_cc1 -x c-header -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -emit-pch -I %S/Inputs/Headers -o %t/use_LibA.pch %s +// RUN: %clang_cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -verify-pch %t/use_LibA.pch +// RUN: rm -f %t/modules-cache/LibA.pcm +// RUN: not %clang_cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=modules-cache -verify-pch %t/use_LibA.pch 2>&1 | FileCheck -check-prefix=VERIFY %s +// RUN: not c-index-test -test-load-source all -x c -fmodules -fdisable-module-hash -fmodules-cache-path=modules-cache -include-pch %t/use_LibA.pch %s 2>&1 | FileCheck -check-prefix=INDEX %s + +// VERIFY: fatal error: malformed or corrupted AST file: 'Unable to load module +// INDEX: {{^}}Failure: AST deserialization error occurred{{$}} + diff --git a/test/Modules/fatal-module-loader-error.m b/test/Modules/fatal-module-loader-error.m index 6af3b4c7c3..2d8dd24e51 100644 --- a/test/Modules/fatal-module-loader-error.m +++ b/test/Modules/fatal-module-loader-error.m @@ -23,4 +23,4 @@ // Also check that libclang does not create a PCH with such an error. // RUN: not c-index-test -write-pch %t.pch -fmodules -fmodules-cache-path=%t \ // RUN: %s -Xclang -fdisable-module-hash -F %S/Inputs 2>&1 | FileCheck %s -// CHECK: Unable to write PCH file +// CHECK: {{^}}Failure: AST deserialization error occurred{{$}} diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 7f5bf4c2ed..8895371d55 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -79,8 +79,33 @@ static unsigned getDefaultParsingOptions() { return options; } +/// \brief Returns 0 in case of success, non-zero in case of a failure. static int checkForErrors(CXTranslationUnit TU); +static void describeLibclangFailure(enum CXErrorCode Err) { + switch (Err) { + case CXError_Success: + fprintf(stderr, "Success\n"); + return; + + case CXError_Failure: + fprintf(stderr, "Failure (no details available)\n"); + return; + + case CXError_Crashed: + fprintf(stderr, "Failure: libclang crashed\n"); + return; + + case CXError_InvalidArguments: + fprintf(stderr, "Failure: invalid arguments passed to a libclang routine\n"); + return; + + case CXError_ASTReadError: + fprintf(stderr, "Failure: AST deserialization error occurred\n"); + return; + } +} + static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column, unsigned end_line, unsigned end_column) { fprintf(out, "[%d:%d - %d:%d]", begin_line, begin_column, @@ -89,10 +114,11 @@ static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column, static unsigned CreateTranslationUnit(CXIndex Idx, const char *file, CXTranslationUnit *TU) { - - *TU = clang_createTranslationUnit(Idx, file); - if (!*TU) { + enum CXErrorCode Err = clang_createTranslationUnit2(Idx, file, TU); + if (Err != CXError_Success) { fprintf(stderr, "Unable to load translation unit from '%s'!\n", file); + describeLibclangFailure(Err); + *TU = 0; return 0; } return 1; @@ -1420,8 +1446,9 @@ int perform_test_load_source(int argc, const char **argv, const char *CommentSchemaFile; struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; + enum CXErrorCode Err; int result; - + Idx = clang_createIndex(/* excludeDeclsFromPCH */ (!strcmp(filter, "local") || !strcmp(filter, "local-display"))? 1 : 0, @@ -1437,13 +1464,14 @@ int perform_test_load_source(int argc, const char **argv, return -1; } - TU = clang_parseTranslationUnit(Idx, 0, - argv + num_unsaved_files, - argc - num_unsaved_files, - unsaved_files, num_unsaved_files, - getDefaultParsingOptions()); - if (!TU) { + Err = clang_parseTranslationUnit2(Idx, 0, + argv + num_unsaved_files, + argc - num_unsaved_files, + unsaved_files, num_unsaved_files, + getDefaultParsingOptions(), &TU); + if (Err != CXError_Success) { fprintf(stderr, "Unable to load translation unit!\n"); + describeLibclangFailure(Err); free_remapped_files(unsaved_files, num_unsaved_files); clang_disposeIndex(Idx); return 1; @@ -1464,6 +1492,7 @@ int perform_test_reparse_source(int argc, const char **argv, int trials, struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; int compiler_arg_idx = 0; + enum CXErrorCode Err; int result, i; int trial; int remap_after_trial = 0; @@ -1489,12 +1518,13 @@ int perform_test_reparse_source(int argc, const char **argv, int trials, /* Load the initial translation unit -- we do this without honoring remapped * files, so that we have a way to test results after changing the source. */ - TU = clang_parseTranslationUnit(Idx, 0, - argv + compiler_arg_idx, - argc - compiler_arg_idx, - 0, 0, getDefaultParsingOptions()); - if (!TU) { + Err = clang_parseTranslationUnit2(Idx, 0, + argv + compiler_arg_idx, + argc - compiler_arg_idx, + 0, 0, getDefaultParsingOptions(), &TU); + if (Err != CXError_Success) { fprintf(stderr, "Unable to load translation unit!\n"); + describeLibclangFailure(Err); free_remapped_files(unsaved_files, num_unsaved_files); clang_disposeIndex(Idx); return 1; @@ -1517,11 +1547,14 @@ int perform_test_reparse_source(int argc, const char **argv, int trials, return -1; } - if (clang_reparseTranslationUnit(TU, - trial >= remap_after_trial ? num_unsaved_files : 0, - trial >= remap_after_trial ? unsaved_files : 0, - clang_defaultReparseOptions(TU))) { + Err = clang_reparseTranslationUnit( + TU, + trial >= remap_after_trial ? num_unsaved_files : 0, + trial >= remap_after_trial ? unsaved_files : 0, + clang_defaultReparseOptions(TU)); + if (Err != CXError_Success) { fprintf(stderr, "Unable to reparse translation unit!\n"); + describeLibclangFailure(Err); clang_disposeTranslationUnit(TU); free_remapped_files(unsaved_files, num_unsaved_files); clang_disposeIndex(Idx); @@ -1943,7 +1976,8 @@ int perform_code_completion(int argc, const char **argv, int timing_only) { struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; CXCodeCompleteResults *results = 0; - CXTranslationUnit TU = 0; + enum CXErrorCode Err; + CXTranslationUnit TU; unsigned I, Repeats = 1; unsigned completionOptions = clang_defaultCodeCompleteOptions(); @@ -1968,21 +2002,27 @@ int perform_code_completion(int argc, const char **argv, int timing_only) { if (getenv("CINDEXTEST_EDITING")) Repeats = 5; - - TU = clang_parseTranslationUnit(CIdx, 0, - argv + num_unsaved_files + 2, - argc - num_unsaved_files - 2, - 0, 0, getDefaultParsingOptions()); - if (!TU) { + + Err = clang_parseTranslationUnit2(CIdx, 0, + argv + num_unsaved_files + 2, + argc - num_unsaved_files - 2, + 0, 0, getDefaultParsingOptions(), &TU); + if (Err != CXError_Success) { fprintf(stderr, "Unable to load translation unit!\n"); + describeLibclangFailure(Err); return 1; } - if (clang_reparseTranslationUnit(TU, 0, 0, clang_defaultReparseOptions(TU))) { + Err = clang_reparseTranslationUnit(TU, 0, 0, + clang_defaultReparseOptions(TU)); + + if (Err != CXError_Success) { fprintf(stderr, "Unable to reparse translation init!\n"); + describeLibclangFailure(Err); + clang_disposeTranslationUnit(TU); return 1; } - + for (I = 0; I != Repeats; ++I) { results = clang_codeCompleteAt(TU, filename, line, column, unsaved_files, num_unsaved_files, @@ -2069,6 +2109,7 @@ static int inspect_cursor_at(int argc, const char **argv) { int errorCode; struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; + enum CXErrorCode Err; CXTranslationUnit TU; CXCursor Cursor; CursorSourceLocation *Locations = 0; @@ -2102,15 +2143,15 @@ static int inspect_cursor_at(int argc, const char **argv) { /* 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) { + Err = clang_parseTranslationUnit2(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(), &TU); + if (Err != CXError_Success) { fprintf(stderr, "unable to parse input\n"); + describeLibclangFailure(Err); return -1; } @@ -2118,11 +2159,14 @@ static int inspect_cursor_at(int argc, const char **argv) { 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; + if (Repeats > 1) { + Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files, + clang_defaultReparseOptions(TU)); + if (Err != CXError_Success) { + describeLibclangFailure(Err); + clang_disposeTranslationUnit(TU); + return 1; + } } if (checkForErrors(TU) != 0) @@ -2235,6 +2279,7 @@ static int find_file_refs_at(int argc, const char **argv) { int errorCode; struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; + enum CXErrorCode Err; CXTranslationUnit TU; CXCursor Cursor; CursorSourceLocation *Locations = 0; @@ -2268,15 +2313,16 @@ static int find_file_refs_at(int argc, const char **argv) { /* 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) { + Err = clang_parseTranslationUnit2(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(), &TU); + if (Err != CXError_Success) { fprintf(stderr, "unable to parse input\n"); + describeLibclangFailure(Err); + clang_disposeTranslationUnit(TU); return -1; } @@ -2284,11 +2330,14 @@ static int find_file_refs_at(int argc, const char **argv) { 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; + if (Repeats > 1) { + Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files, + clang_defaultReparseOptions(TU)); + if (Err != CXError_Success) { + describeLibclangFailure(Err); + clang_disposeTranslationUnit(TU); + return 1; + } } if (checkForErrors(TU) != 0) @@ -2339,6 +2388,7 @@ static int find_file_includes_in(int argc, const char **argv) { CXIndex CIdx; struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; + enum CXErrorCode Err; CXTranslationUnit TU; const char **Filenames = 0; unsigned NumFilenames = 0; @@ -2368,15 +2418,17 @@ static int find_file_includes_in(int argc, const char **argv) { /* 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 + NumFilenames, - argc - num_unsaved_files - 2 - NumFilenames, - unsaved_files, - Repeats > 1? 0 : num_unsaved_files, - getDefaultParsingOptions()); - - if (!TU) { + Err = clang_parseTranslationUnit2( + CIdx, argv[argc - 1], + argv + num_unsaved_files + 1 + NumFilenames, + argc - num_unsaved_files - 2 - NumFilenames, + unsaved_files, + Repeats > 1 ? 0 : num_unsaved_files, getDefaultParsingOptions(), &TU); + + if (Err != CXError_Success) { fprintf(stderr, "unable to parse input\n"); + describeLibclangFailure(Err); + clang_disposeTranslationUnit(TU); return -1; } @@ -2384,11 +2436,14 @@ static int find_file_includes_in(int argc, const char **argv) { 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; + if (Repeats > 1) { + Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files, + clang_defaultReparseOptions(TU)); + if (Err != CXError_Success) { + describeLibclangFailure(Err); + clang_disposeTranslationUnit(TU); + return 1; + } } if (checkForErrors(TU) != 0) @@ -2933,6 +2988,9 @@ static int index_compile_args(int num_args, const char **args, &IndexCB,sizeof(IndexCB), index_opts, 0, args, num_args, 0, 0, 0, getDefaultParsingOptions()); + if (result != CXError_Success) + describeLibclangFailure(result); + if (index_data.fail_for_error) result = -1; @@ -3185,6 +3243,7 @@ int perform_token_annotation(int argc, const char **argv) { CXFile file = 0; CXCursor *cursors = 0; CXSourceRangeList *skipped_ranges = 0; + enum CXErrorCode Err; unsigned i; input += strlen("-test-annotate-tokens="); @@ -3198,14 +3257,15 @@ int perform_token_annotation(int argc, const char **argv) { } CIdx = clang_createIndex(0, 1); - TU = clang_parseTranslationUnit(CIdx, argv[argc - 1], - argv + num_unsaved_files + 2, - argc - num_unsaved_files - 3, - unsaved_files, - num_unsaved_files, - getDefaultParsingOptions()); - if (!TU) { + Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1], + argv + num_unsaved_files + 2, + argc - num_unsaved_files - 3, + unsaved_files, + num_unsaved_files, + getDefaultParsingOptions(), &TU); + if (Err != CXError_Success) { fprintf(stderr, "unable to parse input\n"); + describeLibclangFailure(Err); clang_disposeIndex(CIdx); free(filename); free_remapped_files(unsaved_files, num_unsaved_files); @@ -3220,9 +3280,11 @@ int perform_token_annotation(int argc, const char **argv) { if (getenv("CINDEXTEST_EDITING")) { for (i = 0; i < 5; ++i) { - if (clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files, - clang_defaultReparseOptions(TU))) { + Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files, + clang_defaultReparseOptions(TU)); + if (Err != CXError_Success) { fprintf(stderr, "Unable to reparse translation unit!\n"); + describeLibclangFailure(Err); errorCode = -1; goto teardown; } @@ -3586,6 +3648,7 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) { CXTranslationUnit TU; struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; + enum CXErrorCode Err; int result = 0; Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnostics=*/1); @@ -3594,18 +3657,19 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) { clang_disposeIndex(Idx); return -1; } - - TU = clang_parseTranslationUnit(Idx, 0, - argv + num_unsaved_files, - argc - num_unsaved_files, - unsaved_files, - num_unsaved_files, - CXTranslationUnit_Incomplete | - CXTranslationUnit_DetailedPreprocessingRecord| - CXTranslationUnit_ForSerialization); - if (!TU) { + + Err = clang_parseTranslationUnit2( + Idx, 0, argv + num_unsaved_files, argc - num_unsaved_files, + unsaved_files, num_unsaved_files, + CXTranslationUnit_Incomplete | + CXTranslationUnit_DetailedPreprocessingRecord | + CXTranslationUnit_ForSerialization, + &TU); + if (Err != CXError_Success) { fprintf(stderr, "Unable to load translation unit!\n"); + describeLibclangFailure(Err); free_remapped_files(unsaved_files, num_unsaved_files); + clang_disposeTranslationUnit(TU); clang_disposeIndex(Idx); return 1; } diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index fad9612623..bb21285cda 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -25,6 +25,8 @@ #include "clang/AST/Attr.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticCategories.h" +#include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/Version.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" @@ -34,6 +36,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Serialization/SerializationDiagnostic.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -62,6 +65,7 @@ using namespace clang::cxindex; CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *AU) { if (!AU) return 0; + assert(CIdx); CXTranslationUnit D = new CXTranslationUnitImpl(); D->CIdx = CIdx; D->TheASTUnit = AU; @@ -72,6 +76,18 @@ CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *AU) { return D; } +bool cxtu::isASTReadError(ASTUnit *AU) { + for (ASTUnit::stored_diag_iterator D = AU->stored_diag_begin(), + DEnd = AU->stored_diag_end(); + D != DEnd; ++D) { + if (D->getLevel() >= DiagnosticsEngine::Error && + DiagnosticIDs::getCategoryNumberForDiag(D->getID()) == + diag::DiagCat_AST_Deserialization_Issue) + return true; + } + return false; +} + cxtu::CXTUOwner::~CXTUOwner() { if (TU) clang_disposeTranslationUnit(TU); @@ -2589,11 +2605,22 @@ void clang_toggleCrashRecovery(unsigned isEnabled) { else llvm::CrashRecoveryContext::Disable(); } - + CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, const char *ast_filename) { - if (!CIdx || !ast_filename) - return 0; + CXTranslationUnit TU; + enum CXErrorCode Result = + clang_createTranslationUnit2(CIdx, ast_filename, &TU); + assert((TU && Result == CXError_Success) || + (!TU && Result != CXError_Success)); + return TU; +} + +enum CXErrorCode clang_createTranslationUnit2(CXIndex CIdx, + const char *ast_filename, + CXTranslationUnit *out_TU) { + if (!CIdx || !ast_filename || !out_TU) + return CXError_InvalidArguments; LOG_FUNC_SECTION { *Log << ast_filename; @@ -2603,19 +2630,20 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, FileSystemOptions FileSystemOpts; IntrusiveRefCntPtr Diags; - ASTUnit *TU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts, + ASTUnit *AU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts, CXXIdx->getOnlyLocalDecls(), None, /*CaptureDiagnostics=*/true, /*AllowPCHWithCompilerErrors=*/true, /*UserFilesAreVolatile=*/true); - return MakeCXTranslationUnit(CXXIdx, TU); + *out_TU = MakeCXTranslationUnit(CXXIdx, AU); + return *out_TU ? CXError_Success : CXError_Failure; } unsigned clang_defaultEditingTranslationUnitOptions() { return CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_CacheCompletionResults; } - + CXTranslationUnit clang_createTranslationUnitFromSourceFile(CXIndex CIdx, const char *source_filename, @@ -2638,7 +2666,8 @@ struct ParseTranslationUnitInfo { struct CXUnsavedFile *unsaved_files; unsigned num_unsaved_files; unsigned options; - CXTranslationUnit result; + CXTranslationUnit *out_TU; + CXErrorCode result; }; static void clang_parseTranslationUnit_Impl(void *UserData) { ParseTranslationUnitInfo *PTUI = @@ -2650,10 +2679,18 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { struct CXUnsavedFile *unsaved_files = PTUI->unsaved_files; unsigned num_unsaved_files = PTUI->num_unsaved_files; unsigned options = PTUI->options; - PTUI->result = 0; + CXTranslationUnit *out_TU = PTUI->out_TU; - if (!CIdx) + // Check arguments. + if (!CIdx || !out_TU || + (unsaved_files == NULL && num_unsaved_files != 0)) { + PTUI->result = CXError_InvalidArguments; return; + } + + // Set up the initial return values. + *out_TU = NULL; + PTUI->result = CXError_Failure; CIndexer *CXXIdx = static_cast(CIdx); @@ -2763,15 +2800,40 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { printDiagsToStderr(Unit ? Unit.get() : ErrUnit.get()); } - PTUI->result = MakeCXTranslationUnit(CXXIdx, Unit.take()); + if (isASTReadError(Unit ? Unit.get() : ErrUnit.get())) { + PTUI->result = CXError_ASTReadError; + } else { + *PTUI->out_TU = MakeCXTranslationUnit(CXXIdx, Unit.take()); + PTUI->result = *PTUI->out_TU ? CXError_Success : CXError_Failure; + } } -CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx, - const char *source_filename, - const char * const *command_line_args, - int num_command_line_args, - struct CXUnsavedFile *unsaved_files, - unsigned num_unsaved_files, - unsigned options) { + +CXTranslationUnit +clang_parseTranslationUnit(CXIndex CIdx, + const char *source_filename, + const char *const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options) { + CXTranslationUnit TU; + enum CXErrorCode Result = clang_parseTranslationUnit2( + CIdx, source_filename, command_line_args, num_command_line_args, + unsaved_files, num_unsaved_files, options, &TU); + assert((TU && Result == CXError_Success) || + (!TU && Result != CXError_Success)); + return TU; +} + +enum CXErrorCode clang_parseTranslationUnit2( + CXIndex CIdx, + const char *source_filename, + const char *const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options, + CXTranslationUnit *out_TU) { LOG_FUNC_SECTION { *Log << source_filename << ": "; for (int i = 0; i != num_command_line_args; ++i) @@ -2780,7 +2842,8 @@ CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx, ParseTranslationUnitInfo PTUI = { CIdx, source_filename, command_line_args, num_command_line_args, unsaved_files, - num_unsaved_files, options, 0 }; + num_unsaved_files, options, out_TU, + CXError_Failure }; llvm::CrashRecoveryContext CRC; if (!RunSafely(CRC, clang_parseTranslationUnit_Impl, &PTUI)) { @@ -2803,10 +2866,11 @@ CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx, fprintf(stderr, "],\n"); fprintf(stderr, " 'options' : %d,\n", options); fprintf(stderr, "}\n"); - - return 0; + + return CXError_Crashed; } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { - PrintLibclangResourceUsage(PTUI.result); + if (CXTranslationUnit *TU = PTUI.out_TU) + PrintLibclangResourceUsage(*TU); } return PTUI.result; @@ -2891,7 +2955,8 @@ void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) { if (CTUnit) { // If the translation unit has been marked as unsafe to free, just discard // it. - if (cxtu::getASTUnit(CTUnit)->isUnsafeToFree()) + ASTUnit *Unit = cxtu::getASTUnit(CTUnit); + if (Unit && Unit->isUnsafeToFree()) return; delete cxtu::getASTUnit(CTUnit); @@ -2918,11 +2983,22 @@ struct ReparseTranslationUnitInfo { static void clang_reparseTranslationUnit_Impl(void *UserData) { ReparseTranslationUnitInfo *RTUI = static_cast(UserData); - RTUI->result = 1; // Error. + RTUI->result = CXError_Failure; CXTranslationUnit TU = RTUI->TU; + unsigned num_unsaved_files = RTUI->num_unsaved_files; + struct CXUnsavedFile *unsaved_files = RTUI->unsaved_files; + unsigned options = RTUI->options; + (void) options; + + // Check arguments. if (isNotUsableTU(TU)) { LOG_BAD_TU(TU); + RTUI->result = CXError_InvalidArguments; + return; + } + if (unsaved_files == NULL && num_unsaved_files != 0) { + RTUI->result = CXError_InvalidArguments; return; } @@ -2930,11 +3006,6 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) { delete static_cast(TU->Diagnostics); TU->Diagnostics = 0; - unsigned num_unsaved_files = RTUI->num_unsaved_files; - struct CXUnsavedFile *unsaved_files = RTUI->unsaved_files; - unsigned options = RTUI->options; - (void) options; - CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) setThreadBackgroundPriority(); @@ -2956,9 +3027,11 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) { RemappedFiles->push_back(std::make_pair(unsaved_files[I].Filename, Buffer)); } - + if (!CXXUnit->Reparse(*RemappedFiles.get())) - RTUI->result = 0; + RTUI->result = CXError_Success; + else if (isASTReadError(CXXUnit)) + RTUI->result = CXError_ASTReadError; } int clang_reparseTranslationUnit(CXTranslationUnit TU, @@ -2970,7 +3043,7 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU, } ReparseTranslationUnitInfo RTUI = { TU, num_unsaved_files, unsaved_files, - options, 0 }; + options, CXError_Failure }; if (getenv("LIBCLANG_NOTHREADS")) { clang_reparseTranslationUnit_Impl(&RTUI); @@ -2982,7 +3055,7 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU, if (!RunSafely(CRC, clang_reparseTranslationUnit_Impl, &RTUI)) { fprintf(stderr, "libclang: crash detected during reparsing\n"); cxtu::getASTUnit(TU)->setUnsafeToFree(true); - return 1; + return CXError_Crashed; } else if (getenv("LIBCLANG_RESOURCE_USAGE")) PrintLibclangResourceUsage(TU); @@ -6747,9 +6820,9 @@ Logger &cxindex::Logger::operator<<(CXTranslationUnit TU) { LogOS << " (" << Unit->getASTFileName() << ')'; return *this; } + } else { + LogOS << ""; } - - LogOS << ""; return *this; } diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h index 8639570697..0dbb0024b2 100644 --- a/tools/libclang/CXTranslationUnit.h +++ b/tools/libclang/CXTranslationUnit.h @@ -46,6 +46,10 @@ static inline ASTUnit *getASTUnit(CXTranslationUnit TU) { return TU->TheASTUnit; } +/// \returns true if the ASTUnit has a diagnostic about the AST file being +/// corrupted. +bool isASTReadError(ASTUnit *AU); + static inline bool isNotUsableTU(CXTranslationUnit TU) { return !TU; } diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp index dc7a0c0714..9b83aa00e9 100644 --- a/tools/libclang/Indexing.cpp +++ b/tools/libclang/Indexing.cpp @@ -514,16 +514,22 @@ static void clang_indexSourceFile_Impl(void *UserData) { 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. - + + // Set up the initial return value. + ITUI->result = CXError_Failure; + if (out_TU) *out_TU = 0; - bool requestedToGetTU = (out_TU != 0); + bool requestedToGetTU = (out_TU != 0); - if (!cxIdxAction) + if (!cxIdxAction) { + ITUI->result = CXError_InvalidArguments; return; - if (!client_index_callbacks || index_callbacks_size == 0) + } + if (!client_index_callbacks || index_callbacks_size == 0) { + ITUI->result = CXError_InvalidArguments; return; + } IndexerCallbacks CB; memset(&CB, 0, sizeof(CB)); @@ -671,13 +677,18 @@ static void clang_indexSourceFile_Impl(void *UserData) { if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics()) printDiagsToStderr(Unit); + if (isASTReadError(Unit)) { + ITUI->result = CXError_ASTReadError; + return; + } + if (!Success) return; if (out_TU) *out_TU = CXTU->takeTU(); - ITUI->result = 0; // success. + ITUI->result = CXError_Success; } //===----------------------------------------------------------------------===// @@ -754,14 +765,20 @@ static void clang_indexTranslationUnit_Impl(void *UserData) { IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks; unsigned index_callbacks_size = ITUI->index_callbacks_size; unsigned index_options = ITUI->index_options; - ITUI->result = 1; // init as error. + // Set up the initial return value. + ITUI->result = CXError_Failure; + + // Check arguments. if (isNotUsableTU(TU)) { LOG_BAD_TU(TU); + ITUI->result = CXError_InvalidArguments; return; } - if (!client_index_callbacks || index_callbacks_size == 0) + if (!client_index_callbacks || index_callbacks_size == 0) { + ITUI->result = CXError_InvalidArguments; return; + } CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) @@ -809,7 +826,7 @@ static void clang_indexTranslationUnit_Impl(void *UserData) { indexTranslationUnit(*Unit, *IndexCtx); indexDiagnostics(TU, *IndexCtx); - ITUI->result = 0; + ITUI->result = CXError_Success; } //===----------------------------------------------------------------------===// @@ -981,7 +998,8 @@ int clang_indexSourceFile(CXIndexAction idxAction, index_callbacks_size, index_options, source_filename, command_line_args, num_command_line_args, unsaved_files, - num_unsaved_files, out_TU, TU_options, 0 }; + num_unsaved_files, out_TU, TU_options, + CXError_Failure }; if (getenv("LIBCLANG_NOTHREADS")) { clang_indexSourceFile_Impl(&ITUI); diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 975993adb3..0fd63d3113 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -87,6 +87,7 @@ clang_constructUSR_ObjCProtocol clang_createCXCursorSet clang_createIndex clang_createTranslationUnit +clang_createTranslationUnit2 clang_createTranslationUnitFromSourceFile clang_defaultCodeCompleteOptions clang_defaultDiagnosticDisplayOptions @@ -262,6 +263,7 @@ clang_loadDiagnostics clang_Location_isInSystemHeader clang_Location_isFromMainFile clang_parseTranslationUnit +clang_parseTranslationUnit2 clang_remap_dispose clang_remap_getFilenames clang_remap_getNumFiles -- 2.40.0