summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 11:06:01 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 11:06:01 +0000
commit486754660bb926339aefcf012a3f848592babb8b (patch)
treeecdbc446c9876f4f120f701c243373cd3cb43db3 /tools
parent55e6d896ad333f07bb3b1ba487df214fc268a4ab (diff)
Notes
Diffstat (limited to 'tools')
-rw-r--r--tools/c-index-test/CMakeLists.txt6
-rw-r--r--tools/c-index-test/c-index-test.c249
-rw-r--r--tools/c-index-test/core_main.cpp59
-rw-r--r--tools/clang-check/ClangCheck.cpp8
-rw-r--r--tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs2
-rw-r--r--tools/clang-format-vs/ClangFormat/license.txt2
-rw-r--r--tools/clang-format/ClangFormat.cpp51
-rw-r--r--tools/clang-format/clang-format.el2
-rw-r--r--tools/clang-format/fuzzer/ClangFormatFuzzer.cpp2
-rwxr-xr-xtools/clang-format/git-clang-format1
-rw-r--r--tools/clang-fuzzer/CMakeLists.txt59
-rw-r--r--tools/clang-fuzzer/ClangFuzzer.cpp2
-rw-r--r--tools/clang-fuzzer/ExampleClangLLVMProtoFuzzer.cpp28
-rw-r--r--tools/clang-fuzzer/ExampleClangLoopProtoFuzzer.cpp30
-rw-r--r--tools/clang-fuzzer/ExampleClangProtoFuzzer.cpp22
-rw-r--r--tools/clang-fuzzer/cxx_loop_proto.proto80
-rw-r--r--tools/clang-fuzzer/cxx_proto.proto2
-rw-r--r--tools/clang-fuzzer/fuzzer-initialize/CMakeLists.txt3
-rw-r--r--tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp65
-rw-r--r--tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.h19
-rw-r--r--tools/clang-fuzzer/handle-cxx/handle_cxx.cpp6
-rw-r--r--tools/clang-fuzzer/handle-llvm/CMakeLists.txt30
-rw-r--r--tools/clang-fuzzer/handle-llvm/handle_llvm.cpp178
-rw-r--r--tools/clang-fuzzer/handle-llvm/handle_llvm.h25
-rw-r--r--tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt14
-rw-r--r--tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx.cpp131
-rw-r--r--tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx_main.cpp31
-rw-r--r--tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.cpp2
-rw-r--r--tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.h4
-rw-r--r--tools/clang-fuzzer/proto-to-llvm/CMakeLists.txt14
-rw-r--r--tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.cpp156
-rw-r--r--tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.h23
-rw-r--r--tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm_main.cpp31
-rw-r--r--tools/clang-import-test/CMakeLists.txt6
-rw-r--r--tools/clang-import-test/clang-import-test.cpp24
-rw-r--r--tools/clang-offload-bundler/ClangOffloadBundler.cpp39
-rw-r--r--tools/clang-refactor/CMakeLists.txt2
-rw-r--r--tools/clang-refactor/ClangRefactor.cpp2
-rw-r--r--tools/clang-refactor/TestSupport.cpp2
-rw-r--r--tools/clang-refactor/TestSupport.h2
-rw-r--r--tools/clang-rename/CMakeLists.txt4
-rw-r--r--tools/clang-rename/ClangRename.cpp6
-rw-r--r--tools/diagtool/CMakeLists.txt14
-rw-r--r--tools/diagtool/DiagTool.cpp2
-rw-r--r--tools/diagtool/DiagnosticNames.h6
-rw-r--r--tools/driver/CMakeLists.txt24
-rw-r--r--tools/driver/cc1_main.cpp25
-rw-r--r--tools/driver/cc1as_main.cpp87
-rw-r--r--tools/driver/cc1gen_reproducer_main.cpp196
-rw-r--r--tools/driver/driver.cpp40
-rw-r--r--tools/libclang/BuildSystem.cpp5
-rw-r--r--tools/libclang/CIndex.cpp344
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp97
-rw-r--r--tools/libclang/CIndexDiagnostic.h42
-rw-r--r--tools/libclang/CIndexHigh.cpp4
-rw-r--r--tools/libclang/CIndexer.cpp14
-rw-r--r--tools/libclang/CIndexer.h22
-rw-r--r--tools/libclang/CLog.h4
-rw-r--r--tools/libclang/CMakeLists.txt2
-rw-r--r--tools/libclang/CXCursor.cpp20
-rw-r--r--tools/libclang/CXCursor.h80
-rw-r--r--tools/libclang/CXIndexDataConsumer.cpp37
-rw-r--r--tools/libclang/CXIndexDataConsumer.h13
-rw-r--r--tools/libclang/CXLoadedDiagnostic.cpp2
-rw-r--r--tools/libclang/CXLoadedDiagnostic.h22
-rw-r--r--tools/libclang/CXSourceLocation.h8
-rw-r--r--tools/libclang/CXString.cpp2
-rw-r--r--tools/libclang/CXString.h20
-rw-r--r--tools/libclang/CXType.cpp46
-rw-r--r--tools/libclang/CursorVisitor.h24
-rw-r--r--tools/libclang/Index_Internal.h8
-rw-r--r--tools/libclang/Indexing.cpp25
-rw-r--r--tools/libclang/libclang.exports11
-rw-r--r--tools/scan-build-py/README.md32
-rw-r--r--tools/scan-build-py/libscanbuild/__init__.py3
-rw-r--r--tools/scan-build-py/libscanbuild/analyze.py285
-rw-r--r--tools/scan-build-py/libscanbuild/arguments.py78
-rw-r--r--tools/scan-build-py/libscanbuild/clang.py27
-rw-r--r--tools/scan-build-py/libscanbuild/report.py22
-rw-r--r--tools/scan-build-py/tests/unit/test_analyze.py84
-rw-r--r--tools/scan-build-py/tests/unit/test_clang.py12
-rwxr-xr-xtools/scan-build/bin/scan-build28
-rwxr-xr-xtools/scan-build/libexec/ccc-analyzer4
-rw-r--r--tools/scan-build/man/scan-build.14
-rw-r--r--tools/scan-view/share/startfile.py6
85 files changed, 2740 insertions, 515 deletions
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index d38c7bb28709..53e3421f1b35 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -40,7 +40,11 @@ set_target_properties(c-index-test
# If libxml2 is available, make it available for c-index-test.
if (CLANG_HAVE_LIBXML)
- include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR})
+ if ((CMAKE_OSX_SYSROOT) AND (EXISTS ${CMAKE_OSX_SYSROOT}/${LIBXML2_INCLUDE_DIR}))
+ include_directories(SYSTEM ${CMAKE_OSX_SYSROOT}/${LIBXML2_INCLUDE_DIR})
+ else()
+ include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR})
+ endif()
target_link_libraries(c-index-test PRIVATE ${LIBXML2_LIBRARIES})
endif()
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 99f05669b64c..70ab11866edd 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -64,7 +64,7 @@ extern char *basename(const char *);
extern char *dirname(char *);
#endif
-/** \brief Return the default parsing options. */
+/** Return the default parsing options. */
static unsigned getDefaultParsingOptions() {
unsigned options = CXTranslationUnit_DetailedPreprocessingRecord;
@@ -82,11 +82,76 @@ static unsigned getDefaultParsingOptions() {
options |= CXTranslationUnit_CreatePreambleOnFirstParse;
if (getenv("CINDEXTEST_KEEP_GOING"))
options |= CXTranslationUnit_KeepGoing;
+ if (getenv("CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE"))
+ options |= CXTranslationUnit_LimitSkipFunctionBodiesToPreamble;
return options;
}
-/** \brief Returns 0 in case of success, non-zero in case of a failure. */
+static void ModifyPrintingPolicyAccordingToEnv(CXPrintingPolicy Policy) {
+ struct Mapping {
+ const char *name;
+ enum CXPrintingPolicyProperty property;
+ };
+ struct Mapping mappings[] = {
+ {"CINDEXTEST_PRINTINGPOLICY_INDENTATION", CXPrintingPolicy_Indentation},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSPECIFIERS",
+ CXPrintingPolicy_SuppressSpecifiers},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTAGKEYWORD",
+ CXPrintingPolicy_SuppressTagKeyword},
+ {"CINDEXTEST_PRINTINGPOLICY_INCLUDETAGDEFINITION",
+ CXPrintingPolicy_IncludeTagDefinition},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSCOPE",
+ CXPrintingPolicy_SuppressScope},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSUNWRITTENSCOPE",
+ CXPrintingPolicy_SuppressUnwrittenScope},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSINITIALIZERS",
+ CXPrintingPolicy_SuppressInitializers},
+ {"CINDEXTEST_PRINTINGPOLICY_CONSTANTARRAYSIZEASWRITTEN",
+ CXPrintingPolicy_ConstantArraySizeAsWritten},
+ {"CINDEXTEST_PRINTINGPOLICY_ANONYMOUSTAGLOCATIONS",
+ CXPrintingPolicy_AnonymousTagLocations},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSTRONGLIFETIME",
+ CXPrintingPolicy_SuppressStrongLifetime},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSLIFETIMEQUALIFIERS",
+ CXPrintingPolicy_SuppressLifetimeQualifiers},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTEMPLATEARGSINCXXCONSTRUCTORS",
+ CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors},
+ {"CINDEXTEST_PRINTINGPOLICY_BOOL", CXPrintingPolicy_Bool},
+ {"CINDEXTEST_PRINTINGPOLICY_RESTRICT", CXPrintingPolicy_Restrict},
+ {"CINDEXTEST_PRINTINGPOLICY_ALIGNOF", CXPrintingPolicy_Alignof},
+ {"CINDEXTEST_PRINTINGPOLICY_UNDERSCOREALIGNOF",
+ CXPrintingPolicy_UnderscoreAlignof},
+ {"CINDEXTEST_PRINTINGPOLICY_USEVOIDFORZEROPARAMS",
+ CXPrintingPolicy_UseVoidForZeroParams},
+ {"CINDEXTEST_PRINTINGPOLICY_TERSEOUTPUT", CXPrintingPolicy_TerseOutput},
+ {"CINDEXTEST_PRINTINGPOLICY_POLISHFORDECLARATION",
+ CXPrintingPolicy_PolishForDeclaration},
+ {"CINDEXTEST_PRINTINGPOLICY_HALF", CXPrintingPolicy_Half},
+ {"CINDEXTEST_PRINTINGPOLICY_MSWCHAR", CXPrintingPolicy_MSWChar},
+ {"CINDEXTEST_PRINTINGPOLICY_INCLUDENEWLINES",
+ CXPrintingPolicy_IncludeNewlines},
+ {"CINDEXTEST_PRINTINGPOLICY_MSVCFORMATTING",
+ CXPrintingPolicy_MSVCFormatting},
+ {"CINDEXTEST_PRINTINGPOLICY_CONSTANTSASWRITTEN",
+ CXPrintingPolicy_ConstantsAsWritten},
+ {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSIMPLICITBASE",
+ CXPrintingPolicy_SuppressImplicitBase},
+ {"CINDEXTEST_PRINTINGPOLICY_FULLYQUALIFIEDNAME",
+ CXPrintingPolicy_FullyQualifiedName},
+ };
+
+ unsigned i;
+ for (i = 0; i < sizeof(mappings) / sizeof(struct Mapping); i++) {
+ char *value = getenv(mappings[i].name);
+ if (value) {
+ clang_PrintingPolicy_setProperty(Policy, mappings[i].property,
+ (unsigned)strtoul(value, 0L, 10));
+ }
+ }
+}
+
+/** Returns 0 in case of success, non-zero in case of a failure. */
static int checkForErrors(CXTranslationUnit TU);
static void describeLibclangFailure(enum CXErrorCode Err) {
@@ -169,6 +234,7 @@ static int parse_remapped_files_with_opt(const char *opt_name,
*unsaved_files
= (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) *
*num_unsaved_files);
+ assert(*unsaved_files);
for (i = 0; i != *num_unsaved_files; ++i) {
struct CXUnsavedFile *unsaved = *unsaved_files + i;
const char *arg_string = argv[arg_indices[i]] + prefix_len;
@@ -204,6 +270,7 @@ static int parse_remapped_files_with_opt(const char *opt_name,
/* Read the contents of the file we're remapping to. */
contents = (char *)malloc(unsaved->Length + 1);
+ assert(contents);
if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) {
fprintf(stderr, "error: unexpected %s reading 'to' file %s\n",
(feof(to_file) ? "EOF" : "error"), sep + 1);
@@ -223,6 +290,7 @@ static int parse_remapped_files_with_opt(const char *opt_name,
/* Copy the file name that we're remapping from. */
filename_len = sep - arg_string;
filename = (char *)malloc(filename_len + 1);
+ assert(filename);
memcpy(filename, arg_string, filename_len);
filename[filename_len] = 0;
unsaved->Filename = filename;
@@ -277,6 +345,7 @@ static int parse_remapped_files_with_try(int try_idx,
= (struct CXUnsavedFile *)realloc(unsaved_files_no_try_idx,
sizeof(struct CXUnsavedFile) *
*num_unsaved_files);
+ assert(*unsaved_files);
memcpy(*unsaved_files + num_unsaved_files_no_try_idx,
unsaved_files_try_idx, sizeof(struct CXUnsavedFile) *
num_unsaved_files_try_idx);
@@ -356,7 +425,11 @@ static void PrintRange(CXSourceRange R, const char *str) {
PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
}
-int want_display_name = 0;
+static enum DisplayType {
+ DisplayType_Spelling,
+ DisplayType_DisplayName,
+ DisplayType_Pretty
+} wanted_display_type = DisplayType_Spelling;
static void printVersion(const char *Prefix, CXVersion Version) {
if (Version.Major < 0)
@@ -591,7 +664,7 @@ static void ValidateCommentXML(const char *Str, const char *CommentSchemaFile) {
printf(" CommentXMLValid");
else if (status > 0) {
xmlErrorPtr Error = xmlGetLastError();
- printf(" CommentXMLInvalid [not vaild XML: %s]", Error->message);
+ printf(" CommentXMLInvalid [not valid XML: %s]", Error->message);
} else
printf(" libXMLError");
@@ -656,6 +729,28 @@ static int lineCol_cmp(const void *p1, const void *p2) {
return (int)lhs->col - (int)rhs->col;
}
+static CXString CursorToText(CXCursor Cursor) {
+ CXString text;
+ switch (wanted_display_type) {
+ case DisplayType_Spelling:
+ return clang_getCursorSpelling(Cursor);
+ case DisplayType_DisplayName:
+ return clang_getCursorDisplayName(Cursor);
+ case DisplayType_Pretty: {
+ CXPrintingPolicy Policy = clang_getCursorPrintingPolicy(Cursor);
+ ModifyPrintingPolicyAccordingToEnv(Policy);
+ text = clang_getCursorPrettyPrinted(Cursor, Policy);
+ clang_PrintingPolicy_dispose(Policy);
+ return text;
+ }
+ }
+ assert(0 && "unknown display type"); /* no llvm_unreachable in C. */
+ /* Set to NULL to prevent uninitialized variable warnings. */
+ text.data = NULL;
+ text.private_flags = 0;
+ return text;
+}
+
static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
if (clang_isInvalid(Cursor.kind)) {
@@ -682,8 +777,7 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
int I;
ks = clang_getCursorKindSpelling(Cursor.kind);
- string = want_display_name? clang_getCursorDisplayName(Cursor)
- : clang_getCursorSpelling(Cursor);
+ string = CursorToText(Cursor);
printf("%s=%s", clang_getCString(ks),
clang_getCString(string));
clang_disposeString(ks);
@@ -812,6 +906,8 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
printf(" (variadic)");
if (clang_Cursor_isObjCOptional(Cursor))
printf(" (@optional)");
+ if (clang_isInvalidDeclaration(Cursor))
+ printf(" (invalid)");
switch (clang_getCursorExceptionSpecificationType(Cursor))
{
@@ -1038,6 +1134,13 @@ static const char* GetCursorSource(CXCursor Cursor) {
}
}
+static CXString createCXString(const char *CS) {
+ CXString Str;
+ Str.data = (const void *) CS;
+ Str.private_flags = 0;
+ return Str;
+}
+
/******************************************************************************/
/* Callbacks. */
/******************************************************************************/
@@ -1684,7 +1787,12 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
else if (!strcmp(filter, "all-display") ||
!strcmp(filter, "local-display")) {
ck = NULL;
- want_display_name = 1;
+ wanted_display_type = DisplayType_DisplayName;
+ }
+ else if (!strcmp(filter, "all-pretty") ||
+ !strcmp(filter, "local-pretty")) {
+ ck = NULL;
+ wanted_display_type = DisplayType_Pretty;
}
else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0;
else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
@@ -1752,8 +1860,11 @@ int perform_test_load_source(int argc, const char **argv,
const char *InvocationPath;
Idx = clang_createIndex(/* excludeDeclsFromPCH */
- (!strcmp(filter, "local") ||
- !strcmp(filter, "local-display"))? 1 : 0,
+ (!strcmp(filter, "local") ||
+ !strcmp(filter, "local-display") ||
+ !strcmp(filter, "local-pretty"))
+ ? 1
+ : 0,
/* displayDiagnostics=*/1);
InvocationPath = getenv("CINDEXTEST_INVOCATION_EMISSION_PATH");
if (InvocationPath)
@@ -2064,6 +2175,7 @@ int parse_file_line_column(const char *input, char **filename, unsigned *line,
/* Copy the file name. */
*filename = (char*)malloc(last_colon - input + 1);
+ assert(*filename);
memcpy(*filename, input, last_colon - input);
(*filename)[last_colon - input] = 0;
return 0;
@@ -2158,8 +2270,33 @@ static void print_completion_string(CXCompletionString completion_string,
}
-static void print_completion_result(CXCompletionResult *completion_result,
+static void print_line_column(CXSourceLocation location, FILE *file) {
+ unsigned line, column;
+ clang_getExpansionLocation(location, NULL, &line, &column, NULL);
+ fprintf(file, "%d:%d", line, column);
+}
+
+static void print_token_range(CXTranslationUnit translation_unit,
+ CXSourceLocation start, FILE *file) {
+ CXToken *token = clang_getToken(translation_unit, start);
+
+ fprintf(file, "{");
+ if (token != NULL) {
+ CXSourceRange token_range = clang_getTokenExtent(translation_unit, *token);
+ print_line_column(clang_getRangeStart(token_range), file);
+ fprintf(file, "-");
+ print_line_column(clang_getRangeEnd(token_range), file);
+ clang_disposeTokens(translation_unit, token, 1);
+ }
+
+ fprintf(file, "}");
+}
+
+static void print_completion_result(CXTranslationUnit translation_unit,
+ CXCodeCompleteResults *completion_results,
+ unsigned index,
FILE *file) {
+ CXCompletionResult *completion_result = completion_results->Results + index;
CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
unsigned annotationCount;
enum CXCursorKind ParentKind;
@@ -2167,6 +2304,7 @@ static void print_completion_result(CXCompletionResult *completion_result,
CXString BriefComment;
CXString Annotation;
const char *BriefCommentCString;
+ unsigned i;
fprintf(file, "%s:", clang_getCString(ks));
clang_disposeString(ks);
@@ -2227,7 +2365,19 @@ static void print_completion_result(CXCompletionResult *completion_result,
fprintf(file, "(brief comment: %s)", BriefCommentCString);
}
clang_disposeString(BriefComment);
-
+
+ for (i = 0; i < clang_getCompletionNumFixIts(completion_results, index);
+ ++i) {
+ CXSourceRange correction_range;
+ CXString FixIt = clang_getCompletionFixIt(completion_results, index, i,
+ &correction_range);
+ fprintf(file, " (requires fix-it: ");
+ print_token_range(translation_unit, clang_getRangeStart(correction_range),
+ file);
+ fprintf(file, " to \"%s\")", clang_getCString(FixIt));
+ clang_disposeString(FixIt);
+ }
+
fprintf(file, "\n");
}
@@ -2324,6 +2474,10 @@ int perform_code_completion(int argc, const char **argv, int timing_only) {
completionOptions |= CXCodeComplete_IncludeCodePatterns;
if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
completionOptions |= CXCodeComplete_IncludeBriefComments;
+ if (getenv("CINDEXTEST_COMPLETION_SKIP_PREAMBLE"))
+ completionOptions |= CXCodeComplete_SkipPreamble;
+ if (getenv("CINDEXTEST_COMPLETION_INCLUDE_FIXITS"))
+ completionOptions |= CXCodeComplete_IncludeCompletionsWithFixIts;
if (timing_only)
input += strlen("-code-completion-timing=");
@@ -2388,7 +2542,7 @@ int perform_code_completion(int argc, const char **argv, int timing_only) {
clang_sortCodeCompletionResults(results->Results, results->NumResults);
for (i = 0; i != n; ++i)
- print_completion_result(results->Results + i, stdout);
+ print_completion_result(TU, results, i, stdout);
}
n = clang_codeCompleteGetNumDiagnostics(results);
for (i = 0; i != n; ++i) {
@@ -2471,6 +2625,7 @@ static int inspect_cursor_at(int argc, const char **argv,
assert(NumLocations > 0 && "Unable to count locations?");
Locations = (CursorSourceLocation *)malloc(
NumLocations * sizeof(CursorSourceLocation));
+ assert(Locations);
for (Loc = 0; Loc < NumLocations; ++Loc) {
const char *input = argv[Loc + 1] + strlen(locations_flag);
if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
@@ -2764,6 +2919,7 @@ static int find_file_refs_at(int argc, const char **argv) {
assert(NumLocations > 0 && "Unable to count locations?");
Locations = (CursorSourceLocation *)malloc(
NumLocations * sizeof(CursorSourceLocation));
+ assert(Locations);
for (Loc = 0; Loc < NumLocations; ++Loc) {
const char *input = argv[Loc + 1] + strlen("-file-refs-at=");
if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
@@ -2871,6 +3027,7 @@ static int find_file_includes_in(int argc, const char **argv) {
/* Parse the locations. */
assert(NumFilenames > 0 && "Unable to count filenames?");
Filenames = (const char **)malloc(NumFilenames * sizeof(const char *));
+ assert(Filenames);
for (I = 0; I < NumFilenames; ++I) {
const char *input = argv[I + 1] + strlen("-file-includes-in=");
/* Copy the file name. */
@@ -2954,7 +3111,9 @@ typedef struct {
static ImportedASTFilesData *importedASTs_create() {
ImportedASTFilesData *p;
p = malloc(sizeof(ImportedASTFilesData));
+ assert(p);
p->filenames = malloc(MAX_IMPORTED_ASTFILES * sizeof(const char *));
+ assert(p->filenames);
p->num_files = 0;
return p;
}
@@ -2990,7 +3149,7 @@ typedef struct {
int first_check_printed;
int fail_for_error;
int abort;
- const char *main_filename;
+ CXString main_filename;
ImportedASTFilesData *importedASTs;
IndexDataStringList *strings;
CXTranslationUnit TU;
@@ -3029,6 +3188,7 @@ static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
const char *cname;
CXIdxClientFile file;
unsigned line, column;
+ const char *main_filename;
int isMainFile;
index_data = (IndexData *)client_data;
@@ -3043,7 +3203,8 @@ static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
}
filename = clang_getFileName((CXFile)file);
cname = clang_getCString(filename);
- if (strcmp(cname, index_data->main_filename) == 0)
+ main_filename = clang_getCString(index_data->main_filename);
+ if (strcmp(cname, main_filename) == 0)
isMainFile = 1;
else
isMainFile = 0;
@@ -3085,6 +3246,7 @@ static CXIdxClientContainer makeClientContainer(CXClientData *client_data,
node =
(IndexDataStringList *)malloc(sizeof(IndexDataStringList) + strlen(name) +
digitCount(line) + digitCount(column) + 2);
+ assert(node);
newStr = node->data;
sprintf(newStr, "%s:%d:%d", name, line, column);
@@ -3217,6 +3379,27 @@ static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo,
}
}
+static void printSymbolRole(CXSymbolRole role) {
+ if (role & CXSymbolRole_Declaration)
+ printf(" decl");
+ if (role & CXSymbolRole_Definition)
+ printf(" def");
+ if (role & CXSymbolRole_Reference)
+ printf(" ref");
+ if (role & CXSymbolRole_Read)
+ printf(" read");
+ if (role & CXSymbolRole_Write)
+ printf(" write");
+ if (role & CXSymbolRole_Call)
+ printf(" call");
+ if (role & CXSymbolRole_Dynamic)
+ printf(" dyn");
+ if (role & CXSymbolRole_AddressOf)
+ printf(" addr");
+ if (role & CXSymbolRole_Implicit)
+ printf(" implicit");
+}
+
static void index_diagnostic(CXClientData client_data,
CXDiagnosticSet diagSet, void *reserved) {
CXString str;
@@ -3245,14 +3428,11 @@ static void index_diagnostic(CXClientData client_data,
static CXIdxClientFile index_enteredMainFile(CXClientData client_data,
CXFile file, void *reserved) {
IndexData *index_data;
- CXString filename;
index_data = (IndexData *)client_data;
printCheck(index_data);
- filename = clang_getFileName(file);
- index_data->main_filename = clang_getCString(filename);
- clang_disposeString(filename);
+ index_data->main_filename = clang_getFileName(file);
printf("[enteredMainFile]: ");
printCXIndexFile((CXIdxClientFile)file);
@@ -3438,9 +3618,11 @@ static void index_indexEntityReference(CXClientData client_data,
printCXIndexContainer(info->container);
printf(" | refkind: ");
switch (info->kind) {
- case CXIdxEntityRef_Direct: printf("direct"); break;
- case CXIdxEntityRef_Implicit: printf("implicit"); break;
+ case CXIdxEntityRef_Direct: printf("direct"); break;
+ case CXIdxEntityRef_Implicit: printf("implicit"); break;
}
+ printf(" | role:");
+ printSymbolRole(info->role);
printf("\n");
}
@@ -3470,6 +3652,8 @@ static unsigned getIndexOptions(void) {
index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
if (!getenv("CINDEXTEST_DISABLE_SKIPPARSEDBODIES"))
index_opts |= CXIndexOpt_SkipParsedBodiesInSession;
+ if (getenv("CINDEXTEST_INDEXIMPLICITTEMPLATEINSTANTIATIONS"))
+ index_opts |= CXIndexOpt_IndexImplicitTemplateInstantiations;
return index_opts;
}
@@ -3491,7 +3675,7 @@ static int index_compile_args(int num_args, const char **args,
index_data.first_check_printed = 0;
index_data.fail_for_error = 0;
index_data.abort = 0;
- index_data.main_filename = "";
+ index_data.main_filename = createCXString("");
index_data.importedASTs = importedASTs;
index_data.strings = NULL;
index_data.TU = NULL;
@@ -3507,6 +3691,7 @@ static int index_compile_args(int num_args, const char **args,
if (index_data.fail_for_error)
result = -1;
+ clang_disposeString(index_data.main_filename);
free_client_data(&index_data);
return result;
}
@@ -3528,7 +3713,7 @@ static int index_ast_file(const char *ast_file,
index_data.first_check_printed = 0;
index_data.fail_for_error = 0;
index_data.abort = 0;
- index_data.main_filename = "";
+ index_data.main_filename = createCXString("");
index_data.importedASTs = importedASTs;
index_data.strings = NULL;
index_data.TU = TU;
@@ -3541,6 +3726,7 @@ static int index_ast_file(const char *ast_file,
result = -1;
clang_disposeTranslationUnit(TU);
+ clang_disposeString(index_data.main_filename);
free_client_data(&index_data);
return result;
}
@@ -3664,6 +3850,7 @@ static int index_compile_db(int argc, const char **argv) {
len = strlen(database);
tmp = (char *) malloc(len+1);
+ assert(tmp);
memcpy(tmp, database, len+1);
buildDir = dirname(tmp);
@@ -3845,6 +4032,7 @@ int perform_token_annotation(int argc, const char **argv) {
}
cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
+ assert(cursors);
clang_annotateTokens(TU, tokens, num_tokens, cursors);
if (checkForErrors(TU) != 0) {
@@ -3919,6 +4107,7 @@ perform_test_compilation_db(const char *database, int argc, const char **argv) {
len = strlen(database);
tmp = (char *) malloc(len+1);
+ assert(tmp);
memcpy(tmp, database, len+1);
buildDir = dirname(tmp);
@@ -4033,9 +4222,7 @@ int print_usrs(const char **I, const char **E) {
if (!isUSR(I[2]))
return not_usr("<class USR>", I[2]);
else {
- CXString x;
- x.data = (void*) I[2];
- x.private_flags = 0;
+ CXString x = createCXString(I[2]);
print_usr(clang_constructUSR_ObjCIvar(I[1], x));
}
@@ -4060,9 +4247,7 @@ int print_usrs(const char **I, const char **E) {
if (!isUSR(I[3]))
return not_usr("<class USR>", I[3]);
else {
- CXString x;
- x.data = (void*) I[3];
- x.private_flags = 0;
+ CXString x = createCXString(I[3]);
print_usr(clang_constructUSR_ObjCMethod(I[1], atoi(I[2]), x));
}
I += 4;
@@ -4090,9 +4275,7 @@ int print_usrs(const char **I, const char **E) {
if (!isUSR(I[2]))
return not_usr("<class USR>", I[2]);
else {
- CXString x;
- x.data = (void*) I[2];
- x.private_flags = 0;
+ CXString x = createCXString(I[2]);
print_usr(clang_constructUSR_ObjCProperty(I[1], x));
}
I += 3;
@@ -4261,10 +4444,10 @@ static void printLocation(CXSourceLocation L) {
CXFile File;
CXString FileName;
unsigned line, column, offset;
-
+
clang_getExpansionLocation(L, &File, &line, &column, &offset);
FileName = clang_getFileName(File);
-
+
fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column);
clang_disposeString(FileName);
}
diff --git a/tools/c-index-test/core_main.cpp b/tools/c-index-test/core_main.cpp
index c255f54ba68c..a7732c09d5b0 100644
--- a/tools/c-index-test/core_main.cpp
+++ b/tools/c-index-test/core_main.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/LangOptions.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -16,6 +17,7 @@
#include "clang/Index/IndexDataConsumer.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Index/CodegenNameGenerator.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"
@@ -77,6 +79,7 @@ namespace {
class PrintIndexDataConsumer : public IndexDataConsumer {
raw_ostream &OS;
std::unique_ptr<CodegenNameGenerator> CGNameGen;
+ std::shared_ptr<Preprocessor> PP;
public:
PrintIndexDataConsumer(raw_ostream &OS) : OS(OS) {
@@ -86,15 +89,20 @@ public:
CGNameGen.reset(new CodegenNameGenerator(Ctx));
}
+ void setPreprocessor(std::shared_ptr<Preprocessor> PP) override {
+ this->PP = std::move(PP);
+ }
+
bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles,
ArrayRef<SymbolRelation> Relations,
- FileID FID, unsigned Offset,
- ASTNodeInfo ASTNode) override {
+ SourceLocation Loc, ASTNodeInfo ASTNode) override {
ASTContext &Ctx = D->getASTContext();
SourceManager &SM = Ctx.getSourceManager();
- unsigned Line = SM.getLineNumber(FID, Offset);
- unsigned Col = SM.getColumnNumber(FID, Offset);
+ Loc = SM.getFileLoc(Loc);
+ FileID FID = SM.getFileID(Loc);
+ unsigned Line = SM.getLineNumber(FID, SM.getFileOffset(Loc));
+ unsigned Col = SM.getColumnNumber(FID, SM.getFileOffset(Loc));
OS << Line << ':' << Col << " | ";
printSymbolInfo(getSymbolInfo(D), OS);
@@ -124,12 +132,14 @@ public:
}
bool handleModuleOccurence(const ImportDecl *ImportD, SymbolRoleSet Roles,
- FileID FID, unsigned Offset) override {
+ SourceLocation Loc) override {
ASTContext &Ctx = ImportD->getASTContext();
SourceManager &SM = Ctx.getSourceManager();
- unsigned Line = SM.getLineNumber(FID, Offset);
- unsigned Col = SM.getColumnNumber(FID, Offset);
+ Loc = SM.getFileLoc(Loc);
+ FileID FID = SM.getFileID(Loc);
+ unsigned Line = SM.getLineNumber(FID, SM.getFileOffset(Loc));
+ unsigned Col = SM.getColumnNumber(FID, SM.getFileOffset(Loc));
OS << Line << ':' << Col << " | ";
printSymbolInfo(getSymbolInfo(ImportD), OS);
@@ -142,6 +152,37 @@ public:
return true;
}
+
+ bool handleMacroOccurence(const IdentifierInfo *Name, const MacroInfo *MI,
+ SymbolRoleSet Roles, SourceLocation Loc) override {
+ assert(PP);
+ SourceManager &SM = PP->getSourceManager();
+
+ Loc = SM.getFileLoc(Loc);
+ FileID FID = SM.getFileID(Loc);
+ unsigned Line = SM.getLineNumber(FID, SM.getFileOffset(Loc));
+ unsigned Col = SM.getColumnNumber(FID, SM.getFileOffset(Loc));
+ OS << Line << ':' << Col << " | ";
+
+ printSymbolInfo(getSymbolInfoForMacro(*MI), OS);
+ OS << " | ";
+
+ OS << Name->getName();
+ OS << " | ";
+
+ SmallString<256> USRBuf;
+ if (generateUSRForMacro(Name->getName(), MI->getDefinitionLoc(), SM,
+ USRBuf)) {
+ OS << "<no-usr>";
+ } else {
+ OS << USRBuf;
+ }
+ OS << " | ";
+
+ printSymbolRoles(Roles, OS);
+ OS << " |\n";
+ return true;
+ }
};
} // anonymous namespace
@@ -192,7 +233,7 @@ static bool printSourceSymbols(ArrayRef<const char *> Args,
if (auto Reader = Unit->getASTReader()) {
Reader->getModuleManager().visit([&](serialization::ModuleFile &Mod) -> bool {
OS << "==== Module " << Mod.ModuleName << " ====\n";
- indexModuleFile(Mod, *Reader, DataConsumer, IndexOpts);
+ indexModuleFile(Mod, *Reader, *DataConsumer, IndexOpts);
dumpModuleFileInputs(Mod, *Reader, OS);
return true; // skip module dependencies.
});
@@ -228,7 +269,7 @@ static bool printSourceSymbolsFromModule(StringRef modulePath,
return true;
}
- auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(outs());
+ PrintIndexDataConsumer DataConsumer(outs());
IndexingOptions IndexOpts;
indexASTUnit(*AU, DataConsumer, IndexOpts);
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
index e190c0721afb..f00e9a3df0ad 100644
--- a/tools/clang-check/ClangCheck.cpp
+++ b/tools/clang-check/ClangCheck.cpp
@@ -103,7 +103,7 @@ public:
}
};
-/// \brief Subclasses \c clang::FixItRewriter to not count fixed errors/warnings
+/// Subclasses \c clang::FixItRewriter to not count fixed errors/warnings
/// in the final error counts.
///
/// This has the side-effect that clang-check -fixit exits with code 0 on
@@ -120,7 +120,7 @@ public:
bool IncludeInDiagnosticCounts() const override { return false; }
};
-/// \brief Subclasses \c clang::FixItAction so that we can install the custom
+/// Subclasses \c clang::FixItAction so that we can install the custom
/// \c FixItRewriter.
class FixItAction : public clang::FixItAction {
public:
@@ -138,7 +138,9 @@ public:
if (ASTList)
return clang::CreateASTDeclNodeLister();
if (ASTDump)
- return clang::CreateASTDumper(ASTDumpFilter, /*DumpDecls=*/true,
+ return clang::CreateASTDumper(nullptr /*Dump to stdout.*/,
+ ASTDumpFilter,
+ /*DumpDecls=*/true,
/*Deserialize=*/false,
/*DumpLookups=*/false);
if (ASTPrint)
diff --git a/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
index efb2147f2b43..1071b680aea0 100644
--- a/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
+++ b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
@@ -38,7 +38,7 @@ namespace LLVM.ClangFormat
private string style = "file";
private bool formatOnSave = false;
private string formatOnSaveFileExtensions =
- ".c;.cpp;.cxx;.cc;.tli;.tlh;.h;.hh;.hpp;.hxx;.hh;.inl" +
+ ".c;.cpp;.cxx;.cc;.tli;.tlh;.h;.hh;.hpp;.hxx;.hh;.inl;" +
".java;.js;.ts;.m;.mm;.proto;.protodevel;.td";
public OptionPageGrid Clone()
diff --git a/tools/clang-format-vs/ClangFormat/license.txt b/tools/clang-format-vs/ClangFormat/license.txt
index 9966c8123f5b..76aa2afdf81e 100644
--- a/tools/clang-format-vs/ClangFormat/license.txt
+++ b/tools/clang-format-vs/ClangFormat/license.txt
@@ -4,7 +4,7 @@ LLVM Release License
University of Illinois/NCSA
Open Source License
-Copyright (c) 2007-2017 University of Illinois at Urbana-Champaign.
+Copyright (c) 2007-2018 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp
index b7179ffd6416..de2f9d7fe76e 100644
--- a/tools/clang-format/ClangFormat.cpp
+++ b/tools/clang-format/ClangFormat.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief This file implements a clang-format tool that automatically formats
+/// This file implements a clang-format tool that automatically formats
/// (fragments of) C++ code.
///
//===----------------------------------------------------------------------===//
@@ -22,7 +22,8 @@
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Signals.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/Process.h"
using namespace llvm;
using clang::tooling::Replacements;
@@ -59,17 +60,18 @@ LineRanges("lines", cl::desc("<start line>:<end line> - format a range of\n"
"Can only be used with one input file."),
cl::cat(ClangFormatCategory));
static cl::opt<std::string>
- Style("style",
- cl::desc(clang::format::StyleOptionHelpDescription),
- cl::init("file"), cl::cat(ClangFormatCategory));
+ Style("style", cl::desc(clang::format::StyleOptionHelpDescription),
+ cl::init(clang::format::DefaultFormatStyle),
+ cl::cat(ClangFormatCategory));
static cl::opt<std::string>
-FallbackStyle("fallback-style",
- cl::desc("The name of the predefined style used as a\n"
- "fallback in case clang-format is invoked with\n"
- "-style=file, but can not find the .clang-format\n"
- "file to use.\n"
- "Use -fallback-style=none to skip formatting."),
- cl::init("LLVM"), cl::cat(ClangFormatCategory));
+ FallbackStyle("fallback-style",
+ cl::desc("The name of the predefined style used as a\n"
+ "fallback in case clang-format is invoked with\n"
+ "-style=file, but can not find the .clang-format\n"
+ "file to use.\n"
+ "Use -fallback-style=none to skip formatting."),
+ cl::init(clang::format::DefaultFallbackStyle),
+ cl::cat(ClangFormatCategory));
static cl::opt<std::string>
AssumeFileName("assume-filename",
@@ -337,7 +339,7 @@ static void PrintVersion(raw_ostream &OS) {
}
int main(int argc, const char **argv) {
- llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+ llvm::InitLLVM X(argc, argv);
cl::HideUnrelatedOptions(ClangFormatCategory);
@@ -357,10 +359,27 @@ int main(int argc, const char **argv) {
}
if (DumpConfig) {
+ StringRef FileName;
+ std::unique_ptr<llvm::MemoryBuffer> Code;
+ if (FileNames.empty()) {
+ // We can't read the code to detect the language if there's no
+ // file name, so leave Code empty here.
+ FileName = AssumeFileName;
+ } else {
+ // Read in the code in case the filename alone isn't enough to
+ // detect the language.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getFileOrSTDIN(FileNames[0]);
+ if (std::error_code EC = CodeOrErr.getError()) {
+ llvm::errs() << EC.message() << "\n";
+ return 1;
+ }
+ FileName = (FileNames[0] == "-") ? AssumeFileName : FileNames[0];
+ Code = std::move(CodeOrErr.get());
+ }
llvm::Expected<clang::format::FormatStyle> FormatStyle =
- clang::format::getStyle(
- Style, FileNames.empty() ? AssumeFileName : FileNames[0],
- FallbackStyle);
+ clang::format::getStyle(Style, FileName, FallbackStyle,
+ Code ? Code->getBuffer() : "");
if (!FormatStyle) {
llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n";
return 1;
diff --git a/tools/clang-format/clang-format.el b/tools/clang-format/clang-format.el
index 6c626e0b83d1..4f11daf15fa9 100644
--- a/tools/clang-format/clang-format.el
+++ b/tools/clang-format/clang-format.el
@@ -153,7 +153,7 @@ uses the function `buffer-file-name'."
nil nil clang-format-executable
nil `(,temp-buffer ,temp-file) nil
`("-output-replacements-xml"
- ;; Gaurd against a nil assume-file-name.
+ ;; Guard against a nil assume-file-name.
;; If the clang-format option -assume-filename
;; is given a blank string it will crash as per
;; the following bug report
diff --git a/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp b/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp
index d440a6124b67..0c9ae848d59b 100644
--- a/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp
+++ b/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief This file implements a function that runs Clang format on a single
+/// This file implements a function that runs Clang format on a single
/// input. This function is then linked into the Fuzzer library.
///
//===----------------------------------------------------------------------===//
diff --git a/tools/clang-format/git-clang-format b/tools/clang-format/git-clang-format
index 60cd4fb25b63..0b2103962a31 100755
--- a/tools/clang-format/git-clang-format
+++ b/tools/clang-format/git-clang-format
@@ -79,6 +79,7 @@ def main():
'm', # ObjC
'mm', # ObjC++
'cc', 'cp', 'cpp', 'c++', 'cxx', 'hpp', # C++
+ 'cu', # CUDA
# Other languages that clang-format supports
'proto', 'protodevel', # Protocol Buffers
'java', # Java
diff --git a/tools/clang-fuzzer/CMakeLists.txt b/tools/clang-fuzzer/CMakeLists.txt
index b351ec51652d..5f07e66fe675 100644
--- a/tools/clang-fuzzer/CMakeLists.txt
+++ b/tools/clang-fuzzer/CMakeLists.txt
@@ -9,12 +9,13 @@ elseif(LLVM_USE_SANITIZE_COVERAGE)
unset(DUMMY_MAIN)
endif()
-# Hack to bypass LLVM's cmake sources check and allow multiple libraries and
-# executables from this directory.
+# Needed by LLVM's CMake checks because this file defines multiple targets.
set(LLVM_OPTIONAL_SOURCES
ClangFuzzer.cpp
DummyClangFuzzer.cpp
ExampleClangProtoFuzzer.cpp
+ ExampleClangLoopProtoFuzzer.cpp
+ ExampleClangLLVMProtoFuzzer.cpp
)
if(CLANG_ENABLE_PROTO_FUZZER)
@@ -25,6 +26,7 @@ if(CLANG_ENABLE_PROTO_FUZZER)
include_directories(${PROTOBUF_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS cxx_proto.proto)
+ protobuf_generate_cpp(LOOP_PROTO_SRCS LOOP_PROTO_HDRS cxx_loop_proto.proto)
set(LLVM_OPTIONAL_SOURCES ${LLVM_OPTIONAL_SOURCES} ${PROTO_SRCS})
add_clang_library(clangCXXProto
${PROTO_SRCS}
@@ -34,6 +36,14 @@ if(CLANG_ENABLE_PROTO_FUZZER)
${PROTOBUF_LIBRARIES}
)
+ add_clang_library(clangCXXLoopProto
+ ${LOOP_PROTO_SRCS}
+ ${LOOP_PROTO_HDRS}
+
+ LINK_LIBS
+ ${PROTOBUF_LIBRARIES}
+ )
+
# Build and include libprotobuf-mutator
include(ProtobufMutator)
include_directories(${ProtobufMutator_INCLUDE_DIRS})
@@ -41,24 +51,63 @@ if(CLANG_ENABLE_PROTO_FUZZER)
# Build the protobuf->C++ translation library and driver.
add_clang_subdirectory(proto-to-cxx)
+ # Build the protobuf->LLVM IR translation library and driver.
+ add_clang_subdirectory(proto-to-llvm)
+
+ # Build the fuzzer initialization library.
+ add_clang_subdirectory(fuzzer-initialize)
+
# Build the protobuf fuzzer
add_clang_executable(clang-proto-fuzzer
${DUMMY_MAIN}
ExampleClangProtoFuzzer.cpp
)
- target_link_libraries(clang-proto-fuzzer
- PRIVATE
+ # Build the loop protobuf fuzzer
+ add_clang_executable(clang-loop-proto-fuzzer
+ ${DUMMY_MAIN}
+ ExampleClangLoopProtoFuzzer.cpp
+ )
+
+ # Build the llvm protobuf fuzzer
+ add_clang_executable(clang-llvm-proto-fuzzer
+ ${DUMMY_MAIN}
+ ExampleClangLLVMProtoFuzzer.cpp
+ )
+
+ set(COMMON_PROTO_FUZZ_LIBRARIES
${ProtobufMutator_LIBRARIES}
${PROTOBUF_LIBRARIES}
${LLVM_LIB_FUZZING_ENGINE}
- clangCXXProto
+ clangFuzzerInitialize
+ )
+
+ target_link_libraries(clang-proto-fuzzer
+ PRIVATE
+ ${COMMON_PROTO_FUZZ_LIBRARIES}
clangHandleCXX
+ clangCXXProto
clangProtoToCXX
)
+ target_link_libraries(clang-loop-proto-fuzzer
+ PRIVATE
+ ${COMMON_PROTO_FUZZ_LIBRARIES}
+ clangHandleCXX
+ clangCXXLoopProto
+ clangLoopProtoToCXX
+ )
+ target_link_libraries(clang-llvm-proto-fuzzer
+ PRIVATE
+ ${COMMON_PROTO_FUZZ_LIBRARIES}
+ clangHandleLLVM
+ clangCXXLoopProto
+ clangLoopProtoToLLVM
+ )
+
endif()
add_clang_subdirectory(handle-cxx)
+add_clang_subdirectory(handle-llvm)
add_clang_executable(clang-fuzzer
EXCLUDE_FROM_ALL
diff --git a/tools/clang-fuzzer/ClangFuzzer.cpp b/tools/clang-fuzzer/ClangFuzzer.cpp
index 2d35fb7735f9..f169f58a39b6 100644
--- a/tools/clang-fuzzer/ClangFuzzer.cpp
+++ b/tools/clang-fuzzer/ClangFuzzer.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief This file implements a function that runs Clang on a single
+/// This file implements a function that runs Clang on a single
/// input. This function is then linked into the Fuzzer library.
///
//===----------------------------------------------------------------------===//
diff --git a/tools/clang-fuzzer/ExampleClangLLVMProtoFuzzer.cpp b/tools/clang-fuzzer/ExampleClangLLVMProtoFuzzer.cpp
new file mode 100644
index 000000000000..347ba1c320df
--- /dev/null
+++ b/tools/clang-fuzzer/ExampleClangLLVMProtoFuzzer.cpp
@@ -0,0 +1,28 @@
+//===-- ExampleClangLLVMProtoFuzzer.cpp - Fuzz Clang ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements a function that compiles a single LLVM IR string as
+/// input and uses libprotobuf-mutator to find new inputs. This function is
+/// then linked into the Fuzzer library.
+///
+//===----------------------------------------------------------------------===//
+
+#include "cxx_loop_proto.pb.h"
+#include "fuzzer-initialize/fuzzer_initialize.h"
+#include "handle-llvm/handle_llvm.h"
+#include "proto-to-llvm/loop_proto_to_llvm.h"
+#include "src/libfuzzer/libfuzzer_macro.h"
+
+using namespace clang_fuzzer;
+
+DEFINE_BINARY_PROTO_FUZZER(const LoopFunction &input) {
+ auto S = LoopFunctionToLLVMString(input);
+ HandleLLVM(S, GetCLArgs());
+}
diff --git a/tools/clang-fuzzer/ExampleClangLoopProtoFuzzer.cpp b/tools/clang-fuzzer/ExampleClangLoopProtoFuzzer.cpp
new file mode 100644
index 000000000000..3640be13fafd
--- /dev/null
+++ b/tools/clang-fuzzer/ExampleClangLoopProtoFuzzer.cpp
@@ -0,0 +1,30 @@
+//===-- ExampleClangLoopProtoFuzzer.cpp - Fuzz Clang ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements a function that runs Clang on a single
+/// input and uses libprotobuf-mutator to find new inputs. This function is
+/// then linked into the Fuzzer library. This file differs from
+/// ExampleClangProtoFuzzer in that it uses a different protobuf that includes
+/// C++ code with a single for loop.
+///
+//===----------------------------------------------------------------------===//
+
+#include "cxx_loop_proto.pb.h"
+#include "fuzzer-initialize/fuzzer_initialize.h"
+#include "handle-cxx/handle_cxx.h"
+#include "proto-to-cxx/proto_to_cxx.h"
+#include "src/libfuzzer/libfuzzer_macro.h"
+
+using namespace clang_fuzzer;
+
+DEFINE_BINARY_PROTO_FUZZER(const LoopFunction &input) {
+ auto S = LoopFunctionToString(input);
+ HandleCXX(S, GetCLArgs());
+}
diff --git a/tools/clang-fuzzer/ExampleClangProtoFuzzer.cpp b/tools/clang-fuzzer/ExampleClangProtoFuzzer.cpp
index ab734e85b857..159ded3ca185 100644
--- a/tools/clang-fuzzer/ExampleClangProtoFuzzer.cpp
+++ b/tools/clang-fuzzer/ExampleClangProtoFuzzer.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief This file implements a function that runs Clang on a single
+/// This file implements a function that runs Clang on a single
/// input and uses libprotobuf-mutator to find new inputs. This function is
/// then linked into the Fuzzer library.
///
@@ -17,28 +17,12 @@
#include "cxx_proto.pb.h"
#include "handle-cxx/handle_cxx.h"
#include "proto-to-cxx/proto_to_cxx.h"
-
+#include "fuzzer-initialize/fuzzer_initialize.h"
#include "src/libfuzzer/libfuzzer_macro.h"
-#include <cstring>
-
using namespace clang_fuzzer;
-static std::vector<const char *> CLArgs;
-
-extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
- CLArgs.push_back("-O2");
- for (int I = 1; I < *argc; I++) {
- if (strcmp((*argv)[I], "-ignore_remaining_args=1") == 0) {
- for (I++; I < *argc; I++)
- CLArgs.push_back((*argv)[I]);
- break;
- }
- }
- return 0;
-}
-
DEFINE_BINARY_PROTO_FUZZER(const Function& input) {
auto S = FunctionToString(input);
- HandleCXX(S, CLArgs);
+ HandleCXX(S, GetCLArgs());
}
diff --git a/tools/clang-fuzzer/cxx_loop_proto.proto b/tools/clang-fuzzer/cxx_loop_proto.proto
new file mode 100644
index 000000000000..f2b47ed43d89
--- /dev/null
+++ b/tools/clang-fuzzer/cxx_loop_proto.proto
@@ -0,0 +1,80 @@
+//===-- cxx_loop_proto.proto - Protobuf description of C++ with for loops -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file describes a subset of C++ as a protobuf. It is used to
+/// more easily find interesting inputs for fuzzing Clang. This subset
+/// differs from the one defined in cxx_proto.proto by eliminating while
+/// loops and conditionals. The goal is that the C++ code generated will be
+/// more likely to stress the LLVM loop vectorizer.
+///
+//===----------------------------------------------------------------------===//
+
+syntax = "proto2";
+
+message Const {
+ required int32 val = 1;
+}
+
+message VarRef {
+ // Add an enum for each array in function signature
+ enum Arr {
+ ARR_A = 0;
+ ARR_B = 1;
+ ARR_C = 2;
+ };
+ required Arr arr = 1;
+}
+
+message BinaryOp {
+ enum Op {
+ PLUS = 0;
+ MINUS = 1;
+ MUL = 2;
+ XOR = 3;
+ AND = 4;
+ OR = 5;
+ EQ = 6;
+ NE = 7;
+ LE = 8;
+ GE = 9;
+ LT = 10;
+ GT = 11;
+ };
+ required Op op = 1;
+ required Rvalue left = 2;
+ required Rvalue right = 3;
+}
+
+message Rvalue {
+ oneof rvalue_oneof {
+ Const cons = 1;
+ BinaryOp binop = 2;
+ VarRef varref = 3;
+ }
+}
+
+message AssignmentStatement {
+ required VarRef varref = 1;
+ required Rvalue rvalue = 2;
+}
+
+message Statement {
+ required AssignmentStatement assignment = 1;
+}
+
+message StatementSeq {
+ repeated Statement statements = 1;
+}
+
+message LoopFunction {
+ required StatementSeq statements = 1;
+}
+
+package clang_fuzzer;
diff --git a/tools/clang-fuzzer/cxx_proto.proto b/tools/clang-fuzzer/cxx_proto.proto
index 714a29861e6a..499101fc0fbd 100644
--- a/tools/clang-fuzzer/cxx_proto.proto
+++ b/tools/clang-fuzzer/cxx_proto.proto
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief This file describes a subset of C++ as a protobuf. It is used to
+/// This file describes a subset of C++ as a protobuf. It is used to
/// more easily find interesting inputs for fuzzing Clang.
///
//===----------------------------------------------------------------------===//
diff --git a/tools/clang-fuzzer/fuzzer-initialize/CMakeLists.txt b/tools/clang-fuzzer/fuzzer-initialize/CMakeLists.txt
new file mode 100644
index 000000000000..c149fb3d4b36
--- /dev/null
+++ b/tools/clang-fuzzer/fuzzer-initialize/CMakeLists.txt
@@ -0,0 +1,3 @@
+set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} Support)
+
+add_clang_library(clangFuzzerInitialize fuzzer_initialize.cpp)
diff --git a/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp b/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp
new file mode 100644
index 000000000000..75bf22803bce
--- /dev/null
+++ b/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.cpp
@@ -0,0 +1,65 @@
+//===-- fuzzer_initialize.cpp - Fuzz Clang --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements two functions: one that returns the command line
+/// arguments for a given call to the fuzz target and one that initializes
+/// the fuzzer with the correct command line arguments.
+///
+//===----------------------------------------------------------------------===//
+
+#include "fuzzer_initialize.h"
+
+#include "llvm/InitializePasses.h"
+#include "llvm/PassRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include <cstring>
+
+using namespace clang_fuzzer;
+using namespace llvm;
+
+
+namespace clang_fuzzer {
+
+static std::vector<const char *> CLArgs;
+
+const std::vector<const char *>& GetCLArgs() {
+ return CLArgs;
+}
+
+}
+
+extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
+ InitializeAllTargets();
+ InitializeAllTargetMCs();
+ InitializeAllAsmPrinters();
+ InitializeAllAsmParsers();
+
+ PassRegistry &Registry = *PassRegistry::getPassRegistry();
+ initializeCore(Registry);
+ initializeScalarOpts(Registry);
+ initializeVectorization(Registry);
+ initializeIPO(Registry);
+ initializeAnalysis(Registry);
+ initializeTransformUtils(Registry);
+ initializeInstCombine(Registry);
+ initializeAggressiveInstCombine(Registry);
+ initializeInstrumentation(Registry);
+ initializeTarget(Registry);
+
+ CLArgs.push_back("-O2");
+ for (int I = 1; I < *argc; I++) {
+ if (strcmp((*argv)[I], "-ignore_remaining_args=1") == 0) {
+ for (I++; I < *argc; I++)
+ CLArgs.push_back((*argv)[I]);
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.h b/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.h
new file mode 100644
index 000000000000..83a5cf9dc571
--- /dev/null
+++ b/tools/clang-fuzzer/fuzzer-initialize/fuzzer_initialize.h
@@ -0,0 +1,19 @@
+//==-- fuzzer_initialize.h - Fuzz Clang ------------------------------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a function that returns the command line arguments for a specific
+// call to the fuzz target.
+//
+//===----------------------------------------------------------------------===//
+
+#include <vector>
+
+namespace clang_fuzzer {
+const std::vector<const char *>& GetCLArgs();
+}
diff --git a/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp b/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp
index 312ab91e5fe2..4985fedbe118 100644
--- a/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp
+++ b/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp
@@ -18,17 +18,11 @@
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Option/Option.h"
-#include "llvm/Support/TargetSelect.h"
using namespace clang;
void clang_fuzzer::HandleCXX(const std::string &S,
const std::vector<const char *> &ExtraArgs) {
- llvm::InitializeAllTargets();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllAsmPrinters();
- llvm::InitializeAllAsmParsers();
-
llvm::opt::ArgStringList CC1Args;
CC1Args.push_back("-cc1");
for (auto &A : ExtraArgs)
diff --git a/tools/clang-fuzzer/handle-llvm/CMakeLists.txt b/tools/clang-fuzzer/handle-llvm/CMakeLists.txt
new file mode 100644
index 000000000000..47f9fdf68f40
--- /dev/null
+++ b/tools/clang-fuzzer/handle-llvm/CMakeLists.txt
@@ -0,0 +1,30 @@
+set(LLVM_LINK_COMPONENTS
+ Analysis
+ CodeGen
+ Core
+ ExecutionEngine
+ IPO
+ IRReader
+ MC
+ MCJIT
+ Object
+ RuntimeDyld
+ SelectionDAG
+ Support
+ Target
+ TransformUtils
+ native
+)
+
+# Depend on LLVM IR intrinsic generation.
+set(handle_llvm_deps intrinsics_gen)
+if (CLANG_BUILT_STANDALONE)
+ set(handle_llvm_deps)
+endif()
+
+add_clang_library(clangHandleLLVM
+ handle_llvm.cpp
+
+ DEPENDS
+ ${handle_llvm_deps}
+ )
diff --git a/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp b/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp
new file mode 100644
index 000000000000..ef544ae711ab
--- /dev/null
+++ b/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp
@@ -0,0 +1,178 @@
+//==-- handle_llvm.cpp - Helper function for Clang fuzzers -----------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements HandleLLVM for use by the Clang fuzzers. First runs a loop
+// vectorizer optimization pass over the given IR code. Then mimics lli on both
+// versions to JIT the generated code and execute it. Currently, functions are
+// executed on dummy inputs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "handle_llvm.h"
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/CodeGen/CommandFlags.inc"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/ExecutionEngine/JITEventListener.h"
+#include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/ExecutionEngine/MCJIT.h"
+#include "llvm/ExecutionEngine/ObjectCache.h"
+#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/IR/IRPrintingPasses.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/LegacyPassNameParser.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Pass.h"
+#include "llvm/PassRegistry.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/Vectorize.h"
+
+using namespace llvm;
+
+// Helper function to parse command line args and find the optimization level
+static void getOptLevel(const std::vector<const char *> &ExtraArgs,
+ CodeGenOpt::Level &OLvl) {
+ // Find the optimization level from the command line args
+ OLvl = CodeGenOpt::Default;
+ for (auto &A : ExtraArgs) {
+ if (A[0] == '-' && A[1] == 'O') {
+ switch(A[2]) {
+ case '0': OLvl = CodeGenOpt::None; break;
+ case '1': OLvl = CodeGenOpt::Less; break;
+ case '2': OLvl = CodeGenOpt::Default; break;
+ case '3': OLvl = CodeGenOpt::Aggressive; break;
+ default:
+ errs() << "error: opt level must be between 0 and 3.\n";
+ std::exit(1);
+ }
+ }
+ }
+}
+
+void ErrorAndExit(std::string message) {
+ errs()<< "ERROR: " << message << "\n";
+ std::exit(1);
+}
+
+// Helper function to add optimization passes to the TargetMachine at the
+// specified optimization level, OptLevel
+static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
+ CodeGenOpt::Level OptLevel,
+ unsigned SizeLevel) {
+ // Create and initialize a PassManagerBuilder
+ PassManagerBuilder Builder;
+ Builder.OptLevel = OptLevel;
+ Builder.SizeLevel = SizeLevel;
+ Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel, false);
+ Builder.LoopVectorize = true;
+ Builder.populateModulePassManager(MPM);
+}
+
+// Mimics the opt tool to run an optimization pass over the provided IR
+std::string OptLLVM(const std::string &IR, CodeGenOpt::Level OLvl) {
+ // Create a module that will run the optimization passes
+ SMDiagnostic Err;
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context);
+ if (!M || verifyModule(*M, &errs()))
+ ErrorAndExit("Could not parse IR");
+
+ setFunctionAttributes(getCPUStr(), getFeaturesStr(), *M);
+
+ legacy::PassManager Passes;
+ Triple ModuleTriple(M->getTargetTriple());
+
+ Passes.add(new TargetLibraryInfoWrapperPass(ModuleTriple));
+ Passes.add(createTargetTransformInfoWrapperPass(TargetIRAnalysis()));
+ Passes.add(createVerifierPass());
+
+ AddOptimizationPasses(Passes, OLvl, 0);
+
+ // Add a pass that writes the optimized IR to an output stream
+ std::string outString;
+ raw_string_ostream OS(outString);
+ Passes.add(createPrintModulePass(OS, "", false));
+
+ Passes.run(*M);
+
+ return OS.str();
+}
+
+void CreateAndRunJITFun(const std::string &IR, CodeGenOpt::Level OLvl) {
+ SMDiagnostic Err;
+ LLVMContext Context;
+ std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err,
+ Context);
+ if (!M)
+ ErrorAndExit("Could not parse IR");
+
+ Function *EntryFunc = M->getFunction("foo");
+ if (!EntryFunc)
+ ErrorAndExit("Function not found in module");
+
+ std::string ErrorMsg;
+ EngineBuilder builder(std::move(M));
+ builder.setMArch(MArch);
+ builder.setMCPU(getCPUStr());
+ builder.setMAttrs(getFeatureList());
+ builder.setErrorStr(&ErrorMsg);
+ builder.setEngineKind(EngineKind::JIT);
+ builder.setUseOrcMCJITReplacement(false);
+ builder.setMCJITMemoryManager(make_unique<SectionMemoryManager>());
+ builder.setOptLevel(OLvl);
+ builder.setTargetOptions(InitTargetOptionsFromCodeGenFlags());
+
+ std::unique_ptr<ExecutionEngine> EE(builder.create());
+ if (!EE)
+ ErrorAndExit("Could not create execution engine");
+
+ EE->finalizeObject();
+ EE->runStaticConstructorsDestructors(false);
+
+ typedef void (*func)(int*, int*, int*, int);
+ func f = reinterpret_cast<func>(EE->getPointerToFunction(EntryFunc));
+
+ // Define some dummy arrays to use an input for now
+ int a[] = {1};
+ int b[] = {1};
+ int c[] = {1};
+ f(a, b, c, 1);
+
+ EE->runStaticConstructorsDestructors(true);
+}
+
+// Main fuzz target called by ExampleClangLLVMProtoFuzzer.cpp
+// Mimics the lli tool to JIT the LLVM IR code and execute it
+void clang_fuzzer::HandleLLVM(const std::string &IR,
+ const std::vector<const char *> &ExtraArgs) {
+ // Parse ExtraArgs to set the optimization level
+ CodeGenOpt::Level OLvl;
+ getOptLevel(ExtraArgs, OLvl);
+
+ // First we optimize the IR by running a loop vectorizer pass
+ std::string OptIR = OptLLVM(IR, OLvl);
+
+ CreateAndRunJITFun(OptIR, OLvl);
+ CreateAndRunJITFun(IR, CodeGenOpt::None);
+
+ return;
+}
diff --git a/tools/clang-fuzzer/handle-llvm/handle_llvm.h b/tools/clang-fuzzer/handle-llvm/handle_llvm.h
new file mode 100644
index 000000000000..38aec6799490
--- /dev/null
+++ b/tools/clang-fuzzer/handle-llvm/handle_llvm.h
@@ -0,0 +1,25 @@
+//==-- handle_llvm.h - Helper function for Clang fuzzers -------------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines HandleLLVM for use by the Clang fuzzers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_CLANG_FUZZER_HANDLE_LLVM_HANDLELLVM_H
+#define LLVM_CLANG_TOOLS_CLANG_FUZZER_HANDLE_LLVM_HANDLELLVM_H
+
+#include <string>
+#include <vector>
+
+namespace clang_fuzzer {
+void HandleLLVM(const std::string &S,
+ const std::vector<const char *> &ExtraArgs);
+} // namespace clang_fuzzer
+
+#endif
diff --git a/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt b/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt
index 910b793e0e0d..339959b81af0 100644
--- a/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt
+++ b/tools/clang-fuzzer/proto-to-cxx/CMakeLists.txt
@@ -1,14 +1,22 @@
set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD})
set(CMAKE_CXX_FLAGS ${CXX_FLAGS_NOFUZZ})
-# Hack to bypass LLVM's CMake source checks so we can have both a library and
-# an executable built from this directory.
-set(LLVM_OPTIONAL_SOURCES proto_to_cxx.cpp proto_to_cxx_main.cpp)
+# Needed by LLVM's CMake checks because this file defines multiple targets.
+set(LLVM_OPTIONAL_SOURCES proto_to_cxx.cpp proto_to_cxx_main.cpp
+ loop_proto_to_cxx.cpp loop_proto_to_cxx_main.cpp)
add_clang_library(clangProtoToCXX proto_to_cxx.cpp
DEPENDS clangCXXProto
LINK_LIBS clangCXXProto ${PROTOBUF_LIBRARIES}
)
+add_clang_library(clangLoopProtoToCXX loop_proto_to_cxx.cpp
+ DEPENDS clangCXXLoopProto
+ LINK_LIBS clangCXXLoopProto ${PROTOBUF_LIBRARIES}
+ )
+
add_clang_executable(clang-proto-to-cxx proto_to_cxx_main.cpp)
+add_clang_executable(clang-loop-proto-to-cxx loop_proto_to_cxx_main.cpp)
+
target_link_libraries(clang-proto-to-cxx PRIVATE clangProtoToCXX)
+target_link_libraries(clang-loop-proto-to-cxx PRIVATE clangLoopProtoToCXX)
diff --git a/tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx.cpp b/tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx.cpp
new file mode 100644
index 000000000000..7d8f6650aadb
--- /dev/null
+++ b/tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx.cpp
@@ -0,0 +1,131 @@
+//==-- loop_proto_to_cxx.cpp - Protobuf-C++ conversion ---------------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements functions for converting between protobufs and C++. Differs from
+// proto_to_cxx.cpp by wrapping all the generated C++ code in a single for
+// loop. Also coutputs a different function signature that includes a
+// size_t parameter for the loop to use. The C++ code generated is meant to
+// stress the LLVM loop vectorizer.
+//
+// Still a work in progress.
+//
+//===----------------------------------------------------------------------===//
+
+#include "cxx_loop_proto.pb.h"
+#include "proto_to_cxx.h"
+
+// The following is needed to convert protos in human-readable form
+#include <google/protobuf/text_format.h>
+
+#include <ostream>
+#include <sstream>
+
+namespace clang_fuzzer {
+
+// Forward decls.
+std::ostream &operator<<(std::ostream &os, const BinaryOp &x);
+std::ostream &operator<<(std::ostream &os, const StatementSeq &x);
+
+// Proto to C++.
+std::ostream &operator<<(std::ostream &os, const Const &x) {
+ return os << "(" << x.val() << ")";
+}
+std::ostream &operator<<(std::ostream &os, const VarRef &x) {
+ switch (x.arr()) {
+ case VarRef::ARR_A:
+ return os << "a[i]";
+ case VarRef::ARR_B:
+ return os << "b[i]";
+ case VarRef::ARR_C:
+ return os << "c[i]";
+ }
+}
+std::ostream &operator<<(std::ostream &os, const Rvalue &x) {
+ if (x.has_cons())
+ return os << x.cons();
+ if (x.has_binop())
+ return os << x.binop();
+ if (x.has_varref())
+ return os << x.varref();
+ return os << "1";
+}
+std::ostream &operator<<(std::ostream &os, const BinaryOp &x) {
+ os << "(" << x.left();
+ switch (x.op()) {
+ case BinaryOp::PLUS:
+ os << "+";
+ break;
+ case BinaryOp::MINUS:
+ os << "-";
+ break;
+ case BinaryOp::MUL:
+ os << "*";
+ break;
+ case BinaryOp::XOR:
+ os << "^";
+ break;
+ case BinaryOp::AND:
+ os << "&";
+ break;
+ case BinaryOp::OR:
+ os << "|";
+ break;
+ case BinaryOp::EQ:
+ os << "==";
+ break;
+ case BinaryOp::NE:
+ os << "!=";
+ break;
+ case BinaryOp::LE:
+ os << "<=";
+ break;
+ case BinaryOp::GE:
+ os << ">=";
+ break;
+ case BinaryOp::LT:
+ os << "<";
+ break;
+ case BinaryOp::GT:
+ os << ">";
+ break;
+ }
+ return os << x.right() << ")";
+}
+std::ostream &operator<<(std::ostream &os, const AssignmentStatement &x) {
+ return os << x.varref() << "=" << x.rvalue() << ";\n";
+}
+std::ostream &operator<<(std::ostream &os, const Statement &x) {
+ return os << x.assignment();
+}
+std::ostream &operator<<(std::ostream &os, const StatementSeq &x) {
+ for (auto &st : x.statements())
+ os << st;
+ return os;
+}
+std::ostream &operator<<(std::ostream &os, const LoopFunction &x) {
+ return os << "void foo(int *a, int *b, int *__restrict__ c, size_t s) {\n"
+ << "for (int i=0; i<s; i++){\n"
+ << x.statements() << "}\n}\n";
+}
+
+// ---------------------------------
+
+std::string LoopFunctionToString(const LoopFunction &input) {
+ std::ostringstream os;
+ os << input;
+ return os.str();
+}
+std::string LoopProtoToCxx(const uint8_t *data, size_t size) {
+ LoopFunction message;
+ if (!message.ParsePartialFromArray(data, size))
+ return "#error invalid proto\n";
+ return LoopFunctionToString(message);
+}
+
+} // namespace clang_fuzzer
diff --git a/tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx_main.cpp b/tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx_main.cpp
new file mode 100644
index 000000000000..a4b8e58c1273
--- /dev/null
+++ b/tools/clang-fuzzer/proto-to-cxx/loop_proto_to_cxx_main.cpp
@@ -0,0 +1,31 @@
+//==-- loop_proto_to_cxx_main.cpp - Driver for protobuf-C++ conversion -----==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements a simple driver to print a C++ program from a protobuf with loops.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include <fstream>
+#include <iostream>
+#include <streambuf>
+#include <string>
+
+#include "proto_to_cxx.h"
+
+int main(int argc, char **argv) {
+ for (int i = 1; i < argc; i++) {
+ std::fstream in(argv[i]);
+ std::string str((std::istreambuf_iterator<char>(in)),
+ std::istreambuf_iterator<char>());
+ std::cout << "// " << argv[i] << std::endl;
+ std::cout << clang_fuzzer::LoopProtoToCxx(
+ reinterpret_cast<const uint8_t *>(str.data()), str.size());
+ }
+}
diff --git a/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.cpp b/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.cpp
index cd75e0c99c47..4a86515f5598 100644
--- a/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.cpp
+++ b/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.cpp
@@ -94,7 +94,7 @@ std::string FunctionToString(const Function &input) {
}
std::string ProtoToCxx(const uint8_t *data, size_t size) {
Function message;
- if (!message.ParseFromArray(data, size))
+ if (!message.ParsePartialFromArray(data, size))
return "#error invalid proto\n";
return FunctionToString(message);
}
diff --git a/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.h b/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.h
index 1985e91ba2cd..8d2e2e6f0081 100644
--- a/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.h
+++ b/tools/clang-fuzzer/proto-to-cxx/proto_to_cxx.h
@@ -17,6 +17,10 @@
namespace clang_fuzzer {
class Function;
+class LoopFunction;
+
std::string FunctionToString(const Function &input);
std::string ProtoToCxx(const uint8_t *data, size_t size);
+std::string LoopFunctionToString(const LoopFunction &input);
+std::string LoopProtoToCxx(const uint8_t *data, size_t size);
}
diff --git a/tools/clang-fuzzer/proto-to-llvm/CMakeLists.txt b/tools/clang-fuzzer/proto-to-llvm/CMakeLists.txt
new file mode 100644
index 000000000000..ae58523f2274
--- /dev/null
+++ b/tools/clang-fuzzer/proto-to-llvm/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD})
+set(CMAKE_CXX_FLAGS ${CXX_FLAGS_NOFUZZ})
+
+# Needed by LLVM's CMake checks because this file defines multiple targets.
+set(LLVM_OPTIONAL_SOURCES loop_proto_to_llvm.cpp loop_proto_to_llvm_main.cpp)
+
+add_clang_library(clangLoopProtoToLLVM loop_proto_to_llvm.cpp
+ DEPENDS clangCXXLoopProto
+ LINK_LIBS clangCXXLoopProto ${PROTOBUF_LIBRARIES}
+ )
+
+add_clang_executable(clang-loop-proto-to-llvm loop_proto_to_llvm_main.cpp)
+
+target_link_libraries(clang-loop-proto-to-llvm PRIVATE clangLoopProtoToLLVM)
diff --git a/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.cpp b/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.cpp
new file mode 100644
index 000000000000..16dbcb7b49b2
--- /dev/null
+++ b/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.cpp
@@ -0,0 +1,156 @@
+//==-- loop_proto_to_llvm.cpp - Protobuf-C++ conversion
+//---------------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements functions for converting between protobufs and LLVM IR.
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "loop_proto_to_llvm.h"
+#include "cxx_loop_proto.pb.h"
+
+// The following is needed to convert protos in human-readable form
+#include <google/protobuf/text_format.h>
+
+#include <ostream>
+#include <sstream>
+
+namespace clang_fuzzer {
+
+// Forward decls
+std::string BinopToString(std::ostream &os, const BinaryOp &x);
+std::string StateSeqToString(std::ostream &os, const StatementSeq &x);
+
+// Counter variable to generate new LLVM IR variable names and wrapper function
+std::string get_var() {
+ static int ctr = 0;
+ return "%var" + std::to_string(ctr++);
+}
+
+// Proto to LLVM.
+
+std::string ConstToString(const Const &x) {
+ return std::to_string(x.val());
+}
+std::string VarRefToString(std::ostream &os, const VarRef &x) {
+ std::string arr;
+ switch(x.arr()) {
+ case VarRef::ARR_A:
+ arr = "%a";
+ break;
+ case VarRef::ARR_B:
+ arr = "%b";
+ break;
+ case VarRef::ARR_C:
+ arr = "%c";
+ break;
+ }
+ std::string ptr_var = get_var();
+ os << ptr_var << " = getelementptr i32, i32* " << arr << ", i64 %ct\n";
+ return ptr_var;
+}
+std::string RvalueToString(std::ostream &os, const Rvalue &x) {
+ if(x.has_cons())
+ return ConstToString(x.cons());
+ if(x.has_binop())
+ return BinopToString(os, x.binop());
+ if(x.has_varref()) {
+ std::string var_ref = VarRefToString(os, x.varref());
+ std::string val_var = get_var();
+ os << val_var << " = load i32, i32* " << var_ref << "\n";
+ return val_var;
+ }
+ return "1";
+
+}
+std::string BinopToString(std::ostream &os, const BinaryOp &x) {
+ std::string left = RvalueToString(os, x.left());
+ std::string right = RvalueToString(os, x.right());
+ std::string op;
+ switch (x.op()) {
+ case BinaryOp::PLUS:
+ op = "add";
+ break;
+ case BinaryOp::MINUS:
+ op = "sub";
+ break;
+ case BinaryOp::MUL:
+ op = "mul";
+ break;
+ case BinaryOp::XOR:
+ op = "xor";
+ break;
+ case BinaryOp::AND:
+ op = "and";
+ break;
+ case BinaryOp::OR:
+ op = "or";
+ break;
+ // Support for Boolean operators will be added later
+ case BinaryOp::EQ:
+ case BinaryOp::NE:
+ case BinaryOp::LE:
+ case BinaryOp::GE:
+ case BinaryOp::LT:
+ case BinaryOp::GT:
+ op = "add";
+ break;
+ }
+ std::string val_var = get_var();
+ os << val_var << " = " << op << " i32 " << left << ", " << right << "\n";
+ return val_var;
+}
+std::ostream &operator<<(std::ostream &os, const AssignmentStatement &x) {
+ std::string rvalue = RvalueToString(os, x.rvalue());
+ std::string var_ref = VarRefToString(os, x.varref());
+ return os << "store i32 " << rvalue << ", i32* " << var_ref << "\n";
+}
+std::ostream &operator<<(std::ostream &os, const Statement &x) {
+ return os << x.assignment();
+}
+std::ostream &operator<<(std::ostream &os, const StatementSeq &x) {
+ for (auto &st : x.statements()) {
+ os << st;
+ }
+ return os;
+}
+std::ostream &operator<<(std::ostream &os, const LoopFunction &x) {
+ return os << "define void @foo(i32* %a, i32* %b, i32* noalias %c, i64 %s) {\n"
+ << "%i = alloca i64\n"
+ << "store i64 0, i64* %i\n"
+ << "br label %loop\n\n"
+ << "loop:\n"
+ << "%ct = load i64, i64* %i\n"
+ << "%comp = icmp eq i64 %ct, %s\n"
+ << "br i1 %comp, label %endloop, label %body\n\n"
+ << "body:\n"
+ << x.statements()
+ << "%z = add i64 1, %ct\n"
+ << "store i64 %z, i64* %i\n"
+ << "br label %loop\n\n"
+ << "endloop:\n"
+ << "ret void\n}\n";
+}
+
+// ---------------------------------
+
+std::string LoopFunctionToLLVMString(const LoopFunction &input) {
+ std::ostringstream os;
+ os << input;
+ return os.str();
+}
+std::string LoopProtoToLLVM(const uint8_t *data, size_t size) {
+ LoopFunction message;
+ if (!message.ParsePartialFromArray(data, size))
+ return "#error invalid proto\n";
+ return LoopFunctionToLLVMString(message);
+}
+
+} // namespace clang_fuzzer
diff --git a/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.h b/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.h
new file mode 100644
index 000000000000..51660fcb710b
--- /dev/null
+++ b/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm.h
@@ -0,0 +1,23 @@
+//==-- loop_proto_to_llvm.h - Protobuf-C++ conversion ----------------------------==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines functions for converting between protobufs and LLVM IR.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdint>
+#include <cstddef>
+#include <string>
+
+namespace clang_fuzzer {
+class LoopFunction;
+
+std::string LoopFunctionToLLVMString(const LoopFunction &input);
+std::string LoopProtoToLLVM(const uint8_t *data, size_t size);
+}
diff --git a/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm_main.cpp b/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm_main.cpp
new file mode 100644
index 000000000000..17ca15ec27f5
--- /dev/null
+++ b/tools/clang-fuzzer/proto-to-llvm/loop_proto_to_llvm_main.cpp
@@ -0,0 +1,31 @@
+//==-- loop_proto_to_llvm_main.cpp - Driver for protobuf-LLVM conversion----==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements a simple driver to print a LLVM program from a protobuf with loops
+//
+//===----------------------------------------------------------------------===//
+
+
+#include <fstream>
+#include <iostream>
+#include <streambuf>
+#include <string>
+
+#include "loop_proto_to_llvm.h"
+
+int main(int argc, char **argv) {
+ for (int i = 1; i < argc; i++) {
+ std::fstream in(argv[i]);
+ std::string str((std::istreambuf_iterator<char>(in)),
+ std::istreambuf_iterator<char>());
+ std::cout << ";; " << argv[i] << std::endl;
+ std::cout << clang_fuzzer::LoopProtoToLLVM(
+ reinterpret_cast<const uint8_t *>(str.data()), str.size());
+ }
+}
diff --git a/tools/clang-import-test/CMakeLists.txt b/tools/clang-import-test/CMakeLists.txt
index 836efac8ac3e..dfccfe2304bd 100644
--- a/tools/clang-import-test/CMakeLists.txt
+++ b/tools/clang-import-test/CMakeLists.txt
@@ -1,7 +1,7 @@
set(LLVM_LINK_COMPONENTS
- core
- support
-)
+ Core
+ Support
+ )
if(NOT CLANG_BUILT_STANDALONE)
set(tablegen_deps intrinsics_gen)
diff --git a/tools/clang-import-test/clang-import-test.cpp b/tools/clang-import-test/clang-import-test.cpp
index 1ea7ee3611df..106f3d1d150d 100644
--- a/tools/clang-import-test/clang-import-test.cpp
+++ b/tools/clang-import-test/clang-import-test.cpp
@@ -50,9 +50,10 @@ static llvm::cl::opt<bool>
Direct("direct", llvm::cl::Optional,
llvm::cl::desc("Use the parsed declarations without indirection"));
-static llvm::cl::opt<bool>
- UseOrigins("use-origins", llvm::cl::Optional,
- llvm::cl::desc("Use DeclContext origin information for more accurate lookups"));
+static llvm::cl::opt<bool> UseOrigins(
+ "use-origins", llvm::cl::Optional,
+ llvm::cl::desc(
+ "Use DeclContext origin information for more accurate lookups"));
static llvm::cl::list<std::string>
ClangArgs("Xcc", llvm::cl::ZeroOrMore,
@@ -225,7 +226,7 @@ std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
CI.getDiagnostics(), ModuleName, CI.getHeaderSearchOpts(),
CI.getPreprocessorOpts(), CI.getCodeGenOpts(), LLVMCtx));
}
-} // end namespace
+} // namespace init_convenience
namespace {
@@ -244,7 +245,7 @@ struct CIAndOrigins {
ASTContext &getASTContext() { return CI->getASTContext(); }
FileManager &getFileManager() { return CI->getFileManager(); }
const OriginMap &getOriginMap() {
- static const OriginMap EmptyOriginMap;
+ static const OriginMap EmptyOriginMap{};
if (ExternalASTSource *Source = CI->getASTContext().getExternalSource())
return static_cast<ExternalASTMerger *>(Source)->GetOrigins();
return EmptyOriginMap;
@@ -261,8 +262,8 @@ void AddExternalSource(CIAndOrigins &CI,
{CI.getASTContext(), CI.getFileManager()});
llvm::SmallVector<ExternalASTMerger::ImporterSource, 3> Sources;
for (CIAndOrigins &Import : Imports)
- Sources.push_back(
- {Import.getASTContext(), Import.getFileManager(), Import.getOriginMap()});
+ Sources.push_back({Import.getASTContext(), Import.getFileManager(),
+ Import.getOriginMap()});
auto ES = llvm::make_unique<ExternalASTMerger>(Target, Sources);
CI.getASTContext().setExternalSource(ES.release());
CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage();
@@ -312,7 +313,8 @@ llvm::Expected<CIAndOrigins> Parse(const std::string &Path,
auto &CG = *static_cast<CodeGenerator *>(ASTConsumers.back().get());
if (ShouldDumpAST)
- ASTConsumers.push_back(CreateASTDumper("", true, false, false));
+ ASTConsumers.push_back(CreateASTDumper(nullptr /*Dump to stdout.*/,
+ "", true, false, false));
CI.getDiagnosticClient().BeginSourceFile(
CI.getCompilerInstance().getLangOpts(),
@@ -327,15 +329,15 @@ llvm::Expected<CIAndOrigins> Parse(const std::string &Path,
CG.GetModule()->print(llvm::outs(), nullptr);
if (CI.getDiagnosticClient().getNumErrors())
return llvm::make_error<llvm::StringError>(
- "Errors occured while parsing the expression.", std::error_code());
+ "Errors occurred while parsing the expression.", std::error_code());
return std::move(CI);
}
void Forget(CIAndOrigins &CI, llvm::MutableArrayRef<CIAndOrigins> Imports) {
llvm::SmallVector<ExternalASTMerger::ImporterSource, 3> Sources;
for (CIAndOrigins &Import : Imports)
- Sources.push_back(
- {Import.getASTContext(), Import.getFileManager(), Import.getOriginMap()});
+ Sources.push_back({Import.getASTContext(), Import.getFileManager(),
+ Import.getOriginMap()});
ExternalASTSource *Source = CI.CI->getASTContext().getExternalSource();
auto *Merger = static_cast<ExternalASTMerger *>(Source);
Merger->RemoveSources(Sources);
diff --git a/tools/clang-offload-bundler/ClangOffloadBundler.cpp b/tools/clang-offload-bundler/ClangOffloadBundler.cpp
index 6ff4becb5030..29cd9848d111 100644
--- a/tools/clang-offload-bundler/ClangOffloadBundler.cpp
+++ b/tools/clang-offload-bundler/ClangOffloadBundler.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief This file implements a clang-offload-bundler that bundles different
+/// This file implements a clang-offload-bundler that bundles different
/// files that relate with the same source code but different targets into a
/// single one. Also the implements the opposite functionality, i.e. unbundle
/// files previous created by this tool.
@@ -412,7 +412,7 @@ class ObjectFileHandler final : public FileHandler {
/// read from the buffers.
unsigned NumberOfProcessedInputs = 0;
- /// LLVM context used to to create the auxiliary modules.
+ /// LLVM context used to create the auxiliary modules.
LLVMContext VMContext;
/// LLVM module used to create an object with all the bundle
@@ -536,23 +536,22 @@ public:
// close it and use the name to pass down to clang.
OS.close();
SmallString<128> TargetName = getTriple(TargetNames[HostInputIndex]);
- const char *ClangArgs[] = {"clang",
- "-r",
- "-target",
- TargetName.c_str(),
- "-o",
- OutputFileNames.front().c_str(),
- InputFileNames[HostInputIndex].c_str(),
- BitcodeFileName.c_str(),
- "-nostdlib",
- nullptr};
+ std::vector<StringRef> ClangArgs = {"clang",
+ "-r",
+ "-target",
+ TargetName.c_str(),
+ "-o",
+ OutputFileNames.front().c_str(),
+ InputFileNames[HostInputIndex].c_str(),
+ BitcodeFileName.c_str(),
+ "-nostdlib"};
// If the user asked for the commands to be printed out, we do that instead
// of executing it.
if (PrintExternalCommands) {
errs() << "\"" << ClangBinary.get() << "\"";
- for (unsigned I = 1; ClangArgs[I]; ++I)
- errs() << " \"" << ClangArgs[I] << "\"";
+ for (StringRef Arg : ClangArgs)
+ errs() << " \"" << Arg << "\"";
errs() << "\n";
} else {
// Write the bitcode contents to the temporary file.
@@ -563,7 +562,7 @@ public:
errs() << "error: unable to open temporary file.\n";
return true;
}
- WriteBitcodeToFile(AuxModule.get(), BitcodeFile);
+ WriteBitcodeToFile(*AuxModule, BitcodeFile);
}
bool Failed = sys::ExecuteAndWait(ClangBinary.get(), ClangArgs);
@@ -969,11 +968,11 @@ int main(int argc, const char **argv) {
getOffloadKindAndTriple(Target, Kind, Triple);
bool KindIsValid = !Kind.empty();
- KindIsValid = KindIsValid &&
- StringSwitch<bool>(Kind)
- .Case("host", true)
- .Case("openmp", true)
- .Default(false);
+ KindIsValid = KindIsValid && StringSwitch<bool>(Kind)
+ .Case("host", true)
+ .Case("openmp", true)
+ .Case("hip", true)
+ .Default(false);
bool TripleIsValid = !Triple.empty();
llvm::Triple T(Triple);
diff --git a/tools/clang-refactor/CMakeLists.txt b/tools/clang-refactor/CMakeLists.txt
index d2029066b9b7..b435744ca4bd 100644
--- a/tools/clang-refactor/CMakeLists.txt
+++ b/tools/clang-refactor/CMakeLists.txt
@@ -20,5 +20,3 @@ target_link_libraries(clang-refactor
clangToolingCore
clangToolingRefactor
)
-
-install(TARGETS clang-refactor RUNTIME DESTINATION bin)
diff --git a/tools/clang-refactor/ClangRefactor.cpp b/tools/clang-refactor/ClangRefactor.cpp
index 950b80062cd9..e64f325be242 100644
--- a/tools/clang-refactor/ClangRefactor.cpp
+++ b/tools/clang-refactor/ClangRefactor.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief This file implements a clang-refactor tool that performs various
+/// This file implements a clang-refactor tool that performs various
/// source transformations.
///
//===----------------------------------------------------------------------===//
diff --git a/tools/clang-refactor/TestSupport.cpp b/tools/clang-refactor/TestSupport.cpp
index 9331dfd92eb4..f81f4a8bc8fb 100644
--- a/tools/clang-refactor/TestSupport.cpp
+++ b/tools/clang-refactor/TestSupport.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief This file implements routines that provide refactoring testing
+/// This file implements routines that provide refactoring testing
/// utilities.
///
//===----------------------------------------------------------------------===//
diff --git a/tools/clang-refactor/TestSupport.h b/tools/clang-refactor/TestSupport.h
index 101f35bd94f3..61aa660733fb 100644
--- a/tools/clang-refactor/TestSupport.h
+++ b/tools/clang-refactor/TestSupport.h
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief Declares datatypes and routines that are used by test-specific code
+/// Declares datatypes and routines that are used by test-specific code
/// in clang-refactor.
///
//===----------------------------------------------------------------------===//
diff --git a/tools/clang-rename/CMakeLists.txt b/tools/clang-rename/CMakeLists.txt
index 9689e1c6804d..3b3ab1540a80 100644
--- a/tools/clang-rename/CMakeLists.txt
+++ b/tools/clang-rename/CMakeLists.txt
@@ -3,7 +3,9 @@ set(LLVM_LINK_COMPONENTS
Support
)
-add_clang_tool(clang-rename ClangRename.cpp)
+add_clang_tool(clang-rename
+ ClangRename.cpp
+ )
target_link_libraries(clang-rename
PRIVATE
diff --git a/tools/clang-rename/ClangRename.cpp b/tools/clang-rename/ClangRename.cpp
index 2c14b69ee547..d58f44e4d44e 100644
--- a/tools/clang-rename/ClangRename.cpp
+++ b/tools/clang-rename/ClangRename.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// \brief This file implements a clang-rename tool that automatically finds and
+/// This file implements a clang-rename tool that automatically finds and
/// renames symbols in C++ code.
///
//===----------------------------------------------------------------------===//
@@ -39,7 +39,7 @@
using namespace llvm;
using namespace clang;
-/// \brief An oldname -> newname rename.
+/// An oldname -> newname rename.
struct RenameAllInfo {
unsigned Offset = 0;
std::string QualifiedName;
@@ -51,7 +51,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(RenameAllInfo)
namespace llvm {
namespace yaml {
-/// \brief Specialized MappingTraits to describe how a RenameAllInfo is
+/// Specialized MappingTraits to describe how a RenameAllInfo is
/// (de)serialized.
template <> struct MappingTraits<RenameAllInfo> {
static void mapping(IO &IO, RenameAllInfo &Info) {
diff --git a/tools/diagtool/CMakeLists.txt b/tools/diagtool/CMakeLists.txt
index beb6c35457c4..96d1c390249c 100644
--- a/tools/diagtool/CMakeLists.txt
+++ b/tools/diagtool/CMakeLists.txt
@@ -18,8 +18,14 @@ target_link_libraries(diagtool
clangFrontend
)
-if(UNIX)
- set(CLANGXX_LINK_OR_COPY create_symlink)
-else()
- set(CLANGXX_LINK_OR_COPY copy)
+if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
+ install(TARGETS diagtool
+ COMPONENT diagtool
+ RUNTIME DESTINATION bin)
+
+ if (NOT CMAKE_CONFIGURATION_TYPES)
+ add_llvm_install_targets(install-diagtool
+ DEPENDS diagtool
+ COMPONENT diagtool)
+ endif()
endif()
diff --git a/tools/diagtool/DiagTool.cpp b/tools/diagtool/DiagTool.cpp
index 7582d51ae4f5..d9086af8e989 100644
--- a/tools/diagtool/DiagTool.cpp
+++ b/tools/diagtool/DiagTool.cpp
@@ -48,7 +48,7 @@ void DiagTools::printCommands(llvm::raw_ostream &out) {
if (len > maxName)
maxName = len;
}
- std::sort(toolNames.begin(), toolNames.end());
+ llvm::sort(toolNames.begin(), toolNames.end());
for (std::vector<llvm::StringRef>::iterator it = toolNames.begin(),
ei = toolNames.end(); it != ei; ++it) {
diff --git a/tools/diagtool/DiagnosticNames.h b/tools/diagtool/DiagnosticNames.h
index 598ae6a0ba65..fba59095948c 100644
--- a/tools/diagtool/DiagnosticNames.h
+++ b/tools/diagtool/DiagnosticNames.h
@@ -30,10 +30,10 @@ namespace diagtool {
}
};
- /// \brief Get every diagnostic in the system, sorted by name.
+ /// Get every diagnostic in the system, sorted by name.
llvm::ArrayRef<DiagnosticRecord> getBuiltinDiagnosticsByName();
- /// \brief Get a diagnostic by its ID.
+ /// Get a diagnostic by its ID.
const DiagnosticRecord &getDiagnosticForID(short DiagID);
@@ -101,7 +101,7 @@ namespace diagtool {
}
};
- /// \brief Get every diagnostic group in the system, sorted by name.
+ /// Get every diagnostic group in the system, sorted by name.
llvm::ArrayRef<GroupRecord> getDiagnosticGroups();
template<>
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 22a498422aef..15b0519e4111 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -4,6 +4,7 @@ set( LLVM_LINK_COMPONENTS
CodeGen
Core
IPO
+ AggressiveInstCombine
InstCombine
Instrumentation
MC
@@ -32,6 +33,7 @@ add_clang_tool(clang
driver.cpp
cc1_main.cpp
cc1as_main.cpp
+ cc1gen_reproducer_main.cpp
DEPENDS
${tablegen_deps}
@@ -61,10 +63,6 @@ add_dependencies(clang clang-headers)
if(NOT CLANG_LINKS_TO_CREATE)
set(CLANG_LINKS_TO_CREATE clang++ clang-cl clang-cpp)
-
- if (MSVC)
- list(APPEND CLANG_LINKS_TO_CREATE ../msbuild-bin/cl)
- endif()
endif()
foreach(link ${CLANG_LINKS_TO_CREATE})
@@ -96,20 +94,16 @@ if (APPLE)
set(TOOL_INFO_BUILD_VERSION)
endif()
-if(CLANG_ORDER_FILE AND (LD64_EXECUTABLE OR GOLD_EXECUTABLE))
- include(CMakePushCheckState)
-
- function(check_linker_flag flag out_var)
- cmake_push_check_state()
- set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${flag}")
- check_cxx_compiler_flag("" ${out_var})
- cmake_pop_check_state()
- endfunction()
+if(CLANG_ORDER_FILE AND
+ (LLVM_LINKER_IS_LD64 OR LLVM_LINKER_IS_GOLD OR LLVM_LINKER_IS_LLD))
+ include(CheckLinkerFlag)
- if (LD64_EXECUTABLE)
+ if (LLVM_LINKER_IS_LD64)
set(LINKER_ORDER_FILE_OPTION "-Wl,-order_file,${CLANG_ORDER_FILE}")
- elseif (GOLD_EXECUTABLE)
+ elseif (LLVM_LINKER_IS_GOLD)
set(LINKER_ORDER_FILE_OPTION "-Wl,--section-ordering-file,${CLANG_ORDER_FILE}")
+ elseif (LLVM_LINKER_IS_LLD)
+ set(LINKER_ORDER_FILE_OPTION "-Wl,--symbol-ordering-file,${CLANG_ORDER_FILE}")
endif()
# This is a test to ensure the actual order file works with the linker.
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 1a16746d589d..ef5a191bda0a 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -16,6 +16,7 @@
#include "llvm/Option/Arg.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Config/config.h"
+#include "clang/Basic/Stack.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -26,6 +27,7 @@
#include "clang/Frontend/Utils.h"
#include "clang/FrontendTool/Utils.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
@@ -72,13 +74,6 @@ void initializePollyPasses(llvm::PassRegistry &Registry);
#endif
#ifdef CLANG_HAVE_RLIMITS
-// The amount of stack we think is "sufficient". If less than this much is
-// available, we may be unable to reach our template instantiation depth
-// limit and other similar limits.
-// FIXME: Unify this with the stack we request when spawning a thread to build
-// a module.
-static const int kSufficientStack = 8 << 20;
-
#if defined(__linux__) && defined(__PIE__)
static size_t getCurrentStackAllocation() {
// If we can't compute the current stack usage, allow for 512K of command
@@ -116,7 +111,7 @@ static size_t getCurrentStackAllocation() {
#include <alloca.h>
LLVM_ATTRIBUTE_NOINLINE
-static void ensureStackAddressSpace(int ExtraChunks = 0) {
+static void ensureStackAddressSpace() {
// Linux kernels prior to 4.1 will sometimes locate the heap of a PIE binary
// relatively close to the stack (they are only guaranteed to be 128MiB
// apart). This results in crashes if we happen to heap-allocate more than
@@ -125,7 +120,7 @@ static void ensureStackAddressSpace(int ExtraChunks = 0) {
// To avoid these crashes, ensure that we have sufficient virtual memory
// pages allocated before we start running.
size_t Curr = getCurrentStackAllocation();
- const int kTargetStack = kSufficientStack - 256 * 1024;
+ const int kTargetStack = DesiredStackSize - 256 * 1024;
if (Curr < kTargetStack) {
volatile char *volatile Alloc =
static_cast<volatile char *>(alloca(kTargetStack - Curr));
@@ -145,21 +140,23 @@ static void ensureSufficientStack() {
// Increase the soft stack limit to our desired level, if necessary and
// possible.
- if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < kSufficientStack) {
+ if (rlim.rlim_cur != RLIM_INFINITY &&
+ rlim.rlim_cur < rlim_t(DesiredStackSize)) {
// Try to allocate sufficient stack.
- if (rlim.rlim_max == RLIM_INFINITY || rlim.rlim_max >= kSufficientStack)
- rlim.rlim_cur = kSufficientStack;
+ if (rlim.rlim_max == RLIM_INFINITY ||
+ rlim.rlim_max >= rlim_t(DesiredStackSize))
+ rlim.rlim_cur = DesiredStackSize;
else if (rlim.rlim_cur == rlim.rlim_max)
return;
else
rlim.rlim_cur = rlim.rlim_max;
if (setrlimit(RLIMIT_STACK, &rlim) != 0 ||
- rlim.rlim_cur != kSufficientStack)
+ rlim.rlim_cur != DesiredStackSize)
return;
}
- // We should now have a stack of size at least kSufficientStack. Ensure
+ // We should now have a stack of size at least DesiredStackSize. Ensure
// that we can actually use that much, if necessary.
ensureStackAddressSpace();
}
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 9b90562af903..09db014019bf 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -29,6 +29,7 @@
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCRegisterInfo.h"
@@ -61,7 +62,7 @@ using namespace llvm::opt;
namespace {
-/// \brief Helper class for representing a single invocation of the assembler.
+/// Helper class for representing a single invocation of the assembler.
struct AssemblerInvocation {
/// @name Target Options
/// @{
@@ -93,9 +94,11 @@ struct AssemblerInvocation {
std::string DwarfDebugFlags;
std::string DwarfDebugProducer;
std::string DebugCompilationDir;
+ std::map<const std::string, const std::string> DebugPrefixMap;
llvm::DebugCompressionType CompressDebugSections =
llvm::DebugCompressionType::None;
std::string MainFileName;
+ std::string SplitDwarfFile;
/// @}
/// @name Frontend Options
@@ -181,7 +184,13 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Issue errors on unknown arguments.
for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
- Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args);
+ auto ArgString = A->getAsString(Args);
+ std::string Nearest;
+ if (OptTbl->findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
+ Diags.Report(diag::err_drv_unknown_argument) << ArgString;
+ else
+ Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
+ << ArgString << Nearest;
Success = false;
}
@@ -225,6 +234,9 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
+ for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ))
+ Opts.DebugPrefixMap.insert(StringRef(Arg).split('='));
+
// Frontend Options
if (Args.hasArg(OPT_INPUT)) {
bool First = true;
@@ -240,6 +252,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
}
Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
Opts.OutputPath = Args.getLastArgValue(OPT_o);
+ Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
if (Arg *A = Args.getLastArg(OPT_filetype)) {
StringRef Name = A->getValue();
unsigned OutputType = StringSwitch<unsigned>(Name)
@@ -275,22 +288,17 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
}
static std::unique_ptr<raw_fd_ostream>
-getOutputStream(AssemblerInvocation &Opts, DiagnosticsEngine &Diags,
- bool Binary) {
- if (Opts.OutputPath.empty())
- Opts.OutputPath = "-";
-
+getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
// Make sure that the Out file gets unlinked from the disk if we get a
// SIGINT.
- if (Opts.OutputPath != "-")
- sys::RemoveFileOnSignal(Opts.OutputPath);
+ if (Path != "-")
+ sys::RemoveFileOnSignal(Path);
std::error_code EC;
auto Out = llvm::make_unique<raw_fd_ostream>(
- Opts.OutputPath, EC, (Binary ? sys::fs::F_None : sys::fs::F_Text));
+ Path, EC, (Binary ? sys::fs::F_None : sys::fs::F_Text));
if (EC) {
- Diags.Report(diag::err_fe_unable_to_open_output) << Opts.OutputPath
- << EC.message();
+ Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
return nullptr;
}
@@ -335,9 +343,15 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations);
bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
- std::unique_ptr<raw_fd_ostream> FDOS = getOutputStream(Opts, Diags, IsBinary);
+ if (Opts.OutputPath.empty())
+ Opts.OutputPath = "-";
+ std::unique_ptr<raw_fd_ostream> FDOS =
+ getOutputStream(Opts.OutputPath, Diags, IsBinary);
if (!FDOS)
return true;
+ std::unique_ptr<raw_fd_ostream> DwoOS;
+ if (!Opts.SplitDwarfFile.empty())
+ DwoOS = getOutputStream(Opts.SplitDwarfFile, Diags, IsBinary);
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
@@ -367,6 +381,9 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer));
if (!Opts.DebugCompilationDir.empty())
Ctx.setCompilationDir(Opts.DebugCompilationDir);
+ if (!Opts.DebugPrefixMap.empty())
+ for (const auto &KV : Opts.DebugPrefixMap)
+ Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
if (!Opts.MainFileName.empty())
Ctx.setMainFileName(StringRef(Opts.MainFileName));
Ctx.setDwarfVersion(Opts.DwarfVersion);
@@ -392,17 +409,19 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
MCInstPrinter *IP = TheTarget->createMCInstPrinter(
llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI);
- MCCodeEmitter *CE = nullptr;
- MCAsmBackend *MAB = nullptr;
- if (Opts.ShowEncoding) {
- CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
- MCTargetOptions Options;
- MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple, Opts.CPU, Options);
- }
+
+ std::unique_ptr<MCCodeEmitter> CE;
+ if (Opts.ShowEncoding)
+ CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
+ MCTargetOptions MCOptions;
+ std::unique_ptr<MCAsmBackend> MAB(
+ TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
+
auto FOut = llvm::make_unique<formatted_raw_ostream>(*Out);
Str.reset(TheTarget->createAsmStreamer(
Ctx, std::move(FOut), /*asmverbose*/ true,
- /*useDwarfDirectory*/ true, IP, CE, MAB, Opts.ShowInst));
+ /*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB),
+ Opts.ShowInst));
} else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
Str.reset(createNullStreamer(Ctx));
} else {
@@ -413,18 +432,26 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
Out = BOS.get();
}
- MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
- MCTargetOptions Options;
- MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple,
- Opts.CPU, Options);
+ std::unique_ptr<MCCodeEmitter> CE(
+ TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
+ MCTargetOptions MCOptions;
+ std::unique_ptr<MCAsmBackend> MAB(
+ TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
+ std::unique_ptr<MCObjectWriter> OW =
+ DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
+ : MAB->createObjectWriter(*Out);
+
Triple T(Opts.Triple);
Str.reset(TheTarget->createMCObjectStreamer(
- T, Ctx, std::unique_ptr<MCAsmBackend>(MAB), *Out, std::unique_ptr<MCCodeEmitter>(CE), *STI,
+ T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
/*DWARFMustBeAtTheEnd*/ true));
Str.get()->InitSections(Opts.NoExecStack);
}
+ // Assembly to object compilation should leverage assembly info.
+ Str->setUseAssemblerInfoForParsing(true);
+
bool Failed = false;
std::unique_ptr<MCAsmParser> Parser(
@@ -461,8 +488,12 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
FDOS.reset();
// Delete output file if there were errors.
- if (Failed && Opts.OutputPath != "-")
- sys::fs::remove(Opts.OutputPath);
+ if (Failed) {
+ if (Opts.OutputPath != "-")
+ sys::fs::remove(Opts.OutputPath);
+ if (!Opts.SplitDwarfFile.empty() && Opts.SplitDwarfFile != "-")
+ sys::fs::remove(Opts.SplitDwarfFile);
+ }
return Failed;
}
diff --git a/tools/driver/cc1gen_reproducer_main.cpp b/tools/driver/cc1gen_reproducer_main.cpp
new file mode 100644
index 000000000000..a4c034d8d357
--- /dev/null
+++ b/tools/driver/cc1gen_reproducer_main.cpp
@@ -0,0 +1,196 @@
+//===-- cc1gen_reproducer_main.cpp - Clang reproducer generator ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the clang -cc1gen-reproducer functionality, which
+// generates reproducers for invocations for clang-based tools.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+namespace {
+
+struct UnsavedFileHash {
+ std::string Name;
+ std::string MD5;
+};
+
+struct ClangInvocationInfo {
+ std::string Toolchain;
+ std::string LibclangOperation;
+ std::string LibclangOptions;
+ std::vector<std::string> Arguments;
+ std::vector<std::string> InvocationArguments;
+ std::vector<UnsavedFileHash> UnsavedFileHashes;
+ bool Dump = false;
+};
+
+} // end anonymous namespace
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(UnsavedFileHash)
+
+namespace llvm {
+namespace yaml {
+
+template <> struct MappingTraits<UnsavedFileHash> {
+ static void mapping(IO &IO, UnsavedFileHash &Info) {
+ IO.mapRequired("name", Info.Name);
+ IO.mapRequired("md5", Info.MD5);
+ }
+};
+
+template <> struct MappingTraits<ClangInvocationInfo> {
+ static void mapping(IO &IO, ClangInvocationInfo &Info) {
+ IO.mapRequired("toolchain", Info.Toolchain);
+ IO.mapOptional("libclang.operation", Info.LibclangOperation);
+ IO.mapOptional("libclang.opts", Info.LibclangOptions);
+ IO.mapRequired("args", Info.Arguments);
+ IO.mapOptional("invocation-args", Info.InvocationArguments);
+ IO.mapOptional("unsaved_file_hashes", Info.UnsavedFileHashes);
+ }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+static std::string generateReproducerMetaInfo(const ClangInvocationInfo &Info) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ OS << '{';
+ bool NeedComma = false;
+ auto EmitKey = [&](StringRef Key) {
+ if (NeedComma)
+ OS << ", ";
+ NeedComma = true;
+ OS << '"' << Key << "\": ";
+ };
+ auto EmitStringKey = [&](StringRef Key, StringRef Value) {
+ if (Value.empty())
+ return;
+ EmitKey(Key);
+ OS << '"' << Value << '"';
+ };
+ EmitStringKey("libclang.operation", Info.LibclangOperation);
+ EmitStringKey("libclang.opts", Info.LibclangOptions);
+ if (!Info.InvocationArguments.empty()) {
+ EmitKey("invocation-args");
+ OS << '[';
+ for (const auto &Arg : llvm::enumerate(Info.InvocationArguments)) {
+ if (Arg.index())
+ OS << ',';
+ OS << '"' << Arg.value() << '"';
+ }
+ OS << ']';
+ }
+ OS << '}';
+ // FIXME: Compare unsaved file hashes and report mismatch in the reproducer.
+ if (Info.Dump)
+ llvm::outs() << "REPRODUCER METAINFO: " << OS.str() << "\n";
+ return std::move(OS.str());
+}
+
+/// Generates a reproducer for a set of arguments from a specific invocation.
+static llvm::Optional<driver::Driver::CompilationDiagnosticReport>
+generateReproducerForInvocationArguments(ArrayRef<const char *> Argv,
+ const ClangInvocationInfo &Info) {
+ using namespace driver;
+ auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Argv[0]);
+
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions;
+
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, new IgnoringDiagConsumer());
+ ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
+ Driver TheDriver(Argv[0], llvm::sys::getDefaultTargetTriple(), Diags);
+ TheDriver.setTargetAndMode(TargetAndMode);
+
+ std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Argv));
+ if (C && !C->containsError()) {
+ for (const auto &J : C->getJobs()) {
+ if (const Command *Cmd = dyn_cast<Command>(&J)) {
+ Driver::CompilationDiagnosticReport Report;
+ TheDriver.generateCompilationDiagnostics(
+ *C, *Cmd, generateReproducerMetaInfo(Info), &Report);
+ return Report;
+ }
+ }
+ }
+
+ return None;
+}
+
+std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes);
+
+static void printReproducerInformation(
+ llvm::raw_ostream &OS, const ClangInvocationInfo &Info,
+ const driver::Driver::CompilationDiagnosticReport &Report) {
+ OS << "REPRODUCER:\n";
+ OS << "{\n";
+ OS << R"("files":[)";
+ for (const auto &File : llvm::enumerate(Report.TemporaryFiles)) {
+ if (File.index())
+ OS << ',';
+ OS << '"' << File.value() << '"';
+ }
+ OS << "]\n}\n";
+}
+
+int cc1gen_reproducer_main(ArrayRef<const char *> Argv, const char *Argv0,
+ void *MainAddr) {
+ if (Argv.size() < 1) {
+ llvm::errs() << "error: missing invocation file\n";
+ return 1;
+ }
+ // Parse the invocation descriptor.
+ StringRef Input = Argv[0];
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
+ llvm::MemoryBuffer::getFile(Input);
+ if (!Buffer) {
+ llvm::errs() << "error: failed to read " << Input << ": "
+ << Buffer.getError().message() << "\n";
+ return 1;
+ }
+ llvm::yaml::Input YAML(Buffer.get()->getBuffer());
+ ClangInvocationInfo InvocationInfo;
+ YAML >> InvocationInfo;
+ if (Argv.size() > 1 && Argv[1] == StringRef("-v"))
+ InvocationInfo.Dump = true;
+
+ // Create an invocation that will produce the reproducer.
+ std::vector<const char *> DriverArgs;
+ for (const auto &Arg : InvocationInfo.Arguments)
+ DriverArgs.push_back(Arg.c_str());
+ std::string Path = GetExecutablePath(Argv0, /*CanonicalPrefixes=*/true);
+ DriverArgs[0] = Path.c_str();
+ llvm::Optional<driver::Driver::CompilationDiagnosticReport> Report =
+ generateReproducerForInvocationArguments(DriverArgs, InvocationInfo);
+
+ // Emit the information about the reproduce files to stdout.
+ int Result = 1;
+ if (Report) {
+ printReproducerInformation(llvm::outs(), InvocationInfo, *Report);
+ Result = 0;
+ }
+
+ // Remove the input file.
+ llvm::sys::fs::remove(Input);
+ return Result;
+}
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index fa757da9535c..0455ba029c65 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Driver/Driver.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
@@ -26,7 +26,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/Config/llvm-config.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
@@ -34,9 +33,8 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
-#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Regex.h"
@@ -205,6 +203,8 @@ extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
void *MainAddr);
extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
void *MainAddr);
+extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv,
+ const char *Argv0, void *MainAddr);
static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
SmallVectorImpl<const char *> &ArgVector,
@@ -212,20 +212,21 @@ static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
// Put target and mode arguments at the start of argument list so that
// arguments specified in command line could override them. Avoid putting
// them at index 0, as an option like '-cc1' must remain the first.
- auto InsertionPoint = ArgVector.begin();
- if (InsertionPoint != ArgVector.end())
+ int InsertionPoint = 0;
+ if (ArgVector.size() > 0)
++InsertionPoint;
if (NameParts.DriverMode) {
// Add the mode flag to the arguments.
- ArgVector.insert(InsertionPoint,
+ ArgVector.insert(ArgVector.begin() + InsertionPoint,
GetStableCStr(SavedStrings, NameParts.DriverMode));
}
if (NameParts.TargetIsValid) {
const char *arr[] = {"-target", GetStableCStr(SavedStrings,
NameParts.TargetPrefix)};
- ArgVector.insert(InsertionPoint, std::begin(arr), std::end(arr));
+ ArgVector.insert(ArgVector.begin() + InsertionPoint,
+ std::begin(arr), std::end(arr));
}
}
@@ -309,29 +310,22 @@ static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) {
return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP);
if (Tool == "as")
return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP);
+ if (Tool == "gen-reproducer")
+ return cc1gen_reproducer_main(argv.slice(2), argv[0], GetExecutablePathVP);
// Reject unknown tools.
- llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n";
+ llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
+ << "Valid tools include '-cc1' and '-cc1as'.\n";
return 1;
}
int main(int argc_, const char **argv_) {
- llvm::sys::PrintStackTraceOnErrorSignal(argv_[0]);
- llvm::PrettyStackTraceProgram X(argc_, argv_);
- llvm::llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+ llvm::InitLLVM X(argc_, argv_);
+ SmallVector<const char *, 256> argv(argv_, argv_ + argc_);
if (llvm::sys::Process::FixupStandardFileDescriptors())
return 1;
- SmallVector<const char *, 256> argv;
- llvm::SpecificBumpPtrAllocator<char> ArgAllocator;
- std::error_code EC = llvm::sys::Process::GetArgumentVector(
- argv, llvm::makeArrayRef(argv_, argc_), ArgAllocator);
- if (EC) {
- llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n';
- return 1;
- }
-
llvm::InitializeAllTargets();
auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]);
@@ -490,7 +484,7 @@ int main(int argc_, const char **argv_) {
// On Windows, abort will return an exit code of 3. In these cases,
// generate additional diagnostic information if possible.
bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
DiagnoseCrash |= CommandRes == 3;
#endif
if (DiagnoseCrash) {
@@ -506,7 +500,7 @@ int main(int argc_, const char **argv_) {
// results now. This happens in -disable-free mode.
llvm::TimerGroup::printAll(llvm::errs());
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
// Exit status should not be negative on Win32, unless abnormal termination.
// Once abnormal termiation was caught, negative status should not be
// propagated.
diff --git a/tools/libclang/BuildSystem.cpp b/tools/libclang/BuildSystem.cpp
index 99aa5b6f2ff0..79fa69c40bae 100644
--- a/tools/libclang/BuildSystem.cpp
+++ b/tools/libclang/BuildSystem.cpp
@@ -17,6 +17,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/CBindingWrapping.h"
#include "llvm/Support/Chrono.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -78,7 +79,7 @@ clang_VirtualFileOverlay_writeToBuffer(CXVirtualFileOverlay VFO, unsigned,
unwrap(VFO)->write(OS);
StringRef Data = OS.str();
- *out_buffer_ptr = (char*)malloc(Data.size());
+ *out_buffer_ptr = static_cast<char*>(llvm::safe_malloc(Data.size()));
*out_buffer_size = Data.size();
memcpy(*out_buffer_ptr, Data.data(), Data.size());
return CXError_Success;
@@ -140,7 +141,7 @@ clang_ModuleMapDescriptor_writeToBuffer(CXModuleMapDescriptor MMD, unsigned,
OS << "}\n";
StringRef Data = OS.str();
- *out_buffer_ptr = (char*)malloc(Data.size());
+ *out_buffer_ptr = static_cast<char*>(llvm::safe_malloc(Data.size()));
*out_buffer_size = Data.size();
memcpy(*out_buffer_ptr, Data.data(), Data.size());
return CXError_Success;
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index f4d347108c9f..499d9abf9a8e 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -26,6 +26,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/ASTUnit.h"
@@ -103,7 +104,7 @@ cxtu::CXTUOwner::~CXTUOwner() {
clang_disposeTranslationUnit(TU);
}
-/// \brief Compare two source ranges to determine their relative position in
+/// Compare two source ranges to determine their relative position in
/// the translation unit.
static RangeComparisonResult RangeCompare(SourceManager &SM,
SourceRange R1,
@@ -119,7 +120,7 @@ static RangeComparisonResult RangeCompare(SourceManager &SM,
return RangeOverlap;
}
-/// \brief Determine if a source location falls within, before, or after a
+/// Determine if a source location falls within, before, or after a
/// a given source range.
static RangeComparisonResult LocationCompare(SourceManager &SM,
SourceLocation L, SourceRange R) {
@@ -134,7 +135,7 @@ static RangeComparisonResult LocationCompare(SourceManager &SM,
return RangeOverlap;
}
-/// \brief Translate a Clang source range into a CIndex source range.
+/// Translate a Clang source range into a CIndex source range.
///
/// Clang internally represents ranges where the end location points to the
/// start of the token at the end. However, for external clients it is more
@@ -146,9 +147,13 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
// We want the last character in this location, so we will adjust the
// location accordingly.
SourceLocation EndLoc = R.getEnd();
- if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc))
- EndLoc = SM.getExpansionRange(EndLoc).second;
- if (R.isTokenRange() && EndLoc.isValid()) {
+ bool IsTokenRange = R.isTokenRange();
+ if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc)) {
+ CharSourceRange Expansion = SM.getExpansionRange(EndLoc);
+ EndLoc = Expansion.getEnd();
+ IsTokenRange = Expansion.isTokenRange();
+ }
+ if (IsTokenRange && EndLoc.isValid()) {
unsigned Length = Lexer::MeasureTokenLength(SM.getSpellingLoc(EndLoc),
SM, LangOpts);
EndLoc = EndLoc.getLocWithOffset(Length);
@@ -174,7 +179,7 @@ RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) {
return RangeCompare(AU->getSourceManager(), R, RegionOfInterest);
}
-/// \brief Visit the given cursor and, if requested by the visitor,
+/// Visit the given cursor and, if requested by the visitor,
/// its children.
///
/// \param Cursor the cursor to visit.
@@ -478,7 +483,7 @@ bool CursorVisitor::visitPreprocessedEntities(InputIterator First,
return false;
}
-/// \brief Visit the children of the given cursor.
+/// Visit the children of the given cursor.
///
/// \returns true if the visitation should be aborted, false if it
/// should continue.
@@ -785,7 +790,17 @@ bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) {
return false;
}
-/// \brief Compare two base or member initializers based on their source order.
+static bool HasTrailingReturnType(FunctionDecl *ND) {
+ const QualType Ty = ND->getType();
+ if (const FunctionType *AFT = Ty->getAs<FunctionType>()) {
+ if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(AFT))
+ return FT->hasTrailingReturn();
+ }
+
+ return false;
+}
+
+/// Compare two base or member initializers based on their source order.
static int CompareCXXCtorInitializers(CXXCtorInitializer *const *X,
CXXCtorInitializer *const *Y) {
return (*X)->getSourceOrder() - (*Y)->getSourceOrder();
@@ -804,14 +819,16 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// written. This requires a bit of work.
TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>();
+ const bool HasTrailingRT = HasTrailingReturnType(ND);
// If we have a function declared directly (without the use of a typedef),
// visit just the return type. Otherwise, just visit the function's type
// now.
- if ((FTL && !isa<CXXConversionDecl>(ND) && Visit(FTL.getReturnLoc())) ||
+ if ((FTL && !isa<CXXConversionDecl>(ND) && !HasTrailingRT &&
+ Visit(FTL.getReturnLoc())) ||
(!FTL && Visit(TL)))
return true;
-
+
// Visit the nested-name-specifier, if present.
if (NestedNameSpecifierLoc QualifierLoc = ND->getQualifierLoc())
if (VisitNestedNameSpecifierLoc(QualifierLoc))
@@ -827,7 +844,11 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// Visit the function parameters, if we have a function type.
if (FTL && VisitFunctionTypeLoc(FTL, true))
return true;
-
+
+ // Visit the function's trailing return type.
+ if (FTL && HasTrailingRT && Visit(FTL.getReturnLoc()))
+ return true;
+
// FIXME: Attributes?
}
@@ -1023,8 +1044,8 @@ bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
}
// Now sort the Decls so that they appear in lexical order.
- std::sort(DeclsInContainer.begin(), DeclsInContainer.end(),
- [&SM](Decl *A, Decl *B) {
+ llvm::sort(DeclsInContainer.begin(), DeclsInContainer.end(),
+ [&SM](Decl *A, Decl *B) {
SourceLocation L_A = A->getLocStart();
SourceLocation L_B = B->getLocStart();
return L_A != L_B ?
@@ -1751,6 +1772,7 @@ DEFAULT_TYPELOC_IMPL(IncompleteArray, ArrayType)
DEFAULT_TYPELOC_IMPL(VariableArray, ArrayType)
DEFAULT_TYPELOC_IMPL(DependentSizedArray, ArrayType)
DEFAULT_TYPELOC_IMPL(DependentAddressSpace, Type)
+DEFAULT_TYPELOC_IMPL(DependentVector, Type)
DEFAULT_TYPELOC_IMPL(DependentSizedExtVector, Type)
DEFAULT_TYPELOC_IMPL(Vector, Type)
DEFAULT_TYPELOC_IMPL(ExtVector, VectorType)
@@ -1780,7 +1802,7 @@ bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) {
bool CursorVisitor::VisitAttributes(Decl *D) {
for (const auto *I : D->attrs())
- if (Visit(MakeCXCursor(I, D, TU)))
+ if (!I->isImplicit() && Visit(MakeCXCursor(I, D, TU)))
return true;
return false;
@@ -2099,7 +2121,7 @@ void EnqueueVisitor::EnqueueChildren(const Stmt *S) {
namespace {
class OMPClauseEnqueue : public ConstOMPClauseVisitor<OMPClauseEnqueue> {
EnqueueVisitor *Visitor;
- /// \brief Process clauses with list of variables.
+ /// Process clauses with list of variables.
template <typename T>
void VisitOMPClauseList(T *Node);
public:
@@ -2577,7 +2599,7 @@ void EnqueueVisitor::VisitMemberExpr(const MemberExpr *M) {
return;
// Ignore base anonymous struct/union fields, otherwise they will shadow the
- // real field that that we are interested in.
+ // real field that we are interested in.
if (auto *SubME = dyn_cast<MemberExpr>(M->getBase())) {
if (auto *FD = dyn_cast_or_null<FieldDecl>(SubME->getMemberDecl())) {
if (FD->isAnonymousStructOrUnion()) {
@@ -3360,9 +3382,15 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
= options & CXTranslationUnit_CacheCompletionResults;
bool IncludeBriefCommentsInCodeCompletion
= options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
- bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies;
bool SingleFileParse = options & CXTranslationUnit_SingleFileParse;
bool ForSerialization = options & CXTranslationUnit_ForSerialization;
+ SkipFunctionBodiesScope SkipFunctionBodies = SkipFunctionBodiesScope::None;
+ if (options & CXTranslationUnit_SkipFunctionBodies) {
+ SkipFunctionBodies =
+ (options & CXTranslationUnit_LimitSkipFunctionBodiesToPreamble)
+ ? SkipFunctionBodiesScope::Preamble
+ : SkipFunctionBodiesScope::PreambleAndMainFile;
+ }
// Configure the diagnostics.
IntrusiveRefCntPtr<DiagnosticsEngine>
@@ -4233,6 +4261,14 @@ int clang_File_isEqual(CXFile file1, CXFile file2) {
return FEnt1->getUniqueID() == FEnt2->getUniqueID();
}
+CXString clang_File_tryGetRealPathName(CXFile SFile) {
+ if (!SFile)
+ return cxstring::createNull();
+
+ FileEntry *FEnt = static_cast<FileEntry *>(SFile);
+ return cxstring::createRef(FEnt->tryGetRealPathName());
+}
+
//===----------------------------------------------------------------------===//
// CXCursor Operations.
//===----------------------------------------------------------------------===//
@@ -4690,6 +4726,195 @@ CXStringSet *clang_Cursor_getObjCManglings(CXCursor C) {
return cxstring::createSet(Manglings);
}
+CXPrintingPolicy clang_getCursorPrintingPolicy(CXCursor C) {
+ if (clang_Cursor_isNull(C))
+ return 0;
+ return new PrintingPolicy(getCursorContext(C).getPrintingPolicy());
+}
+
+void clang_PrintingPolicy_dispose(CXPrintingPolicy Policy) {
+ if (Policy)
+ delete static_cast<PrintingPolicy *>(Policy);
+}
+
+unsigned
+clang_PrintingPolicy_getProperty(CXPrintingPolicy Policy,
+ enum CXPrintingPolicyProperty Property) {
+ if (!Policy)
+ return 0;
+
+ PrintingPolicy *P = static_cast<PrintingPolicy *>(Policy);
+ switch (Property) {
+ case CXPrintingPolicy_Indentation:
+ return P->Indentation;
+ case CXPrintingPolicy_SuppressSpecifiers:
+ return P->SuppressSpecifiers;
+ case CXPrintingPolicy_SuppressTagKeyword:
+ return P->SuppressTagKeyword;
+ case CXPrintingPolicy_IncludeTagDefinition:
+ return P->IncludeTagDefinition;
+ case CXPrintingPolicy_SuppressScope:
+ return P->SuppressScope;
+ case CXPrintingPolicy_SuppressUnwrittenScope:
+ return P->SuppressUnwrittenScope;
+ case CXPrintingPolicy_SuppressInitializers:
+ return P->SuppressInitializers;
+ case CXPrintingPolicy_ConstantArraySizeAsWritten:
+ return P->ConstantArraySizeAsWritten;
+ case CXPrintingPolicy_AnonymousTagLocations:
+ return P->AnonymousTagLocations;
+ case CXPrintingPolicy_SuppressStrongLifetime:
+ return P->SuppressStrongLifetime;
+ case CXPrintingPolicy_SuppressLifetimeQualifiers:
+ return P->SuppressLifetimeQualifiers;
+ case CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors:
+ return P->SuppressTemplateArgsInCXXConstructors;
+ case CXPrintingPolicy_Bool:
+ return P->Bool;
+ case CXPrintingPolicy_Restrict:
+ return P->Restrict;
+ case CXPrintingPolicy_Alignof:
+ return P->Alignof;
+ case CXPrintingPolicy_UnderscoreAlignof:
+ return P->UnderscoreAlignof;
+ case CXPrintingPolicy_UseVoidForZeroParams:
+ return P->UseVoidForZeroParams;
+ case CXPrintingPolicy_TerseOutput:
+ return P->TerseOutput;
+ case CXPrintingPolicy_PolishForDeclaration:
+ return P->PolishForDeclaration;
+ case CXPrintingPolicy_Half:
+ return P->Half;
+ case CXPrintingPolicy_MSWChar:
+ return P->MSWChar;
+ case CXPrintingPolicy_IncludeNewlines:
+ return P->IncludeNewlines;
+ case CXPrintingPolicy_MSVCFormatting:
+ return P->MSVCFormatting;
+ case CXPrintingPolicy_ConstantsAsWritten:
+ return P->ConstantsAsWritten;
+ case CXPrintingPolicy_SuppressImplicitBase:
+ return P->SuppressImplicitBase;
+ case CXPrintingPolicy_FullyQualifiedName:
+ return P->FullyQualifiedName;
+ }
+
+ assert(false && "Invalid CXPrintingPolicyProperty");
+ return 0;
+}
+
+void clang_PrintingPolicy_setProperty(CXPrintingPolicy Policy,
+ enum CXPrintingPolicyProperty Property,
+ unsigned Value) {
+ if (!Policy)
+ return;
+
+ PrintingPolicy *P = static_cast<PrintingPolicy *>(Policy);
+ switch (Property) {
+ case CXPrintingPolicy_Indentation:
+ P->Indentation = Value;
+ return;
+ case CXPrintingPolicy_SuppressSpecifiers:
+ P->SuppressSpecifiers = Value;
+ return;
+ case CXPrintingPolicy_SuppressTagKeyword:
+ P->SuppressTagKeyword = Value;
+ return;
+ case CXPrintingPolicy_IncludeTagDefinition:
+ P->IncludeTagDefinition = Value;
+ return;
+ case CXPrintingPolicy_SuppressScope:
+ P->SuppressScope = Value;
+ return;
+ case CXPrintingPolicy_SuppressUnwrittenScope:
+ P->SuppressUnwrittenScope = Value;
+ return;
+ case CXPrintingPolicy_SuppressInitializers:
+ P->SuppressInitializers = Value;
+ return;
+ case CXPrintingPolicy_ConstantArraySizeAsWritten:
+ P->ConstantArraySizeAsWritten = Value;
+ return;
+ case CXPrintingPolicy_AnonymousTagLocations:
+ P->AnonymousTagLocations = Value;
+ return;
+ case CXPrintingPolicy_SuppressStrongLifetime:
+ P->SuppressStrongLifetime = Value;
+ return;
+ case CXPrintingPolicy_SuppressLifetimeQualifiers:
+ P->SuppressLifetimeQualifiers = Value;
+ return;
+ case CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors:
+ P->SuppressTemplateArgsInCXXConstructors = Value;
+ return;
+ case CXPrintingPolicy_Bool:
+ P->Bool = Value;
+ return;
+ case CXPrintingPolicy_Restrict:
+ P->Restrict = Value;
+ return;
+ case CXPrintingPolicy_Alignof:
+ P->Alignof = Value;
+ return;
+ case CXPrintingPolicy_UnderscoreAlignof:
+ P->UnderscoreAlignof = Value;
+ return;
+ case CXPrintingPolicy_UseVoidForZeroParams:
+ P->UseVoidForZeroParams = Value;
+ return;
+ case CXPrintingPolicy_TerseOutput:
+ P->TerseOutput = Value;
+ return;
+ case CXPrintingPolicy_PolishForDeclaration:
+ P->PolishForDeclaration = Value;
+ return;
+ case CXPrintingPolicy_Half:
+ P->Half = Value;
+ return;
+ case CXPrintingPolicy_MSWChar:
+ P->MSWChar = Value;
+ return;
+ case CXPrintingPolicy_IncludeNewlines:
+ P->IncludeNewlines = Value;
+ return;
+ case CXPrintingPolicy_MSVCFormatting:
+ P->MSVCFormatting = Value;
+ return;
+ case CXPrintingPolicy_ConstantsAsWritten:
+ P->ConstantsAsWritten = Value;
+ return;
+ case CXPrintingPolicy_SuppressImplicitBase:
+ P->SuppressImplicitBase = Value;
+ return;
+ case CXPrintingPolicy_FullyQualifiedName:
+ P->FullyQualifiedName = Value;
+ return;
+ }
+
+ assert(false && "Invalid CXPrintingPolicyProperty");
+}
+
+CXString clang_getCursorPrettyPrinted(CXCursor C, CXPrintingPolicy cxPolicy) {
+ if (clang_Cursor_isNull(C))
+ return cxstring::createEmpty();
+
+ if (clang_isDeclaration(C.kind)) {
+ const Decl *D = getCursorDecl(C);
+ if (!D)
+ return cxstring::createEmpty();
+
+ SmallString<128> Str;
+ llvm::raw_svector_ostream OS(Str);
+ PrintingPolicy *UserPolicy = static_cast<PrintingPolicy *>(cxPolicy);
+ D->print(OS, UserPolicy ? *UserPolicy
+ : getCursorContext(C).getPrintingPolicy());
+
+ return cxstring::createDup(OS.str());
+ }
+
+ return cxstring::createEmpty();
+}
+
CXString clang_getCursorDisplayName(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getCursorSpelling(C);
@@ -4838,6 +5063,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("VariableRef");
case CXCursor_IntegerLiteral:
return cxstring::createRef("IntegerLiteral");
+ case CXCursor_FixedPointLiteral:
+ return cxstring::createRef("FixedPointLiteral");
case CXCursor_FloatingLiteral:
return cxstring::createRef("FloatingLiteral");
case CXCursor_ImaginaryLiteral:
@@ -5421,6 +5648,15 @@ unsigned clang_isDeclaration(enum CXCursorKind K) {
(K >= CXCursor_FirstExtraDecl && K <= CXCursor_LastExtraDecl);
}
+unsigned clang_isInvalidDeclaration(CXCursor C) {
+ if (clang_isDeclaration(C.kind)) {
+ if (const Decl *D = getCursorDecl(C))
+ return D->isInvalidDecl();
+ }
+
+ return 0;
+}
+
unsigned clang_isReference(enum CXCursorKind K) {
return K >= CXCursor_FirstRef && K <= CXCursor_LastRef;
}
@@ -5727,7 +5963,7 @@ static SourceRange getRawCursorExtent(CXCursor C) {
return SourceRange();
}
-/// \brief Retrieves the "raw" cursor extent, which is then extended to include
+/// Retrieves the "raw" cursor extent, which is then extended to include
/// the decl-specifier-seq for declarations.
static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
if (clang_isDeclaration(C.kind)) {
@@ -6420,6 +6656,42 @@ static void getTokens(ASTUnit *CXXUnit, SourceRange Range,
} while (Lex.getBufferLocation() < EffectiveBufferEnd);
}
+CXToken *clang_getToken(CXTranslationUnit TU, CXSourceLocation Location) {
+ LOG_FUNC_SECTION {
+ *Log << TU << ' ' << Location;
+ }
+
+ if (isNotUsableTU(TU)) {
+ LOG_BAD_TU(TU);
+ return NULL;
+ }
+
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
+ if (!CXXUnit)
+ return NULL;
+
+ SourceLocation Begin = cxloc::translateSourceLocation(Location);
+ if (Begin.isInvalid())
+ return NULL;
+ SourceManager &SM = CXXUnit->getSourceManager();
+ std::pair<FileID, unsigned> DecomposedEnd = SM.getDecomposedLoc(Begin);
+ DecomposedEnd.second += Lexer::MeasureTokenLength(Begin, SM, CXXUnit->getLangOpts());
+
+ SourceLocation End = SM.getComposedLoc(DecomposedEnd.first, DecomposedEnd.second);
+
+ SmallVector<CXToken, 32> CXTokens;
+ getTokens(CXXUnit, SourceRange(Begin, End), CXTokens);
+
+ if (CXTokens.empty())
+ return NULL;
+
+ CXTokens.resize(1);
+ CXToken *Token = static_cast<CXToken *>(llvm::safe_malloc(sizeof(CXToken)));
+
+ memmove(Token, CXTokens.data(), sizeof(CXToken));
+ return Token;
+}
+
void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
CXToken **Tokens, unsigned *NumTokens) {
LOG_FUNC_SECTION {
@@ -6452,7 +6724,8 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
if (CXTokens.empty())
return;
- *Tokens = (CXToken *)malloc(sizeof(CXToken) * CXTokens.size());
+ *Tokens = static_cast<CXToken *>(
+ llvm::safe_malloc(sizeof(CXToken) * CXTokens.size()));
memmove(*Tokens, CXTokens.data(), sizeof(CXToken) * CXTokens.size());
*NumTokens = CXTokens.size();
}
@@ -6536,7 +6809,7 @@ public:
bool postVisitChildren(CXCursor cursor);
void AnnotateTokens();
- /// \brief Determine whether the annotator saw any cursors that have
+ /// Determine whether the annotator saw any cursors that have
/// context-sensitive keywords.
bool hasContextSensitiveKeywords() const {
return HasContextSensitiveKeywords;
@@ -6561,7 +6834,7 @@ static inline void updateCursorAnnotation(CXCursor &Cursor,
Cursor = updateC;
}
-/// \brief It annotates and advances tokens with a cursor until the comparison
+/// It annotates and advances tokens with a cursor until the comparison
//// between the cursor location and the source range is the same as
/// \arg compResult.
///
@@ -6586,7 +6859,7 @@ void AnnotateTokensWorker::annotateAndAdvanceTokens(CXCursor updateC,
}
}
-/// \brief Special annotation handling for macro argument tokens.
+/// Special annotation handling for macro argument tokens.
/// \returns true if it advanced beyond all macro tokens, false otherwise.
bool AnnotateTokensWorker::annotateAndAdvanceFunctionMacroTokens(
CXCursor updateC,
@@ -6830,7 +7103,7 @@ static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor,
namespace {
-/// \brief Uses the macro expansions in the preprocessing record to find
+/// Uses the macro expansions in the preprocessing record to find
/// and mark tokens that are macro arguments. This info is used by the
/// AnnotateTokensWorker.
class MarkMacroArgTokensVisitor {
@@ -6905,7 +7178,7 @@ MarkMacroArgTokensVisitorDelegate(CXCursor cursor, CXCursor parent,
parent);
}
-/// \brief Used by \c annotatePreprocessorTokens.
+/// Used by \c annotatePreprocessorTokens.
/// \returns true if lexing was finished, false otherwise.
static bool lexNext(Lexer &Lex, Token &Tok,
unsigned &NextIdx, unsigned NumTokens) {
@@ -7358,10 +7631,10 @@ static void getCursorPlatformAvailabilityForDecl(
if (AvailabilityAttrs.empty())
return;
- std::sort(AvailabilityAttrs.begin(), AvailabilityAttrs.end(),
- [](AvailabilityAttr *LHS, AvailabilityAttr *RHS) {
- return LHS->getPlatform()->getName() <
- RHS->getPlatform()->getName();
+ llvm::sort(AvailabilityAttrs.begin(), AvailabilityAttrs.end(),
+ [](AvailabilityAttr *LHS, AvailabilityAttr *RHS) {
+ return LHS->getPlatform()->getName() <
+ RHS->getPlatform()->getName();
});
ASTContext &Ctx = D->getASTContext();
auto It = std::unique(
@@ -7479,8 +7752,8 @@ CXTLSKind clang_getCursorTLSKind(CXCursor cursor) {
return CXTLS_None;
}
- /// \brief If the given cursor is the "templated" declaration
- /// descibing a class or function template, return the class or
+ /// If the given cursor is the "templated" declaration
+ /// describing a class or function template, return the class or
/// function template.
static const Decl *maybeGetTemplateCursor(const Decl *D) {
if (!D)
@@ -8135,6 +8408,7 @@ CXSourceRangeList *clang_getSkippedRanges(CXTranslationUnit TU, CXFile file) {
SourceManager &sm = Ctx.getSourceManager();
FileEntry *fileEntry = static_cast<FileEntry *>(file);
FileID wantedFileID = sm.translateFile(fileEntry);
+ bool isMainFile = wantedFileID == sm.getMainFileID();
const std::vector<SourceRange> &SkippedRanges = ppRec->getSkippedRanges();
std::vector<SourceRange> wantedRanges;
@@ -8142,6 +8416,8 @@ CXSourceRangeList *clang_getSkippedRanges(CXTranslationUnit TU, CXFile file) {
i != ei; ++i) {
if (sm.getFileID(i->getBegin()) == wantedFileID || sm.getFileID(i->getEnd()) == wantedFileID)
wantedRanges.push_back(*i);
+ else if (isMainFile && (astUnit->isInPreambleFileID(i->getBegin()) || astUnit->isInPreambleFileID(i->getEnd())))
+ wantedRanges.push_back(*i);
}
skipped->count = wantedRanges.size();
@@ -8200,8 +8476,8 @@ void clang::PrintLibclangResourceUsage(CXTranslationUnit TU) {
// Misc. utility functions.
//===----------------------------------------------------------------------===//
-/// Default to using an 8 MB stack size on "safety" threads.
-static unsigned SafetyStackThreadSize = 8 << 20;
+/// Default to using our desired 8 MB stack size on "safety" threads.
+static unsigned SafetyStackThreadSize = DesiredStackSize;
namespace clang {
@@ -8246,7 +8522,7 @@ void cxindex::printDiagsToStderr(ASTUnit *Unit) {
fprintf(stderr, "%s\n", clang_getCString(Msg));
clang_disposeString(Msg);
}
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
// On Windows, force a flush, since there may be multiple copies of
// stderr and stdout in the file system, all with different buffers
// but writing to the same device.
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index d4af0870c0b6..f49f9763c362 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -16,6 +16,7 @@
#include "CIndexDiagnostic.h"
#include "CLog.h"
#include "CXCursor.h"
+#include "CXSourceLocation.h"
#include "CXString.h"
#include "CXTranslationUnit.h"
#include "clang/AST/Decl.h"
@@ -240,7 +241,7 @@ clang_getCompletionBriefComment(CXCompletionString completion_string) {
namespace {
-/// \brief The CXCodeCompleteResults structure we allocate internally;
+/// The CXCodeCompleteResults structure we allocate internally;
/// the client only sees the initial CXCodeCompleteResults structure.
///
/// Normally, clients of CXString shouldn't care whether or not a CXString is
@@ -251,62 +252,105 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
AllocatedCXCodeCompleteResults(IntrusiveRefCntPtr<FileManager> FileMgr);
~AllocatedCXCodeCompleteResults();
- /// \brief Diagnostics produced while performing code completion.
+ /// Diagnostics produced while performing code completion.
SmallVector<StoredDiagnostic, 8> Diagnostics;
- /// \brief Allocated API-exposed wrappters for Diagnostics.
+ /// Allocated API-exposed wrappters for Diagnostics.
SmallVector<CXStoredDiagnostic *, 8> DiagnosticsWrappers;
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
- /// \brief Diag object
+ /// Diag object
IntrusiveRefCntPtr<DiagnosticsEngine> Diag;
- /// \brief Language options used to adjust source locations.
+ /// Language options used to adjust source locations.
LangOptions LangOpts;
- /// \brief File manager, used for diagnostics.
+ /// File manager, used for diagnostics.
IntrusiveRefCntPtr<FileManager> FileMgr;
- /// \brief Source manager, used for diagnostics.
+ /// Source manager, used for diagnostics.
IntrusiveRefCntPtr<SourceManager> SourceMgr;
- /// \brief Temporary buffers that will be deleted once we have finished with
+ /// Temporary buffers that will be deleted once we have finished with
/// the code-completion results.
SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers;
- /// \brief Allocator used to store globally cached code-completion results.
+ /// Allocator used to store globally cached code-completion results.
std::shared_ptr<clang::GlobalCodeCompletionAllocator>
CachedCompletionAllocator;
- /// \brief Allocator used to store code completion results.
+ /// Allocator used to store code completion results.
std::shared_ptr<clang::GlobalCodeCompletionAllocator> CodeCompletionAllocator;
- /// \brief Context under which completion occurred.
+ /// Context under which completion occurred.
enum clang::CodeCompletionContext::Kind ContextKind;
- /// \brief A bitfield representing the acceptable completions for the
+ /// A bitfield representing the acceptable completions for the
/// current context.
unsigned long long Contexts;
- /// \brief The kind of the container for the current context for completions.
+ /// The kind of the container for the current context for completions.
enum CXCursorKind ContainerKind;
- /// \brief The USR of the container for the current context for completions.
+ /// The USR of the container for the current context for completions.
std::string ContainerUSR;
- /// \brief a boolean value indicating whether there is complete information
+ /// a boolean value indicating whether there is complete information
/// about the container
unsigned ContainerIsIncomplete;
- /// \brief A string containing the Objective-C selector entered thus far for a
+ /// A string containing the Objective-C selector entered thus far for a
/// message send.
std::string Selector;
+
+ /// Vector of fix-its for each completion result that *must* be applied
+ /// before that result for the corresponding completion item.
+ std::vector<std::vector<FixItHint>> FixItsVector;
};
} // end anonymous namespace
-/// \brief Tracks the number of code-completion result objects that are
+unsigned clang_getCompletionNumFixIts(CXCodeCompleteResults *results,
+ unsigned completion_index) {
+ AllocatedCXCodeCompleteResults *allocated_results = (AllocatedCXCodeCompleteResults *)results;
+
+ if (!allocated_results || allocated_results->FixItsVector.size() <= completion_index)
+ return 0;
+
+ return static_cast<unsigned>(allocated_results->FixItsVector[completion_index].size());
+}
+
+CXString clang_getCompletionFixIt(CXCodeCompleteResults *results,
+ unsigned completion_index,
+ unsigned fixit_index,
+ CXSourceRange *replacement_range) {
+ AllocatedCXCodeCompleteResults *allocated_results = (AllocatedCXCodeCompleteResults *)results;
+
+ if (!allocated_results || allocated_results->FixItsVector.size() <= completion_index) {
+ if (replacement_range)
+ *replacement_range = clang_getNullRange();
+ return cxstring::createNull();
+ }
+
+ ArrayRef<FixItHint> FixIts = allocated_results->FixItsVector[completion_index];
+ if (FixIts.size() <= fixit_index) {
+ if (replacement_range)
+ *replacement_range = clang_getNullRange();
+ return cxstring::createNull();
+ }
+
+ const FixItHint &FixIt = FixIts[fixit_index];
+ if (replacement_range) {
+ *replacement_range = cxloc::translateSourceRange(
+ *allocated_results->SourceMgr, allocated_results->LangOpts,
+ FixIt.RemoveRange);
+ }
+
+ return cxstring::createRef(FixIt.CodeToInsert.c_str());
+}
+
+/// Tracks the number of code-completion result objects that are
/// currently active.
///
/// Used for debugging purposes only.
@@ -531,8 +575,10 @@ namespace {
CodeCompletionResult *Results,
unsigned NumResults) override {
StoredResults.reserve(StoredResults.size() + NumResults);
+ if (includeFixIts())
+ AllocatedResults.FixItsVector.reserve(NumResults);
for (unsigned I = 0; I != NumResults; ++I) {
- CodeCompletionString *StoredCompletion
+ CodeCompletionString *StoredCompletion
= Results[I].CreateCodeCompletionString(S, Context, getAllocator(),
getCodeCompletionTUInfo(),
includeBriefComments());
@@ -541,8 +587,10 @@ namespace {
R.CursorKind = Results[I].CursorKind;
R.CompletionString = StoredCompletion;
StoredResults.push_back(R);
+ if (includeFixIts())
+ AllocatedResults.FixItsVector.emplace_back(std::move(Results[I].FixIts));
}
-
+
enum CodeCompletionContext::Kind contextKind = Context.getKind();
AllocatedResults.ContextKind = contextKind;
@@ -643,13 +691,14 @@ clang_codeCompleteAt_Impl(CXTranslationUnit TU, const char *complete_filename,
ArrayRef<CXUnsavedFile> unsaved_files,
unsigned options) {
bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments;
+ bool SkipPreamble = options & CXCodeComplete_SkipPreamble;
+ bool IncludeFixIts = options & CXCodeComplete_IncludeCompletionsWithFixIts;
#ifdef UDP_CODE_COMPLETION_LOGGER
#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime();
#endif
#endif
-
bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != nullptr;
if (cxtu::isNotUsableTU(TU)) {
@@ -689,6 +738,8 @@ clang_codeCompleteAt_Impl(CXTranslationUnit TU, const char *complete_filename,
// Create a code-completion consumer to capture the results.
CodeCompleteOptions Opts;
Opts.IncludeBriefComments = IncludeBriefComments;
+ Opts.LoadExternal = !SkipPreamble;
+ Opts.IncludeFixIts = IncludeFixIts;
CaptureCompletionResults Capture(Opts, *Results, &TU);
// Perform completion.
@@ -911,7 +962,7 @@ CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *ResultsIn) {
return cxstring::createDup(Results->Selector);
}
-/// \brief Simple utility function that appends a \p New string to the given
+/// Simple utility function that appends a \p New string to the given
/// \p Old string, using the \p Buffer for storage.
///
/// \param Old The string to which we are appending. This parameter will be
@@ -935,7 +986,7 @@ static void AppendToString(StringRef &Old, StringRef New,
Old = Buffer.str();
}
-/// \brief Get the typed-text blocks from the given code-completion string
+/// Get the typed-text blocks from the given code-completion string
/// and return them as a single string.
///
/// \param String The code-completion string whose typed-text blocks will be
@@ -962,7 +1013,7 @@ namespace {
= (CodeCompletionString *)XR.CompletionString;
CodeCompletionString *Y
= (CodeCompletionString *)YR.CompletionString;
-
+
SmallString<256> XBuffer;
StringRef XText = GetTypedName(X, XBuffer);
SmallString<256> YBuffer;
diff --git a/tools/libclang/CIndexDiagnostic.h b/tools/libclang/CIndexDiagnostic.h
index 9f406987ebf1..e865df0894a6 100644
--- a/tools/libclang/CIndexDiagnostic.h
+++ b/tools/libclang/CIndexDiagnostic.h
@@ -58,34 +58,34 @@ public:
virtual ~CXDiagnosticImpl();
- /// \brief Return the severity of the diagnostic.
+ /// Return the severity of the diagnostic.
virtual CXDiagnosticSeverity getSeverity() const = 0;
- /// \brief Return the location of the diagnostic.
+ /// Return the location of the diagnostic.
virtual CXSourceLocation getLocation() const = 0;
- /// \brief Return the spelling of the diagnostic.
+ /// Return the spelling of the diagnostic.
virtual CXString getSpelling() const = 0;
- /// \brief Return the text for the diagnostic option.
+ /// Return the text for the diagnostic option.
virtual CXString getDiagnosticOption(CXString *Disable) const = 0;
- /// \brief Return the category of the diagnostic.
+ /// Return the category of the diagnostic.
virtual unsigned getCategory() const = 0;
- /// \brief Return the category string of the diagnostic.
+ /// Return the category string of the diagnostic.
virtual CXString getCategoryText() const = 0;
- /// \brief Return the number of source ranges for the diagnostic.
+ /// Return the number of source ranges for the diagnostic.
virtual unsigned getNumRanges() const = 0;
- /// \brief Return the source ranges for the diagnostic.
+ /// Return the source ranges for the diagnostic.
virtual CXSourceRange getRange(unsigned Range) const = 0;
- /// \brief Return the number of FixIts.
+ /// Return the number of FixIts.
virtual unsigned getNumFixIts() const = 0;
- /// \brief Return the FixIt information (source range and inserted text).
+ /// Return the FixIt information (source range and inserted text).
virtual CXString getFixIt(unsigned FixIt,
CXSourceRange *ReplacementRange) const = 0;
@@ -107,7 +107,7 @@ private:
Kind K;
};
-/// \brief The storage behind a CXDiagnostic
+/// The storage behind a CXDiagnostic
struct CXStoredDiagnostic : public CXDiagnosticImpl {
const StoredDiagnostic &Diag;
const LangOptions &LangOpts;
@@ -119,34 +119,34 @@ struct CXStoredDiagnostic : public CXDiagnosticImpl {
~CXStoredDiagnostic() override {}
- /// \brief Return the severity of the diagnostic.
+ /// Return the severity of the diagnostic.
CXDiagnosticSeverity getSeverity() const override;
- /// \brief Return the location of the diagnostic.
+ /// Return the location of the diagnostic.
CXSourceLocation getLocation() const override;
- /// \brief Return the spelling of the diagnostic.
+ /// Return the spelling of the diagnostic.
CXString getSpelling() const override;
- /// \brief Return the text for the diagnostic option.
+ /// Return the text for the diagnostic option.
CXString getDiagnosticOption(CXString *Disable) const override;
- /// \brief Return the category of the diagnostic.
+ /// Return the category of the diagnostic.
unsigned getCategory() const override;
- /// \brief Return the category string of the diagnostic.
+ /// Return the category string of the diagnostic.
CXString getCategoryText() const override;
- /// \brief Return the number of source ranges for the diagnostic.
+ /// Return the number of source ranges for the diagnostic.
unsigned getNumRanges() const override;
- /// \brief Return the source ranges for the diagnostic.
+ /// Return the source ranges for the diagnostic.
CXSourceRange getRange(unsigned Range) const override;
- /// \brief Return the number of FixIts.
+ /// Return the number of FixIts.
unsigned getNumFixIts() const override;
- /// \brief Return the FixIt information (source range and inserted text).
+ /// Return the FixIt information (source range and inserted text).
CXString getFixIt(unsigned FixIt,
CXSourceRange *ReplacementRange) const override;
diff --git a/tools/libclang/CIndexHigh.cpp b/tools/libclang/CIndexHigh.cpp
index d4666c2288c9..a9cd2cac42ec 100644
--- a/tools/libclang/CIndexHigh.cpp
+++ b/tools/libclang/CIndexHigh.cpp
@@ -65,7 +65,7 @@ struct FindFileIdRefVisitData {
return cxtu::getASTUnit(TU)->getASTContext();
}
- /// \brief We are looking to find all semantically relevant identifiers,
+ /// We are looking to find all semantically relevant identifiers,
/// so the definition of "canonical" here is different than in the AST, e.g.
///
/// \code
@@ -129,7 +129,7 @@ private:
} // end anonymous namespace.
-/// \brief For a macro \arg Loc, returns the file spelling location and sets
+/// For a macro \arg Loc, returns the file spelling location and sets
/// to \arg isMacroArg whether the spelling resides inside a macro definition or
/// a macro argument.
static SourceLocation getFileSpellingLoc(SourceManager &SM,
diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp
index 62ea88172069..3c6e1530f198 100644
--- a/tools/libclang/CIndexer.cpp
+++ b/tools/libclang/CIndexer.cpp
@@ -17,20 +17,20 @@
#include "clang/Basic/Version.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Config/llvm-config.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MutexGuard.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/YAMLParser.h"
#include <cstdio>
#ifdef __CYGWIN__
#include <cygwin/version.h>
#include <sys/cygwin.h>
-#define LLVM_ON_WIN32 1
+#define _WIN32 1
#endif
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
@@ -46,7 +46,7 @@ const std::string &CIndexer::getClangResourcesPath() {
SmallString<128> LibClangPath;
// Find the location where this library lives (libclang.dylib).
-#ifdef LLVM_ON_WIN32
+#ifdef _WIN32
MEMORY_BASIC_INFORMATION mbi;
char path[MAX_PATH];
VirtualQuery((void *)(uintptr_t)clang_createTranslationUnit, &mbi,
@@ -112,7 +112,7 @@ LibclangInvocationReporter::LibclangInvocationReporter(
// Write out the information about the invocation to it.
auto WriteStringKey = [&OS](StringRef Key, StringRef Value) {
OS << R"(")" << Key << R"(":")";
- OS << Value << '"';
+ OS << llvm::yaml::escape(Value) << '"';
};
OS << '{';
WriteStringKey("toolchain", Idx.getClangToolchainPath());
@@ -126,14 +126,14 @@ LibclangInvocationReporter::LibclangInvocationReporter(
for (const auto &I : llvm::enumerate(Args)) {
if (I.index())
OS << ',';
- OS << '"' << I.value() << '"';
+ OS << '"' << llvm::yaml::escape(I.value()) << '"';
}
if (!InvocationArgs.empty()) {
OS << R"(],"invocation-args":[)";
for (const auto &I : llvm::enumerate(InvocationArgs)) {
if (I.index())
OS << ',';
- OS << '"' << I.value() << '"';
+ OS << '"' << llvm::yaml::escape(I.value()) << '"';
}
}
if (!UnsavedFiles.empty()) {
diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h
index 6c46eed4fb98..3ba35d6db601 100644
--- a/tools/libclang/CIndexer.h
+++ b/tools/libclang/CIndexer.h
@@ -52,7 +52,7 @@ public:
Options(CXGlobalOpt_None), PCHContainerOps(std::move(PCHContainerOps)) {
}
- /// \brief Whether we only want to see "local" declarations (that did not
+ /// Whether we only want to see "local" declarations (that did not
/// come from a previous precompiled header). If false, we want to see all
/// declarations.
bool getOnlyLocalDecls() const { return OnlyLocalDecls; }
@@ -74,7 +74,7 @@ public:
return Options & opt;
}
- /// \brief Get the path of the clang resource files.
+ /// Get the path of the clang resource files.
const std::string &getClangResourcesPath();
StringRef getClangToolchainPath();
@@ -103,47 +103,47 @@ private:
std::string File;
};
- /// \brief Return the current size to request for "safety".
+ /// Return the current size to request for "safety".
unsigned GetSafetyThreadStackSize();
- /// \brief Set the current size to request for "safety" (or 0, if safety
+ /// Set the current size to request for "safety" (or 0, if safety
/// threads should not be used).
void SetSafetyThreadStackSize(unsigned Value);
- /// \brief Execution the given code "safely", using crash recovery or safety
+ /// Execution the given code "safely", using crash recovery or safety
/// threads when possible.
///
/// \return False if a crash was detected.
bool RunSafely(llvm::CrashRecoveryContext &CRC, llvm::function_ref<void()> Fn,
unsigned Size = 0);
- /// \brief Set the thread priority to background.
+ /// Set the thread priority to background.
/// FIXME: Move to llvm/Support.
void setThreadBackgroundPriority();
- /// \brief Print libclang's resource usage to standard error.
+ /// Print libclang's resource usage to standard error.
void PrintLibclangResourceUsage(CXTranslationUnit TU);
namespace cxindex {
void printDiagsToStderr(ASTUnit *Unit);
- /// \brief If \c MacroDefLoc points at a macro definition with \c II as
+ /// If \c MacroDefLoc points at a macro definition with \c II as
/// its name, this retrieves its MacroInfo.
MacroInfo *getMacroInfo(const IdentifierInfo &II,
SourceLocation MacroDefLoc, CXTranslationUnit TU);
- /// \brief Retrieves the corresponding MacroInfo of a MacroDefinitionRecord.
+ /// Retrieves the corresponding MacroInfo of a MacroDefinitionRecord.
const MacroInfo *getMacroInfo(const MacroDefinitionRecord *MacroDef,
CXTranslationUnit TU);
- /// \brief If \c Loc resides inside the definition of \c MI and it points at
+ /// If \c Loc resides inside the definition of \c MI and it points at
/// an identifier that has ever been a macro name, this returns the latest
/// MacroDefinitionRecord for that name, otherwise it returns NULL.
MacroDefinitionRecord *checkForMacroInMacroDefinition(const MacroInfo *MI,
SourceLocation Loc,
CXTranslationUnit TU);
- /// \brief If \c Tok resides inside the definition of \c MI and it points at
+ /// If \c Tok resides inside the definition of \c MI and it points at
/// an identifier that has ever been a macro name, this returns the latest
/// MacroDefinitionRecord for that name, otherwise it returns NULL.
MacroDefinitionRecord *checkForMacroInMacroDefinition(const MacroInfo *MI,
diff --git a/tools/libclang/CLog.h b/tools/libclang/CLog.h
index e1d6a57e4a01..a935995a1135 100644
--- a/tools/libclang/CLog.h
+++ b/tools/libclang/CLog.h
@@ -31,7 +31,7 @@ namespace cxindex {
class Logger;
typedef IntrusiveRefCntPtr<Logger> LogRef;
-/// \brief Collects logging output and writes it to stderr when it's destructed.
+/// Collects logging output and writes it to stderr when it's destructed.
/// Common use case:
/// \code
/// if (LogRef Log = Logger::make(__func__)) {
@@ -90,7 +90,7 @@ public:
}
}
-/// \brief Macros to automate common uses of Logger. Like this:
+/// Macros to automate common uses of Logger. Like this:
/// \code
/// LOG_FUNC_SECTION {
/// *Log << "blah";
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index 44406378207b..e539c8308e75 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -67,7 +67,7 @@ option(LIBCLANG_BUILD_STATIC
set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/libclang.exports)
if(MSVC)
- # Avoid LNK4197 not to spceify libclang.def here.
+ # Avoid LNK4197 by not specifying libclang.exports here.
# Each functions is exported as "dllexport" in include/clang-c.
# KB835326
set(LLVM_EXPORTED_SYMBOL_FILE)
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index fb61249a778f..b4ad0595cc53 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -305,6 +305,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
K = CXCursor_IntegerLiteral;
break;
+ case Stmt::FixedPointLiteralClass:
+ K = CXCursor_FixedPointLiteral;
+ break;
+
case Stmt::FloatingLiteralClass:
K = CXCursor_FloatingLiteral;
break;
@@ -1196,19 +1200,19 @@ int clang_Cursor_getNumTemplateArguments(CXCursor C) {
}
enum CXGetTemplateArgumentStatus {
- /** \brief The operation completed successfully */
+ /** The operation completed successfully */
CXGetTemplateArgumentStatus_Success = 0,
- /** \brief The specified cursor did not represent a FunctionDecl. */
+ /** The specified cursor did not represent a FunctionDecl. */
CXGetTemplateArgumentStatus_CursorNotFunctionDecl = -1,
- /** \brief The specified cursor was not castable to a FunctionDecl. */
+ /** The specified cursor was not castable to a FunctionDecl. */
CXGetTemplateArgumentStatus_BadFunctionDeclCast = -2,
- /** \brief A NULL FunctionTemplateSpecializationInfo was retrieved. */
+ /** A NULL FunctionTemplateSpecializationInfo was retrieved. */
CXGetTemplateArgumentStatus_NullTemplSpecInfo = -3,
- /** \brief An invalid (OOB) argument index was specified */
+ /** An invalid (OOB) argument index was specified */
CXGetTemplateArgumentStatus_InvalidIndex = -4
};
@@ -1469,17 +1473,17 @@ void clang_getOverriddenCursors(CXCursor cursor,
assert(cxcursor::getCursorTU(backRefCursor) == TU);
Vec->push_back(backRefCursor);
- // Get the overriden cursors.
+ // Get the overridden cursors.
cxcursor::getOverriddenCursors(cursor, *Vec);
- // Did we get any overriden cursors? If not, return Vec to the pool
+ // Did we get any overridden cursors? If not, return Vec to the pool
// of available cursor vectors.
if (Vec->size() == 1) {
pool.AvailableCursors.push_back(Vec);
return;
}
- // Now tell the caller about the overriden cursors.
+ // Now tell the caller about the overridden cursors.
assert(Vec->size() > 1);
*overridden = &((*Vec)[1]);
*num_overridden = Vec->size() - 1;
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index 083b86934d16..a5d9fff2a55a 100644
--- a/tools/libclang/CXCursor.h
+++ b/tools/libclang/CXCursor.h
@@ -58,109 +58,109 @@ CXCursor MakeCXCursor(const clang::Stmt *S, const clang::Decl *Parent,
SourceRange RegionOfInterest = SourceRange());
CXCursor MakeCXCursorInvalid(CXCursorKind K, CXTranslationUnit TU = nullptr);
-/// \brief Create an Objective-C superclass reference at the given location.
+/// Create an Objective-C superclass reference at the given location.
CXCursor MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super,
SourceLocation Loc,
CXTranslationUnit TU);
-/// \brief Unpack an ObjCSuperClassRef cursor into the interface it references
+/// Unpack an ObjCSuperClassRef cursor into the interface it references
/// and optionally the location where the reference occurred.
std::pair<const ObjCInterfaceDecl *, SourceLocation>
getCursorObjCSuperClassRef(CXCursor C);
-/// \brief Create an Objective-C protocol reference at the given location.
+/// Create an Objective-C protocol reference at the given location.
CXCursor MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto,
SourceLocation Loc,
CXTranslationUnit TU);
-/// \brief Unpack an ObjCProtocolRef cursor into the protocol it references
+/// Unpack an ObjCProtocolRef cursor into the protocol it references
/// and optionally the location where the reference occurred.
std::pair<const ObjCProtocolDecl *, SourceLocation>
getCursorObjCProtocolRef(CXCursor C);
-/// \brief Create an Objective-C class reference at the given location.
+/// Create an Objective-C class reference at the given location.
CXCursor MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class,
SourceLocation Loc,
CXTranslationUnit TU);
-/// \brief Unpack an ObjCClassRef cursor into the class it references
+/// Unpack an ObjCClassRef cursor into the class it references
/// and optionally the location where the reference occurred.
std::pair<const ObjCInterfaceDecl *, SourceLocation>
getCursorObjCClassRef(CXCursor C);
-/// \brief Create a type reference at the given location.
+/// Create a type reference at the given location.
CXCursor MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc,
CXTranslationUnit TU);
-/// \brief Unpack a TypeRef cursor into the class it references
+/// Unpack a TypeRef cursor into the class it references
/// and optionally the location where the reference occurred.
std::pair<const TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C);
-/// \brief Create a reference to a template at the given location.
+/// Create a reference to a template at the given location.
CXCursor MakeCursorTemplateRef(const TemplateDecl *Template, SourceLocation Loc,
CXTranslationUnit TU);
-/// \brief Unpack a TemplateRef cursor into the template it references and
+/// Unpack a TemplateRef cursor into the template it references and
/// the location where the reference occurred.
std::pair<const TemplateDecl *, SourceLocation>
getCursorTemplateRef(CXCursor C);
-/// \brief Create a reference to a namespace or namespace alias at the given
+/// Create a reference to a namespace or namespace alias at the given
/// location.
CXCursor MakeCursorNamespaceRef(const NamedDecl *NS, SourceLocation Loc,
CXTranslationUnit TU);
-/// \brief Unpack a NamespaceRef cursor into the namespace or namespace alias
+/// Unpack a NamespaceRef cursor into the namespace or namespace alias
/// it references and the location where the reference occurred.
std::pair<const NamedDecl *, SourceLocation> getCursorNamespaceRef(CXCursor C);
-/// \brief Create a reference to a variable at the given location.
+/// Create a reference to a variable at the given location.
CXCursor MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc,
CXTranslationUnit TU);
-/// \brief Unpack a VariableRef cursor into the variable it references and the
+/// Unpack a VariableRef cursor into the variable it references and the
/// location where the where the reference occurred.
std::pair<const VarDecl *, SourceLocation> getCursorVariableRef(CXCursor C);
-/// \brief Create a reference to a field at the given location.
+/// Create a reference to a field at the given location.
CXCursor MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc,
CXTranslationUnit TU);
-/// \brief Unpack a MemberRef cursor into the field it references and the
+/// Unpack a MemberRef cursor into the field it references and the
/// location where the reference occurred.
std::pair<const FieldDecl *, SourceLocation> getCursorMemberRef(CXCursor C);
-/// \brief Create a CXX base specifier cursor.
+/// Create a CXX base specifier cursor.
CXCursor MakeCursorCXXBaseSpecifier(const CXXBaseSpecifier *B,
CXTranslationUnit TU);
-/// \brief Unpack a CXXBaseSpecifier cursor into a CXXBaseSpecifier.
+/// Unpack a CXXBaseSpecifier cursor into a CXXBaseSpecifier.
const CXXBaseSpecifier *getCursorCXXBaseSpecifier(CXCursor C);
-/// \brief Create a preprocessing directive cursor.
+/// Create a preprocessing directive cursor.
CXCursor MakePreprocessingDirectiveCursor(SourceRange Range,
CXTranslationUnit TU);
-/// \brief Unpack a given preprocessing directive to retrieve its source range.
+/// Unpack a given preprocessing directive to retrieve its source range.
SourceRange getCursorPreprocessingDirective(CXCursor C);
-/// \brief Create a macro definition cursor.
+/// Create a macro definition cursor.
CXCursor MakeMacroDefinitionCursor(const MacroDefinitionRecord *,
CXTranslationUnit TU);
-/// \brief Unpack a given macro definition cursor to retrieve its
+/// Unpack a given macro definition cursor to retrieve its
/// source range.
const MacroDefinitionRecord *getCursorMacroDefinition(CXCursor C);
-/// \brief Create a macro expansion cursor.
+/// Create a macro expansion cursor.
CXCursor MakeMacroExpansionCursor(MacroExpansion *, CXTranslationUnit TU);
-/// \brief Create a "pseudo" macro expansion cursor, using a macro definition
+/// Create a "pseudo" macro expansion cursor, using a macro definition
/// and a source location.
CXCursor MakeMacroExpansionCursor(MacroDefinitionRecord *, SourceLocation Loc,
CXTranslationUnit TU);
-/// \brief Wraps a macro expansion cursor and provides a common interface
+/// Wraps a macro expansion cursor and provides a common interface
/// for a normal macro expansion cursor or a "pseudo" one.
///
/// "Pseudo" macro expansion cursors (essentially a macro definition along with
@@ -194,46 +194,46 @@ public:
SourceRange getSourceRange() const;
};
-/// \brief Unpack a given macro expansion cursor to retrieve its info.
+/// Unpack a given macro expansion cursor to retrieve its info.
static inline MacroExpansionCursor getCursorMacroExpansion(CXCursor C) {
return C;
}
-/// \brief Create an inclusion directive cursor.
+/// Create an inclusion directive cursor.
CXCursor MakeInclusionDirectiveCursor(InclusionDirective *,
CXTranslationUnit TU);
-/// \brief Unpack a given inclusion directive cursor to retrieve its
+/// Unpack a given inclusion directive cursor to retrieve its
/// source range.
const InclusionDirective *getCursorInclusionDirective(CXCursor C);
-/// \brief Create a label reference at the given location.
+/// Create a label reference at the given location.
CXCursor MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc,
CXTranslationUnit TU);
-/// \brief Unpack a label reference into the label statement it refers to and
+/// Unpack a label reference into the label statement it refers to and
/// the location of the reference.
std::pair<const LabelStmt *, SourceLocation> getCursorLabelRef(CXCursor C);
-/// \brief Create a overloaded declaration reference cursor for an expression.
+/// Create a overloaded declaration reference cursor for an expression.
CXCursor MakeCursorOverloadedDeclRef(const OverloadExpr *E,
CXTranslationUnit TU);
-/// \brief Create a overloaded declaration reference cursor for a declaration.
+/// Create a overloaded declaration reference cursor for a declaration.
CXCursor MakeCursorOverloadedDeclRef(const Decl *D, SourceLocation Location,
CXTranslationUnit TU);
-/// \brief Create a overloaded declaration reference cursor for a template name.
+/// Create a overloaded declaration reference cursor for a template name.
CXCursor MakeCursorOverloadedDeclRef(TemplateName Template,
SourceLocation Location,
CXTranslationUnit TU);
-/// \brief Internal storage for an overloaded declaration reference cursor;
+/// Internal storage for an overloaded declaration reference cursor;
typedef llvm::PointerUnion3<const OverloadExpr *, const Decl *,
OverloadedTemplateStorage *>
OverloadedDeclRefStorage;
-/// \brief Unpack an overloaded declaration reference into an expression,
+/// Unpack an overloaded declaration reference into an expression,
/// declaration, or template name along with the source location.
std::pair<OverloadedDeclRefStorage, SourceLocation>
getCursorOverloadedDeclRef(CXCursor C);
@@ -251,14 +251,14 @@ CXTranslationUnit getCursorTU(CXCursor Cursor);
void getOverriddenCursors(CXCursor cursor,
SmallVectorImpl<CXCursor> &overridden);
-/// \brief Create an opaque pool used for fast generation of overriden
+/// Create an opaque pool used for fast generation of overridden
/// CXCursor arrays.
void *createOverridenCXCursorsPool();
-/// \brief Dispose of the overriden CXCursors pool.
+/// Dispose of the overridden CXCursors pool.
void disposeOverridenCXCursorsPool(void *pool);
-/// \brief Returns a index/location pair for a selector identifier if the cursor
+/// Returns a index/location pair for a selector identifier if the cursor
/// points to one.
std::pair<int, SourceLocation> getSelectorIdentifierIndexAndLoc(CXCursor);
static inline int getSelectorIdentifierIndex(CXCursor cursor) {
@@ -279,7 +279,7 @@ static inline CXCursor getTypeRefedCallExprCursor(CXCursor cursor) {
CXCursor getTypeRefCursor(CXCursor cursor);
-/// \brief Generate a USR for \arg D and put it in \arg Buf.
+/// 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(const Decl *D, SmallVectorImpl<char> &Buf);
@@ -290,7 +290,7 @@ inline bool operator!=(CXCursor X, CXCursor Y) {
return !(X == Y);
}
-/// \brief Return true if the cursor represents a declaration that is the
+/// Return true if the cursor represents a declaration that is the
/// first in a declaration group.
bool isFirstInDeclGroup(CXCursor C);
diff --git a/tools/libclang/CXIndexDataConsumer.cpp b/tools/libclang/CXIndexDataConsumer.cpp
index 89ac23be7344..616a0797f52b 100644
--- a/tools/libclang/CXIndexDataConsumer.cpp
+++ b/tools/libclang/CXIndexDataConsumer.cpp
@@ -148,15 +148,17 @@ public:
return true;
}
};
+
+CXSymbolRole getSymbolRole(SymbolRoleSet Role) {
+ // CXSymbolRole mirrors low 9 bits of clang::index::SymbolRole.
+ return CXSymbolRole(static_cast<uint32_t>(Role) & ((1 << 9) - 1));
+}
}
-bool CXIndexDataConsumer::handleDeclOccurence(const Decl *D,
- SymbolRoleSet Roles,
- ArrayRef<SymbolRelation> Relations,
- FileID FID, unsigned Offset,
- ASTNodeInfo ASTNode) {
- SourceLocation Loc = getASTContext().getSourceManager()
- .getLocForStartOfFile(FID).getLocWithOffset(Offset);
+bool CXIndexDataConsumer::handleDeclOccurence(
+ const Decl *D, SymbolRoleSet Roles, ArrayRef<SymbolRelation> Relations,
+ SourceLocation Loc, ASTNodeInfo ASTNode) {
+ Loc = getASTContext().getSourceManager().getFileLoc(Loc);
if (Roles & (unsigned)SymbolRole::Reference) {
const NamedDecl *ND = dyn_cast<NamedDecl>(D);
@@ -184,6 +186,7 @@ bool CXIndexDataConsumer::handleDeclOccurence(const Decl *D,
if (Roles & (unsigned)SymbolRole::Implicit) {
Kind = CXIdxEntityRef_Implicit;
}
+ CXSymbolRole CXRole = getSymbolRole(Roles);
CXCursor Cursor;
if (ASTNode.OrigE) {
@@ -202,7 +205,7 @@ bool CXIndexDataConsumer::handleDeclOccurence(const Decl *D,
}
handleReference(ND, Loc, Cursor,
dyn_cast_or_null<NamedDecl>(ASTNode.Parent),
- ASTNode.ContainerDC, ASTNode.OrigE, Kind);
+ ASTNode.ContainerDC, ASTNode.OrigE, Kind, CXRole);
} else {
const DeclContext *LexicalDC = ASTNode.ContainerDC;
@@ -220,8 +223,7 @@ bool CXIndexDataConsumer::handleDeclOccurence(const Decl *D,
bool CXIndexDataConsumer::handleModuleOccurence(const ImportDecl *ImportD,
SymbolRoleSet Roles,
- FileID FID,
- unsigned Offset) {
+ SourceLocation Loc) {
IndexingDeclVisitor(*this, SourceLocation(), nullptr).Visit(ImportD);
return !shouldAbort();
}
@@ -889,13 +891,14 @@ bool CXIndexDataConsumer::handleReference(const NamedDecl *D, SourceLocation Loc
const NamedDecl *Parent,
const DeclContext *DC,
const Expr *E,
- CXIdxEntityRefKind Kind) {
- if (!D)
+ CXIdxEntityRefKind Kind,
+ CXSymbolRole Role) {
+ if (!D || !DC)
return false;
CXCursor Cursor = E ? MakeCXCursor(E, cast<Decl>(DC), CXTU)
: getRefCursor(D, Loc);
- return handleReference(D, Loc, Cursor, Parent, DC, E, Kind);
+ return handleReference(D, Loc, Cursor, Parent, DC, E, Kind, Role);
}
bool CXIndexDataConsumer::handleReference(const NamedDecl *D, SourceLocation Loc,
@@ -903,11 +906,12 @@ bool CXIndexDataConsumer::handleReference(const NamedDecl *D, SourceLocation Loc
const NamedDecl *Parent,
const DeclContext *DC,
const Expr *E,
- CXIdxEntityRefKind Kind) {
+ CXIdxEntityRefKind Kind,
+ CXSymbolRole Role) {
if (!CB.indexEntityReference)
return false;
- if (!D)
+ if (!D || !DC)
return false;
if (Loc.isInvalid())
return false;
@@ -939,7 +943,8 @@ bool CXIndexDataConsumer::handleReference(const NamedDecl *D, SourceLocation Loc
getIndexLoc(Loc),
&RefEntity,
Parent ? &ParentEntity : nullptr,
- &Container };
+ &Container,
+ Role };
CB.indexEntityReference(ClientData, &Info);
return true;
}
diff --git a/tools/libclang/CXIndexDataConsumer.h b/tools/libclang/CXIndexDataConsumer.h
index a54baadd0774..19e39b281ab0 100644
--- a/tools/libclang/CXIndexDataConsumer.h
+++ b/tools/libclang/CXIndexDataConsumer.h
@@ -260,7 +260,7 @@ public:
}
unsigned getNumAttrs() const { return (unsigned)CXAttrs.size(); }
- /// \brief Retain/Release only useful when we allocate a AttrListInfo from the
+ /// Retain/Release only useful when we allocate a AttrListInfo from the
/// BumpPtrAllocator, and not from the stack; so that we keep a pointer
// in the EntityInfo
void Retain() { ++ref_cnt; }
@@ -436,13 +436,15 @@ public:
const NamedDecl *Parent,
const DeclContext *DC,
const Expr *E = nullptr,
- CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct);
+ CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct,
+ CXSymbolRole Role = CXSymbolRole_None);
bool handleReference(const NamedDecl *D, SourceLocation Loc,
const NamedDecl *Parent,
const DeclContext *DC,
const Expr *E = nullptr,
- CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct);
+ CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct,
+ CXSymbolRole Role = CXSymbolRole_None);
bool isNotFromSourceFile(SourceLocation Loc) const;
@@ -463,12 +465,11 @@ public:
private:
bool handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
ArrayRef<index::SymbolRelation> Relations,
- FileID FID, unsigned Offset,
- ASTNodeInfo ASTNode) override;
+ SourceLocation Loc, ASTNodeInfo ASTNode) override;
bool handleModuleOccurence(const ImportDecl *ImportD,
index::SymbolRoleSet Roles,
- FileID FID, unsigned Offset) override;
+ SourceLocation Loc) override;
void finish() override;
diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp
index 36c3dcabb924..fd6881e03ab0 100644
--- a/tools/libclang/CXLoadedDiagnostic.cpp
+++ b/tools/libclang/CXLoadedDiagnostic.cpp
@@ -47,7 +47,7 @@ public:
FileManager FakeFiles;
llvm::DenseMap<unsigned, const FileEntry *> Files;
- /// \brief Copy the string into our own allocator.
+ /// Copy the string into our own allocator.
const char *copyString(StringRef Blob) {
char *mem = Alloc.Allocate<char>(Blob.size() + 1);
memcpy(mem, Blob.data(), Blob.size());
diff --git a/tools/libclang/CXLoadedDiagnostic.h b/tools/libclang/CXLoadedDiagnostic.h
index 1209d76669f8..521ebd84bf13 100644
--- a/tools/libclang/CXLoadedDiagnostic.h
+++ b/tools/libclang/CXLoadedDiagnostic.h
@@ -27,34 +27,34 @@ public:
~CXLoadedDiagnostic() override;
- /// \brief Return the severity of the diagnostic.
+ /// Return the severity of the diagnostic.
CXDiagnosticSeverity getSeverity() const override;
- /// \brief Return the location of the diagnostic.
+ /// Return the location of the diagnostic.
CXSourceLocation getLocation() const override;
- /// \brief Return the spelling of the diagnostic.
+ /// Return the spelling of the diagnostic.
CXString getSpelling() const override;
- /// \brief Return the text for the diagnostic option.
+ /// Return the text for the diagnostic option.
CXString getDiagnosticOption(CXString *Disable) const override;
- /// \brief Return the category of the diagnostic.
+ /// Return the category of the diagnostic.
unsigned getCategory() const override;
- /// \brief Return the category string of the diagnostic.
+ /// Return the category string of the diagnostic.
CXString getCategoryText() const override;
- /// \brief Return the number of source ranges for the diagnostic.
+ /// Return the number of source ranges for the diagnostic.
unsigned getNumRanges() const override;
- /// \brief Return the source ranges for the diagnostic.
+ /// Return the source ranges for the diagnostic.
CXSourceRange getRange(unsigned Range) const override;
- /// \brief Return the number of FixIts.
+ /// Return the number of FixIts.
unsigned getNumFixIts() const override;
- /// \brief Return the FixIt information (source range and inserted text).
+ /// Return the FixIt information (source range and inserted text).
CXString getFixIt(unsigned FixIt,
CXSourceRange *ReplacementRange) const override;
@@ -62,7 +62,7 @@ public:
return D->getKind() == LoadedDiagnosticKind;
}
- /// \brief Decode the CXSourceLocation into file, line, column, and offset.
+ /// Decode the CXSourceLocation into file, line, column, and offset.
static void decodeLocation(CXSourceLocation location,
CXFile *file,
unsigned *line,
diff --git a/tools/libclang/CXSourceLocation.h b/tools/libclang/CXSourceLocation.h
index f0b3f4954919..dddc8475906c 100644
--- a/tools/libclang/CXSourceLocation.h
+++ b/tools/libclang/CXSourceLocation.h
@@ -25,7 +25,7 @@ class SourceManager;
namespace cxloc {
-/// \brief Translate a Clang source location into a CIndex source location.
+/// Translate a Clang source location into a CIndex source location.
static inline CXSourceLocation
translateSourceLocation(const SourceManager &SM, const LangOptions &LangOpts,
SourceLocation Loc) {
@@ -37,7 +37,7 @@ translateSourceLocation(const SourceManager &SM, const LangOptions &LangOpts,
return Result;
}
-/// \brief Translate a Clang source location into a CIndex source location.
+/// Translate a Clang source location into a CIndex source location.
static inline CXSourceLocation translateSourceLocation(ASTContext &Context,
SourceLocation Loc) {
return translateSourceLocation(Context.getSourceManager(),
@@ -45,7 +45,7 @@ static inline CXSourceLocation translateSourceLocation(ASTContext &Context,
Loc);
}
-/// \brief Translate a Clang source range into a CIndex source range.
+/// Translate a Clang source range into a CIndex source range.
///
/// Clang internally represents ranges where the end location points to the
/// start of the token at the end. However, for external clients it is more
@@ -55,7 +55,7 @@ CXSourceRange translateSourceRange(const SourceManager &SM,
const LangOptions &LangOpts,
const CharSourceRange &R);
-/// \brief Translate a Clang source range into a CIndex source range.
+/// Translate a Clang source range into a CIndex source range.
static inline CXSourceRange translateSourceRange(ASTContext &Context,
SourceRange R) {
return translateSourceRange(Context.getSourceManager(),
diff --git a/tools/libclang/CXString.cpp b/tools/libclang/CXString.cpp
index 448603179203..cef4e53a42c2 100644
--- a/tools/libclang/CXString.cpp
+++ b/tools/libclang/CXString.cpp
@@ -96,7 +96,7 @@ CXString createRef(StringRef String) {
CXString createDup(StringRef String) {
CXString Result;
- char *Spelling = static_cast<char *>(malloc(String.size() + 1));
+ char *Spelling = static_cast<char *>(llvm::safe_malloc(String.size() + 1));
memmove(Spelling, String.data(), String.size());
Spelling[String.size()] = 0;
Result.data = Spelling;
diff --git a/tools/libclang/CXString.h b/tools/libclang/CXString.h
index 6473eb2d7103..ed1926118701 100644
--- a/tools/libclang/CXString.h
+++ b/tools/libclang/CXString.h
@@ -27,33 +27,33 @@ namespace cxstring {
struct CXStringBuf;
-/// \brief Create a CXString object for an empty "" string.
+/// Create a CXString object for an empty "" string.
CXString createEmpty();
-/// \brief Create a CXString object for an NULL string.
+/// Create a CXString object for an NULL string.
///
/// A NULL string should be used as an "invalid" value in case of errors.
CXString createNull();
-/// \brief Create a CXString object from a nul-terminated C string. New
+/// Create a CXString object from a nul-terminated C string. New
/// CXString may contain a pointer to \p String.
///
/// \p String should not be changed by the caller afterwards.
CXString createRef(const char *String);
-/// \brief Create a CXString object from a nul-terminated C string. New
+/// Create a CXString object from a nul-terminated C string. New
/// CXString will contain a copy of \p String.
///
/// \p String can be changed or freed by the caller.
CXString createDup(const char *String);
-/// \brief Create a CXString object from a StringRef. New CXString may
+/// Create a CXString object from a StringRef. New CXString may
/// contain a pointer to the undrelying data of \p String.
///
/// \p String should not be changed by the caller afterwards.
CXString createRef(StringRef String);
-/// \brief Create a CXString object from a StringRef. New CXString will
+/// Create a CXString object from a StringRef. New CXString will
/// contain a copy of \p String.
///
/// \p String can be changed or freed by the caller.
@@ -65,12 +65,12 @@ CXString createDup(StringRef String);
// If you need to make a copy, call \c createDup(StringRef(String)).
CXString createRef(std::string String) = delete;
-/// \brief Create a CXString object that is backed by a string buffer.
+/// Create a CXString object that is backed by a string buffer.
CXString createCXString(CXStringBuf *buf);
CXStringSet *createSet(const std::vector<std::string> &Strings);
-/// \brief A string pool used for fast allocation/deallocation of strings.
+/// A string pool used for fast allocation/deallocation of strings.
class CXStringPool {
public:
~CXStringPool();
@@ -89,13 +89,13 @@ struct CXStringBuf {
CXStringBuf(CXTranslationUnit TU) : TU(TU) {}
- /// \brief Return this buffer to the pool.
+ /// Return this buffer to the pool.
void dispose();
};
CXStringBuf *getCXStringBuf(CXTranslationUnit TU);
-/// \brief Returns true if the CXString data is managed by a pool.
+/// Returns true if the CXString data is managed by a pool.
bool isManagedByPool(CXString str);
}
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index dfc015247768..7c0f307944a1 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -53,6 +53,12 @@ static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) {
BTCASE(Float);
BTCASE(Double);
BTCASE(LongDouble);
+ BTCASE(ShortAccum);
+ BTCASE(Accum);
+ BTCASE(LongAccum);
+ BTCASE(UShortAccum);
+ BTCASE(UAccum);
+ BTCASE(ULongAccum);
BTCASE(Float16);
BTCASE(Float128);
BTCASE(NullPtr);
@@ -119,6 +125,10 @@ CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) {
if (auto *ATT = T->getAs<AttributedType>()) {
return MakeCXType(ATT->getModifiedType(), TU);
}
+ // Handle paren types as the original type
+ if (auto *PTT = T->getAs<ParenType>()) {
+ return MakeCXType(PTT->getInnerType(), TU);
+ }
ASTContext &Ctx = cxtu::getASTUnit(TU)->getASTContext();
if (Ctx.getLangOpts().ObjC1) {
@@ -542,6 +552,12 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(Float);
TKIND(Double);
TKIND(LongDouble);
+ TKIND(ShortAccum);
+ TKIND(Accum);
+ TKIND(LongAccum);
+ TKIND(UShortAccum);
+ TKIND(UAccum);
+ TKIND(ULongAccum);
TKIND(Float16);
TKIND(Float128);
TKIND(NullPtr);
@@ -689,13 +705,41 @@ CXType clang_getCursorResultType(CXCursor C) {
return MakeCXType(QualType(), cxcursor::getCursorTU(C));
}
+// FIXME: We should expose the canThrow(...) result instead of the EST.
+static CXCursor_ExceptionSpecificationKind
+getExternalExceptionSpecificationKind(ExceptionSpecificationType EST) {
+ switch (EST) {
+ case EST_None:
+ return CXCursor_ExceptionSpecificationKind_None;
+ case EST_DynamicNone:
+ return CXCursor_ExceptionSpecificationKind_DynamicNone;
+ case EST_Dynamic:
+ return CXCursor_ExceptionSpecificationKind_Dynamic;
+ case EST_MSAny:
+ return CXCursor_ExceptionSpecificationKind_MSAny;
+ case EST_BasicNoexcept:
+ return CXCursor_ExceptionSpecificationKind_BasicNoexcept;
+ case EST_NoexceptFalse:
+ case EST_NoexceptTrue:
+ case EST_DependentNoexcept:
+ return CXCursor_ExceptionSpecificationKind_ComputedNoexcept;
+ case EST_Unevaluated:
+ return CXCursor_ExceptionSpecificationKind_Unevaluated;
+ case EST_Uninstantiated:
+ return CXCursor_ExceptionSpecificationKind_Uninstantiated;
+ case EST_Unparsed:
+ return CXCursor_ExceptionSpecificationKind_Unparsed;
+ }
+ llvm_unreachable("invalid EST value");
+}
+
int clang_getExceptionSpecificationType(CXType X) {
QualType T = GetQualType(X);
if (T.isNull())
return -1;
if (const auto *FD = T->getAs<FunctionProtoType>())
- return static_cast<int>(FD->getExceptionSpecType());
+ return getExternalExceptionSpecificationKind(FD->getExceptionSpecType());
return -1;
}
diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h
index 82f251a348f0..f2fb68fab954 100644
--- a/tools/libclang/CursorVisitor.h
+++ b/tools/libclang/CursorVisitor.h
@@ -55,44 +55,44 @@ class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
public TypeLocVisitor<CursorVisitor, bool>
{
public:
- /// \brief Callback called after child nodes of a cursor have been visited.
+ /// Callback called after child nodes of a cursor have been visited.
/// Return true to break visitation or false to continue.
typedef bool (*PostChildrenVisitorTy)(CXCursor cursor,
CXClientData client_data);
private:
- /// \brief The translation unit we are traversing.
+ /// The translation unit we are traversing.
CXTranslationUnit TU;
ASTUnit *AU;
- /// \brief The parent cursor whose children we are traversing.
+ /// The parent cursor whose children we are traversing.
CXCursor Parent;
- /// \brief The declaration that serves at the parent of any statement or
+ /// The declaration that serves at the parent of any statement or
/// expression nodes.
const Decl *StmtParent;
- /// \brief The visitor function.
+ /// The visitor function.
CXCursorVisitor Visitor;
PostChildrenVisitorTy PostChildrenVisitor;
- /// \brief The opaque client data, to be passed along to the visitor.
+ /// The opaque client data, to be passed along to the visitor.
CXClientData ClientData;
- /// \brief Whether we should visit the preprocessing record entries last,
+ /// Whether we should visit the preprocessing record entries last,
/// after visiting other declarations.
bool VisitPreprocessorLast;
- /// \brief Whether we should visit declarations or preprocessing record
+ /// Whether we should visit declarations or preprocessing record
/// entries that are #included inside the \arg RegionOfInterest.
bool VisitIncludedEntities;
- /// \brief When valid, a source range to which the cursor should restrict
+ /// When valid, a source range to which the cursor should restrict
/// its search.
SourceRange RegionOfInterest;
- /// \brief Whether we should only visit declarations and not preprocessing
+ /// Whether we should only visit declarations and not preprocessing
/// record entries.
bool VisitDeclsOnly;
@@ -110,7 +110,7 @@ private:
using DeclVisitor<CursorVisitor, bool>::Visit;
using TypeLocVisitor<CursorVisitor, bool>::Visit;
- /// \brief Determine whether this particular source range comes before, comes
+ /// Determine whether this particular source range comes before, comes
/// after, or overlaps the region of interest.
///
/// \param R a half-open source range retrieved from the abstract syntax tree.
@@ -177,7 +177,7 @@ public:
bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false);
- /// \brief Visit declarations and preprocessed entities for the file region
+ /// Visit declarations and preprocessed entities for the file region
/// designated by \see RegionOfInterest.
bool visitFileRegion();
diff --git a/tools/libclang/Index_Internal.h b/tools/libclang/Index_Internal.h
index 98f069c88738..fbe3cabf04c8 100644
--- a/tools/libclang/Index_Internal.h
+++ b/tools/libclang/Index_Internal.h
@@ -40,15 +40,15 @@ typedef struct _CXCursorAndRangeVisitorBlock {
#endif // !__has_feature(blocks)
-/// \brief The result of comparing two source ranges.
+/// The result of comparing two source ranges.
enum RangeComparisonResult {
- /// \brief Either the ranges overlap or one of the ranges is invalid.
+ /// Either the ranges overlap or one of the ranges is invalid.
RangeOverlap,
- /// \brief The first range ends before the second range starts.
+ /// The first range ends before the second range starts.
RangeBefore,
- /// \brief The first range starts after the second range ends.
+ /// The first range starts after the second range ends.
RangeAfter
};
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
index 021ebcfcfe43..4da046b28233 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -45,7 +45,7 @@ namespace {
// Skip Parsed Bodies
//===----------------------------------------------------------------------===//
-/// \brief A "region" in source code identified by the file/offset of the
+/// A "region" in source code identified by the file/offset of the
/// preprocessor conditional directive that it belongs to.
/// Multiple, non-consecutive ranges can be parts of the same region.
///
@@ -249,7 +249,8 @@ public:
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange, const FileEntry *File,
StringRef SearchPath, StringRef RelativePath,
- const Module *Imported) override {
+ const Module *Imported,
+ SrcMgr::CharacteristicKind FileType) override {
bool isImport = (IncludeTok.is(tok::identifier) &&
IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import);
DataConsumer.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled,
@@ -401,6 +402,8 @@ static IndexingOptions getIndexingOptionsFromCXOptions(unsigned index_options) {
IndexingOptions IdxOpts;
if (index_options & CXIndexOpt_IndexFunctionLocalSymbols)
IdxOpts.IndexFunctionLocals = true;
+ if (index_options & CXIndexOpt_IndexImplicitTemplateInstantiations)
+ IdxOpts.IndexImplicitInstantiation = true;
return IdxOpts;
}
@@ -659,8 +662,7 @@ static CXErrorCode clang_indexTranslationUnit_Impl(
? index_callbacks_size : sizeof(CB);
memcpy(&CB, client_index_callbacks, ClientCBSize);
- auto DataConsumer = std::make_shared<CXIndexDataConsumer>(client_data, CB,
- index_options, TU);
+ CXIndexDataConsumer DataConsumer(client_data, CB, index_options, TU);
ASTUnit *Unit = cxtu::getASTUnit(TU);
if (!Unit)
@@ -669,21 +671,22 @@ static CXErrorCode clang_indexTranslationUnit_Impl(
ASTUnit::ConcurrencyCheck Check(*Unit);
if (const FileEntry *PCHFile = Unit->getPCHFile())
- DataConsumer->importedPCH(PCHFile);
+ DataConsumer.importedPCH(PCHFile);
FileManager &FileMgr = Unit->getFileManager();
if (Unit->getOriginalSourceFileName().empty())
- DataConsumer->enteredMainFile(nullptr);
+ DataConsumer.enteredMainFile(nullptr);
else
- DataConsumer->enteredMainFile(FileMgr.getFile(Unit->getOriginalSourceFileName()));
+ DataConsumer.enteredMainFile(
+ FileMgr.getFile(Unit->getOriginalSourceFileName()));
- DataConsumer->setASTContext(Unit->getASTContext());
- DataConsumer->startedTranslationUnit();
+ DataConsumer.setASTContext(Unit->getASTContext());
+ DataConsumer.startedTranslationUnit();
- indexPreprocessingRecord(*Unit, *DataConsumer);
+ indexPreprocessingRecord(*Unit, DataConsumer);
indexASTUnit(*Unit, DataConsumer, getIndexingOptionsFromCXOptions(index_options));
- DataConsumer->indexDiagnostics();
+ DataConsumer.indexDiagnostics();
return CXError_Success;
}
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 4d3a029567d4..95a42712c4af 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -46,6 +46,7 @@ clang_Cursor_isVariadic
clang_Cursor_getModule
clang_Cursor_getStorageClass
clang_File_isEqual
+clang_File_tryGetRealPathName
clang_Module_getASTFile
clang_Module_getParent
clang_Module_getName
@@ -170,6 +171,8 @@ clang_getCompletionBriefComment
clang_getCompletionChunkCompletionString
clang_getCompletionChunkKind
clang_getCompletionChunkText
+clang_getCompletionNumFixIts
+clang_getCompletionFixIt
clang_getCompletionNumAnnotations
clang_getCompletionParent
clang_getCompletionPriority
@@ -178,6 +181,8 @@ clang_getCursorAvailability
clang_getCursorCompletionString
clang_getCursorDefinition
clang_getCursorDisplayName
+clang_getCursorPrintingPolicy
+clang_getCursorPrettyPrinted
clang_getCursorExtent
clang_getCursorExceptionSpecificationType
clang_getCursorKind
@@ -220,6 +225,7 @@ clang_getExceptionSpecificationType
clang_getFieldDeclBitWidth
clang_getExpansionLocation
clang_getFile
+clang_getFileContents
clang_getFileLocation
clang_getFileName
clang_getFileTime
@@ -256,6 +262,7 @@ clang_getSpecializedCursorTemplate
clang_getSpellingLocation
clang_getTUResourceUsageName
clang_getTemplateCursorKind
+clang_getToken
clang_getTokenExtent
clang_getTokenKind
clang_getTokenLocation
@@ -290,6 +297,7 @@ clang_isAttribute
clang_isConstQualifiedType
clang_isCursorDefinition
clang_isDeclaration
+clang_isInvalidDeclaration
clang_isExpression
clang_isFileMultipleIncludeGuarded
clang_isFunctionTypeVariadic
@@ -357,3 +365,6 @@ clang_EvalResult_isUnsignedInt
clang_EvalResult_getAsDouble
clang_EvalResult_getAsStr
clang_EvalResult_dispose
+clang_PrintingPolicy_getProperty
+clang_PrintingPolicy_setProperty
+clang_PrintingPolicy_dispose
diff --git a/tools/scan-build-py/README.md b/tools/scan-build-py/README.md
index 54bfc37ff76d..720bde1cf3b1 100644
--- a/tools/scan-build-py/README.md
+++ b/tools/scan-build-py/README.md
@@ -41,6 +41,32 @@ goes like this:
Use `--help` to know more about the commands.
+How to use the experimental Cross Translation Unit analysis
+-----------------------------------------------------------
+
+To run the CTU analysis, a compilation database file has to be created:
+
+ $ intercept-build <your build command>
+
+To run the Clang Static Analyzer against a compilation database
+with CTU analysis enabled, execute:
+
+ $ analyze-build --ctu
+
+For CTU analysis an additional (function-definition) collection-phase is required.
+For debugging purposes, it is possible to separately execute the collection
+and the analysis phase. By doing this, the intermediate files used for
+the analysis are kept on the disk in `./ctu-dir`.
+
+ # Collect and store the data required by the CTU analysis
+ $ analyze-build --ctu-collect-only
+
+ # Analyze using the previously collected data
+ $ analyze-build --ctu-analyze-only
+
+Use `--help` to get more information about the commands.
+
+
Limitations
-----------
@@ -58,11 +84,11 @@ tool has three distinct model to run the analyzer:
This is the default behaviour, can be enforced with `--override-compiler`
flag.
-2. Use special library to intercept compiler calls durring the build process.
+2. Use special library to intercept compiler calls during the build process.
The analyzer run against each modules after the build finished.
Use `--intercept-first` flag to get this model.
-3. Use compiler wrappers to intercept compiler calls durring the build process.
+3. Use compiler wrappers to intercept compiler calls during the build process.
The analyzer run against each modules after the build finished.
Use `--intercept-first` and `--override-compiler` flags together to get
this model.
@@ -79,7 +105,7 @@ process removes removes intermediate modules (generated sources) the analyzer
output still kept.
The 2. and 3. generate the compilation database first, and filters out those
-modules which are not exists. So, it's suitable for incremental analysis durring
+modules which are not exists. So, it's suitable for incremental analysis during
the development.
The 2. mode is available only on FreeBSD and Linux. Where library preload
diff --git a/tools/scan-build-py/libscanbuild/__init__.py b/tools/scan-build-py/libscanbuild/__init__.py
index 800926ebb6f2..e7b74879167e 100644
--- a/tools/scan-build-py/libscanbuild/__init__.py
+++ b/tools/scan-build-py/libscanbuild/__init__.py
@@ -19,6 +19,9 @@ ENVIRONMENT_KEY = 'INTERCEPT_BUILD'
Execution = collections.namedtuple('Execution', ['pid', 'cwd', 'cmd'])
+CtuConfig = collections.namedtuple('CtuConfig', ['collect', 'analyze', 'dir',
+ 'func_map_cmd'])
+
def duplicate_check(method):
""" Predicate to detect duplicated entries.
diff --git a/tools/scan-build-py/libscanbuild/analyze.py b/tools/scan-build-py/libscanbuild/analyze.py
index b5614b5b6da0..5a7cc20a517e 100644
--- a/tools/scan-build-py/libscanbuild/analyze.py
+++ b/tools/scan-build-py/libscanbuild/analyze.py
@@ -22,16 +22,19 @@ import functools
import subprocess
import contextlib
import datetime
+import shutil
+import glob
+from collections import defaultdict
from libscanbuild import command_entry_point, compiler_wrapper, \
- wrapper_environment, run_build, run_command
+ wrapper_environment, run_build, run_command, CtuConfig
from libscanbuild.arguments import parse_args_for_scan_build, \
parse_args_for_analyze_build
from libscanbuild.intercept import capture
from libscanbuild.report import document
from libscanbuild.compilation import split_command, classify_source, \
compiler_language
-from libscanbuild.clang import get_version, get_arguments
+from libscanbuild.clang import get_version, get_arguments, get_triple_arch
from libscanbuild.shell import decode
__all__ = ['scan_build', 'analyze_build', 'analyze_compiler_wrapper']
@@ -39,6 +42,9 @@ __all__ = ['scan_build', 'analyze_build', 'analyze_compiler_wrapper']
COMPILER_WRAPPER_CC = 'analyze-cc'
COMPILER_WRAPPER_CXX = 'analyze-c++'
+CTU_FUNCTION_MAP_FILENAME = 'externalFnMap.txt'
+CTU_TEMP_FNMAP_FOLDER = 'tmpExternalFnMaps'
+
@command_entry_point
def scan_build():
@@ -56,7 +62,7 @@ def scan_build():
exit_code = capture(args)
# Run the analyzer against the captured commands.
if need_analyzer(args.build):
- run_analyzer_parallel(args)
+ govern_analyzer_runs(args)
else:
# Run build command and analyzer with compiler wrappers.
environment = setup_environment(args)
@@ -75,7 +81,7 @@ def analyze_build():
# will re-assign the report directory as new output
with report_directory(args.output, args.keep_empty) as args.output:
# Run the analyzer against a compilation db.
- run_analyzer_parallel(args)
+ govern_analyzer_runs(args)
# Cover report generation and bug counting.
number_of_bugs = document(args)
# Set exit status as it was requested.
@@ -88,13 +94,115 @@ def need_analyzer(args):
When static analyzer run against project configure step, it should be
silent and no need to run the analyzer or generate report.
- To run `scan-build` against the configure step might be neccessary,
+ To run `scan-build` against the configure step might be necessary,
when compiler wrappers are used. That's the moment when build setup
check the compiler and capture the location for the build process. """
return len(args) and not re.search('configure|autogen', args[0])
+def prefix_with(constant, pieces):
+ """ From a sequence create another sequence where every second element
+ is from the original sequence and the odd elements are the prefix.
+
+ eg.: prefix_with(0, [1,2,3]) creates [0, 1, 0, 2, 0, 3] """
+
+ return [elem for piece in pieces for elem in [constant, piece]]
+
+
+def get_ctu_config_from_args(args):
+ """ CTU configuration is created from the chosen phases and dir. """
+
+ return (
+ CtuConfig(collect=args.ctu_phases.collect,
+ analyze=args.ctu_phases.analyze,
+ dir=args.ctu_dir,
+ func_map_cmd=args.func_map_cmd)
+ if hasattr(args, 'ctu_phases') and hasattr(args.ctu_phases, 'dir')
+ else CtuConfig(collect=False, analyze=False, dir='', func_map_cmd=''))
+
+
+def get_ctu_config_from_json(ctu_conf_json):
+ """ CTU configuration is created from the chosen phases and dir. """
+
+ ctu_config = json.loads(ctu_conf_json)
+ # Recover namedtuple from json when coming from analyze-cc or analyze-c++
+ return CtuConfig(collect=ctu_config[0],
+ analyze=ctu_config[1],
+ dir=ctu_config[2],
+ func_map_cmd=ctu_config[3])
+
+
+def create_global_ctu_function_map(func_map_lines):
+ """ Takes iterator of individual function maps and creates a global map
+ keeping only unique names. We leave conflicting names out of CTU.
+
+ :param func_map_lines: Contains the id of a function (mangled name) and
+ the originating source (the corresponding AST file) name.
+ :type func_map_lines: Iterator of str.
+ :returns: Mangled name - AST file pairs.
+ :rtype: List of (str, str) tuples.
+ """
+
+ mangled_to_asts = defaultdict(set)
+
+ for line in func_map_lines:
+ mangled_name, ast_file = line.strip().split(' ', 1)
+ mangled_to_asts[mangled_name].add(ast_file)
+
+ mangled_ast_pairs = []
+
+ for mangled_name, ast_files in mangled_to_asts.items():
+ if len(ast_files) == 1:
+ mangled_ast_pairs.append((mangled_name, next(iter(ast_files))))
+
+ return mangled_ast_pairs
+
+
+def merge_ctu_func_maps(ctudir):
+ """ Merge individual function maps into a global one.
+
+ As the collect phase runs parallel on multiple threads, all compilation
+ units are separately mapped into a temporary file in CTU_TEMP_FNMAP_FOLDER.
+ These function maps contain the mangled names of functions and the source
+ (AST generated from the source) which had them.
+ These files should be merged at the end into a global map file:
+ CTU_FUNCTION_MAP_FILENAME."""
+
+ def generate_func_map_lines(fnmap_dir):
+ """ Iterate over all lines of input files in a determined order. """
+
+ files = glob.glob(os.path.join(fnmap_dir, '*'))
+ files.sort()
+ for filename in files:
+ with open(filename, 'r') as in_file:
+ for line in in_file:
+ yield line
+
+ def write_global_map(arch, mangled_ast_pairs):
+ """ Write (mangled function name, ast file) pairs into final file. """
+
+ extern_fns_map_file = os.path.join(ctudir, arch,
+ CTU_FUNCTION_MAP_FILENAME)
+ with open(extern_fns_map_file, 'w') as out_file:
+ for mangled_name, ast_file in mangled_ast_pairs:
+ out_file.write('%s %s\n' % (mangled_name, ast_file))
+
+ triple_arches = glob.glob(os.path.join(ctudir, '*'))
+ for triple_path in triple_arches:
+ if os.path.isdir(triple_path):
+ triple_arch = os.path.basename(triple_path)
+ fnmap_dir = os.path.join(ctudir, triple_arch,
+ CTU_TEMP_FNMAP_FOLDER)
+
+ func_map_lines = generate_func_map_lines(fnmap_dir)
+ mangled_ast_pairs = create_global_ctu_function_map(func_map_lines)
+ write_global_map(triple_arch, mangled_ast_pairs)
+
+ # Remove all temporary files
+ shutil.rmtree(fnmap_dir, ignore_errors=True)
+
+
def run_analyzer_parallel(args):
""" Runs the analyzer against the given compilation database. """
@@ -109,7 +217,8 @@ def run_analyzer_parallel(args):
'output_format': args.output_format,
'output_failures': args.output_failures,
'direct_args': analyzer_params(args),
- 'force_debug': args.force_debug
+ 'force_debug': args.force_debug,
+ 'ctu': get_ctu_config_from_args(args)
}
logging.debug('run analyzer against compilation database')
@@ -127,6 +236,38 @@ def run_analyzer_parallel(args):
pool.join()
+def govern_analyzer_runs(args):
+ """ Governs multiple runs in CTU mode or runs once in normal mode. """
+
+ ctu_config = get_ctu_config_from_args(args)
+ # If we do a CTU collect (1st phase) we remove all previous collection
+ # data first.
+ if ctu_config.collect:
+ shutil.rmtree(ctu_config.dir, ignore_errors=True)
+
+ # If the user asked for a collect (1st) and analyze (2nd) phase, we do an
+ # all-in-one run where we deliberately remove collection data before and
+ # also after the run. If the user asks only for a single phase data is
+ # left so multiple analyze runs can use the same data gathered by a single
+ # collection run.
+ if ctu_config.collect and ctu_config.analyze:
+ # CTU strings are coming from args.ctu_dir and func_map_cmd,
+ # so we can leave it empty
+ args.ctu_phases = CtuConfig(collect=True, analyze=False,
+ dir='', func_map_cmd='')
+ run_analyzer_parallel(args)
+ merge_ctu_func_maps(ctu_config.dir)
+ args.ctu_phases = CtuConfig(collect=False, analyze=True,
+ dir='', func_map_cmd='')
+ run_analyzer_parallel(args)
+ shutil.rmtree(ctu_config.dir, ignore_errors=True)
+ else:
+ # Single runs (collect or analyze) are launched from here.
+ run_analyzer_parallel(args)
+ if ctu_config.collect:
+ merge_ctu_func_maps(ctu_config.dir)
+
+
def setup_environment(args):
""" Set up environment for build command to interpose compiler wrapper. """
@@ -140,7 +281,8 @@ def setup_environment(args):
'ANALYZE_BUILD_REPORT_FORMAT': args.output_format,
'ANALYZE_BUILD_REPORT_FAILURES': 'yes' if args.output_failures else '',
'ANALYZE_BUILD_PARAMETERS': ' '.join(analyzer_params(args)),
- 'ANALYZE_BUILD_FORCE_DEBUG': 'yes' if args.force_debug else ''
+ 'ANALYZE_BUILD_FORCE_DEBUG': 'yes' if args.force_debug else '',
+ 'ANALYZE_BUILD_CTU': json.dumps(get_ctu_config_from_args(args))
})
return environment
@@ -173,7 +315,8 @@ def analyze_compiler_wrapper_impl(result, execution):
'').split(' '),
'force_debug': os.getenv('ANALYZE_BUILD_FORCE_DEBUG'),
'directory': execution.cwd,
- 'command': [execution.cmd[0], '-c'] + compilation.flags
+ 'command': [execution.cmd[0], '-c'] + compilation.flags,
+ 'ctu': get_ctu_config_from_json(os.getenv('ANALYZE_BUILD_CTU'))
}
# call static analyzer against the compilation
for source in compilation.files:
@@ -223,14 +366,6 @@ def analyzer_params(args):
""" A group of command line arguments can mapped to command
line arguments of the analyzer. This method generates those. """
- def prefix_with(constant, pieces):
- """ From a sequence create another sequence where every second element
- is from the original sequence and the odd elements are the prefix.
-
- eg.: prefix_with(0, [1,2,3]) creates [0, 1, 0, 2, 0, 3] """
-
- return [elem for piece in pieces for elem in [constant, piece]]
-
result = []
if args.store_model:
@@ -294,14 +429,15 @@ def require(required):
'direct_args', # arguments from command line
'force_debug', # kill non debug macros
'output_dir', # where generated report files shall go
- 'output_format', # it's 'plist' or 'html' or both
- 'output_failures']) # generate crash reports or not
+ 'output_format', # it's 'plist', 'html', both or plist-multi-file
+ 'output_failures', # generate crash reports or not
+ 'ctu']) # ctu control options
def run(opts):
""" Entry point to run (or not) static analyzer against a single entry
of the compilation database.
This complex task is decomposed into smaller methods which are calling
- each other in chain. If the analyzis is not possibe the given method
+ each other in chain. If the analyzis is not possible the given method
just return and break the chain.
The passed parameter is a python dictionary. Each method first check
@@ -317,7 +453,7 @@ def run(opts):
return arch_check(opts)
except Exception:
- logging.error("Problem occured during analyzis.", exc_info=1)
+ logging.error("Problem occurred during analyzis.", exc_info=1)
return None
@@ -383,7 +519,10 @@ def run_analyzer(opts, continuation=report_failure):
def target():
""" Creates output file name for reports. """
- if opts['output_format'] in {'plist', 'plist-html'}:
+ if opts['output_format'] in {
+ 'plist',
+ 'plist-html',
+ 'plist-multi-file'}:
(handle, name) = tempfile.mkstemp(prefix='report-',
suffix='.plist',
dir=opts['output_dir'])
@@ -407,8 +546,109 @@ def run_analyzer(opts, continuation=report_failure):
return result
+def func_map_list_src_to_ast(func_src_list):
+ """ Turns textual function map list with source files into a
+ function map list with ast files. """
+
+ func_ast_list = []
+ for fn_src_txt in func_src_list:
+ mangled_name, path = fn_src_txt.split(" ", 1)
+ # Normalize path on windows as well
+ path = os.path.splitdrive(path)[1]
+ # Make relative path out of absolute
+ path = path[1:] if path[0] == os.sep else path
+ ast_path = os.path.join("ast", path + ".ast")
+ func_ast_list.append(mangled_name + " " + ast_path)
+ return func_ast_list
+
+
+@require(['clang', 'directory', 'flags', 'direct_args', 'file', 'ctu'])
+def ctu_collect_phase(opts):
+ """ Preprocess source by generating all data needed by CTU analysis. """
+
+ def generate_ast(triple_arch):
+ """ Generates ASTs for the current compilation command. """
+
+ args = opts['direct_args'] + opts['flags']
+ ast_joined_path = os.path.join(opts['ctu'].dir, triple_arch, 'ast',
+ os.path.realpath(opts['file'])[1:] +
+ '.ast')
+ ast_path = os.path.abspath(ast_joined_path)
+ ast_dir = os.path.dirname(ast_path)
+ if not os.path.isdir(ast_dir):
+ try:
+ os.makedirs(ast_dir)
+ except OSError:
+ # In case an other process already created it.
+ pass
+ ast_command = [opts['clang'], '-emit-ast']
+ ast_command.extend(args)
+ ast_command.append('-w')
+ ast_command.append(opts['file'])
+ ast_command.append('-o')
+ ast_command.append(ast_path)
+ logging.debug("Generating AST using '%s'", ast_command)
+ run_command(ast_command, cwd=opts['directory'])
+
+ def map_functions(triple_arch):
+ """ Generate function map file for the current source. """
+
+ args = opts['direct_args'] + opts['flags']
+ funcmap_command = [opts['ctu'].func_map_cmd]
+ funcmap_command.append(opts['file'])
+ funcmap_command.append('--')
+ funcmap_command.extend(args)
+ logging.debug("Generating function map using '%s'", funcmap_command)
+ func_src_list = run_command(funcmap_command, cwd=opts['directory'])
+ func_ast_list = func_map_list_src_to_ast(func_src_list)
+ extern_fns_map_folder = os.path.join(opts['ctu'].dir, triple_arch,
+ CTU_TEMP_FNMAP_FOLDER)
+ if not os.path.isdir(extern_fns_map_folder):
+ try:
+ os.makedirs(extern_fns_map_folder)
+ except OSError:
+ # In case an other process already created it.
+ pass
+ if func_ast_list:
+ with tempfile.NamedTemporaryFile(mode='w',
+ dir=extern_fns_map_folder,
+ delete=False) as out_file:
+ out_file.write("\n".join(func_ast_list) + "\n")
+
+ cwd = opts['directory']
+ cmd = [opts['clang'], '--analyze'] + opts['direct_args'] + opts['flags'] \
+ + [opts['file']]
+ triple_arch = get_triple_arch(cmd, cwd)
+ generate_ast(triple_arch)
+ map_functions(triple_arch)
+
+
+@require(['ctu'])
+def dispatch_ctu(opts, continuation=run_analyzer):
+ """ Execute only one phase of 2 phases of CTU if needed. """
+
+ ctu_config = opts['ctu']
+
+ if ctu_config.collect or ctu_config.analyze:
+ assert ctu_config.collect != ctu_config.analyze
+ if ctu_config.collect:
+ return ctu_collect_phase(opts)
+ if ctu_config.analyze:
+ cwd = opts['directory']
+ cmd = [opts['clang'], '--analyze'] + opts['direct_args'] \
+ + opts['flags'] + [opts['file']]
+ triarch = get_triple_arch(cmd, cwd)
+ ctu_options = ['ctu-dir=' + os.path.join(ctu_config.dir, triarch),
+ 'experimental-enable-naive-ctu-analysis=true']
+ analyzer_options = prefix_with('-analyzer-config', ctu_options)
+ direct_options = prefix_with('-Xanalyzer', analyzer_options)
+ opts['direct_args'].extend(direct_options)
+
+ return continuation(opts)
+
+
@require(['flags', 'force_debug'])
-def filter_debug_flags(opts, continuation=run_analyzer):
+def filter_debug_flags(opts, continuation=dispatch_ctu):
""" Filter out nondebug macros when requested. """
if opts.pop('force_debug'):
@@ -475,6 +715,7 @@ def arch_check(opts, continuation=language_check):
logging.debug('analysis, on default arch')
return continuation(opts)
+
# To have good results from static analyzer certain compiler options shall be
# omitted. The compiler flag filtering only affects the static analyzer run.
#
diff --git a/tools/scan-build-py/libscanbuild/arguments.py b/tools/scan-build-py/libscanbuild/arguments.py
index 2735123f9f16..a5d0c6bda661 100644
--- a/tools/scan-build-py/libscanbuild/arguments.py
+++ b/tools/scan-build-py/libscanbuild/arguments.py
@@ -18,8 +18,8 @@ import sys
import argparse
import logging
import tempfile
-from libscanbuild import reconfigure_logging
-from libscanbuild.clang import get_checkers
+from libscanbuild import reconfigure_logging, CtuConfig
+from libscanbuild.clang import get_checkers, is_ctu_capable
__all__ = ['parse_args_for_intercept_build', 'parse_args_for_analyze_build',
'parse_args_for_scan_build']
@@ -98,6 +98,11 @@ def normalize_args_for_analyze(args, from_build_command):
# add cdb parameter invisibly to make report module working.
args.cdb = 'compile_commands.json'
+ # Make ctu_dir an abspath as it is needed inside clang
+ if not from_build_command and hasattr(args, 'ctu_phases') \
+ and hasattr(args.ctu_phases, 'dir'):
+ args.ctu_dir = os.path.abspath(args.ctu_dir)
+
def validate_args_for_analyze(parser, args, from_build_command):
""" Command line parsing is done by the argparse module, but semantic
@@ -122,6 +127,18 @@ def validate_args_for_analyze(parser, args, from_build_command):
elif not from_build_command and not os.path.exists(args.cdb):
parser.error(message='compilation database is missing')
+ # If the user wants CTU mode
+ if not from_build_command and hasattr(args, 'ctu_phases') \
+ and hasattr(args.ctu_phases, 'dir'):
+ # If CTU analyze_only, the input directory should exist
+ if args.ctu_phases.analyze and not args.ctu_phases.collect \
+ and not os.path.exists(args.ctu_dir):
+ parser.error(message='missing CTU directory')
+ # Check CTU capability via checking clang-func-mapping
+ if not is_ctu_capable(args.func_map_cmd):
+ parser.error(message="""This version of clang does not support CTU
+ functionality or clang-func-mapping command not found.""")
+
def create_intercept_parser():
""" Creates a parser for command-line arguments to 'intercept'. """
@@ -218,7 +235,15 @@ def create_analyze_parser(from_build_command):
default='html',
action='store_const',
help="""Cause the results as a set of .html and .plist files.""")
- # TODO: implement '-view '
+ format_group.add_argument(
+ '--plist-multi-file',
+ '-plist-multi-file',
+ dest='output_format',
+ const='plist-multi-file',
+ default='html',
+ action='store_const',
+ help="""Cause the results as a set of .plist files with extra
+ information on related files.""")
advanced = parser.add_argument_group('advanced options')
advanced.add_argument(
@@ -256,7 +281,7 @@ def create_analyze_parser(from_build_command):
'-maxloop',
metavar='<loop count>',
type=int,
- help="""Specifiy the number of times a block can be visited before
+ help="""Specify the number of times a block can be visited before
giving up. Increase for more comprehensive coverage at a cost of
speed.""")
advanced.add_argument(
@@ -333,6 +358,51 @@ def create_analyze_parser(from_build_command):
if from_build_command:
parser.add_argument(
dest='build', nargs=argparse.REMAINDER, help="""Command to run.""")
+ else:
+ ctu = parser.add_argument_group('cross translation unit analysis')
+ ctu_mutex_group = ctu.add_mutually_exclusive_group()
+ ctu_mutex_group.add_argument(
+ '--ctu',
+ action='store_const',
+ const=CtuConfig(collect=True, analyze=True,
+ dir='', func_map_cmd=''),
+ dest='ctu_phases',
+ help="""Perform cross translation unit (ctu) analysis (both collect
+ and analyze phases) using default <ctu-dir> for temporary output.
+ At the end of the analysis, the temporary directory is removed.""")
+ ctu.add_argument(
+ '--ctu-dir',
+ metavar='<ctu-dir>',
+ dest='ctu_dir',
+ default='ctu-dir',
+ help="""Defines the temporary directory used between ctu
+ phases.""")
+ ctu_mutex_group.add_argument(
+ '--ctu-collect-only',
+ action='store_const',
+ const=CtuConfig(collect=True, analyze=False,
+ dir='', func_map_cmd=''),
+ dest='ctu_phases',
+ help="""Perform only the collect phase of ctu.
+ Keep <ctu-dir> for further use.""")
+ ctu_mutex_group.add_argument(
+ '--ctu-analyze-only',
+ action='store_const',
+ const=CtuConfig(collect=False, analyze=True,
+ dir='', func_map_cmd=''),
+ dest='ctu_phases',
+ help="""Perform only the analyze phase of ctu. <ctu-dir> should be
+ present and will not be removed after analysis.""")
+ ctu.add_argument(
+ '--use-func-map-cmd',
+ metavar='<path>',
+ dest='func_map_cmd',
+ default='clang-func-mapping',
+ help="""'%(prog)s' uses the 'clang-func-mapping' executable
+ relative to itself for generating function maps for static
+ analysis. One can override this behavior with this option by using
+ the 'clang-func-mapping' packaged with Xcode (on OS X) or from the
+ PATH.""")
return parser
diff --git a/tools/scan-build-py/libscanbuild/clang.py b/tools/scan-build-py/libscanbuild/clang.py
index 192e708782c1..ab422066cab1 100644
--- a/tools/scan-build-py/libscanbuild/clang.py
+++ b/tools/scan-build-py/libscanbuild/clang.py
@@ -8,11 +8,13 @@
Since Clang command line interface is so rich, but this project is using only
a subset of that, it makes sense to create a function specific wrapper. """
+import subprocess
import re
from libscanbuild import run_command
from libscanbuild.shell import decode
-__all__ = ['get_version', 'get_arguments', 'get_checkers']
+__all__ = ['get_version', 'get_arguments', 'get_checkers', 'is_ctu_capable',
+ 'get_triple_arch']
# regex for activated checker
ACTIVE_CHECKER_PATTERN = re.compile(r'^-analyzer-checker=(.*)$')
@@ -152,3 +154,26 @@ def get_checkers(clang, plugins):
raise Exception('Could not query Clang for available checkers.')
return checkers
+
+
+def is_ctu_capable(func_map_cmd):
+ """ Detects if the current (or given) clang and function mapping
+ executables are CTU compatible. """
+
+ try:
+ run_command([func_map_cmd, '-version'])
+ except (OSError, subprocess.CalledProcessError):
+ return False
+ return True
+
+
+def get_triple_arch(command, cwd):
+ """Returns the architecture part of the target triple for the given
+ compilation command. """
+
+ cmd = get_arguments(command, cwd)
+ try:
+ separator = cmd.index("-triple")
+ return cmd[separator + 1]
+ except (IndexError, ValueError):
+ return ""
diff --git a/tools/scan-build-py/libscanbuild/report.py b/tools/scan-build-py/libscanbuild/report.py
index 54b9695d927f..b3753c1d9d4e 100644
--- a/tools/scan-build-py/libscanbuild/report.py
+++ b/tools/scan-build-py/libscanbuild/report.py
@@ -13,7 +13,6 @@ import os
import os.path
import sys
import shutil
-import itertools
import plistlib
import glob
import json
@@ -255,24 +254,29 @@ def read_crashes(output_dir):
def read_bugs(output_dir, html):
+ # type: (str, bool) -> Generator[Dict[str, Any], None, None]
""" Generate a unique sequence of bugs from given output directory.
Duplicates can be in a project if the same module was compiled multiple
times with different compiler options. These would be better to show in
the final report (cover) only once. """
- parser = parse_bug_html if html else parse_bug_plist
- pattern = '*.html' if html else '*.plist'
+ def empty(file_name):
+ return os.stat(file_name).st_size == 0
duplicate = duplicate_check(
lambda bug: '{bug_line}.{bug_path_length}:{bug_file}'.format(**bug))
- bugs = itertools.chain.from_iterable(
- # parser creates a bug generator not the bug itself
- parser(filename)
- for filename in glob.iglob(os.path.join(output_dir, pattern)))
-
- return (bug for bug in bugs if not duplicate(bug))
+ # get the right parser for the job.
+ parser = parse_bug_html if html else parse_bug_plist
+ # get the input files, which are not empty.
+ pattern = os.path.join(output_dir, '*.html' if html else '*.plist')
+ bug_files = (file for file in glob.iglob(pattern) if not empty(file))
+
+ for bug_file in bug_files:
+ for bug in parser(bug_file):
+ if not duplicate(bug):
+ yield bug
def parse_bug_plist(filename):
diff --git a/tools/scan-build-py/tests/unit/test_analyze.py b/tools/scan-build-py/tests/unit/test_analyze.py
index a250ff22132c..9964a296b8dd 100644
--- a/tools/scan-build-py/tests/unit/test_analyze.py
+++ b/tools/scan-build-py/tests/unit/test_analyze.py
@@ -4,12 +4,12 @@
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
-import libear
-import libscanbuild.analyze as sut
import unittest
import re
import os
import os.path
+import libear
+import libscanbuild.analyze as sut
class ReportDirectoryTest(unittest.TestCase):
@@ -333,3 +333,83 @@ class RequireDecoratorTest(unittest.TestCase):
def test_method_exception_not_caught(self):
self.assertRaises(Exception, method_exception_from_inside, dict())
+
+
+class PrefixWithTest(unittest.TestCase):
+
+ def test_gives_empty_on_empty(self):
+ res = sut.prefix_with(0, [])
+ self.assertFalse(res)
+
+ def test_interleaves_prefix(self):
+ res = sut.prefix_with(0, [1, 2, 3])
+ self.assertListEqual([0, 1, 0, 2, 0, 3], res)
+
+
+class MergeCtuMapTest(unittest.TestCase):
+
+ def test_no_map_gives_empty(self):
+ pairs = sut.create_global_ctu_function_map([])
+ self.assertFalse(pairs)
+
+ def test_multiple_maps_merged(self):
+ concat_map = ['c:@F@fun1#I# ast/fun1.c.ast',
+ 'c:@F@fun2#I# ast/fun2.c.ast',
+ 'c:@F@fun3#I# ast/fun3.c.ast']
+ pairs = sut.create_global_ctu_function_map(concat_map)
+ self.assertTrue(('c:@F@fun1#I#', 'ast/fun1.c.ast') in pairs)
+ self.assertTrue(('c:@F@fun2#I#', 'ast/fun2.c.ast') in pairs)
+ self.assertTrue(('c:@F@fun3#I#', 'ast/fun3.c.ast') in pairs)
+ self.assertEqual(3, len(pairs))
+
+ def test_not_unique_func_left_out(self):
+ concat_map = ['c:@F@fun1#I# ast/fun1.c.ast',
+ 'c:@F@fun2#I# ast/fun2.c.ast',
+ 'c:@F@fun1#I# ast/fun7.c.ast']
+ pairs = sut.create_global_ctu_function_map(concat_map)
+ self.assertFalse(('c:@F@fun1#I#', 'ast/fun1.c.ast') in pairs)
+ self.assertFalse(('c:@F@fun1#I#', 'ast/fun7.c.ast') in pairs)
+ self.assertTrue(('c:@F@fun2#I#', 'ast/fun2.c.ast') in pairs)
+ self.assertEqual(1, len(pairs))
+
+ def test_duplicates_are_kept(self):
+ concat_map = ['c:@F@fun1#I# ast/fun1.c.ast',
+ 'c:@F@fun2#I# ast/fun2.c.ast',
+ 'c:@F@fun1#I# ast/fun1.c.ast']
+ pairs = sut.create_global_ctu_function_map(concat_map)
+ self.assertTrue(('c:@F@fun1#I#', 'ast/fun1.c.ast') in pairs)
+ self.assertTrue(('c:@F@fun2#I#', 'ast/fun2.c.ast') in pairs)
+ self.assertEqual(2, len(pairs))
+
+ def test_space_handled_in_source(self):
+ concat_map = ['c:@F@fun1#I# ast/f un.c.ast']
+ pairs = sut.create_global_ctu_function_map(concat_map)
+ self.assertTrue(('c:@F@fun1#I#', 'ast/f un.c.ast') in pairs)
+ self.assertEqual(1, len(pairs))
+
+
+class FuncMapSrcToAstTest(unittest.TestCase):
+
+ def test_empty_gives_empty(self):
+ fun_ast_lst = sut.func_map_list_src_to_ast([])
+ self.assertFalse(fun_ast_lst)
+
+ def test_sources_to_asts(self):
+ fun_src_lst = ['c:@F@f1#I# ' + os.path.join(os.sep + 'path', 'f1.c'),
+ 'c:@F@f2#I# ' + os.path.join(os.sep + 'path', 'f2.c')]
+ fun_ast_lst = sut.func_map_list_src_to_ast(fun_src_lst)
+ self.assertTrue('c:@F@f1#I# ' +
+ os.path.join('ast', 'path', 'f1.c.ast')
+ in fun_ast_lst)
+ self.assertTrue('c:@F@f2#I# ' +
+ os.path.join('ast', 'path', 'f2.c.ast')
+ in fun_ast_lst)
+ self.assertEqual(2, len(fun_ast_lst))
+
+ def test_spaces_handled(self):
+ fun_src_lst = ['c:@F@f1#I# ' + os.path.join(os.sep + 'path', 'f 1.c')]
+ fun_ast_lst = sut.func_map_list_src_to_ast(fun_src_lst)
+ self.assertTrue('c:@F@f1#I# ' +
+ os.path.join('ast', 'path', 'f 1.c.ast')
+ in fun_ast_lst)
+ self.assertEqual(1, len(fun_ast_lst))
diff --git a/tools/scan-build-py/tests/unit/test_clang.py b/tools/scan-build-py/tests/unit/test_clang.py
index eef8c26bbd19..07ac4d9fb806 100644
--- a/tools/scan-build-py/tests/unit/test_clang.py
+++ b/tools/scan-build-py/tests/unit/test_clang.py
@@ -92,3 +92,15 @@ class ClangGetCheckersTest(unittest.TestCase):
self.assertEqual('Checker One description', result.get('checker.one'))
self.assertTrue('checker.two' in result)
self.assertEqual('Checker Two description', result.get('checker.two'))
+
+
+class ClangIsCtuCapableTest(unittest.TestCase):
+ def test_ctu_not_found(self):
+ is_ctu = sut.is_ctu_capable('not-found-clang-func-mapping')
+ self.assertFalse(is_ctu)
+
+
+class ClangGetTripleArchTest(unittest.TestCase):
+ def test_arch_is_not_empty(self):
+ arch = sut.get_triple_arch(['clang', '-E', '-'], '.')
+ self.assertTrue(len(arch) > 0)
diff --git a/tools/scan-build/bin/scan-build b/tools/scan-build/bin/scan-build
index cbf3bf3d6f0b..c50f900cc45e 100755
--- a/tools/scan-build/bin/scan-build
+++ b/tools/scan-build/bin/scan-build
@@ -51,6 +51,7 @@ my %Options = (
OutputDir => undef, # Parent directory to store HTML files.
HtmlTitle => basename($CurrentDir)." - scan-build results",
IgnoreErrors => 0, # Ignore build errors.
+ KeepCC => 0, # Do not override CC and CXX make variables
ViewResults => 0, # View results when the build terminates.
ExitStatusFoundBugs => 0, # Exit status reflects whether bugs were found
ShowDescription => 0, # Display the description of the defect in the list
@@ -1012,7 +1013,7 @@ sub RunXcodebuild {
}
close(DETECT_XCODE);
- # If --override-compiler is explicitely requested, resort to the old
+ # If --override-compiler is explicitly requested, resort to the old
# behavior regardless of Xcode version.
if ($Options{OverrideCompiler}) {
$oldBehavior = 1;
@@ -1062,6 +1063,7 @@ sub RunXcodebuild {
sub RunBuildCommand {
my $Args = shift;
my $IgnoreErrors = shift;
+ my $KeepCC = shift;
my $Cmd = $Args->[0];
my $CCAnalyzer = shift;
my $CXXAnalyzer = shift;
@@ -1099,8 +1101,10 @@ sub RunBuildCommand {
unshift @$Args, $CXXAnalyzer;
}
elsif ($Cmd eq "make" or $Cmd eq "gmake" or $Cmd eq "mingw32-make") {
- AddIfNotPresent($Args, "CC=$CCAnalyzer");
- AddIfNotPresent($Args, "CXX=$CXXAnalyzer");
+ if (!$KeepCC) {
+ AddIfNotPresent($Args, "CC=$CCAnalyzer");
+ AddIfNotPresent($Args, "CXX=$CXXAnalyzer");
+ }
if ($IgnoreErrors) {
AddIfNotPresent($Args,"-k");
AddIfNotPresent($Args,"-i");
@@ -1158,6 +1162,12 @@ OPTIONS:
currently supports make and xcodebuild. This is a convenience option; one
can specify this behavior directly using build options.
+ --keep-cc
+
+ Do not override CC and CXX make variables. Useful when running make in
+ autoconf-based (and similar) projects where configure can add extra flags
+ to those variables.
+
--html-title [title]
--html-title=[title]
@@ -1236,7 +1246,7 @@ ADVANCED OPTIONS:
-maxloop <loop count>
- Specifiy the number of times a block can be visited before giving up.
+ Specify the number of times a block can be visited before giving up.
Default is 4. Increase for more comprehensive coverage at a cost of speed.
-internal-stats
@@ -1532,6 +1542,12 @@ sub ProcessArgs {
next;
}
+ if ($arg eq "--keep-cc") {
+ shift @$Args;
+ $Options{KeepCC} = 1;
+ next;
+ }
+
if ($arg =~ /^--use-cc(=(.+))?$/) {
shift @$Args;
my $cc;
@@ -1838,8 +1854,8 @@ my %EnvVars = (
);
# Run the build.
-my $ExitStatus = RunBuildCommand(\@ARGV, $Options{IgnoreErrors}, $Cmd, $CmdCXX,
- \%EnvVars);
+my $ExitStatus = RunBuildCommand(\@ARGV, $Options{IgnoreErrors}, $Options{KeepCC},
+ $Cmd, $CmdCXX, \%EnvVars);
if (defined $Options{OutputFormat}) {
if ($Options{OutputFormat} =~ /plist/) {
diff --git a/tools/scan-build/libexec/ccc-analyzer b/tools/scan-build/libexec/ccc-analyzer
index b0ec7e7e7487..73cd2ff3d915 100755
--- a/tools/scan-build/libexec/ccc-analyzer
+++ b/tools/scan-build/libexec/ccc-analyzer
@@ -419,7 +419,7 @@ my %LangMap = (
'cc' => 'c++',
'C' => 'c++',
'ii' => 'c++-cpp-output',
- 'i' => $IsCXX ? 'c++-cpp-output' : 'c-cpp-output',
+ 'i' => $IsCXX ? 'c++-cpp-output' : 'cpp-output',
'm' => 'objective-c',
'mi' => 'objective-c-cpp-output',
'mm' => 'objective-c++',
@@ -439,7 +439,7 @@ my %LangsAccepted = (
"c" => 1,
"c++" => 1,
"objective-c++" => 1,
- "c-cpp-output" => 1,
+ "cpp-output" => 1,
"objective-c-cpp-output" => 1,
"c++-cpp-output" => 1
);
diff --git a/tools/scan-build/man/scan-build.1 b/tools/scan-build/man/scan-build.1
index fd18d1f5c70a..3e3252e1b643 100644
--- a/tools/scan-build/man/scan-build.1
+++ b/tools/scan-build/man/scan-build.1
@@ -1,6 +1,6 @@
.\" This file is distributed under the University of Illinois Open Source
.\" License. See LICENSE.TXT for details.
-.\" $Id: scan-build.1 253074 2015-11-13 20:34:15Z jroelofs $
+.\" $Id: scan-build.1 329399 2018-04-06 15:14:32Z alexfh $
.Dd May 25, 2012
.Dt SCAN-BUILD 1
.Os "clang" "3.5"
@@ -116,7 +116,7 @@ model is used. Specifying
uses a simpler, less powerful constraint model used by checker-0.160
and earlier.
.It Fl maxloop Ar N
-Specifiy the number of times a block can be visited before giving
+Specify the number of times a block can be visited before giving
up. Default is 4. Increase for more comprehensive coverage at a
cost of speed.
.It Fl no-failure-reports
diff --git a/tools/scan-view/share/startfile.py b/tools/scan-view/share/startfile.py
index 673935909f82..f58dbeeaf817 100644
--- a/tools/scan-view/share/startfile.py
+++ b/tools/scan-view/share/startfile.py
@@ -62,7 +62,7 @@ class Controller(BaseController):
preexec_fn=setsid, startupinfo=startupinfo)
# It is assumed that this kind of tools (gnome-open, kfmclient,
- # exo-open, xdg-open and open for OSX) immediately exit after lauching
+ # exo-open, xdg-open and open for OSX) immediately exit after launching
# the specific application
returncode = pipe.wait()
if hasattr(self, 'fixreturncode'):
@@ -85,7 +85,7 @@ class Controller(BaseController):
if sys.platform[:3] == 'win':
class Start(BaseController):
- '''Controller for the win32 start progam through os.startfile.'''
+ '''Controller for the win32 start program through os.startfile.'''
def open(self, filename):
try:
@@ -201,6 +201,6 @@ else:
def open(filename):
- '''Open a file or an URL in the registered default application.'''
+ '''Open a file or a URL in the registered default application.'''
return _open(filename)