diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:49:41 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:49:41 +0000 |
| commit | 45b533945f0851ec234ca846e1af5ee1e4df0b6e (patch) | |
| tree | 0a5b74c0b9ca73aded34df95c91fcaf3815230d8 /tools | |
| parent | 7e86edd64bfae4e324224452e4ea879b3371a4bd (diff) | |
Notes
Diffstat (limited to 'tools')
54 files changed, 1868 insertions, 1111 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index b2b2f6aa954c7..dba676a1f7561 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,19 +1,23 @@ -add_subdirectory(diagtool) -add_subdirectory(driver) -add_subdirectory(clang-format) -add_subdirectory(clang-format-vs) -add_subdirectory(clang-fuzzer) +create_subdirectory_options(CLANG TOOL) -add_subdirectory(c-index-test) -add_subdirectory(libclang) +add_clang_subdirectory(diagtool) +add_clang_subdirectory(driver) +add_clang_subdirectory(clang-format) +add_clang_subdirectory(clang-format-vs) +add_clang_subdirectory(clang-fuzzer) +add_clang_subdirectory(scan-build) +add_clang_subdirectory(scan-view) + +add_clang_subdirectory(c-index-test) +add_clang_subdirectory(libclang) if(CLANG_ENABLE_ARCMT) - add_subdirectory(arcmt-test) - add_subdirectory(c-arcmt-test) + add_clang_subdirectory(arcmt-test) + add_clang_subdirectory(c-arcmt-test) endif() if(CLANG_ENABLE_STATIC_ANALYZER) - add_subdirectory(clang-check) + add_clang_subdirectory(clang-check) endif() # We support checking out the clang-tools-extra repository into the 'extra' diff --git a/tools/Makefile b/tools/Makefile index 2ee12992f23ff..5c362bfc9aade 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -15,7 +15,7 @@ DIRS := PARALLEL_DIRS := clang-format driver diagtool ifeq ($(ENABLE_CLANG_STATIC_ANALYZER), 1) - PARALLEL_DIRS += clang-check + PARALLEL_DIRS += clang-check scan-build scan-view endif ifeq ($(ENABLE_CLANG_ARCMT), 1) diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt index d0872fd2eff38..c78a42ffe8eb6 100644 --- a/tools/c-index-test/CMakeLists.txt +++ b/tools/c-index-test/CMakeLists.txt @@ -28,3 +28,23 @@ if (CLANG_HAVE_LIBXML) include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR}) target_link_libraries(c-index-test ${LIBXML2_LIBRARIES}) endif() + +if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) + if(INTERNAL_INSTALL_PREFIX) + set(INSTALL_DESTINATION "${INTERNAL_INSTALL_PREFIX}/bin") + else() + set(INSTALL_DESTINATION bin) + endif() + + install(TARGETS c-index-test + RUNTIME DESTINATION "${INSTALL_DESTINATION}" + COMPONENT c-index-test) + + if (NOT CMAKE_CONFIGURATION_TYPES) # don't add this for IDE's. + add_custom_target(install-c-index-test + DEPENDS c-index-test + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=c-index-test + -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") + endif() +endif() diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index eeeb832cd8738..48f22eb4bbf65 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -76,7 +76,9 @@ static unsigned getDefaultParsingOptions() { options |= CXTranslationUnit_SkipFunctionBodies; if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS")) options |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; - + if (getenv("CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE")) + options |= CXTranslationUnit_CreatePreambleOnFirstParse; + return options; } @@ -767,6 +769,8 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) { clang_disposeString(DeprecatedMessage); clang_disposeString(UnavailableMessage); + if (clang_CXXField_isMutable(Cursor)) + printf(" (mutable)"); if (clang_CXXMethod_isStatic(Cursor)) printf(" (static)"); if (clang_CXXMethod_isVirtual(Cursor)) @@ -1246,6 +1250,32 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p, } /******************************************************************************/ +/* Visibility testing. */ +/******************************************************************************/ + +static enum CXChildVisitResult PrintVisibility(CXCursor cursor, CXCursor p, + CXClientData d) { + const char *visibility = 0; + + if (clang_isInvalid(clang_getCursorKind(cursor))) + return CXChildVisit_Recurse; + + switch (clang_getCursorVisibility(cursor)) { + case CXVisibility_Invalid: break; + case CXVisibility_Hidden: visibility = "Hidden"; break; + case CXVisibility_Protected: visibility = "Protected"; break; + case CXVisibility_Default: visibility = "Default"; break; + } + + if (visibility) { + PrintCursor(cursor, NULL); + printf("visibility=%s\n", visibility); + } + + return CXChildVisit_Recurse; +} + +/******************************************************************************/ /* Typekind testing. */ /******************************************************************************/ @@ -1430,6 +1460,8 @@ static enum CXChildVisitResult PrintTypeSize(CXCursor cursor, CXCursor p, static enum CXChildVisitResult PrintMangledName(CXCursor cursor, CXCursor p, CXClientData d) { CXString MangledName; + if (clang_isUnexposed(clang_getCursorKind(cursor))) + return CXChildVisit_Recurse; PrintCursor(cursor, NULL); MangledName = clang_Cursor_getMangling(cursor); printf(" [mangled=%s]\n", clang_getCString(MangledName)); @@ -1437,6 +1469,25 @@ static enum CXChildVisitResult PrintMangledName(CXCursor cursor, CXCursor p, return CXChildVisit_Continue; } +static enum CXChildVisitResult PrintManglings(CXCursor cursor, CXCursor p, + CXClientData d) { + unsigned I, E; + CXStringSet *Manglings = NULL; + if (clang_isUnexposed(clang_getCursorKind(cursor))) + return CXChildVisit_Recurse; + if (!clang_isDeclaration(clang_getCursorKind(cursor))) + return CXChildVisit_Recurse; + if (clang_getCursorKind(cursor) == CXCursor_ParmDecl) + return CXChildVisit_Continue; + PrintCursor(cursor, NULL); + Manglings = clang_Cursor_getCXXManglings(cursor); + for (I = 0, E = Manglings->Count; I < E; ++I) + printf(" [mangled=%s]", clang_getCString(Manglings->Strings[I])); + clang_disposeStringSet(Manglings); + printf("\n"); + return CXChildVisit_Recurse; +} + /******************************************************************************/ /* Bitwidth testing. */ /******************************************************************************/ @@ -4061,6 +4112,7 @@ static void print_usage(void) { " c-index-test -test-inclusion-stack-tu <AST file>\n"); fprintf(stderr, " c-index-test -test-print-linkage-source {<args>}*\n" + " c-index-test -test-print-visibility {<args>}*\n" " c-index-test -test-print-type {<args>}*\n" " c-index-test -test-print-type-size {<args>}*\n" " c-index-test -test-print-bitwidth {<args>}*\n" @@ -4148,6 +4200,9 @@ int cindextest_main(int argc, const char **argv) { else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0) return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage, NULL); + else if (argc > 2 && strcmp(argv[1], "-test-print-visibility") == 0) + return perform_test_load_source(argc - 2, argv + 2, "all", PrintVisibility, + NULL); else if (argc > 2 && strcmp(argv[1], "-test-print-type") == 0) return perform_test_load_source(argc - 2, argv + 2, "all", PrintType, 0); @@ -4159,6 +4214,8 @@ int cindextest_main(int argc, const char **argv) { PrintBitWidth, 0); else if (argc > 2 && strcmp(argv[1], "-test-print-mangle") == 0) return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL); + else if (argc > 2 && strcmp(argv[1], "-test-print-manglings") == 0) + return perform_test_load_tu(argv[2], "all", NULL, PrintManglings, NULL); else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) { if (argc > 2) return print_usrs(argv + 2, argv + argc); diff --git a/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs index c3aa8fecded58..df872b2e21982 100644 --- a/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs +++ b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs @@ -19,10 +19,10 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
using System;
+using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.IO;
-using System.Reflection;
using System.Runtime.InteropServices;
using System.Xml.Linq;
@@ -32,13 +32,53 @@ namespace LLVM.ClangFormat [CLSCompliant(false), ComVisible(true)]
public class OptionPageGrid : DialogPage
{
- private string style = "File";
+ private string assumeFilename = "";
+ private string fallbackStyle = "LLVM";
+ private bool sortIncludes = false;
+ private string style = "file";
+
+ public class StyleConverter : TypeConverter
+ {
+ protected ArrayList values;
+ public StyleConverter()
+ {
+ // Initializes the standard values list with defaults.
+ values = new ArrayList(new string[] { "file", "Chromium", "Google", "LLVM", "Mozilla", "WebKit" });
+ }
+
+ public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+ {
+ return new StandardValuesCollection(values);
+ }
+
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ if (sourceType == typeof(string))
+ return true;
+
+ return base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
+ {
+ string s = value as string;
+ if (s == null)
+ return base.ConvertFrom(context, culture, value);
+
+ return value;
+ }
+ }
[Category("LLVM/Clang")]
[DisplayName("Style")]
[Description("Coding style, currently supports:\n" +
- " - Predefined styles ('LLVM', 'Google', 'Chromium', 'Mozilla').\n" +
- " - 'File' to search for a YAML .clang-format or _clang-format\n" +
+ " - Predefined styles ('LLVM', 'Google', 'Chromium', 'Mozilla', 'WebKit').\n" +
+ " - 'file' to search for a YAML .clang-format or _clang-format\n" +
" configuration file.\n" +
" - A YAML configuration snippet.\n\n" +
"'File':\n" +
@@ -48,11 +88,81 @@ namespace LLVM.ClangFormat " The content of a .clang-format configuration file, as string.\n" +
" Example: '{BasedOnStyle: \"LLVM\", IndentWidth: 8}'\n\n" +
"See also: http://clang.llvm.org/docs/ClangFormatStyleOptions.html.")]
+ [TypeConverter(typeof(StyleConverter))]
public string Style
{
get { return style; }
set { style = value; }
}
+
+ public sealed class FilenameConverter : TypeConverter
+ {
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ if (sourceType == typeof(string))
+ return true;
+
+ return base.CanConvertFrom(context, sourceType);
+ }
+
+ public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
+ {
+ string s = value as string;
+ if (s == null)
+ return base.ConvertFrom(context, culture, value);
+
+ // Check if string contains quotes. On Windows, file names cannot contain quotes.
+ // We do not accept them however to avoid hard-to-debug problems.
+ // A quote in user input would end the parameter quote and so break the command invocation.
+ if (s.IndexOf('\"') != -1)
+ throw new NotSupportedException("Filename cannot contain quotes");
+
+ return value;
+ }
+ }
+
+ [Category("LLVM/Clang")]
+ [DisplayName("Assume Filename")]
+ [Description("When reading from stdin, clang-format assumes this " +
+ "filename to look for a style config file (with 'file' style) " +
+ "and to determine the language.")]
+ [TypeConverter(typeof(FilenameConverter))]
+ public string AssumeFilename
+ {
+ get { return assumeFilename; }
+ set { assumeFilename = value; }
+ }
+
+ public sealed class FallbackStyleConverter : StyleConverter
+ {
+ public FallbackStyleConverter()
+ {
+ // Add "none" to the list of styles.
+ values.Insert(0, "none");
+ }
+ }
+
+ [Category("LLVM/Clang")]
+ [DisplayName("Fallback Style")]
+ [Description("The name of the predefined style used as a fallback in case clang-format " +
+ "is invoked with 'file' style, but can not find the configuration file.\n" +
+ "Use 'none' fallback style to skip formatting.")]
+ [TypeConverter(typeof(FallbackStyleConverter))]
+ public string FallbackStyle
+ {
+ get { return fallbackStyle; }
+ set { fallbackStyle = value; }
+ }
+
+ [Category("LLVM/Clang")]
+ [DisplayName("Sort includes")]
+ [Description("Sort touched include lines.\n\n" +
+ "See also: http://clang.llvm.org/docs/ClangFormat.html.")]
+ public bool SortIncludes
+ {
+ get { return sortIncludes; }
+ set { sortIncludes = value; }
+ }
}
[PackageRegistration(UseManagedResourcesOnly = true)]
@@ -138,10 +248,17 @@ namespace LLVM.ClangFormat // Poor man's escaping - this will not work when quotes are already escaped
// in the input (but we don't need more).
string style = GetStyle().Replace("\"", "\\\"");
+ string fallbackStyle = GetFallbackStyle().Replace("\"", "\\\"");
process.StartInfo.Arguments = " -offset " + offset +
" -length " + length +
" -output-replacements-xml " +
- " -style \"" + style + "\"";
+ " -style \"" + style + "\"" +
+ " -fallback-style \"" + fallbackStyle + "\"";
+ if (GetSortIncludes())
+ process.StartInfo.Arguments += " -sort-includes ";
+ string assumeFilename = GetAssumeFilename();
+ if (!string.IsNullOrEmpty(assumeFilename))
+ process.StartInfo.Arguments += " -assume-filename \"" + assumeFilename + "\"";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
@@ -211,6 +328,24 @@ namespace LLVM.ClangFormat return page.Style;
}
+ private string GetAssumeFilename()
+ {
+ var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
+ return page.AssumeFilename;
+ }
+
+ private string GetFallbackStyle()
+ {
+ var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
+ return page.FallbackStyle;
+ }
+
+ private bool GetSortIncludes()
+ {
+ var page = (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
+ return page.SortIncludes;
+ }
+
private string GetDocumentParent(IWpfTextView view)
{
ITextDocument document;
diff --git a/tools/clang-format-vs/ClangFormat/Properties/AssemblyInfo.cs b/tools/clang-format-vs/ClangFormat/Properties/AssemblyInfo.cs index e6e4de488012a..b1cef49414b5e 100644 --- a/tools/clang-format-vs/ClangFormat/Properties/AssemblyInfo.cs +++ b/tools/clang-format-vs/ClangFormat/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("1.1.0.0")]
+[assembly: AssemblyFileVersion("1.1.0.0")]
diff --git a/tools/clang-format-vs/README.txt b/tools/clang-format-vs/README.txt index 636b89f3c6736..b23355d0cebcc 100644 --- a/tools/clang-format-vs/README.txt +++ b/tools/clang-format-vs/README.txt @@ -2,9 +2,10 @@ This directory contains a VSPackage project to generate a Visual Studio extensio for clang-format.
Build prerequisites are:
-- Visual Studio 2012 Professional
-- Visual Studio 2010 Professional
-- Visual Studio 2010 SDK.
+- Visual Studio 2013 Professional
+- Visual Studio 2013 SDK
+- Visual Studio 2010 Professional (?)
+- Visual Studio 2010 SDK (?)
The extension is built using CMake by setting BUILD_CLANG_FORMAT_VS_PLUGIN=ON
when configuring a Clang build, and building the clang_format_vsix target.
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp index 5037e901f3b41..36f237fc750c9 100644 --- a/tools/clang-format/ClangFormat.cpp +++ b/tools/clang-format/ClangFormat.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/Signals.h" using namespace llvm; +using clang::tooling::Replacements; static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden); @@ -73,11 +74,11 @@ FallbackStyle("fallback-style", cl::init("LLVM"), cl::cat(ClangFormatCategory)); static cl::opt<std::string> -AssumeFilename("assume-filename", +AssumeFileName("assume-filename", cl::desc("When reading from stdin, clang-format assumes this\n" "filename to look for a style config file (with\n" "-style=file) and to determine the language."), - cl::cat(ClangFormatCategory)); + cl::init("<stdin>"), cl::cat(ClangFormatCategory)); static cl::opt<bool> Inplace("i", cl::desc("Inplace edit <file>s, if specified."), @@ -97,6 +98,12 @@ static cl::opt<unsigned> "clang-format from an editor integration"), cl::init(0), cl::cat(ClangFormatCategory)); +static cl::opt<bool> SortIncludes( + "sort-includes", + cl::desc("If set, overrides the include sorting behavior determined by the " + "SortIncludes style flag"), + cl::cat(ClangFormatCategory)); + static cl::list<std::string> FileNames(cl::Positional, cl::desc("[<file> ...]"), cl::cat(ClangFormatCategory)); @@ -104,12 +111,11 @@ namespace clang { namespace format { static FileID createInMemoryFile(StringRef FileName, MemoryBuffer *Source, - SourceManager &Sources, FileManager &Files) { - const FileEntry *Entry = Files.getVirtualFile(FileName == "-" ? "<stdin>" : - FileName, - Source->getBufferSize(), 0); - Sources.overrideFileContents(Entry, Source, true); - return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User); + SourceManager &Sources, FileManager &Files, + vfs::InMemoryFileSystem *MemFS) { + MemFS->addFileNoOwn(FileName, 0, Source); + return Sources.createFileID(Files.getFile(FileName), SourceLocation(), + SrcMgr::C_User); } // Parses <start line>:<end line> input to a pair of line numbers. @@ -121,30 +127,40 @@ static bool parseLineRange(StringRef Input, unsigned &FromLine, LineRange.second.getAsInteger(0, ToLine); } -static bool fillRanges(SourceManager &Sources, FileID ID, - const MemoryBuffer *Code, - std::vector<CharSourceRange> &Ranges) { +static bool fillRanges(MemoryBuffer *Code, + std::vector<tooling::Range> &Ranges) { + IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( + new vfs::InMemoryFileSystem); + FileManager Files(FileSystemOptions(), InMemoryFileSystem); + DiagnosticsEngine Diagnostics( + IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), + new DiagnosticOptions); + SourceManager Sources(Diagnostics, Files); + FileID ID = createInMemoryFile("<irrelevant>", Code, Sources, Files, + InMemoryFileSystem.get()); if (!LineRanges.empty()) { if (!Offsets.empty() || !Lengths.empty()) { - llvm::errs() << "error: cannot use -lines with -offset/-length\n"; + errs() << "error: cannot use -lines with -offset/-length\n"; return true; } for (unsigned i = 0, e = LineRanges.size(); i < e; ++i) { unsigned FromLine, ToLine; if (parseLineRange(LineRanges[i], FromLine, ToLine)) { - llvm::errs() << "error: invalid <start line>:<end line> pair\n"; + errs() << "error: invalid <start line>:<end line> pair\n"; return true; } if (FromLine > ToLine) { - llvm::errs() << "error: start line should be less than end line\n"; + errs() << "error: start line should be less than end line\n"; return true; } SourceLocation Start = Sources.translateLineCol(ID, FromLine, 1); SourceLocation End = Sources.translateLineCol(ID, ToLine, UINT_MAX); if (Start.isInvalid() || End.isInvalid()) return true; - Ranges.push_back(CharSourceRange::getCharRange(Start, End)); + unsigned Offset = Sources.getFileOffset(Start); + unsigned Length = Sources.getFileOffset(End) - Offset; + Ranges.push_back(tooling::Range(Offset, Length)); } return false; } @@ -153,14 +169,12 @@ static bool fillRanges(SourceManager &Sources, FileID ID, Offsets.push_back(0); if (Offsets.size() != Lengths.size() && !(Offsets.size() == 1 && Lengths.empty())) { - llvm::errs() - << "error: number of -offset and -length arguments must match.\n"; + errs() << "error: number of -offset and -length arguments must match.\n"; return true; } for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { if (Offsets[i] >= Code->getBufferSize()) { - llvm::errs() << "error: offset " << Offsets[i] - << " is outside the file\n"; + errs() << "error: offset " << Offsets[i] << " is outside the file\n"; return true; } SourceLocation Start = @@ -168,97 +182,122 @@ static bool fillRanges(SourceManager &Sources, FileID ID, SourceLocation End; if (i < Lengths.size()) { if (Offsets[i] + Lengths[i] > Code->getBufferSize()) { - llvm::errs() << "error: invalid length " << Lengths[i] - << ", offset + length (" << Offsets[i] + Lengths[i] - << ") is outside the file.\n"; + errs() << "error: invalid length " << Lengths[i] + << ", offset + length (" << Offsets[i] + Lengths[i] + << ") is outside the file.\n"; return true; } End = Start.getLocWithOffset(Lengths[i]); } else { End = Sources.getLocForEndOfFile(ID); } - Ranges.push_back(CharSourceRange::getCharRange(Start, End)); + unsigned Offset = Sources.getFileOffset(Start); + unsigned Length = Sources.getFileOffset(End) - Offset; + Ranges.push_back(tooling::Range(Offset, Length)); } return false; } static void outputReplacementXML(StringRef Text) { + // FIXME: When we sort includes, we need to make sure the stream is correct + // utf-8. size_t From = 0; size_t Index; - while ((Index = Text.find_first_of("\n\r", From)) != StringRef::npos) { - llvm::outs() << Text.substr(From, Index - From); + while ((Index = Text.find_first_of("\n\r<&", From)) != StringRef::npos) { + outs() << Text.substr(From, Index - From); switch (Text[Index]) { case '\n': - llvm::outs() << " "; + outs() << " "; break; case '\r': - llvm::outs() << " "; + outs() << " "; + break; + case '<': + outs() << "<"; + break; + case '&': + outs() << "&"; break; default: llvm_unreachable("Unexpected character encountered!"); } From = Index + 1; } - llvm::outs() << Text.substr(From); + outs() << Text.substr(From); +} + +static void outputReplacementsXML(const Replacements &Replaces) { + for (const auto &R : Replaces) { + outs() << "<replacement " + << "offset='" << R.getOffset() << "' " + << "length='" << R.getLength() << "'>"; + outputReplacementXML(R.getReplacementText()); + outs() << "</replacement>\n"; + } } // Returns true on error. static bool format(StringRef FileName) { - FileManager Files((FileSystemOptions())); - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), - new DiagnosticOptions); - SourceManager Sources(Diagnostics, Files); ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = MemoryBuffer::getFileOrSTDIN(FileName); if (std::error_code EC = CodeOrErr.getError()) { - llvm::errs() << EC.message() << "\n"; + errs() << EC.message() << "\n"; return true; } std::unique_ptr<llvm::MemoryBuffer> Code = std::move(CodeOrErr.get()); if (Code->getBufferSize() == 0) return false; // Empty files are formatted correctly. - FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files); - std::vector<CharSourceRange> Ranges; - if (fillRanges(Sources, ID, Code.get(), Ranges)) + std::vector<tooling::Range> Ranges; + if (fillRanges(Code.get(), Ranges)) return true; + StringRef AssumedFileName = (FileName == "-") ? AssumeFileName : FileName; + FormatStyle FormatStyle = getStyle(Style, AssumedFileName, FallbackStyle); + if (SortIncludes.getNumOccurrences() != 0) + FormatStyle.SortIncludes = SortIncludes; + unsigned CursorPosition = Cursor; + Replacements Replaces = sortIncludes(FormatStyle, Code->getBuffer(), Ranges, + AssumedFileName, &CursorPosition); + std::string ChangedCode = + tooling::applyAllReplacements(Code->getBuffer(), Replaces); + for (const auto &R : Replaces) + Ranges.push_back({R.getOffset(), R.getLength()}); - FormatStyle FormatStyle = getStyle( - Style, (FileName == "-") ? AssumeFilename : FileName, FallbackStyle); bool IncompleteFormat = false; - tooling::Replacements Replaces = - reformat(FormatStyle, Sources, ID, Ranges, &IncompleteFormat); + Replacements FormatChanges = reformat(FormatStyle, ChangedCode, Ranges, + AssumedFileName, &IncompleteFormat); + Replaces = tooling::mergeReplacements(Replaces, FormatChanges); if (OutputXML) { - llvm::outs() << "<?xml version='1.0'?>\n<replacements " - "xml:space='preserve' incomplete_format='" - << (IncompleteFormat ? "true" : "false") << "'>\n"; + outs() << "<?xml version='1.0'?>\n<replacements " + "xml:space='preserve' incomplete_format='" + << (IncompleteFormat ? "true" : "false") << "'>\n"; if (Cursor.getNumOccurrences() != 0) - llvm::outs() << "<cursor>" - << tooling::shiftedCodePosition(Replaces, Cursor) - << "</cursor>\n"; + outs() << "<cursor>" + << tooling::shiftedCodePosition(FormatChanges, CursorPosition) + << "</cursor>\n"; - for (tooling::Replacements::const_iterator I = Replaces.begin(), - E = Replaces.end(); - I != E; ++I) { - llvm::outs() << "<replacement " - << "offset='" << I->getOffset() << "' " - << "length='" << I->getLength() << "'>"; - outputReplacementXML(I->getReplacementText()); - llvm::outs() << "</replacement>\n"; - } - llvm::outs() << "</replacements>\n"; + outputReplacementsXML(Replaces); + outs() << "</replacements>\n"; } else { + IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( + new vfs::InMemoryFileSystem); + FileManager Files(FileSystemOptions(), InMemoryFileSystem); + DiagnosticsEngine Diagnostics( + IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), + new DiagnosticOptions); + SourceManager Sources(Diagnostics, Files); + FileID ID = createInMemoryFile(AssumedFileName, Code.get(), Sources, Files, + InMemoryFileSystem.get()); Rewriter Rewrite(Sources, LangOptions()); tooling::applyAllReplacements(Replaces, Rewrite); if (Inplace) { if (FileName == "-") - llvm::errs() << "error: cannot use -i when reading from stdin.\n"; + errs() << "error: cannot use -i when reading from stdin.\n"; else if (Rewrite.overwriteChangedFiles()) return true; } else { if (Cursor.getNumOccurrences() != 0) outs() << "{ \"Cursor\": " - << tooling::shiftedCodePosition(Replaces, Cursor) + << tooling::shiftedCodePosition(FormatChanges, CursorPosition) << ", \"IncompleteFormat\": " << (IncompleteFormat ? "true" : "false") << " }\n"; Rewrite.getEditBuffer(ID).write(outs()); @@ -283,7 +322,7 @@ int main(int argc, const char **argv) { cl::SetVersionPrinter(PrintVersion); cl::ParseCommandLineOptions( argc, argv, - "A tool to format C/C++/Obj-C code.\n\n" + "A tool to format C/C++/Java/JavaScript/Objective-C/Protobuf code.\n\n" "If no arguments are specified, it formats the code from standard input\n" "and writes the result to the standard output.\n" "If <file>s are given, it reformats the files. If -i is specified\n" @@ -296,9 +335,9 @@ int main(int argc, const char **argv) { if (DumpConfig) { std::string Config = clang::format::configurationAsText(clang::format::getStyle( - Style, FileNames.empty() ? AssumeFilename : FileNames[0], + Style, FileNames.empty() ? AssumeFileName : FileNames[0], FallbackStyle)); - llvm::outs() << Config << "\n"; + outs() << Config << "\n"; return 0; } @@ -312,8 +351,8 @@ int main(int argc, const char **argv) { break; default: if (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty()) { - llvm::errs() << "error: -offset, -length and -lines can only be used for " - "single file.\n"; + errs() << "error: -offset, -length and -lines can only be used for " + "single file.\n"; return 1; } for (unsigned i = 0; i < FileNames.size(); ++i) @@ -322,3 +361,4 @@ int main(int argc, const char **argv) { } return Error ? 1 : 0; } + diff --git a/tools/clang-format/clang-format-diff.py b/tools/clang-format/clang-format-diff.py index 64efb83a8c19e..9e02bb09387f8 100755 --- a/tools/clang-format/clang-format-diff.py +++ b/tools/clang-format/clang-format-diff.py @@ -52,6 +52,8 @@ def main(): r'|protodevel|java)', help='custom pattern selecting file paths to reformat ' '(case insensitive, overridden by -regex)') + parser.add_argument('-sort-includes', action='store_true', default=False, + help='let clang-format sort include blocks') parser.add_argument('-v', '--verbose', action='store_true', help='be more verbose, ineffective without -i') parser.add_argument( @@ -96,6 +98,8 @@ def main(): command = [binary, filename] if args.i: command.append('-i') + if args.sort_includes: + command.append('-sort-includes') command.extend(lines) if args.style: command.extend(['-style', args.style]) diff --git a/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp b/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp index fe4941a5ba1a0..5334ce873eca4 100644 --- a/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp +++ b/tools/clang-format/fuzzer/ClangFormatFuzzer.cpp @@ -15,11 +15,12 @@ #include "clang/Format/Format.h" -extern "C" void LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { +extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { // FIXME: fuzz more things: different styles, different style features. std::string s((const char *)data, size); auto Style = getGoogleStyle(clang::format::FormatStyle::LK_Cpp); Style.ColumnLimit = 60; applyAllReplacements(s, clang::format::reformat( Style, s, {clang::tooling::Range(0, s.size())})); + return 0; } diff --git a/tools/clang-fuzzer/ClangFuzzer.cpp b/tools/clang-fuzzer/ClangFuzzer.cpp index 124911cd4a54d..d07cf5027b2a5 100644 --- a/tools/clang-fuzzer/ClangFuzzer.cpp +++ b/tools/clang-fuzzer/ClangFuzzer.cpp @@ -20,7 +20,7 @@ using namespace clang; -extern "C" void LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { +extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { std::string s((const char *)data, size); llvm::opt::ArgStringList CC1Args; CC1Args.push_back("-cc1"); @@ -40,7 +40,8 @@ extern "C" void LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { std::unique_ptr<tooling::ToolAction> action( tooling::newFrontendActionFactory<clang::SyntaxOnlyAction>()); std::shared_ptr<PCHContainerOperations> PCHContainerOps = - std::make_shared<RawPCHContainerOperations>(); + std::make_shared<PCHContainerOperations>(); action->runInvocation(Invocation.release(), Files.get(), PCHContainerOps, &Diags); + return 0; } diff --git a/tools/diagtool/ShowEnabledWarnings.cpp b/tools/diagtool/ShowEnabledWarnings.cpp index 06f74320b7fc5..abbd3afbd58c6 100644 --- a/tools/diagtool/ShowEnabledWarnings.cpp +++ b/tools/diagtool/ShowEnabledWarnings.cpp @@ -64,9 +64,11 @@ createDiagnostics(unsigned int argc, char **argv) { new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer)); // Try to build a CompilerInvocation. + SmallVector<const char *, 4> Args; + Args.push_back("diagtool"); + Args.append(argv, argv + argc); std::unique_ptr<CompilerInvocation> Invocation( - createInvocationFromCommandLine(llvm::makeArrayRef(argv, argc), - InterimDiags)); + createInvocationFromCommandLine(Args, InterimDiags)); if (!Invocation) return nullptr; diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 3f1ed40abe4d7..fca9b616751ba 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -3,7 +3,6 @@ set( LLVM_LINK_COMPONENTS Analysis CodeGen Core - IPA IPO InstCombine Instrumentation @@ -52,38 +51,29 @@ endif() add_dependencies(clang clang-headers) -if(UNIX) - set(CLANGXX_LINK_OR_COPY create_symlink) -# Create a relative symlink - set(clang_binary "clang${CMAKE_EXECUTABLE_SUFFIX}") -else() - set(CLANGXX_LINK_OR_COPY copy) - set(clang_binary "${LLVM_RUNTIME_OUTPUT_INTDIR}/clang${CMAKE_EXECUTABLE_SUFFIX}") -endif() - -# Create the clang++ symlink in the build directory. -set(clang_pp "${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}") -add_custom_command(TARGET clang POST_BUILD - COMMAND ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY} "${clang_binary}" "${clang_pp}" - WORKING_DIRECTORY "${LLVM_RUNTIME_OUTPUT_INTDIR}") - -set_property(DIRECTORY APPEND - PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${clang_pp}) +install(TARGETS clang + RUNTIME DESTINATION bin + COMPONENT clang) -# Create the clang-cl symlink in the build directory. -set(clang_cl "${LLVM_RUNTIME_OUTPUT_INTDIR}/clang-cl${CMAKE_EXECUTABLE_SUFFIX}") -add_custom_command(TARGET clang POST_BUILD - COMMAND ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY} "${clang_binary}" "${clang_cl}" - WORKING_DIRECTORY "${LLVM_RUNTIME_OUTPUT_INTDIR}") +if(NOT CMAKE_CONFIGURATION_TYPES) + add_custom_target(install-clang + DEPENDS clang + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=clang + -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") +endif() -set_property(DIRECTORY APPEND - PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${clang_cl}) +if(NOT CLANG_LINKS_TO_CREATE) + set(CLANG_LINKS_TO_CREATE clang++ clang-cl) -install(TARGETS clang - RUNTIME DESTINATION bin) + if (WIN32) + list(APPEND CLANG_LINKS_TO_CREATE ../msbuild-bin/cl) + endif() +endif() -# Create the clang++ and clang-cl symlinks at installation time. -install(SCRIPT clang_symlink.cmake -DCMAKE_INSTALL_PREFIX=\"${CMAKE_INSTALL_PREFIX}\") +foreach(link ${CLANG_LINKS_TO_CREATE}) + add_clang_symlink(${link} clang) +endforeach() # Configure plist creation for OS X. set (TOOL_INFO_PLIST "Info.plist" CACHE STRING "Plist name") @@ -96,10 +86,7 @@ if (APPLE) set(TOOL_INFO_UTI "${CLANG_VENDOR_UTI}") set(TOOL_INFO_VERSION "${CLANG_VERSION}") - if (LLVM_SUBMIT_VERSION) - set(TOOL_INFO_BUILD_VERSION - "${LLVM_SUBMIT_VERSION}.${LLVM_SUBMIT_SUBVERSION}") - endif() + set(TOOL_INFO_BUILD_VERSION "${LLVM_MAJOR_VERSION}.${LLVM_MINOR_VERSION}") set(TOOL_INFO_PLIST_OUT "${CMAKE_CURRENT_BINARY_DIR}/${TOOL_INFO_PLIST}") target_link_libraries(clang diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp index fd0fbb4c5a26b..59b7af521743b 100644 --- a/tools/driver/cc1as_main.cpp +++ b/tools/driver/cc1as_main.cpp @@ -125,6 +125,10 @@ struct AssemblerInvocation { unsigned RelaxAll : 1; unsigned NoExecStack : 1; unsigned FatalWarnings : 1; + unsigned IncrementalLinkerCompatible : 1; + + /// The name of the relocation model to use. + std::string RelocationModel; /// @} @@ -141,7 +145,8 @@ public: RelaxAll = 0; NoExecStack = 0; FatalWarnings = 0; - DwarfVersion = 3; + IncrementalLinkerCompatible = 0; + DwarfVersion = 0; } static bool CreateFromArgs(AssemblerInvocation &Res, @@ -192,14 +197,10 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, Opts.IncludePaths = Args.getAllArgValues(OPT_I); Opts.NoInitialTextSection = Args.hasArg(OPT_n); Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels); - Opts.GenDwarfForAssembly = Args.hasArg(OPT_g_Flag); + // Any DebugInfoKind implies GenDwarfForAssembly. + Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ); Opts.CompressDebugSections = Args.hasArg(OPT_compress_debug_sections); - if (Args.hasArg(OPT_gdwarf_2)) - Opts.DwarfVersion = 2; - if (Args.hasArg(OPT_gdwarf_3)) - Opts.DwarfVersion = 3; - if (Args.hasArg(OPT_gdwarf_4)) - Opts.DwarfVersion = 4; + Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 0, Diags); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); Opts.DwarfDebugProducer = Args.getLastArgValue(OPT_dwarf_debug_producer); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); @@ -248,6 +249,9 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings); + Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); + Opts.IncrementalLinkerCompatible = + Args.hasArg(OPT_mincremental_linker_compatible); return Success; } @@ -321,8 +325,19 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); - // FIXME: Assembler behavior can change with -static. - MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), Reloc::Default, + + llvm::Reloc::Model RM = llvm::Reloc::Default; + if (Opts.RelocationModel == "static") { + RM = llvm::Reloc::Static; + } else if (Opts.RelocationModel == "pic") { + RM = llvm::Reloc::PIC_; + } else { + assert(Opts.RelocationModel == "dynamic-no-pic" && + "Invalid PIC model!"); + RM = llvm::Reloc::DynamicNoPIC; + } + + MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), RM, CodeModel::Default, Ctx); if (Opts.SaveTemporaryLabels) Ctx.setAllowTemporaryLabels(false); @@ -383,9 +398,10 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple, Opts.CPU); Triple T(Opts.Triple); - Str.reset(TheTarget->createMCObjectStreamer(T, Ctx, *MAB, *Out, CE, *STI, - Opts.RelaxAll, - /*DWARFMustBeAtTheEnd*/ true)); + Str.reset(TheTarget->createMCObjectStreamer( + T, Ctx, *MAB, *Out, CE, *STI, Opts.RelaxAll, + Opts.IncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ true)); Str.get()->InitSections(Opts.NoExecStack); } @@ -496,4 +512,3 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { return !!Failed; } - diff --git a/tools/driver/clang_symlink.cmake b/tools/driver/clang_symlink.cmake deleted file mode 100644 index c01259543c90a..0000000000000 --- a/tools/driver/clang_symlink.cmake +++ /dev/null @@ -1,43 +0,0 @@ -# We need to execute this script at installation time because the -# DESTDIR environment variable may be unset at configuration time. -# See PR8397. - -if(UNIX) - set(CLANGXX_LINK_OR_COPY create_symlink) - set(CLANGXX_DESTDIR $ENV{DESTDIR}) -else() - set(CLANGXX_LINK_OR_COPY copy) -endif() - -# CMAKE_EXECUTABLE_SUFFIX is undefined on cmake scripts. See PR9286. -if( WIN32 ) - set(EXECUTABLE_SUFFIX ".exe") -else() - set(EXECUTABLE_SUFFIX "") -endif() - -set(bindir "${CLANGXX_DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/") -set(clang "clang${EXECUTABLE_SUFFIX}") -set(clangxx "clang++${EXECUTABLE_SUFFIX}") -set(clang_cl "clang-cl${EXECUTABLE_SUFFIX}") -set(cl "cl${EXECUTABLE_SUFFIX}") - -message("Creating clang++ executable based on ${clang}") - -execute_process( - COMMAND "${CMAKE_COMMAND}" -E ${CLANGXX_LINK_OR_COPY} "${clang}" "${clangxx}" - WORKING_DIRECTORY "${bindir}") - -message("Creating clang-cl executable based on ${clang}") - -execute_process( - COMMAND "${CMAKE_COMMAND}" -E ${CLANGXX_LINK_OR_COPY} "${clang}" "${clang_cl}" - WORKING_DIRECTORY "${bindir}") - -if (WIN32) - message("Creating cl executable based on ${clang}") - - execute_process( - COMMAND "${CMAKE_COMMAND}" -E ${CLANGXX_LINK_OR_COPY} "${clang}" "../msbuild-bin/${cl}" - WORKING_DIRECTORY "${bindir}") -endif() diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index 5925447841fc2..ea218d5403d83 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -18,6 +18,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "clang/Driver/ToolChain.h" #include "clang/Frontend/ChainedDiagnosticConsumer.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/SerializedDiagnosticPrinter.h" @@ -44,7 +45,6 @@ #include "llvm/Support/Regex.h" #include "llvm/Support/Signals.h" #include "llvm/Support/StringSaver.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" @@ -201,94 +201,33 @@ extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr); -struct DriverSuffix { - const char *Suffix; - const char *ModeFlag; -}; - -static const DriverSuffix *FindDriverSuffix(StringRef ProgName) { - // A list of known driver suffixes. Suffixes are compared against the - // program name in order. If there is a match, the frontend type if updated as - // necessary by applying the ModeFlag. - static const DriverSuffix DriverSuffixes[] = { - {"clang", nullptr}, - {"clang++", "--driver-mode=g++"}, - {"clang-c++", "--driver-mode=g++"}, - {"clang-cc", nullptr}, - {"clang-cpp", "--driver-mode=cpp"}, - {"clang-g++", "--driver-mode=g++"}, - {"clang-gcc", nullptr}, - {"clang-cl", "--driver-mode=cl"}, - {"cc", nullptr}, - {"cpp", "--driver-mode=cpp"}, - {"cl", "--driver-mode=cl"}, - {"++", "--driver-mode=g++"}, - }; - - for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) - if (ProgName.endswith(DriverSuffixes[i].Suffix)) - return &DriverSuffixes[i]; - return nullptr; -} - -static void ParseProgName(SmallVectorImpl<const char *> &ArgVector, - std::set<std::string> &SavedStrings) { - // Try to infer frontend type and default target from the program name by - // comparing it against DriverSuffixes in order. - - // If there is a match, the function tries to identify a target as prefix. - // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target - // prefix "x86_64-linux". If such a target prefix is found, is gets added via - // -target as implicit first argument. - - std::string ProgName =llvm::sys::path::stem(ArgVector[0]); -#ifdef LLVM_ON_WIN32 - // Transform to lowercase for case insensitive file systems. - ProgName = StringRef(ProgName).lower(); -#endif - - StringRef ProgNameRef = ProgName; - const DriverSuffix *DS = FindDriverSuffix(ProgNameRef); - - if (!DS) { - // Try again after stripping any trailing version number: - // clang++3.5 -> clang++ - ProgNameRef = ProgNameRef.rtrim("0123456789."); - DS = FindDriverSuffix(ProgNameRef); +static void insertTargetAndModeArgs(StringRef Target, StringRef Mode, + SmallVectorImpl<const char *> &ArgVector, + std::set<std::string> &SavedStrings) { + if (!Mode.empty()) { + // Add the mode flag to the arguments. + auto it = ArgVector.begin(); + if (it != ArgVector.end()) + ++it; + ArgVector.insert(it, GetStableCStr(SavedStrings, Mode)); } - if (!DS) { - // Try again after stripping trailing -component. - // clang++-tot -> clang++ - ProgNameRef = ProgNameRef.slice(0, ProgNameRef.rfind('-')); - DS = FindDriverSuffix(ProgNameRef); + if (!Target.empty()) { + auto it = ArgVector.begin(); + if (it != ArgVector.end()) + ++it; + const char *arr[] = {"-target", GetStableCStr(SavedStrings, Target)}; + ArgVector.insert(it, std::begin(arr), std::end(arr)); } +} - if (DS) { - if (const char *Flag = DS->ModeFlag) { - // Add Flag to the arguments. - auto it = ArgVector.begin(); - if (it != ArgVector.end()) - ++it; - ArgVector.insert(it, Flag); - } - - StringRef::size_type LastComponent = ProgNameRef.rfind( - '-', ProgNameRef.size() - strlen(DS->Suffix)); - if (LastComponent == StringRef::npos) - return; - - // Infer target from the prefix. - StringRef Prefix = ProgNameRef.slice(0, LastComponent); - std::string IgnoredError; - if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) { - auto it = ArgVector.begin(); - if (it != ArgVector.end()) - ++it; - const char *arr[] = { "-target", GetStableCStr(SavedStrings, Prefix) }; - ArgVector.insert(it, std::begin(arr), std::end(arr)); - } - } +static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver, + SmallVectorImpl<const char *> &Opts) { + llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts); + // The first instance of '#' should be replaced with '=' in each option. + for (const char *Opt : Opts) + if (char *NumberSignPtr = const_cast<char *>(::strchr(Opt, '#'))) + *NumberSignPtr = '='; } static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) { @@ -335,7 +274,7 @@ CreateAndPopulateDiagOpts(ArrayRef<const char *> argv) { } static void SetInstallDir(SmallVectorImpl<const char *> &argv, - Driver &TheDriver) { + Driver &TheDriver, bool CanonicalPrefixes) { // Attempt to find the original path used to invoke the driver, to determine // the installed path. We do this manually, because we want to support that // path being a symlink. @@ -346,7 +285,11 @@ static void SetInstallDir(SmallVectorImpl<const char *> &argv, if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName( llvm::sys::path::filename(InstalledPath.str()))) InstalledPath = *Tmp; - llvm::sys::fs::make_absolute(InstalledPath); + + // FIXME: We don't actually canonicalize this, we just make it absolute. + if (CanonicalPrefixes) + llvm::sys::fs::make_absolute(InstalledPath); + InstalledPath = llvm::sys::path::parent_path(InstalledPath); if (llvm::sys::fs::exists(InstalledPath.c_str())) TheDriver.setInstalledDir(InstalledPath); @@ -380,16 +323,35 @@ int main(int argc_, const char **argv_) { return 1; } + llvm::InitializeAllTargets(); + std::string ProgName = argv[0]; + std::pair<std::string, std::string> TargetAndMode = + ToolChain::getTargetAndModeFromProgramName(ProgName); + llvm::BumpPtrAllocator A; - llvm::BumpPtrStringSaver Saver(A); + llvm::StringSaver Saver(A); + + // Parse response files using the GNU syntax, unless we're in CL mode. There + // are two ways to put clang in CL compatibility mode: argv[0] is either + // clang-cl or cl, or --driver-mode=cl is on the command line. The normal + // command line parsing can't happen until after response file parsing, so we + // have to manually search for a --driver-mode=cl argument the hard way. + // Finally, our -cc1 tools don't care which tokenization mode we use because + // response files written by clang will tokenize the same way in either mode. + llvm::cl::TokenizerCallback Tokenizer = &llvm::cl::TokenizeGNUCommandLine; + if (TargetAndMode.second == "--driver-mode=cl" || + std::find_if(argv.begin(), argv.end(), [](const char *F) { + return F && strcmp(F, "--driver-mode=cl") == 0; + }) != argv.end()) { + Tokenizer = &llvm::cl::TokenizeWindowsCommandLine; + } // Determines whether we want nullptr markers in argv to indicate response // files end-of-lines. We only use this for the /LINK driver argument. bool MarkEOLs = true; if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) MarkEOLs = false; - llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, argv, - MarkEOLs); + llvm::cl::ExpandResponseFiles(Saver, Tokenizer, argv, MarkEOLs); // Handle -cc1 integrated tools, even if -cc1 was expanded from a response // file. @@ -415,6 +377,29 @@ int main(int argc_, const char **argv_) { } } + // Handle CL and _CL_ which permits additional command line options to be + // prepended or appended. + if (Tokenizer == &llvm::cl::TokenizeWindowsCommandLine) { + // Arguments in "CL" are prepended. + llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL"); + if (OptCL.hasValue()) { + SmallVector<const char *, 8> PrependedOpts; + getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts); + + // Insert right after the program name to prepend to the argument list. + argv.insert(argv.begin() + 1, PrependedOpts.begin(), PrependedOpts.end()); + } + // Arguments in "_CL_" are appended. + llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_"); + if (Opt_CL_.hasValue()) { + SmallVector<const char *, 8> AppendedOpts; + getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts); + + // Insert at the end of the argument list to append. + argv.append(AppendedOpts.begin(), AppendedOpts.end()); + } + } + std::set<std::string> SavedStrings; // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the // scenes. @@ -447,10 +432,10 @@ int main(int argc_, const char **argv_) { ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); - SetInstallDir(argv, TheDriver); + SetInstallDir(argv, TheDriver, CanonicalPrefixes); - llvm::InitializeAllTargets(); - ParseProgName(argv, SavedStrings); + insertTargetAndModeArgs(TargetAndMode.first, TargetAndMode.second, argv, + SavedStrings); SetBackdoorDriverOutputsFromEnvVars(TheDriver); diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 8225a6c44293e..dbda13c23532d 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -29,7 +29,6 @@ #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" -#include "clang/CodeGen/ObjectFilePCHContainerOperations.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -148,7 +147,7 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM, SourceLocation EndLoc = R.getEnd(); if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc)) EndLoc = SM.getExpansionRange(EndLoc).second; - if (R.isTokenRange() && !EndLoc.isInvalid()) { + if (R.isTokenRange() && EndLoc.isValid()) { unsigned Length = Lexer::MeasureTokenLength(SM.getSpellingLoc(EndLoc), SM, LangOpts); EndLoc = EndLoc.getLocWithOffset(Length); @@ -665,6 +664,13 @@ bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) { llvm_unreachable("Translation units are visited directly by Visit()"); } +bool CursorVisitor::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + return Visit(MakeCXCursor(D->getTemplatedDecl(), TU, RegionOfInterest)); +} + bool CursorVisitor::VisitTypeAliasDecl(TypeAliasDecl *D) { if (TypeSourceInfo *TSInfo = D->getTypeSourceInfo()) return Visit(TSInfo->getTypeLoc()); @@ -711,11 +717,8 @@ bool CursorVisitor::VisitClassTemplateSpecializationDecl( return true; } } - - if (ShouldVisitBody && VisitCXXRecordDecl(D)) - return true; - - return false; + + return ShouldVisitBody && VisitCXXRecordDecl(D); } bool CursorVisitor::VisitClassTemplatePartialSpecializationDecl( @@ -940,11 +943,8 @@ bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { return true; } - if (ND->isThisDeclarationADefinition() && - Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest))) - return true; - - return false; + return ND->isThisDeclarationADefinition() && + Visit(MakeCXCursor(ND->getBody(), StmtParent, TU, RegionOfInterest)); } template <typename DeclIt> @@ -1461,9 +1461,19 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { case BuiltinType::OCLImage1dBuffer: case BuiltinType::OCLImage2d: case BuiltinType::OCLImage2dArray: + case BuiltinType::OCLImage2dDepth: + case BuiltinType::OCLImage2dArrayDepth: + case BuiltinType::OCLImage2dMSAA: + case BuiltinType::OCLImage2dArrayMSAA: + case BuiltinType::OCLImage2dMSAADepth: + case BuiltinType::OCLImage2dArrayMSAADepth: case BuiltinType::OCLImage3d: case BuiltinType::OCLSampler: case BuiltinType::OCLEvent: + case BuiltinType::OCLClkEvent: + case BuiltinType::OCLQueue: + case BuiltinType::OCLNDRange: + case BuiltinType::OCLReserveID: #define BUILTIN_TYPE(Id, SingletonId) #define SIGNED_TYPE(Id, SingletonId) case BuiltinType::Id: #define UNSIGNED_TYPE(Id, SingletonId) case BuiltinType::Id: @@ -1514,10 +1524,7 @@ bool CursorVisitor::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { } bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { - if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU))) - return true; - - return false; + return Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU)); } bool CursorVisitor::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { @@ -1635,10 +1642,7 @@ bool CursorVisitor::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { } bool CursorVisitor::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { - if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) - return true; - - return false; + return VisitNestedNameSpecifierLoc(TL.getQualifierLoc()); } bool CursorVisitor::VisitDependentTemplateSpecializationTypeLoc( @@ -1745,13 +1749,27 @@ DEF_JOB(StmtVisit, Stmt, StmtVisitKind) DEF_JOB(MemberExprParts, MemberExpr, MemberExprPartsKind) DEF_JOB(DeclRefExprParts, DeclRefExpr, DeclRefExprPartsKind) DEF_JOB(OverloadExprParts, OverloadExpr, OverloadExprPartsKind) -DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo, - ExplicitTemplateArgsVisitKind) DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind) DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind) DEF_JOB(PostChildrenVisit, void, PostChildrenVisitKind) #undef DEF_JOB +class ExplicitTemplateArgsVisit : public VisitorJob { +public: + ExplicitTemplateArgsVisit(const TemplateArgumentLoc *Begin, + const TemplateArgumentLoc *End, CXCursor parent) + : VisitorJob(parent, VisitorJob::ExplicitTemplateArgsVisitKind, Begin, + End) {} + static bool classof(const VisitorJob *VJ) { + return VJ->getKind() == ExplicitTemplateArgsVisitKind; + } + const TemplateArgumentLoc *begin() const { + return static_cast<const TemplateArgumentLoc *>(data[0]); + } + const TemplateArgumentLoc *end() { + return static_cast<const TemplateArgumentLoc *>(data[1]); + } +}; class DeclVisit : public VisitorJob { public: DeclVisit(const Decl *D, CXCursor parent, bool isFirst) : @@ -1930,12 +1948,17 @@ public: void VisitOMPOrderedDirective(const OMPOrderedDirective *D); void VisitOMPAtomicDirective(const OMPAtomicDirective *D); void VisitOMPTargetDirective(const OMPTargetDirective *D); + void VisitOMPTargetDataDirective(const OMPTargetDataDirective *D); void VisitOMPTeamsDirective(const OMPTeamsDirective *D); + void VisitOMPTaskLoopDirective(const OMPTaskLoopDirective *D); + void VisitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective *D); + void VisitOMPDistributeDirective(const OMPDistributeDirective *D); private: void AddDeclarationNameInfo(const Stmt *S); void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier); - void AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A); + void AddExplicitTemplateArgs(const TemplateArgumentLoc *A, + unsigned NumTemplateArgs); void AddMemberRef(const FieldDecl *D, SourceLocation L); void AddStmt(const Stmt *S); void AddDecl(const Decl *D, bool isFirst = true); @@ -1965,10 +1988,9 @@ void EnqueueVisitor::AddDecl(const Decl *D, bool isFirst) { if (D) WL.push_back(DeclVisit(D, Parent, isFirst)); } -void EnqueueVisitor:: - AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A) { - if (A) - WL.push_back(ExplicitTemplateArgsVisit(A, Parent)); +void EnqueueVisitor::AddExplicitTemplateArgs(const TemplateArgumentLoc *A, + unsigned NumTemplateArgs) { + WL.push_back(ExplicitTemplateArgsVisit(A, A + NumTemplateArgs, Parent)); } void EnqueueVisitor::AddMemberRef(const FieldDecl *D, SourceLocation L) { if (D) @@ -2019,6 +2041,10 @@ void OMPClauseEnqueue::VisitOMPSafelenClause(const OMPSafelenClause *C) { Visitor->AddStmt(C->getSafelen()); } +void OMPClauseEnqueue::VisitOMPSimdlenClause(const OMPSimdlenClause *C) { + Visitor->AddStmt(C->getSimdlen()); +} + void OMPClauseEnqueue::VisitOMPCollapseClause(const OMPCollapseClause *C) { Visitor->AddStmt(C->getNumForLoops()); } @@ -2032,7 +2058,9 @@ void OMPClauseEnqueue::VisitOMPScheduleClause(const OMPScheduleClause *C) { Visitor->AddStmt(C->getHelperChunkSize()); } -void OMPClauseEnqueue::VisitOMPOrderedClause(const OMPOrderedClause *) {} +void OMPClauseEnqueue::VisitOMPOrderedClause(const OMPOrderedClause *C) { + Visitor->AddStmt(C->getNumForLoops()); +} void OMPClauseEnqueue::VisitOMPNowaitClause(const OMPNowaitClause *) {} @@ -2050,6 +2078,40 @@ void OMPClauseEnqueue::VisitOMPCaptureClause(const OMPCaptureClause *) {} void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *) {} +void OMPClauseEnqueue::VisitOMPThreadsClause(const OMPThreadsClause *) {} + +void OMPClauseEnqueue::VisitOMPSIMDClause(const OMPSIMDClause *) {} + +void OMPClauseEnqueue::VisitOMPNogroupClause(const OMPNogroupClause *) {} + +void OMPClauseEnqueue::VisitOMPDeviceClause(const OMPDeviceClause *C) { + Visitor->AddStmt(C->getDevice()); +} + +void OMPClauseEnqueue::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) { + Visitor->AddStmt(C->getNumTeams()); +} + +void OMPClauseEnqueue::VisitOMPThreadLimitClause(const OMPThreadLimitClause *C) { + Visitor->AddStmt(C->getThreadLimit()); +} + +void OMPClauseEnqueue::VisitOMPPriorityClause(const OMPPriorityClause *C) { + Visitor->AddStmt(C->getPriority()); +} + +void OMPClauseEnqueue::VisitOMPGrainsizeClause(const OMPGrainsizeClause *C) { + Visitor->AddStmt(C->getGrainsize()); +} + +void OMPClauseEnqueue::VisitOMPNumTasksClause(const OMPNumTasksClause *C) { + Visitor->AddStmt(C->getNumTasks()); +} + +void OMPClauseEnqueue::VisitOMPHintClause(const OMPHintClause *C) { + Visitor->AddStmt(C->getHint()); +} + template<typename T> void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { for (const auto *I : Node->varlists()) { @@ -2088,6 +2150,9 @@ void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) { } void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) { VisitOMPClauseList(C); + for (auto *E : C->privates()) { + Visitor->AddStmt(E); + } for (auto *E : C->lhs_exprs()) { Visitor->AddStmt(E); } @@ -2100,6 +2165,9 @@ void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) { } void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) { VisitOMPClauseList(C); + for (const auto *E : C->privates()) { + Visitor->AddStmt(E); + } for (const auto *E : C->inits()) { Visitor->AddStmt(E); } @@ -2147,6 +2215,9 @@ void OMPClauseEnqueue::VisitOMPFlushClause(const OMPFlushClause *C) { void OMPClauseEnqueue::VisitOMPDependClause(const OMPDependClause *C) { VisitOMPClauseList(C); } +void OMPClauseEnqueue::VisitOMPMapClause(const OMPMapClause *C) { + VisitOMPClauseList(C); +} } void EnqueueVisitor::EnqueueChildren(const OMPClause *S) { @@ -2171,10 +2242,8 @@ void EnqueueVisitor::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { AddTypeLoc(E->getTypeSourceInfo()); } void EnqueueVisitor::VisitCompoundStmt(const CompoundStmt *S) { - for (CompoundStmt::const_reverse_body_iterator I = S->body_rbegin(), - E = S->body_rend(); I != E; ++I) { - AddStmt(*I); - } + for (auto &I : llvm::reverse(S->body())) + AddStmt(I); } void EnqueueVisitor:: VisitMSDependentExistsStmt(const MSDependentExistsStmt *S) { @@ -2186,7 +2255,8 @@ VisitMSDependentExistsStmt(const MSDependentExistsStmt *S) { void EnqueueVisitor:: VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *E) { - AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); + if (E->hasExplicitTemplateArgs()) + AddExplicitTemplateArgs(E->getTemplateArgs(), E->getNumTemplateArgs()); AddDeclarationNameInfo(E); if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc()) AddNestedNameSpecifierLoc(QualifierLoc); @@ -2261,14 +2331,14 @@ void EnqueueVisitor::VisitCXXForRangeStmt(const CXXForRangeStmt *S) { } void EnqueueVisitor::VisitDeclRefExpr(const DeclRefExpr *DR) { - if (DR->hasExplicitTemplateArgs()) { - AddExplicitTemplateArgs(&DR->getExplicitTemplateArgs()); - } + if (DR->hasExplicitTemplateArgs()) + AddExplicitTemplateArgs(DR->getTemplateArgs(), DR->getNumTemplateArgs()); WL.push_back(DeclRefExprParts(DR, Parent)); } void EnqueueVisitor::VisitDependentScopeDeclRefExpr( const DependentScopeDeclRefExpr *E) { - AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); + if (E->hasExplicitTemplateArgs()) + AddExplicitTemplateArgs(E->getTemplateArgs(), E->getNumTemplateArgs()); AddDeclarationNameInfo(E); AddNestedNameSpecifierLoc(E->getQualifierLoc()); } @@ -2364,7 +2434,6 @@ void EnqueueVisitor::VisitObjCMessageExpr(const ObjCMessageExpr *M) { void EnqueueVisitor::VisitOffsetOfExpr(const OffsetOfExpr *E) { // Visit the components of the offsetof expression. for (unsigned N = E->getNumComponents(), I = N; I > 0; --I) { - typedef OffsetOfExpr::OffsetOfNode OffsetOfNode; const OffsetOfNode &Node = E->getComponent(I-1); switch (Node.getKind()) { case OffsetOfNode::Array: @@ -2382,7 +2451,8 @@ void EnqueueVisitor::VisitOffsetOfExpr(const OffsetOfExpr *E) { AddTypeLoc(E->getTypeSourceInfo()); } void EnqueueVisitor::VisitOverloadExpr(const OverloadExpr *E) { - AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); + if (E->hasExplicitTemplateArgs()) + AddExplicitTemplateArgs(E->getTemplateArgs(), E->getNumTemplateArgs()); WL.push_back(OverloadExprParts(E, Parent)); } void EnqueueVisitor::VisitUnaryExprOrTypeTraitExpr( @@ -2549,6 +2619,11 @@ void EnqueueVisitor::VisitOMPTargetDirective(const OMPTargetDirective *D) { VisitOMPExecutableDirective(D); } +void EnqueueVisitor::VisitOMPTargetDataDirective(const + OMPTargetDataDirective *D) { + VisitOMPExecutableDirective(D); +} + void EnqueueVisitor::VisitOMPTeamsDirective(const OMPTeamsDirective *D) { VisitOMPExecutableDirective(D); } @@ -2562,6 +2637,20 @@ void EnqueueVisitor::VisitOMPCancelDirective(const OMPCancelDirective *D) { VisitOMPExecutableDirective(D); } +void EnqueueVisitor::VisitOMPTaskLoopDirective(const OMPTaskLoopDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPTaskLoopSimdDirective( + const OMPTaskLoopSimdDirective *D) { + VisitOMPLoopDirective(D); +} + +void EnqueueVisitor::VisitOMPDistributeDirective( + const OMPDistributeDirective *D) { + VisitOMPLoopDirective(D); +} + void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) { EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S); } @@ -2597,12 +2686,9 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) { continue; } case VisitorJob::ExplicitTemplateArgsVisitKind: { - const ASTTemplateArgumentListInfo *ArgList = - cast<ExplicitTemplateArgsVisit>(&LI)->get(); - for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(), - *ArgEnd = Arg + ArgList->NumTemplateArgs; - Arg != ArgEnd; ++Arg) { - if (VisitTemplateArgumentLoc(*Arg)) + for (const TemplateArgumentLoc &Arg : + *cast<ExplicitTemplateArgsVisit>(&LI)) { + if (VisitTemplateArgumentLoc(Arg)) return true; } continue; @@ -2804,10 +2890,9 @@ bool CursorVisitor::Visit(const Stmt *S) { namespace { typedef SmallVector<SourceRange, 4> RefNamePieces; -RefNamePieces -buildPieces(unsigned NameFlags, bool IsMemberRefExpr, - const DeclarationNameInfo &NI, const SourceRange &QLoc, - const ASTTemplateArgumentListInfo *TemplateArgs = nullptr) { +RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr, + const DeclarationNameInfo &NI, SourceRange QLoc, + const SourceRange *TemplateArgsLoc = nullptr) { const bool WantQualifier = NameFlags & CXNameRange_WantQualifier; const bool WantTemplateArgs = NameFlags & CXNameRange_WantTemplateArgs; const bool WantSinglePiece = NameFlags & CXNameRange_WantSinglePiece; @@ -2821,11 +2906,10 @@ buildPieces(unsigned NameFlags, bool IsMemberRefExpr, if (Kind != DeclarationName::CXXOperatorName || IsMemberRefExpr) Pieces.push_back(NI.getLoc()); - - if (WantTemplateArgs && TemplateArgs) - Pieces.push_back(SourceRange(TemplateArgs->LAngleLoc, - TemplateArgs->RAngleLoc)); - + + if (WantTemplateArgs && TemplateArgsLoc && TemplateArgsLoc->isValid()) + Pieces.push_back(*TemplateArgsLoc); + if (Kind == DeclarationName::CXXOperatorName) { Pieces.push_back(SourceLocation::getFromRawEncoding( NI.getInfo().CXXOperatorName.BeginOpNameLoc)); @@ -2955,7 +3039,8 @@ enum CXErrorCode clang_createTranslationUnit2(CXIndex CIdx, CompilerInstance::createDiagnostics(new DiagnosticOptions()); std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile( ast_filename, CXXIdx->getPCHContainerOperations()->getRawReader(), Diags, - FileSystemOpts, CXXIdx->getOnlyLocalDecls(), None, + FileSystemOpts, /*UseDebugInfo=*/false, + CXXIdx->getOnlyLocalDecls(), None, /*CaptureDiagnostics=*/true, /*AllowPCHWithCompilerErrors=*/true, /*UserFilesAreVolatile=*/true); @@ -2982,35 +3067,19 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, Options); } -struct ParseTranslationUnitInfo { - CXIndex CIdx; - const char *source_filename; - const char *const *command_line_args; - int num_command_line_args; - ArrayRef<CXUnsavedFile> unsaved_files; - unsigned options; - CXTranslationUnit *out_TU; - CXErrorCode &result; -}; -static void clang_parseTranslationUnit_Impl(void *UserData) { - const ParseTranslationUnitInfo *PTUI = - static_cast<ParseTranslationUnitInfo *>(UserData); - CXIndex CIdx = PTUI->CIdx; - const char *source_filename = PTUI->source_filename; - const char * const *command_line_args = PTUI->command_line_args; - int num_command_line_args = PTUI->num_command_line_args; - unsigned options = PTUI->options; - CXTranslationUnit *out_TU = PTUI->out_TU; - +static CXErrorCode +clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, + int num_command_line_args, + ArrayRef<CXUnsavedFile> unsaved_files, + unsigned options, CXTranslationUnit *out_TU) { // Set up the initial return values. if (out_TU) *out_TU = nullptr; // Check arguments. - if (!CIdx || !out_TU) { - PTUI->result = CXError_InvalidArguments; - return; - } + if (!CIdx || !out_TU) + return CXError_InvalidArguments; CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); @@ -3018,6 +3087,8 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { setThreadBackgroundPriority(); bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble; + bool CreatePreambleOnFirstParse = + options & CXTranslationUnit_CreatePreambleOnFirstParse; // FIXME: Add a flag for modules. TranslationUnitKind TUKind = (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete; @@ -3044,7 +3115,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { llvm::CrashRecoveryContextCleanupRegistrar< std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get()); - for (auto &UF : PTUI->unsaved_files) { + for (auto &UF : unsaved_files) { std::unique_ptr<llvm::MemoryBuffer> MB = llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); RemappedFiles->push_back(std::make_pair(UF.Filename, MB.release())); @@ -3070,12 +3141,12 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { break; } } - if (!FoundSpellCheckingArgument) - Args->push_back("-fno-spell-checking"); - Args->insert(Args->end(), command_line_args, command_line_args + num_command_line_args); + if (!FoundSpellCheckingArgument) + Args->insert(Args->begin() + 1, "-fno-spell-checking"); + // The 'source_filename' argument is optional. If the caller does not // specify it then it is assumed that the source file is specified // in the actual argument list. @@ -3092,21 +3163,26 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { unsigned NumErrors = Diags->getClient()->getNumErrors(); std::unique_ptr<ASTUnit> ErrUnit; + // Unless the user specified that they want the preamble on the first parse + // set it up to be created on the first reparse. This makes the first parse + // faster, trading for a slower (first) reparse. + unsigned PrecompilePreambleAfterNParses = + !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse; std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCommandLine( Args->data(), Args->data() + Args->size(), CXXIdx->getPCHContainerOperations(), Diags, CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), /*CaptureDiagnostics=*/true, *RemappedFiles.get(), - /*RemappedFilesKeepOriginalName=*/true, PrecompilePreamble, TUKind, - CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion, + /*RemappedFilesKeepOriginalName=*/true, PrecompilePreambleAfterNParses, + TUKind, CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion, /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies, - /*UserFilesAreVolatile=*/true, ForSerialization, &ErrUnit)); + /*UserFilesAreVolatile=*/true, ForSerialization, + CXXIdx->getPCHContainerOperations()->getRawReader().getFormat(), + &ErrUnit)); // Early failures in LoadFromCommandLine may return with ErrUnit unset. - if (!Unit && !ErrUnit) { - PTUI->result = CXError_ASTReadError; - return; - } + if (!Unit && !ErrUnit) + return CXError_ASTReadError; if (NumErrors != Diags->getClient()->getNumErrors()) { // Make sure to check that 'Unit' is non-NULL. @@ -3114,12 +3190,11 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { printDiagsToStderr(Unit ? Unit.get() : ErrUnit.get()); } - if (isASTReadError(Unit ? Unit.get() : ErrUnit.get())) { - PTUI->result = CXError_ASTReadError; - } else { - *PTUI->out_TU = MakeCXTranslationUnit(CXXIdx, Unit.release()); - PTUI->result = *PTUI->out_TU ? CXError_Success : CXError_Failure; - } + if (isASTReadError(Unit ? Unit.get() : ErrUnit.get())) + return CXError_ASTReadError; + + *out_TU = MakeCXTranslationUnit(CXXIdx, Unit.release()); + return *out_TU ? CXError_Success : CXError_Failure; } CXTranslationUnit @@ -3141,14 +3216,23 @@ clang_parseTranslationUnit(CXIndex CIdx, } enum CXErrorCode clang_parseTranslationUnit2( - CXIndex CIdx, - const char *source_filename, - const char *const *command_line_args, - int num_command_line_args, - struct CXUnsavedFile *unsaved_files, - unsigned num_unsaved_files, - unsigned options, - CXTranslationUnit *out_TU) { + CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + unsigned options, CXTranslationUnit *out_TU) { + SmallVector<const char *, 4> Args; + Args.push_back("clang"); + Args.append(command_line_args, command_line_args + num_command_line_args); + return clang_parseTranslationUnit2FullArgv( + CIdx, source_filename, Args.data(), Args.size(), unsaved_files, + num_unsaved_files, options, out_TU); +} + +enum CXErrorCode clang_parseTranslationUnit2FullArgv( + CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + unsigned options, CXTranslationUnit *out_TU) { LOG_FUNC_SECTION { *Log << source_filename << ": "; for (int i = 0; i != num_command_line_args; ++i) @@ -3159,18 +3243,14 @@ enum CXErrorCode clang_parseTranslationUnit2( return CXError_InvalidArguments; CXErrorCode result = CXError_Failure; - ParseTranslationUnitInfo PTUI = { - CIdx, - source_filename, - command_line_args, - num_command_line_args, - llvm::makeArrayRef(unsaved_files, num_unsaved_files), - options, - out_TU, - result}; + auto ParseTranslationUnitImpl = [=, &result] { + result = clang_parseTranslationUnit_Impl( + CIdx, source_filename, command_line_args, num_command_line_args, + llvm::makeArrayRef(unsaved_files, num_unsaved_files), options, out_TU); + }; llvm::CrashRecoveryContext CRC; - if (!RunSafely(CRC, clang_parseTranslationUnit_Impl, &PTUI)) { + if (!RunSafely(CRC, ParseTranslationUnitImpl)) { fprintf(stderr, "libclang: crash detected during parsing: {\n"); fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); fprintf(stderr, " 'command_line_args' : ["); @@ -3193,7 +3273,7 @@ enum CXErrorCode clang_parseTranslationUnit2( return CXError_Crashed; } else if (getenv("LIBCLANG_RESOURCE_USAGE")) { - if (CXTranslationUnit *TU = PTUI.out_TU) + if (CXTranslationUnit *TU = out_TU) PrintLibclangResourceUsage(*TU); } @@ -3204,27 +3284,15 @@ unsigned clang_defaultSaveOptions(CXTranslationUnit TU) { return CXSaveTranslationUnit_None; } -namespace { - -struct SaveTranslationUnitInfo { - CXTranslationUnit TU; - const char *FileName; - unsigned options; - CXSaveError result; -}; - -} - -static void clang_saveTranslationUnit_Impl(void *UserData) { - SaveTranslationUnitInfo *STUI = - static_cast<SaveTranslationUnitInfo*>(UserData); - - CIndexer *CXXIdx = STUI->TU->CIdx; +static CXSaveError clang_saveTranslationUnit_Impl(CXTranslationUnit TU, + const char *FileName, + unsigned options) { + CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) setThreadBackgroundPriority(); - bool hadError = cxtu::getASTUnit(STUI->TU)->Save(STUI->FileName); - STUI->result = hadError ? CXSaveError_Unknown : CXSaveError_None; + bool hadError = cxtu::getASTUnit(TU)->Save(FileName); + return hadError ? CXSaveError_Unknown : CXSaveError_None; } int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName, @@ -3243,16 +3311,19 @@ int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName, if (!CXXUnit->hasSema()) return CXSaveError_InvalidTU; - SaveTranslationUnitInfo STUI = { TU, FileName, options, CXSaveError_None }; + CXSaveError result; + auto SaveTranslationUnitImpl = [=, &result]() { + result = clang_saveTranslationUnit_Impl(TU, FileName, options); + }; if (!CXXUnit->getDiagnostics().hasUnrecoverableErrorOccurred() || getenv("LIBCLANG_NOTHREADS")) { - clang_saveTranslationUnit_Impl(&STUI); + SaveTranslationUnitImpl(); if (getenv("LIBCLANG_RESOURCE_USAGE")) PrintLibclangResourceUsage(TU); - return STUI.result; + return result; } // We have an AST that has invalid nodes due to compiler errors. @@ -3260,7 +3331,7 @@ int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName, llvm::CrashRecoveryContext CRC; - if (!RunSafely(CRC, clang_saveTranslationUnit_Impl, &STUI)) { + if (!RunSafely(CRC, SaveTranslationUnitImpl)) { fprintf(stderr, "libclang: crash detected during AST saving: {\n"); fprintf(stderr, " 'filename' : '%s'\n", FileName); fprintf(stderr, " 'options' : %d,\n", options); @@ -3272,7 +3343,7 @@ int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName, PrintLibclangResourceUsage(TU); } - return STUI.result; + return result; } void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) { @@ -3296,25 +3367,14 @@ unsigned clang_defaultReparseOptions(CXTranslationUnit TU) { return CXReparse_None; } -struct ReparseTranslationUnitInfo { - CXTranslationUnit TU; - ArrayRef<CXUnsavedFile> unsaved_files; - unsigned options; - CXErrorCode &result; -}; - -static void clang_reparseTranslationUnit_Impl(void *UserData) { - const ReparseTranslationUnitInfo *RTUI = - static_cast<ReparseTranslationUnitInfo *>(UserData); - CXTranslationUnit TU = RTUI->TU; - unsigned options = RTUI->options; - (void) options; - +static CXErrorCode +clang_reparseTranslationUnit_Impl(CXTranslationUnit TU, + ArrayRef<CXUnsavedFile> unsaved_files, + unsigned options) { // Check arguments. if (isNotUsableTU(TU)) { LOG_BAD_TU(TU); - RTUI->result = CXError_InvalidArguments; - return; + return CXError_InvalidArguments; } // Reset the associated diagnostics. @@ -3335,7 +3395,7 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) { llvm::CrashRecoveryContextCleanupRegistrar< std::vector<ASTUnit::RemappedFile> > RemappedCleanup(RemappedFiles.get()); - for (auto &UF : RTUI->unsaved_files) { + for (auto &UF : unsaved_files) { std::unique_ptr<llvm::MemoryBuffer> MB = llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); RemappedFiles->push_back(std::make_pair(UF.Filename, MB.release())); @@ -3343,9 +3403,10 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) { if (!CXXUnit->Reparse(CXXIdx->getPCHContainerOperations(), *RemappedFiles.get())) - RTUI->result = CXError_Success; - else if (isASTReadError(CXXUnit)) - RTUI->result = CXError_ASTReadError; + return CXError_Success; + if (isASTReadError(CXXUnit)) + return CXError_ASTReadError; + return CXError_Failure; } int clang_reparseTranslationUnit(CXTranslationUnit TU, @@ -3359,19 +3420,20 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU, if (num_unsaved_files && !unsaved_files) return CXError_InvalidArguments; - CXErrorCode result = CXError_Failure; - ReparseTranslationUnitInfo RTUI = { - TU, llvm::makeArrayRef(unsaved_files, num_unsaved_files), options, - result}; + CXErrorCode result; + auto ReparseTranslationUnitImpl = [=, &result]() { + result = clang_reparseTranslationUnit_Impl( + TU, llvm::makeArrayRef(unsaved_files, num_unsaved_files), options); + }; if (getenv("LIBCLANG_NOTHREADS")) { - clang_reparseTranslationUnit_Impl(&RTUI); + ReparseTranslationUnitImpl(); return result; } llvm::CrashRecoveryContext CRC; - if (!RunSafely(CRC, clang_reparseTranslationUnit_Impl, &RTUI)) { + if (!RunSafely(CRC, ReparseTranslationUnitImpl)) { fprintf(stderr, "libclang: crash detected during reparsing\n"); cxtu::getASTUnit(TU)->setUnsafeToFree(true); return CXError_Crashed; @@ -3551,6 +3613,26 @@ static SourceLocation getLocationFromExpr(const Expr *E) { return E->getLocStart(); } +static std::string getMangledStructor(std::unique_ptr<MangleContext> &M, + std::unique_ptr<llvm::DataLayout> &DL, + const NamedDecl *ND, + unsigned StructorType) { + std::string FrontendBuf; + llvm::raw_string_ostream FOS(FrontendBuf); + + if (const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(ND)) + M->mangleCXXCtor(CD, static_cast<CXXCtorType>(StructorType), FOS); + else if (const auto *DD = dyn_cast_or_null<CXXDestructorDecl>(ND)) + M->mangleCXXDtor(DD, static_cast<CXXDtorType>(StructorType), FOS); + + std::string BackendBuf; + llvm::raw_string_ostream BOS(BackendBuf); + + llvm::Mangler::getNameWithPrefix(BOS, llvm::Twine(FOS.str()), *DL); + + return BOS.str(); +} + extern "C" { unsigned clang_visitChildren(CXCursor parent, @@ -3780,6 +3862,19 @@ CXString clang_getCursorSpelling(CXCursor C) { return cxstring::createRef("packed"); } + if (C.kind == CXCursor_VisibilityAttr) { + const VisibilityAttr *AA = cast<VisibilityAttr>(cxcursor::getCursorAttr(C)); + switch (AA->getVisibility()) { + case VisibilityAttr::VisibilityType::Default: + return cxstring::createRef("default"); + case VisibilityAttr::VisibilityType::Hidden: + return cxstring::createRef("hidden"); + case VisibilityAttr::VisibilityType::Protected: + return cxstring::createRef("protected"); + } + llvm_unreachable("unknown visibility type"); + } + return cxstring::createEmpty(); } @@ -3893,11 +3988,15 @@ CXString clang_Cursor_getMangling(CXCursor C) { std::string FrontendBuf; llvm::raw_string_ostream FrontendBufOS(FrontendBuf); - MC->mangleName(ND, FrontendBufOS); + if (MC->shouldMangleDeclName(ND)) { + MC->mangleName(ND, FrontendBufOS); + } else { + ND->printName(FrontendBufOS); + } // Now apply backend mangling. std::unique_ptr<llvm::DataLayout> DL( - new llvm::DataLayout(Ctx.getTargetInfo().getTargetDescription())); + new llvm::DataLayout(Ctx.getTargetInfo().getDataLayoutString())); std::string FinalBuf; llvm::raw_string_ostream FinalBufOS(FinalBuf); @@ -3907,6 +4006,54 @@ CXString clang_Cursor_getMangling(CXCursor C) { return cxstring::createDup(FinalBufOS.str()); } +CXStringSet *clang_Cursor_getCXXManglings(CXCursor C) { + if (clang_isInvalid(C.kind) || !clang_isDeclaration(C.kind)) + return nullptr; + + const Decl *D = getCursorDecl(C); + if (!(isa<CXXRecordDecl>(D) || isa<CXXMethodDecl>(D))) + return nullptr; + + const NamedDecl *ND = cast<NamedDecl>(D); + + ASTContext &Ctx = ND->getASTContext(); + std::unique_ptr<MangleContext> M(Ctx.createMangleContext()); + std::unique_ptr<llvm::DataLayout> DL( + new llvm::DataLayout(Ctx.getTargetInfo().getDataLayoutString())); + + std::vector<std::string> Manglings; + + auto hasDefaultCXXMethodCC = [](ASTContext &C, const CXXMethodDecl *MD) { + auto DefaultCC = C.getDefaultCallingConvention(/*IsVariadic=*/false, + /*IsCSSMethod=*/true); + auto CC = MD->getType()->getAs<FunctionProtoType>()->getCallConv(); + return CC == DefaultCC; + }; + + if (const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(ND)) { + Manglings.emplace_back(getMangledStructor(M, DL, CD, Ctor_Base)); + + if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily()) + if (!CD->getParent()->isAbstract()) + Manglings.emplace_back(getMangledStructor(M, DL, CD, Ctor_Complete)); + + if (Ctx.getTargetInfo().getCXXABI().isMicrosoft()) + if (CD->hasAttr<DLLExportAttr>() && CD->isDefaultConstructor()) + if (!(hasDefaultCXXMethodCC(Ctx, CD) && CD->getNumParams() == 0)) + Manglings.emplace_back(getMangledStructor(M, DL, CD, + Ctor_DefaultClosure)); + } else if (const auto *DD = dyn_cast_or_null<CXXDestructorDecl>(ND)) { + Manglings.emplace_back(getMangledStructor(M, DL, DD, Dtor_Base)); + if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily()) { + Manglings.emplace_back(getMangledStructor(M, DL, DD, Dtor_Complete)); + if (DD->isVirtual()) + Manglings.emplace_back(getMangledStructor(M, DL, DD, Dtor_Deleting)); + } + } + + return cxstring::createSet(Manglings); +} + CXString clang_getCursorDisplayName(CXCursor C) { if (!clang_isDeclaration(C.kind)) return clang_getCursorSpelling(C); @@ -4071,6 +4218,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return cxstring::createRef("UnaryOperator"); case CXCursor_ArraySubscriptExpr: return cxstring::createRef("ArraySubscriptExpr"); + case CXCursor_OMPArraySectionExpr: + return cxstring::createRef("OMPArraySectionExpr"); case CXCursor_BinaryOperator: return cxstring::createRef("BinaryOperator"); case CXCursor_CompoundAssignOperator: @@ -4259,6 +4408,12 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return cxstring::createRef("attribute(host)"); case CXCursor_CUDASharedAttr: return cxstring::createRef("attribute(shared)"); + case CXCursor_VisibilityAttr: + return cxstring::createRef("attribute(visibility)"); + case CXCursor_DLLExport: + return cxstring::createRef("attribute(dllexport)"); + case CXCursor_DLLImport: + return cxstring::createRef("attribute(dllimport)"); case CXCursor_PreprocessingDirective: return cxstring::createRef("preprocessing directive"); case CXCursor_MacroDefinition: @@ -4349,14 +4504,24 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return cxstring::createRef("OMPAtomicDirective"); case CXCursor_OMPTargetDirective: return cxstring::createRef("OMPTargetDirective"); + case CXCursor_OMPTargetDataDirective: + return cxstring::createRef("OMPTargetDataDirective"); case CXCursor_OMPTeamsDirective: return cxstring::createRef("OMPTeamsDirective"); case CXCursor_OMPCancellationPointDirective: return cxstring::createRef("OMPCancellationPointDirective"); case CXCursor_OMPCancelDirective: return cxstring::createRef("OMPCancelDirective"); + case CXCursor_OMPTaskLoopDirective: + return cxstring::createRef("OMPTaskLoopDirective"); + case CXCursor_OMPTaskLoopSimdDirective: + return cxstring::createRef("OMPTaskLoopSimdDirective"); + case CXCursor_OMPDistributeDirective: + return cxstring::createRef("OMPDistributeDirective"); case CXCursor_OverloadCandidate: return cxstring::createRef("OverloadCandidate"); + case CXCursor_TypeAliasTemplateDecl: + return cxstring::createRef("TypeAliasTemplateDecl"); } llvm_unreachable("Unhandled CXCursorKind"); @@ -5100,6 +5265,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::Import: case Decl::OMPThreadPrivate: case Decl::ObjCTypeParam: + case Decl::BuiltinTemplate: return C; // Declaration kinds that don't make any sense here, but are @@ -5362,10 +5528,12 @@ CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, unsigned NameFlags, break; case CXCursor_DeclRefExpr: - if (const DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C))) - Pieces = buildPieces(NameFlags, false, E->getNameInfo(), - E->getQualifierLoc().getSourceRange(), - E->getOptionalExplicitTemplateArgs()); + if (const DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C))) { + SourceRange TemplateArgLoc(E->getLAngleLoc(), E->getRAngleLoc()); + Pieces = + buildPieces(NameFlags, false, E->getNameInfo(), + E->getQualifierLoc().getSourceRange(), &TemplateArgLoc); + } break; case CXCursor_CallExpr: @@ -6055,16 +6223,6 @@ MarkMacroArgTokensVisitorDelegate(CXCursor cursor, CXCursor parent, parent); } -namespace { - struct clang_annotateTokens_Data { - CXTranslationUnit TU; - ASTUnit *CXXUnit; - CXToken *Tokens; - unsigned NumTokens; - CXCursor *Cursors; - }; -} - /// \brief Used by \c annotatePreprocessorTokens. /// \returns true if lexing was finished, false otherwise. static bool lexNext(Lexer &Lex, Token &Tok, @@ -6074,10 +6232,7 @@ static bool lexNext(Lexer &Lex, Token &Tok, ++NextIdx; Lex.LexFromRawLexer(Tok); - if (Tok.is(tok::eof)) - return true; - - return false; + return Tok.is(tok::eof); } static void annotatePreprocessorTokens(CXTranslationUnit TU, @@ -6184,13 +6339,9 @@ static void annotatePreprocessorTokens(CXTranslationUnit TU, } // This gets run a separate thread to avoid stack blowout. -static void clang_annotateTokensImpl(void *UserData) { - CXTranslationUnit TU = ((clang_annotateTokens_Data*)UserData)->TU; - ASTUnit *CXXUnit = ((clang_annotateTokens_Data*)UserData)->CXXUnit; - CXToken *Tokens = ((clang_annotateTokens_Data*)UserData)->Tokens; - const unsigned NumTokens = ((clang_annotateTokens_Data*)UserData)->NumTokens; - CXCursor *Cursors = ((clang_annotateTokens_Data*)UserData)->Cursors; - +static void clang_annotateTokensImpl(CXTranslationUnit TU, ASTUnit *CXXUnit, + CXToken *Tokens, unsigned NumTokens, + CXCursor *Cursors) { CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) setThreadBackgroundPriority(); @@ -6326,11 +6477,12 @@ void clang_annotateTokens(CXTranslationUnit TU, return; ASTUnit::ConcurrencyCheck Check(*CXXUnit); - - clang_annotateTokens_Data data = { TU, CXXUnit, Tokens, NumTokens, Cursors }; + + auto AnnotateTokensImpl = [=]() { + clang_annotateTokensImpl(TU, CXXUnit, Tokens, NumTokens, Cursors); + }; llvm::CrashRecoveryContext CRC; - if (!RunSafely(CRC, clang_annotateTokensImpl, &data, - GetSafetyThreadStackSize() * 2)) { + if (!RunSafely(CRC, AnnotateTokensImpl, GetSafetyThreadStackSize() * 2)) { fprintf(stderr, "libclang: crash detected while annotating tokens\n"); } } @@ -6361,6 +6513,27 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) { } // end: extern "C" //===----------------------------------------------------------------------===// +// Operations for querying visibility of a cursor. +//===----------------------------------------------------------------------===// + +extern "C" { +CXVisibilityKind clang_getCursorVisibility(CXCursor cursor) { + if (!clang_isDeclaration(cursor.kind)) + return CXVisibility_Invalid; + + const Decl *D = cxcursor::getCursorDecl(cursor); + if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D)) + switch (ND->getVisibility()) { + case HiddenVisibility: return CXVisibility_Hidden; + case ProtectedVisibility: return CXVisibility_Protected; + case DefaultVisibility: return CXVisibility_Default; + }; + + return CXVisibility_Invalid; +} +} // end: extern "C" + +//===----------------------------------------------------------------------===// // Operations for querying language of a cursor. //===----------------------------------------------------------------------===// @@ -6418,7 +6591,7 @@ extern "C" { static CXAvailabilityKind getCursorAvailabilityForDecl(const Decl *D) { if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted()) - return CXAvailability_Available; + return CXAvailability_NotAvailable; switch (D->getAvailability()) { case AR_Available: @@ -6612,8 +6785,6 @@ enum CX_StorageClass clang_Cursor_getStorageClass(CXCursor C) { return CX_SC_Static; case SC_PrivateExtern: return CX_SC_PrivateExtern; - case SC_OpenCLWorkGroupLocal: - return CX_SC_OpenCLWorkGroupLocal; case SC_Auto: return CX_SC_Auto; case SC_Register: @@ -6893,6 +7064,16 @@ CXFile clang_Module_getTopLevelHeader(CXTranslationUnit TU, //===----------------------------------------------------------------------===// extern "C" { +unsigned clang_CXXField_isMutable(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + if (const auto D = cxcursor::getCursorDecl(C)) + if (const auto FD = dyn_cast_or_null<FieldDecl>(D)) + return FD->isMutable() ? 1 : 0; + return 0; +} + unsigned clang_CXXMethod_isPureVirtual(CXCursor C) { if (!clang_isDeclaration(C.kind)) return 0; @@ -7179,14 +7360,13 @@ static unsigned SafetyStackThreadSize = 8 << 20; namespace clang { -bool RunSafely(llvm::CrashRecoveryContext &CRC, - void (*Fn)(void*), void *UserData, +bool RunSafely(llvm::CrashRecoveryContext &CRC, llvm::function_ref<void()> Fn, unsigned Size) { if (!Size) Size = GetSafetyThreadStackSize(); if (Size) - return CRC.RunSafelyOnThread(Fn, UserData, Size); - return CRC.RunSafely(Fn, UserData); + return CRC.RunSafelyOnThread(Fn, Size); + return CRC.RunSafely(Fn); } unsigned GetSafetyThreadStackSize() { @@ -7408,8 +7588,6 @@ Logger &cxindex::Logger::operator<<(const llvm::format_object_base &Fmt) { static llvm::ManagedStatic<llvm::sys::Mutex> LoggingMutex; cxindex::Logger::~Logger() { - LogOS.flush(); - llvm::sys::ScopedLock L(*LoggingMutex); static llvm::TimeRecord sBeginTR = llvm::TimeRecord::getCurrentTime(); diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index 9609a693abdf9..344ed27021a16 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -646,25 +646,12 @@ namespace { }; } -extern "C" { -struct CodeCompleteAtInfo { - CXTranslationUnit TU; - const char *complete_filename; - unsigned complete_line; - unsigned complete_column; - ArrayRef<CXUnsavedFile> unsaved_files; - unsigned options; - CXCodeCompleteResults *result; -}; -static void clang_codeCompleteAt_Impl(void *UserData) { - CodeCompleteAtInfo *CCAI = static_cast<CodeCompleteAtInfo*>(UserData); - CXTranslationUnit TU = CCAI->TU; - const char *complete_filename = CCAI->complete_filename; - unsigned complete_line = CCAI->complete_line; - unsigned complete_column = CCAI->complete_column; - unsigned options = CCAI->options; +static CXCodeCompleteResults * +clang_codeCompleteAt_Impl(CXTranslationUnit TU, const char *complete_filename, + unsigned complete_line, unsigned complete_column, + ArrayRef<CXUnsavedFile> unsaved_files, + unsigned options) { bool IncludeBriefComments = options & CXCodeComplete_IncludeBriefComments; - CCAI->result = nullptr; #ifdef UDP_CODE_COMPLETION_LOGGER #ifdef UDP_CODE_COMPLETION_LOGGER_PORT @@ -676,12 +663,12 @@ static void clang_codeCompleteAt_Impl(void *UserData) { if (cxtu::isNotUsableTU(TU)) { LOG_BAD_TU(TU); - return; + return nullptr; } ASTUnit *AST = cxtu::getASTUnit(TU); if (!AST) - return; + return nullptr; CIndexer *CXXIdx = TU->CIdx; if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing)) @@ -692,7 +679,7 @@ static void clang_codeCompleteAt_Impl(void *UserData) { // Perform the remapping of source files. SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; - for (auto &UF : CCAI->unsaved_files) { + for (auto &UF : unsaved_files) { std::unique_ptr<llvm::MemoryBuffer> MB = llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); RemappedFiles.push_back(std::make_pair(UF.Filename, MB.release())); @@ -804,8 +791,10 @@ static void clang_codeCompleteAt_Impl(void *UserData) { } #endif #endif - CCAI->result = Results; + return Results; } + +extern "C" { CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU, const char *complete_filename, unsigned complete_line, @@ -821,25 +810,28 @@ CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU, if (num_unsaved_files && !unsaved_files) return nullptr; - CodeCompleteAtInfo CCAI = {TU, complete_filename, complete_line, - complete_column, llvm::makeArrayRef(unsaved_files, num_unsaved_files), - options, nullptr}; + CXCodeCompleteResults *result; + auto CodeCompleteAtImpl = [=, &result]() { + result = clang_codeCompleteAt_Impl( + TU, complete_filename, complete_line, complete_column, + llvm::makeArrayRef(unsaved_files, num_unsaved_files), options); + }; if (getenv("LIBCLANG_NOTHREADS")) { - clang_codeCompleteAt_Impl(&CCAI); - return CCAI.result; + CodeCompleteAtImpl(); + return result; } llvm::CrashRecoveryContext CRC; - if (!RunSafely(CRC, clang_codeCompleteAt_Impl, &CCAI)) { + if (!RunSafely(CRC, CodeCompleteAtImpl)) { fprintf(stderr, "libclang: crash detected in code completion\n"); cxtu::getASTUnit(TU)->setUnsafeToFree(true); return nullptr; } else if (getenv("LIBCLANG_RESOURCE_USAGE")) PrintLibclangResourceUsage(TU); - return CCAI.result; + return result; } unsigned clang_defaultCodeCompleteOptions(void) { diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h index bf55301d618e6..94c27a05600fd 100644 --- a/tools/libclang/CIndexer.h +++ b/tools/libclang/CIndexer.h @@ -85,8 +85,8 @@ public: /// threads when possible. /// /// \return False if a crash was detected. - bool RunSafely(llvm::CrashRecoveryContext &CRC, - void (*Fn)(void*), void *UserData, unsigned Size = 0); + bool RunSafely(llvm::CrashRecoveryContext &CRC, llvm::function_ref<void()> Fn, + unsigned Size = 0); /// \brief Set the thread priority to background. /// FIXME: Move to llvm/Support. diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index 06db70e61ad5d..5267c02db5f4c 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -102,21 +102,16 @@ if(ENABLE_SHARED) PROPERTIES VERSION ${LIBCLANG_LIBRARY_VERSION} DEFINE_SYMBOL _CINDEX_LIB_) + elseif(APPLE) + set(LIBCLANG_LINK_FLAGS " -Wl,-compatibility_version -Wl,1") + set(LIBCLANG_LINK_FLAGS "${LIBCLANG_LINK_FLAGS} -Wl,-current_version -Wl,${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}") + + set_property(TARGET libclang APPEND_STRING PROPERTY + LINK_FLAGS ${LIBCLANG_LINK_FLAGS}) else() set_target_properties(libclang PROPERTIES VERSION ${LIBCLANG_LIBRARY_VERSION} DEFINE_SYMBOL _CINDEX_LIB_) endif() - - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(LIBCLANG_LINK_FLAGS " -Wl,-compatibility_version -Wl,1") - if (DEFINED ${LLVM_SUBMIT_VERSION}) - set(LIBCLANG_LINK_FLAGS - "${LIBCLANG_LINK_FLAGS} -Wl,-current_version -Wl,${LLVM_SUBMIT_VERSION}.${LLVM_SUBMIT_SUBVERSION}") - endif() - - set_property(TARGET libclang APPEND_STRING PROPERTY - LINK_FLAGS ${LIBCLANG_LINK_FLAGS}) - endif() endif() diff --git a/tools/libclang/CXCompilationDatabase.cpp b/tools/libclang/CXCompilationDatabase.cpp index 1e4a2cd44aabb..82498bf54c749 100644 --- a/tools/libclang/CXCompilationDatabase.cpp +++ b/tools/libclang/CXCompilationDatabase.cpp @@ -111,6 +111,16 @@ clang_CompileCommand_getDirectory(CXCompileCommand CCmd) return cxstring::createRef(cmd->Directory.c_str()); } +CXString +clang_CompileCommand_getFilename(CXCompileCommand CCmd) +{ + if (!CCmd) + return cxstring::createNull(); + + CompileCommand *cmd = static_cast<CompileCommand *>(CCmd); + return cxstring::createRef(cmd->Filename.c_str()); +} + unsigned clang_CompileCommand_getNumArgs(CXCompileCommand CCmd) { diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 099edcf14fed3..c766d2d69fa95 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -58,6 +58,9 @@ static CXCursorKind GetCursorKind(const Attr *A) { case attr::CUDAGlobal: return CXCursor_CUDAGlobalAttr; case attr::CUDAHost: return CXCursor_CUDAHostAttr; case attr::CUDAShared: return CXCursor_CUDASharedAttr; + case attr::Visibility: return CXCursor_VisibilityAttr; + case attr::DLLExport: return CXCursor_DLLExport; + case attr::DLLImport: return CXCursor_DLLImport; } return CXCursor_UnexposedAttr; @@ -226,6 +229,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::AtomicExprClass: case Stmt::BinaryConditionalOperatorClass: case Stmt::TypeTraitExprClass: + case Stmt::CoroutineBodyStmtClass: + case Stmt::CoawaitExprClass: + case Stmt::CoreturnStmtClass: + case Stmt::CoyieldExprClass: case Stmt::CXXBindTemporaryExprClass: case Stmt::CXXDefaultArgExprClass: case Stmt::CXXDefaultInitExprClass: @@ -324,10 +331,15 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, K = CXCursor_UnaryExpr; break; + case Stmt::MSPropertySubscriptExprClass: case Stmt::ArraySubscriptExprClass: K = CXCursor_ArraySubscriptExpr; break; + case Stmt::OMPArraySectionExprClass: + K = CXCursor_OMPArraySectionExpr; + break; + case Stmt::BinaryOperatorClass: K = CXCursor_BinaryOperator; break; @@ -585,6 +597,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::OMPTargetDirectiveClass: K = CXCursor_OMPTargetDirective; break; + case Stmt::OMPTargetDataDirectiveClass: + K = CXCursor_OMPTargetDataDirective; + break; case Stmt::OMPTeamsDirectiveClass: K = CXCursor_OMPTeamsDirective; break; @@ -594,6 +609,15 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::OMPCancelDirectiveClass: K = CXCursor_OMPCancelDirective; break; + case Stmt::OMPTaskLoopDirectiveClass: + K = CXCursor_OMPTaskLoopDirective; + break; + case Stmt::OMPTaskLoopSimdDirectiveClass: + K = CXCursor_OMPTaskLoopSimdDirective; + break; + case Stmt::OMPDistributeDirectiveClass: + K = CXCursor_OMPDistributeDirective; + break; } CXCursor C = { K, 0, { Parent, S, TU } }; diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp index 754ad55a66040..2c10d34844b75 100644 --- a/tools/libclang/CXLoadedDiagnostic.cpp +++ b/tools/libclang/CXLoadedDiagnostic.cpp @@ -25,6 +25,7 @@ #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" + using namespace clang; //===----------------------------------------------------------------------===// @@ -56,7 +57,7 @@ public: return mem; } }; -} +} // end anonymous namespace //===----------------------------------------------------------------------===// // Cleanup. @@ -246,7 +247,7 @@ public: CXDiagnosticSet load(const char *file); }; -} +} // end anonymous namespace CXDiagnosticSet DiagLoader::load(const char *file) { TopDiags = llvm::make_unique<CXLoadedDiagnosticSetImpl>(); @@ -264,7 +265,7 @@ CXDiagnosticSet DiagLoader::load(const char *file) { reportInvalidFile(EC.message()); break; } - return 0; + return nullptr; } return (CXDiagnosticSet)TopDiags.release(); diff --git a/tools/libclang/CXString.cpp b/tools/libclang/CXString.cpp index dec8ebcd98e14..1ccbed3b5c243 100644 --- a/tools/libclang/CXString.cpp +++ b/tools/libclang/CXString.cpp @@ -112,6 +112,15 @@ CXString createCXString(CXStringBuf *buf) { return Str; } +CXStringSet *createSet(const std::vector<std::string> &Strings) { + CXStringSet *Set = new CXStringSet; + Set->Count = Strings.size(); + Set->Strings = new CXString[Set->Count]; + for (unsigned SI = 0, SE = Set->Count; SI < SE; ++SI) + Set->Strings[SI] = createDup(Strings[SI]); + return Set; +} + //===----------------------------------------------------------------------===// // String pools. @@ -175,5 +184,13 @@ void clang_disposeString(CXString string) { break; } } + +void clang_disposeStringSet(CXStringSet *set) { + for (unsigned SI = 0, SE = set->Count; SI < SE; ++SI) + clang_disposeString(set->Strings[SI]); + delete[] set->Strings; + delete set; +} + } // end: extern "C" diff --git a/tools/libclang/CXString.h b/tools/libclang/CXString.h index 72ac0cf46914a..6473eb2d7103d 100644 --- a/tools/libclang/CXString.h +++ b/tools/libclang/CXString.h @@ -68,6 +68,8 @@ CXString createRef(std::string String) = delete; /// \brief 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. class CXStringPool { public: diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp index 1318e86b55539..72c12cd16b978 100644 --- a/tools/libclang/CXType.cpp +++ b/tools/libclang/CXType.cpp @@ -90,6 +90,7 @@ static CXTypeKind GetTypeKind(QualType T) { TKCASE(DependentSizedArray); TKCASE(Vector); TKCASE(MemberPointer); + TKCASE(Auto); default: return CXType_Unexposed; } @@ -101,6 +102,11 @@ CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) { CXTypeKind TK = CXType_Invalid; if (TU && !T.isNull()) { + // Handle attributed types as the original type + if (auto *ATT = T->getAs<AttributedType>()) { + return MakeCXType(ATT->getModifiedType(), TU); + } + ASTContext &Ctx = cxtu::getASTUnit(TU)->getASTContext(); if (Ctx.getLangOpts().ObjC1) { QualType UnqualT = T.getUnqualifiedType(); @@ -139,7 +145,7 @@ extern "C" { CXType clang_getCursorType(CXCursor C) { using namespace cxcursor; - + CXTranslationUnit TU = cxcursor::getCursorTU(C); if (!TU) return MakeCXType(QualType(), TU); @@ -159,23 +165,17 @@ CXType clang_getCursorType(CXCursor C) { return MakeCXType(Context.getTypeDeclType(TD), TU); if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) return MakeCXType(Context.getObjCInterfaceType(ID), TU); - if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { - if (TypeSourceInfo *TSInfo = DD->getTypeSourceInfo()) - return MakeCXType(TSInfo->getType(), TU); - return MakeCXType(DD->getType(), TU); - } + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) + return MakeCXType(DD->getType(), TU); if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) return MakeCXType(VD->getType(), TU); if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) return MakeCXType(PD->getType(), TU); - if (const FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D)) { - if (TypeSourceInfo *TSInfo = FTD->getTemplatedDecl()->getTypeSourceInfo()) - return MakeCXType(TSInfo->getType(), TU); + if (const FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D)) return MakeCXType(FTD->getTemplatedDecl()->getType(), TU); - } return MakeCXType(QualType(), TU); } - + if (clang_isReference(C.kind)) { switch (C.kind) { case CXCursor_ObjCSuperClassRef: { @@ -183,18 +183,18 @@ CXType clang_getCursorType(CXCursor C) { = Context.getObjCInterfaceType(getCursorObjCSuperClassRef(C).first); return MakeCXType(T, TU); } - + case CXCursor_ObjCClassRef: { QualType T = Context.getObjCInterfaceType(getCursorObjCClassRef(C).first); return MakeCXType(T, TU); } - + case CXCursor_TypeRef: { QualType T = Context.getTypeDeclType(getCursorTypeRef(C).first); return MakeCXType(T, TU); } - + case CXCursor_CXXBaseSpecifier: return cxtype::MakeCXType(getCursorCXXBaseSpecifier(C)->getType(), TU); @@ -211,7 +211,7 @@ CXType clang_getCursorType(CXCursor C) { default: break; } - + return MakeCXType(QualType(), TU); } @@ -349,10 +349,10 @@ unsigned clang_isRestrictQualifiedType(CXType CT) { CXType clang_getPointeeType(CXType CT) { QualType T = GetQualType(CT); const Type *TP = T.getTypePtrOrNull(); - + if (!TP) return MakeCXType(QualType(), GetTU(CT)); - + switch (TP->getTypeClass()) { case Type::Pointer: T = cast<PointerType>(TP)->getPointeeType(); @@ -411,7 +411,7 @@ try_again: D = cast<TemplateSpecializationType>(TP)->getTemplateName() .getAsTemplateDecl(); break; - + case Type::InjectedClassName: D = cast<InjectedClassNameType>(TP)->getDecl(); break; @@ -421,7 +421,7 @@ try_again: case Type::Elaborated: TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull(); goto try_again; - + default: break; } @@ -484,6 +484,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) { TKIND(DependentSizedArray); TKIND(Vector); TKIND(MemberPointer); + TKIND(Auto); } #undef TKIND return cxstring::createRef(s); diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h index 91f63b40f6a59..3e5b0c9120c54 100644 --- a/tools/libclang/CursorVisitor.h +++ b/tools/libclang/CursorVisitor.h @@ -195,6 +195,7 @@ public: bool VisitChildren(CXCursor Parent); // Declaration visitors + bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); bool VisitTypeAliasDecl(TypeAliasDecl *D); bool VisitAttributes(Decl *D); bool VisitBlockDecl(BlockDecl *B); diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp index 5539971f04a78..64df4b85beac7 100644 --- a/tools/libclang/IndexBody.cpp +++ b/tools/libclang/IndexBody.cpp @@ -8,19 +8,19 @@ //===----------------------------------------------------------------------===// #include "IndexingContext.h" -#include "clang/AST/DataRecursiveASTVisitor.h" +#include "clang/AST/RecursiveASTVisitor.h" using namespace clang; using namespace cxindex; namespace { -class BodyIndexer : public DataRecursiveASTVisitor<BodyIndexer> { +class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> { IndexingContext &IndexCtx; const NamedDecl *Parent; const DeclContext *ParentDC; - typedef DataRecursiveASTVisitor<BodyIndexer> base; + typedef RecursiveASTVisitor<BodyIndexer> base; public: BodyIndexer(IndexingContext &indexCtx, const NamedDecl *Parent, const DeclContext *DC) @@ -125,10 +125,11 @@ public: return true; } - bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E, + DataRecursionQueue *Q = nullptr) { if (E->getOperatorLoc().isInvalid()) return true; // implicit. - return base::TraverseCXXOperatorCallExpr(E); + return base::TraverseCXXOperatorCallExpr(E, Q); } bool VisitDeclStmt(DeclStmt *S) { diff --git a/tools/libclang/IndexTypeSourceInfo.cpp b/tools/libclang/IndexTypeSourceInfo.cpp index 706870e514b8e..9666052ed1818 100644 --- a/tools/libclang/IndexTypeSourceInfo.cpp +++ b/tools/libclang/IndexTypeSourceInfo.cpp @@ -8,14 +8,14 @@ //===----------------------------------------------------------------------===// #include "IndexingContext.h" -#include "clang/AST/DataRecursiveASTVisitor.h" +#include "clang/AST/RecursiveASTVisitor.h" using namespace clang; using namespace cxindex; namespace { -class TypeIndexer : public DataRecursiveASTVisitor<TypeIndexer> { +class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> { IndexingContext &IndexCtx; const NamedDecl *Parent; const DeclContext *ParentDC; diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp index e35640029e62c..d6e35b0019c9c 100644 --- a/tools/libclang/Indexing.cpp +++ b/tools/libclang/Indexing.cpp @@ -462,48 +462,24 @@ struct IndexSessionData { : CIdx(cIdx), SkipBodyData(new SessionSkipBodyData) {} }; -struct IndexSourceFileInfo { - CXIndexAction idxAction; - CXClientData client_data; - IndexerCallbacks *index_callbacks; - unsigned index_callbacks_size; - unsigned index_options; - const char *source_filename; - const char *const *command_line_args; - int num_command_line_args; - ArrayRef<CXUnsavedFile> unsaved_files; - CXTranslationUnit *out_TU; - unsigned TU_options; - CXErrorCode &result; -}; - } // anonymous namespace -static void clang_indexSourceFile_Impl(void *UserData) { - const IndexSourceFileInfo *ITUI = - static_cast<IndexSourceFileInfo *>(UserData); - CXIndexAction cxIdxAction = ITUI->idxAction; - CXClientData client_data = ITUI->client_data; - IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks; - unsigned index_callbacks_size = ITUI->index_callbacks_size; - unsigned index_options = ITUI->index_options; - const char *source_filename = ITUI->source_filename; - const char * const *command_line_args = ITUI->command_line_args; - int num_command_line_args = ITUI->num_command_line_args; - CXTranslationUnit *out_TU = ITUI->out_TU; - unsigned TU_options = ITUI->TU_options; - +static CXErrorCode clang_indexSourceFile_Impl( + CXIndexAction cxIdxAction, CXClientData client_data, + IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size, + unsigned index_options, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + ArrayRef<CXUnsavedFile> unsaved_files, CXTranslationUnit *out_TU, + unsigned TU_options) { if (out_TU) *out_TU = nullptr; bool requestedToGetTU = (out_TU != nullptr); if (!cxIdxAction) { - ITUI->result = CXError_InvalidArguments; - return; + return CXError_InvalidArguments; } if (!client_index_callbacks || index_callbacks_size == 0) { - ITUI->result = CXError_InvalidArguments; - return; + return CXError_InvalidArguments; } IndexerCallbacks CB; @@ -557,7 +533,7 @@ static void clang_indexSourceFile_Impl(void *UserData) { CInvok(createInvocationFromCommandLine(*Args, Diags)); if (!CInvok) - return; + return CXError_Failure; // Recover resources if we crash before exiting this function. llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation, @@ -565,7 +541,7 @@ static void clang_indexSourceFile_Impl(void *UserData) { CInvokCleanup(CInvok.get()); if (CInvok->getFrontendOpts().Inputs.empty()) - return; + return CXError_Failure; typedef SmallVector<std::unique_ptr<llvm::MemoryBuffer>, 8> MemBufferOwner; std::unique_ptr<MemBufferOwner> BufOwner(new MemBufferOwner); @@ -574,7 +550,7 @@ static void clang_indexSourceFile_Impl(void *UserData) { llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner> BufOwnerCleanup( BufOwner.get()); - for (auto &UF : ITUI->unsaved_files) { + for (auto &UF : unsaved_files) { std::unique_ptr<llvm::MemoryBuffer> MB = llvm::MemoryBuffer::getMemBufferCopy(getContents(UF), UF.Filename); CInvok->getPreprocessorOpts().addRemappedFile(UF.Filename, MB.get()); @@ -590,12 +566,14 @@ static void clang_indexSourceFile_Impl(void *UserData) { if (index_options & CXIndexOpt_SuppressWarnings) CInvok->getDiagnosticOpts().IgnoreWarnings = true; + // Make sure to use the raw module format. + CInvok->getHeaderSearchOpts().ModuleFormat = + CXXIdx->getPCHContainerOperations()->getRawReader().getFormat(); + ASTUnit *Unit = ASTUnit::create(CInvok.get(), Diags, CaptureDiagnostics, /*UserFilesAreVolatile=*/true); - if (!Unit) { - ITUI->result = CXError_InvalidArguments; - return; - } + if (!Unit) + return CXError_InvalidArguments; std::unique_ptr<CXTUOwner> CXTU( new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit))); @@ -623,6 +601,7 @@ static void clang_indexSourceFile_Impl(void *UserData) { bool Persistent = requestedToGetTU; bool OnlyLocalDecls = false; bool PrecompilePreamble = false; + bool CreatePreambleOnFirstParse = false; bool CacheCodeCompletionResults = false; PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); PPOpts.AllowPCHWithCompilerErrors = true; @@ -630,6 +609,8 @@ static void clang_indexSourceFile_Impl(void *UserData) { if (requestedToGetTU) { OnlyLocalDecls = CXXIdx->getOnlyLocalDecls(); PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble; + CreatePreambleOnFirstParse = + TU_options & CXTranslationUnit_CreatePreambleOnFirstParse; // FIXME: Add a flag for modules. CacheCodeCompletionResults = TU_options & CXTranslationUnit_CacheCompletionResults; @@ -642,49 +623,38 @@ static void clang_indexSourceFile_Impl(void *UserData) { if (!requestedToGetTU && !CInvok->getLangOpts()->Modules) PPOpts.DetailedRecord = false; + // Unless the user specified that they want the preamble on the first parse + // set it up to be created on the first reparse. This makes the first parse + // faster, trading for a slower (first) reparse. + unsigned PrecompilePreambleAfterNParses = + !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse; DiagnosticErrorTrap DiagTrap(*Diags); bool Success = ASTUnit::LoadFromCompilerInvocationAction( CInvok.get(), CXXIdx->getPCHContainerOperations(), Diags, IndexAction.get(), Unit, Persistent, CXXIdx->getClangResourcesPath(), - OnlyLocalDecls, CaptureDiagnostics, PrecompilePreamble, + OnlyLocalDecls, CaptureDiagnostics, PrecompilePreambleAfterNParses, CacheCodeCompletionResults, /*IncludeBriefCommentsInCodeCompletion=*/false, /*UserFilesAreVolatile=*/true); if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics()) printDiagsToStderr(Unit); - if (isASTReadError(Unit)) { - ITUI->result = CXError_ASTReadError; - return; - } + if (isASTReadError(Unit)) + return CXError_ASTReadError; if (!Success) - return; + return CXError_Failure; if (out_TU) *out_TU = CXTU->takeTU(); - ITUI->result = CXError_Success; + return CXError_Success; } //===----------------------------------------------------------------------===// // clang_indexTranslationUnit Implementation //===----------------------------------------------------------------------===// -namespace { - -struct IndexTranslationUnitInfo { - CXIndexAction idxAction; - CXClientData client_data; - IndexerCallbacks *index_callbacks; - unsigned index_callbacks_size; - unsigned index_options; - CXTranslationUnit TU; - int result; -}; - -} // anonymous namespace - static void indexPreprocessingRecord(ASTUnit &Unit, IndexingContext &IdxCtx) { Preprocessor &PP = Unit.getPreprocessor(); if (!PP.getPreprocessingRecord()) @@ -711,9 +681,7 @@ static void indexPreprocessingRecord(ASTUnit &Unit, IndexingContext &IdxCtx) { static bool topLevelDeclVisitor(void *context, const Decl *D) { IndexingContext &IdxCtx = *static_cast<IndexingContext*>(context); IdxCtx.indexTopLevelDecl(D); - if (IdxCtx.shouldAbort()) - return false; - return true; + return !IdxCtx.shouldAbort(); } static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IdxCtx) { @@ -728,27 +696,17 @@ static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx) { IdxCtx.handleDiagnosticSet(DiagSet); } -static void clang_indexTranslationUnit_Impl(void *UserData) { - IndexTranslationUnitInfo *ITUI = - static_cast<IndexTranslationUnitInfo*>(UserData); - CXTranslationUnit TU = ITUI->TU; - CXClientData client_data = ITUI->client_data; - IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks; - unsigned index_callbacks_size = ITUI->index_callbacks_size; - unsigned index_options = ITUI->index_options; - - // Set up the initial return value. - ITUI->result = CXError_Failure; - +static CXErrorCode clang_indexTranslationUnit_Impl( + CXIndexAction idxAction, CXClientData client_data, + IndexerCallbacks *client_index_callbacks, unsigned index_callbacks_size, + unsigned index_options, CXTranslationUnit TU) { // Check arguments. if (isNotUsableTU(TU)) { LOG_BAD_TU(TU); - ITUI->result = CXError_InvalidArguments; - return; + return CXError_InvalidArguments; } if (!client_index_callbacks || index_callbacks_size == 0) { - ITUI->result = CXError_InvalidArguments; - return; + return CXError_InvalidArguments; } CIndexer *CXXIdx = TU->CIdx; @@ -777,7 +735,7 @@ static void clang_indexTranslationUnit_Impl(void *UserData) { ASTUnit *Unit = cxtu::getASTUnit(TU); if (!Unit) - return; + return CXError_Failure; ASTUnit::ConcurrencyCheck Check(*Unit); @@ -797,7 +755,7 @@ static void clang_indexTranslationUnit_Impl(void *UserData) { indexTranslationUnit(*Unit, *IndexCtx); indexDiagnostics(TU, *IndexCtx); - ITUI->result = CXError_Success; + return CXError_Success; } //===----------------------------------------------------------------------===// @@ -959,6 +917,22 @@ int clang_indexSourceFile(CXIndexAction idxAction, unsigned num_unsaved_files, CXTranslationUnit *out_TU, unsigned TU_options) { + SmallVector<const char *, 4> Args; + Args.push_back("clang"); + Args.append(command_line_args, command_line_args + num_command_line_args); + return clang_indexSourceFileFullArgv( + idxAction, client_data, index_callbacks, index_callbacks_size, + index_options, source_filename, Args.data(), Args.size(), unsaved_files, + num_unsaved_files, out_TU, TU_options); +} + +int clang_indexSourceFileFullArgv( + CXIndexAction idxAction, CXClientData client_data, + IndexerCallbacks *index_callbacks, unsigned index_callbacks_size, + unsigned index_options, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + CXTranslationUnit *out_TU, unsigned TU_options) { LOG_FUNC_SECTION { *Log << source_filename << ": "; for (int i = 0; i != num_command_line_args; ++i) @@ -969,28 +943,23 @@ int clang_indexSourceFile(CXIndexAction idxAction, return CXError_InvalidArguments; CXErrorCode result = CXError_Failure; - IndexSourceFileInfo ITUI = { - idxAction, - client_data, - index_callbacks, - index_callbacks_size, - index_options, - source_filename, - command_line_args, - num_command_line_args, - llvm::makeArrayRef(unsaved_files, num_unsaved_files), - out_TU, - TU_options, - result}; + auto IndexSourceFileImpl = [=, &result]() { + result = clang_indexSourceFile_Impl( + idxAction, client_data, index_callbacks, index_callbacks_size, + index_options, source_filename, command_line_args, + num_command_line_args, + llvm::makeArrayRef(unsaved_files, num_unsaved_files), out_TU, + TU_options); + }; if (getenv("LIBCLANG_NOTHREADS")) { - clang_indexSourceFile_Impl(&ITUI); + IndexSourceFileImpl(); return result; } llvm::CrashRecoveryContext CRC; - if (!RunSafely(CRC, clang_indexSourceFile_Impl, &ITUI)) { + if (!RunSafely(CRC, IndexSourceFileImpl)) { fprintf(stderr, "libclang: crash detected during indexing source file: {\n"); fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); fprintf(stderr, " 'command_line_args' : ["); @@ -1030,24 +999,27 @@ int clang_indexTranslationUnit(CXIndexAction idxAction, *Log << TU; } - IndexTranslationUnitInfo ITUI = { idxAction, client_data, index_callbacks, - index_callbacks_size, index_options, TU, - 0 }; + CXErrorCode result; + auto IndexTranslationUnitImpl = [=, &result]() { + result = clang_indexTranslationUnit_Impl( + idxAction, client_data, index_callbacks, index_callbacks_size, + index_options, TU); + }; if (getenv("LIBCLANG_NOTHREADS")) { - clang_indexTranslationUnit_Impl(&ITUI); - return ITUI.result; + IndexTranslationUnitImpl(); + return result; } llvm::CrashRecoveryContext CRC; - if (!RunSafely(CRC, clang_indexTranslationUnit_Impl, &ITUI)) { + if (!RunSafely(CRC, IndexTranslationUnitImpl)) { fprintf(stderr, "libclang: crash detected during indexing TU\n"); return 1; } - return ITUI.result; + return result; } void clang_indexLoc_getFileLocation(CXIdxLoc location, diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp index bf6e172fc074b..f7640c63e05c1 100644 --- a/tools/libclang/IndexingContext.cpp +++ b/tools/libclang/IndexingContext.cpp @@ -804,10 +804,7 @@ bool IndexingContext::markEntityOccurrenceInFile(const NamedDecl *D, RefFileOccurrence RefOccur(FE, D); std::pair<llvm::DenseSet<RefFileOccurrence>::iterator, bool> res = RefFileOccurrences.insert(RefOccur); - if (!res.second) - return true; // already in map. - - return false; + return !res.second; // already in map } const NamedDecl *IndexingContext::getEntityDecl(const NamedDecl *D) const { diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index f6a7175579aa3..993644d02fc15 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -2,6 +2,7 @@ clang_CXCursorSet_contains clang_CXCursorSet_insert clang_CXIndex_getGlobalOptions clang_CXIndex_setGlobalOptions +clang_CXXField_isMutable clang_CXXMethod_isConst clang_CXXMethod_isPureVirtual clang_CXXMethod_isStatic @@ -14,6 +15,7 @@ clang_Cursor_getTemplateArgumentValue clang_Cursor_getTemplateArgumentUnsignedValue clang_Cursor_getBriefCommentText clang_Cursor_getCommentRange +clang_Cursor_getCXXManglings clang_Cursor_getMangling clang_Cursor_getParsedComment clang_Cursor_getRawCommentText @@ -119,6 +121,7 @@ clang_disposeOverriddenCursors clang_disposeCXPlatformAvailability clang_disposeSourceRangeList clang_disposeString +clang_disposeStringSet clang_disposeTokens clang_disposeTranslationUnit clang_enableStackTraces @@ -173,6 +176,7 @@ clang_getCursorSemanticParent clang_getCursorSpelling clang_getCursorType clang_getCursorUSR +clang_getCursorVisibility clang_getDeclObjCTypeEncoding clang_getDefinitionSpellingAndExtent clang_getDiagnostic @@ -246,6 +250,7 @@ clang_hashCursor clang_indexLoc_getCXSourceLocation clang_indexLoc_getFileLocation clang_indexSourceFile +clang_indexSourceFileFullArgv clang_indexTranslationUnit clang_index_getCXXClassDeclInfo clang_index_getClientContainer @@ -281,6 +286,7 @@ clang_Location_isInSystemHeader clang_Location_isFromMainFile clang_parseTranslationUnit clang_parseTranslationUnit2 +clang_parseTranslationUnit2FullArgv clang_remap_dispose clang_remap_getFilenames clang_remap_getNumFiles @@ -297,6 +303,9 @@ clang_CompileCommands_dispose clang_CompileCommands_getSize clang_CompileCommands_getCommand clang_CompileCommand_getDirectory +clang_CompileCommand_getFilename +clang_CompileCommand_getMappedSourceContent +clang_CompileCommand_getMappedSourcePath clang_CompileCommand_getNumArgs clang_CompileCommand_getArg clang_visitChildren diff --git a/tools/scan-build/CMakeLists.txt b/tools/scan-build/CMakeLists.txt new file mode 100644 index 0000000000000..78c243d8e0d65 --- /dev/null +++ b/tools/scan-build/CMakeLists.txt @@ -0,0 +1,82 @@ +option(CLANG_INSTALL_SCANBUILD "Install the scan-build tool" ON) + +include(GNUInstallDirs) + +if (WIN32 AND NOT CYGWIN) + set(BinFiles + scan-build.bat) + set(LibexecFiles + ccc-analyzer.bat + c++-analyzer.bat) +else() + set(BinFiles + scan-build) + set(LibexecFiles + ccc-analyzer + c++-analyzer) + if (APPLE) + list(APPEND BinFiles + set-xcode-analyzer) + endif() +endif() + +set(ManPages + scan-build.1) + +set(ShareFiles + scanview.css + sorttable.js) + + +if(CLANG_INSTALL_SCANBUILD) + foreach(BinFile ${BinFiles}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/${BinFile} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/bin + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile} + ${CMAKE_BINARY_DIR}/bin/ + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile}) + list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/${BinFile}) + install(PROGRAMS bin/${BinFile} DESTINATION bin) + endforeach() + + foreach(LibexecFile ${LibexecFiles}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/libexec/${LibexecFile} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/libexec + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${LibexecFile} + ${CMAKE_BINARY_DIR}/libexec/ + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/libexec/${LibexecFile}) + list(APPEND Depends ${CMAKE_BINARY_DIR}/libexec/${LibexecFile}) + install(PROGRAMS libexec/${LibexecFile} DESTINATION libexec) + endforeach() + + foreach(ManPage ${ManPages}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/${ManPage} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1 + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/man/${ManPage} + ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/ + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/man/${ManPage}) + list(APPEND Depends ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_MANDIR}/man1/${ManPage}) + install(PROGRAMS man/${ManPage} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) + endforeach() + + foreach(ShareFile ${ShareFiles}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/share/scan-build/${ShareFile} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/share/scan-build + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/share/scan-build/${ShareFile} + ${CMAKE_BINARY_DIR}/share/scan-build/ + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/share/scan-build/${ShareFile}) + list(APPEND Depends ${CMAKE_BINARY_DIR}/share/scan-build/${ShareFile}) + install(FILES share/scan-build/${ShareFile} DESTINATION share/scan-build) + endforeach() + + add_custom_target(scan-build ALL DEPENDS ${Depends}) + set_target_properties(scan-build PROPERTIES FOLDER "Misc") +endif() diff --git a/tools/scan-build/Makefile b/tools/scan-build/Makefile new file mode 100644 index 0000000000000..23aa19882a527 --- /dev/null +++ b/tools/scan-build/Makefile @@ -0,0 +1,53 @@ +##===- tools/scan-build/Makefile ---------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. + +include $(CLANG_LEVEL)/../../Makefile.config +include $(CLANG_LEVEL)/Makefile + +ifeq ($(HOST_OS),MingW) + Suffix := .bat +endif + +CLANG_INSTALL_SCANBUILD ?= 1 + +ifeq ($(CLANG_INSTALL_SCANBUILD), 1) + InstallTargets := $(ToolDir)/scan-build$(Suffix) \ + $(LibexecDir)/c++-analyzer$(Suffix) \ + $(LibexecDir)/ccc-analyzer$(Suffix) \ + $(ShareDir)/scan-build/scanview.css \ + $(ShareDir)/scan-build/sorttable.js \ + $(ShareDir)/man/man1/scan-build.1 + + ifeq ($(HOST_OS),Darwin) + InstallTargets := $(InstallTargets) $(ToolDir)/set-xcode-analyzer + endif +endif + +all:: $(InstallTargets) + +$(ToolDir)/%: bin/% Makefile $(ToolDir)/.dir + $(Echo) "Copying $(notdir $<) to the 'bin' directory..." + $(Verb)cp $< $@ + $(Verb)chmod +x $@ + +$(LibexecDir)/%: libexec/% Makefile $(LibexecDir)/.dir + $(Echo) "Copying $(notdir $<) to the 'libexec' directory..." + $(Verb)cp $< $@ + $(Verb)chmod +x $@ + +$(ShareDir)/man/man1/%: man/% Makefile $(ShareDir)/man/man1/.dir + $(Echo) "Copying $(notdir $<) to the 'man' directory..." + $(Verb)cp $< $@ + +$(ShareDir)/scan-build/%: share/scan-build/% Makefile $(ShareDir)/scan-build/.dir + $(Echo) "Copying $(notdir $<) to the 'share' directory..." + $(Verb)cp $< $@ + diff --git a/tools/scan-build/scan-build b/tools/scan-build/bin/scan-build index d7cadc3e59e12..6a14484970a27 100755 --- a/tools/scan-build/scan-build +++ b/tools/scan-build/bin/scan-build @@ -24,8 +24,8 @@ use Term::ANSIColor; use Term::ANSIColor qw(:constants); use Cwd qw/ getcwd abs_path /; use Sys::Hostname; +use Hash::Util qw(lock_keys); -my $Verbose = 0; # Verbose output from this script. my $Prog = "scan-build"; my $BuildName; my $BuildDate; @@ -39,15 +39,40 @@ my $UseColor = (defined $TERM and $TERM =~ 'xterm-.*color' and -t STDOUT my $UserName = HtmlEscape(getlogin() || getpwuid($<) || 'unknown'); my $HostName = HtmlEscape(hostname() || 'unknown'); my $CurrentDir = HtmlEscape(getcwd()); -my $CurrentDirSuffix = basename($CurrentDir); -my @PluginsToLoad; my $CmdArgs; -my $HtmlTitle; - my $Date = localtime(); +# Command-line/config arguments. +my %Options = ( + Verbose => 0, # Verbose output from this script. + AnalyzeHeaders => 0, + OutputDir => undef, # Parent directory to store HTML files. + HtmlTitle => basename($CurrentDir)." - scan-build results", + IgnoreErrors => 0, # Ignore build errors. + ViewResults => 0, # View results when the build terminates. + ExitStatusFoundBugs => 0, # Exit status reflects whether bugs were found + KeepEmpty => 0, # Don't remove output directory even with 0 results. + EnableCheckers => {}, + DisableCheckers => {}, + UseCC => undef, # C compiler to use for compilation. + UseCXX => undef, # C++ compiler to use for compilation. + AnalyzerTarget => undef, + StoreModel => undef, + ConstraintsModel => undef, + InternalStats => undef, + OutputFormat => "html", + ConfigOptions => [], # Options to pass through to the analyzer's -analyzer-config flag. + ReportFailures => undef, + AnalyzerStats => 0, + MaxLoop => 0, + PluginsToLoad => [], + AnalyzerDiscoveryMethod => undef, + OverrideCompiler => 0 # The flag corresponding to the --override-compiler command line option. +); +lock_keys(%Options); + ##----------------------------------------------------------------------------## # Diagnostics ##----------------------------------------------------------------------------## @@ -231,7 +256,7 @@ sub SetHtmlEnv { return; } - if ($Verbose) { + if ($Options{Verbose}) { Diag("Emitting reports for this run to '$Dir'.\n"); } @@ -437,7 +462,7 @@ sub CopyFiles { my $Dir = shift; - my $JS = Cwd::realpath("$RealBin/sorttable.js"); + my $JS = Cwd::realpath("$RealBin/../share/scan-build/sorttable.js"); DieDiag("Cannot find 'sorttable.js'.\n") if (! -r $JS); @@ -447,7 +472,7 @@ sub CopyFiles { DieDiag("Could not copy 'sorttable.js' to '$Dir'.\n") if (! -r "$Dir/sorttable.js"); - my $CSS = Cwd::realpath("$RealBin/scanview.css"); + my $CSS = Cwd::realpath("$RealBin/../share/scan-build/scanview.css"); DieDiag("Cannot find 'scanview.css'.\n") if (! -r $CSS); @@ -582,7 +607,7 @@ sub Postprocess { print OUT <<ENDTEXT; <html> <head> -<title>${HtmlTitle}</title> +<title>${Options{HtmlTitle}}</title> <link type="text/css" rel="stylesheet" href="scanview.css"/> <script src="sorttable.js"></script> <script language='javascript' type="text/javascript"> @@ -637,7 +662,7 @@ function ToggleDisplay(CheckButton, ClassName) { <!-- SUMMARYENDHEAD --> </head> <body> -<h1>${HtmlTitle}</h1> +<h1>${Options{HtmlTitle}}</h1> <table> <tr><th>User:</th><td>${UserName}\@${HostName}</td></tr> @@ -912,21 +937,25 @@ sub AddIfNotPresent { } sub SetEnv { - my $Options = shift @_; - foreach my $opt ('CC', 'CXX', 'CLANG', 'CLANG_CXX', - 'CCC_ANALYZER_ANALYSIS', 'CCC_ANALYZER_PLUGINS', - 'CCC_ANALYZER_CONFIG') { - die "$opt is undefined\n" if (!defined $opt); - $ENV{$opt} = $Options->{$opt}; + my $EnvVars = shift @_; + foreach my $var ('CC', 'CXX', 'CLANG', 'CLANG_CXX', + 'CCC_ANALYZER_ANALYSIS', 'CCC_ANALYZER_PLUGINS', + 'CCC_ANALYZER_CONFIG') { + die "$var is undefined\n" if (!defined $var); + $ENV{$var} = $EnvVars->{$var}; } - foreach my $opt ('CCC_ANALYZER_STORE_MODEL', - 'CCC_ANALYZER_PLUGINS', - 'CCC_ANALYZER_INTERNAL_STATS', - 'CCC_ANALYZER_OUTPUT_FORMAT') { - my $x = $Options->{$opt}; - if (defined $x) { $ENV{$opt} = $x } + foreach my $var ('CCC_ANALYZER_STORE_MODEL', + 'CCC_ANALYZER_CONSTRAINTS_MODEL', + 'CCC_ANALYZER_INTERNAL_STATS', + 'CCC_ANALYZER_OUTPUT_FORMAT', + 'CCC_CC', + 'CCC_CXX', + 'CCC_REPORT_FAILURES', + 'CLANG_ANALYZER_TARGET') { + my $x = $EnvVars->{$var}; + if (defined $x) { $ENV{$var} = $x } } - my $Verbose = $Options->{'VERBOSE'}; + my $Verbose = $EnvVars->{'VERBOSE'}; if ($Verbose >= 2) { $ENV{'CCC_ANALYZER_VERBOSE'} = 1; } @@ -935,15 +964,12 @@ sub SetEnv { } } -# The flag corresponding to the --override-compiler command line option. -my $OverrideCompiler = 0; - sub RunXcodebuild { my $Args = shift; my $IgnoreErrors = shift; my $CCAnalyzer = shift; my $CXXAnalyzer = shift; - my $Options = shift; + my $EnvVars = shift; if ($IgnoreErrors) { AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES"); @@ -972,14 +998,14 @@ sub RunXcodebuild { # If --override-compiler is explicitely requested, resort to the old # behavior regardless of Xcode version. - if ($OverrideCompiler) { + if ($Options{OverrideCompiler}) { $oldBehavior = 1; } if ($oldBehavior == 0) { - my $OutputDir = $Options->{"OUTPUT_DIR"}; - my $CLANG = $Options->{"CLANG"}; - my $OtherFlags = $Options->{"CCC_ANALYZER_ANALYSIS"}; + my $OutputDir = $EnvVars->{"OUTPUT_DIR"}; + my $CLANG = $EnvVars->{"CLANG"}; + my $OtherFlags = $EnvVars->{"CCC_ANALYZER_ANALYSIS"}; push @$Args, "RUN_CLANG_STATIC_ANALYZER=YES", "CLANG_ANALYZER_OUTPUT=plist-html", @@ -991,7 +1017,7 @@ sub RunXcodebuild { } # Default to old behavior where we insert a bogus compiler. - SetEnv($Options); + SetEnv($EnvVars); # Check if using iPhone SDK 3.0 (simulator). If so the compiler being # used should be gcc-4.2. @@ -1023,14 +1049,14 @@ sub RunBuildCommand { my $Cmd = $Args->[0]; my $CCAnalyzer = shift; my $CXXAnalyzer = shift; - my $Options = shift; + my $EnvVars = shift; if ($Cmd =~ /\bxcodebuild$/) { - return RunXcodebuild($Args, $IgnoreErrors, $CCAnalyzer, $CXXAnalyzer, $Options); + return RunXcodebuild($Args, $IgnoreErrors, $CCAnalyzer, $CXXAnalyzer, $EnvVars); } # Setup the environment. - SetEnv($Options); + SetEnv($EnvVars); if ($Cmd =~ /(.*\/?gcc[^\/]*$)/ or $Cmd =~ /(.*\/?cc[^\/]*$)/ or @@ -1074,6 +1100,7 @@ sub RunBuildCommand { sub DisplayHelp { + my $ArgClangNotFoundErrMsg = shift; print <<ENDTEXT; USAGE: $Prog [options] <build command> [build options] @@ -1145,10 +1172,21 @@ OPTIONS: scan-build to use a specific compiler for *compilation* then you can use this option to specify a path to that compiler. + If the given compiler is a cross compiler, you may also need to provide + --analyzer-target option to properly analyze the source code because static + analyzer runs as if the code is compiled for the host machine by default. + --use-c++ [compiler path] --use-c++=[compiler path] - This is the same as "-use-cc" but for C++ code. + This is the same as "--use-cc" but for C++ code. + + --analyzer-target [target triple name for analysis] + --analyzer-target=[target triple name for analysis] + + This provides target triple information to clang static analyzer. + It only changes the target for analysis but doesn't change the target of a + real compiler given by --use-cc and --use-c++ options. -v @@ -1221,32 +1259,41 @@ LOADING CHECKERS: -load-plugin [plugin library] ENDTEXT - # Query clang for list of checkers that are enabled. + if (defined $Clang && -x $Clang) { + # Query clang for list of checkers that are enabled. - # create a list to load the plugins via the 'Xclang' command line - # argument - my @PluginLoadCommandline_xclang; - foreach my $param ( @PluginsToLoad ) { - push ( @PluginLoadCommandline_xclang, "-Xclang" ); - push ( @PluginLoadCommandline_xclang, $param ); - } - my %EnabledCheckers; - foreach my $lang ("c", "objective-c", "objective-c++", "c++") { - my $ExecLine = join(' ', qq/"$Clang"/, @PluginLoadCommandline_xclang, "--analyze", "-x", $lang, "-", "-###", "2>&1", "|"); - open(PS, $ExecLine); - while (<PS>) { - foreach my $val (split /\s+/) { - $val =~ s/\"//g; - if ($val =~ /-analyzer-checker\=([^\s]+)/) { - $EnabledCheckers{$1} = 1; + # create a list to load the plugins via the 'Xclang' command line + # argument + my @PluginLoadCommandline_xclang; + foreach my $param ( @{$Options{PluginsToLoad}} ) { + push ( @PluginLoadCommandline_xclang, "-Xclang" ); + push ( @PluginLoadCommandline_xclang, "-load" ); + push ( @PluginLoadCommandline_xclang, "-Xclang" ); + push ( @PluginLoadCommandline_xclang, $param ); + } + + my %EnabledCheckers; + foreach my $lang ("c", "objective-c", "objective-c++", "c++") { + my $ExecLine = join(' ', qq/"$Clang"/, @PluginLoadCommandline_xclang, "--analyze", "-x", $lang, "-", "-###", "2>&1", "|"); + open(PS, $ExecLine); + while (<PS>) { + foreach my $val (split /\s+/) { + $val =~ s/\"//g; + if ($val =~ /-analyzer-checker\=([^\s]+)/) { + $EnabledCheckers{$1} = 1; + } } } } - } - # Query clang for complete list of checkers. - if (defined $Clang && -x $Clang) { - my $ExecLine = join(' ', qq/"$Clang"/, "-cc1", @PluginsToLoad, "-analyzer-checker-help", "2>&1", "|"); + # Query clang for complete list of checkers. + my @PluginLoadCommandline; + foreach my $param ( @{$Options{PluginsToLoad}} ) { + push ( @PluginLoadCommandline, "-load" ); + push ( @PluginLoadCommandline, $param ); + } + + my $ExecLine = join(' ', qq/"$Clang"/, "-cc1", @PluginLoadCommandline, "-analyzer-checker-help", "2>&1", "|"); open(PS, $ExecLine); my $foundCheckers = 0; while (<PS>) { @@ -1302,6 +1349,12 @@ ENDTEXT } close PS; } + else { + print " *** Could not query Clang for the list of available checkers.\n"; + if (defined $ArgClangNotFoundErrMsg) { + print " *** Reason: $ArgClangNotFoundErrMsg\n"; + } + } print <<ENDTEXT @@ -1347,284 +1400,331 @@ sub ShellEscape { } ##----------------------------------------------------------------------------## +# FindClang - searches for 'clang' executable. +##----------------------------------------------------------------------------## + +sub FindClang { + if (!defined $Options{AnalyzerDiscoveryMethod}) { + $Clang = Cwd::realpath("$RealBin/bin/clang") if (-f "$RealBin/bin/clang"); + if (!defined $Clang || ! -x $Clang) { + $Clang = Cwd::realpath("$RealBin/clang") if (-f "$RealBin/clang"); + } + if (!defined $Clang || ! -x $Clang) { + return "error: Cannot find an executable 'clang' relative to" . + " scan-build. Consider using --use-analyzer to pick a version of" . + " 'clang' to use for static analysis.\n"; + } + } + else { + if ($Options{AnalyzerDiscoveryMethod} =~ /^[Xx]code$/) { + my $xcrun = `which xcrun`; + chomp $xcrun; + if ($xcrun eq "") { + return "Cannot find 'xcrun' to find 'clang' for analysis.\n"; + } + $Clang = `$xcrun -toolchain XcodeDefault -find clang`; + chomp $Clang; + if ($Clang eq "") { + return "No 'clang' executable found by 'xcrun'\n"; + } + } + else { + $Clang = $Options{AnalyzerDiscoveryMethod}; + if (!defined $Clang or not -x $Clang) { + return "Cannot find an executable clang at '$Options{AnalyzerDiscoveryMethod}'\n"; + } + } + } + return undef; +} + +##----------------------------------------------------------------------------## # Process command-line arguments. ##----------------------------------------------------------------------------## -my $AnalyzeHeaders = 0; -my $HtmlDir; # Parent directory to store HTML files. -my $IgnoreErrors = 0; # Ignore build errors. -my $ViewResults = 0; # View results when the build terminates. -my $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found -my $KeepEmpty = 0; # Don't remove output directory even with 0 results. -my @AnalysesToRun; -my $StoreModel; -my $ConstraintsModel; -my $InternalStats; -my @ConfigOptions; -my $OutputFormat = "html"; -my $AnalyzerStats = 0; -my $MaxLoop = 0; my $RequestDisplayHelp = 0; my $ForceDisplayHelp = 0; -my $AnalyzerDiscoveryMethod; -if (!@ARGV) { - $ForceDisplayHelp = 1 -} +sub ProcessArgs { + my $Args = shift; + my $NumArgs = 0; -while (@ARGV) { + while (@$Args) { - # Scan for options we recognize. + $NumArgs++; - my $arg = $ARGV[0]; + # Scan for options we recognize. - if ($arg eq "-h" or $arg eq "--help") { - $RequestDisplayHelp = 1; - shift @ARGV; - next; - } + my $arg = $Args->[0]; - if ($arg eq '-analyze-headers') { - shift @ARGV; - $AnalyzeHeaders = 1; - next; - } + if ($arg eq "-h" or $arg eq "--help") { + $RequestDisplayHelp = 1; + shift @$Args; + next; + } + + if ($arg eq '-analyze-headers') { + shift @$Args; + $Options{AnalyzeHeaders} = 1; + next; + } - if ($arg eq "-o") { - shift @ARGV; + if ($arg eq "-o") { + shift @$Args; - if (!@ARGV) { - DieDiag("'-o' option requires a target directory name.\n"); + if (!@$Args) { + DieDiag("'-o' option requires a target directory name.\n"); + } + + # Construct an absolute path. Uses the current working directory + # as a base if the original path was not absolute. + my $OutDir = shift @$Args; + mkpath($OutDir) unless (-e $OutDir); # abs_path wants existing dir + $Options{OutputDir} = abs_path($OutDir); + + next; } - # Construct an absolute path. Uses the current working directory - # as a base if the original path was not absolute. - $HtmlDir = abs_path(shift @ARGV); + if ($arg =~ /^--html-title(=(.+))?$/) { + shift @$Args; - next; - } + if (!defined $2 || $2 eq '') { + if (!@$Args) { + DieDiag("'--html-title' option requires a string.\n"); + } + + $Options{HtmlTitle} = shift @$Args; + } else { + $Options{HtmlTitle} = $2; + } + + next; + } - if ($arg =~ /^--html-title(=(.+))?$/) { - shift @ARGV; + if ($arg eq "-k" or $arg eq "--keep-going") { + shift @$Args; + $Options{IgnoreErrors} = 1; + next; + } + + if ($arg =~ /^--use-cc(=(.+))?$/) { + shift @$Args; + my $cc; - if (!defined $2 || $2 eq '') { - if (!@ARGV) { - DieDiag("'--html-title' option requires a string.\n"); + if (!defined $2 || $2 eq "") { + if (!@$Args) { + DieDiag("'--use-cc' option requires a compiler executable name.\n"); + } + $cc = shift @$Args; + } + else { + $cc = $2; } - $HtmlTitle = shift @ARGV; - } else { - $HtmlTitle = $2; + $Options{UseCC} = $cc; + next; } - next; - } + if ($arg =~ /^--use-c\+\+(=(.+))?$/) { + shift @$Args; + my $cxx; - if ($arg eq "-k" or $arg eq "--keep-going") { - shift @ARGV; - $IgnoreErrors = 1; - next; - } + if (!defined $2 || $2 eq "") { + if (!@$Args) { + DieDiag("'--use-c++' option requires a compiler executable name.\n"); + } + $cxx = shift @$Args; + } + else { + $cxx = $2; + } + + $Options{UseCXX} = $cxx; + next; + } - if ($arg =~ /^--use-cc(=(.+))?$/) { - shift @ARGV; - my $cc; + if ($arg =~ /^--analyzer-target(=(.+))?$/) { + shift @ARGV; + my $AnalyzerTarget; - if (!defined $2 || $2 eq "") { - if (!@ARGV) { - DieDiag("'--use-cc' option requires a compiler executable name.\n"); + if (!defined $2 || $2 eq "") { + if (!@ARGV) { + DieDiag("'--analyzer-target' option requires a target triple name.\n"); + } + $AnalyzerTarget = shift @ARGV; } - $cc = shift @ARGV; + else { + $AnalyzerTarget = $2; + } + + $Options{AnalyzerTarget} = $AnalyzerTarget; + next; } - else { - $cc = $2; + + if ($arg eq "-v") { + shift @$Args; + $Options{Verbose}++; + next; } - $ENV{"CCC_CC"} = $cc; - next; - } + if ($arg eq "-V" or $arg eq "--view") { + shift @$Args; + $Options{ViewResults} = 1; + next; + } - if ($arg =~ /^--use-c\+\+(=(.+))?$/) { - shift @ARGV; - my $cxx; + if ($arg eq "--status-bugs") { + shift @$Args; + $Options{ExitStatusFoundBugs} = 1; + next; + } - if (!defined $2 || $2 eq "") { - if (!@ARGV) { - DieDiag("'--use-c++' option requires a compiler executable name.\n"); - } - $cxx = shift @ARGV; + if ($arg eq "-store") { + shift @$Args; + $Options{StoreModel} = shift @$Args; + next; } - else { - $cxx = $2; + + if ($arg eq "-constraints") { + shift @$Args; + $Options{ConstraintsModel} = shift @$Args; + next; } - $ENV{"CCC_CXX"} = $cxx; - next; - } + if ($arg eq "-internal-stats") { + shift @$Args; + $Options{InternalStats} = 1; + next; + } - if ($arg eq "-v") { - shift @ARGV; - $Verbose++; - next; - } + if ($arg eq "-plist") { + shift @$Args; + $Options{OutputFormat} = "plist"; + next; + } - if ($arg eq "-V" or $arg eq "--view") { - shift @ARGV; - $ViewResults = 1; - next; - } + if ($arg eq "-plist-html") { + shift @$Args; + $Options{OutputFormat} = "plist-html"; + next; + } - if ($arg eq "--status-bugs") { - shift @ARGV; - $ExitStatusFoundBugs = 1; - next; - } + if ($arg eq "-analyzer-config") { + shift @$Args; + push @{$Options{ConfigOptions}}, shift @$Args; + next; + } - if ($arg eq "-store") { - shift @ARGV; - $StoreModel = shift @ARGV; - next; - } + if ($arg eq "-no-failure-reports") { + shift @$Args; + $Options{ReportFailures} = 0; + next; + } - if ($arg eq "-constraints") { - shift @ARGV; - $ConstraintsModel = shift @ARGV; - next; - } + if ($arg eq "-stats") { + shift @$Args; + $Options{AnalyzerStats} = 1; + next; + } - if ($arg eq "-internal-stats") { - shift @ARGV; - $InternalStats = 1; - next; - } + if ($arg eq "-maxloop") { + shift @$Args; + $Options{MaxLoop} = shift @$Args; + next; + } - if ($arg eq "-plist") { - shift @ARGV; - $OutputFormat = "plist"; - next; - } - if ($arg eq "-plist-html") { - shift @ARGV; - $OutputFormat = "plist-html"; - next; - } + if ($arg eq "-enable-checker") { + shift @$Args; + my $Checker = shift @$Args; + # Store $NumArgs to preserve the order the checkers were enabled. + $Options{EnableCheckers}{$Checker} = $NumArgs; + delete $Options{DisableCheckers}{$Checker}; + next; + } - if ($arg eq "-analyzer-config") { - shift @ARGV; - push @ConfigOptions, "-analyzer-config", shift @ARGV; - next; - } + if ($arg eq "-disable-checker") { + shift @$Args; + my $Checker = shift @$Args; + # Store $NumArgs to preserve the order the checkers were disabled. + $Options{DisableCheckers}{$Checker} = $NumArgs; + delete $Options{EnableCheckers}{$Checker}; + next; + } - if ($arg eq "-no-failure-reports") { - shift @ARGV; - $ENV{"CCC_REPORT_FAILURES"} = 0; - next; - } - if ($arg eq "-stats") { - shift @ARGV; - $AnalyzerStats = 1; - next; - } - if ($arg eq "-maxloop") { - shift @ARGV; - $MaxLoop = shift @ARGV; - next; - } - if ($arg eq "-enable-checker") { - shift @ARGV; - push @AnalysesToRun, "-analyzer-checker", shift @ARGV; - next; - } - if ($arg eq "-disable-checker") { - shift @ARGV; - push @AnalysesToRun, "-analyzer-disable-checker", shift @ARGV; - next; - } - if ($arg eq "-load-plugin") { - shift @ARGV; - push @PluginsToLoad, "-load", shift @ARGV; - next; - } - if ($arg eq "--use-analyzer") { - shift @ARGV; - $AnalyzerDiscoveryMethod = shift @ARGV; - next; - } - if ($arg =~ /^--use-analyzer=(.+)$/) { - shift @ARGV; - $AnalyzerDiscoveryMethod = $1; - next; - } - if ($arg eq "--keep-empty") { - shift @ARGV; - $KeepEmpty = 1; - next; - } + if ($arg eq "-load-plugin") { + shift @$Args; + push @{$Options{PluginsToLoad}}, shift @$Args; + next; + } - if ($arg eq "--override-compiler") { - shift @ARGV; - $OverrideCompiler = 1; - next; - } + if ($arg eq "--use-analyzer") { + shift @$Args; + $Options{AnalyzerDiscoveryMethod} = shift @$Args; + next; + } + + if ($arg =~ /^--use-analyzer=(.+)$/) { + shift @$Args; + $Options{AnalyzerDiscoveryMethod} = $1; + next; + } + + if ($arg eq "--keep-empty") { + shift @$Args; + $Options{KeepEmpty} = 1; + next; + } + + if ($arg eq "--override-compiler") { + shift @$Args; + $Options{OverrideCompiler} = 1; + next; + } - DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/); + DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/); - last; + $NumArgs--; + last; + } + return $NumArgs; +} + +if (!@ARGV) { + $ForceDisplayHelp = 1 } +ProcessArgs(\@ARGV); +# All arguments are now shifted from @ARGV. The rest is a build command, if any. + if (!@ARGV and !$RequestDisplayHelp) { ErrorDiag("No build command specified.\n\n"); $ForceDisplayHelp = 1; } -# Find 'clang' -if (!defined $AnalyzerDiscoveryMethod) { - $Clang = Cwd::realpath("$RealBin/bin/clang"); - if (!defined $Clang || ! -x $Clang) { - $Clang = Cwd::realpath("$RealBin/clang"); - } - if (!defined $Clang || ! -x $Clang) { - if (!$RequestDisplayHelp && !$ForceDisplayHelp) { - DieDiag("error: Cannot find an executable 'clang' relative to scan-build." . - " Consider using --use-analyzer to pick a version of 'clang' to use for static analysis.\n"); - } - } -} -else { - if ($AnalyzerDiscoveryMethod =~ /^[Xx]code$/) { - my $xcrun = `which xcrun`; - chomp $xcrun; - if ($xcrun eq "") { - DieDiag("Cannot find 'xcrun' to find 'clang' for analysis.\n"); - } - $Clang = `$xcrun -toolchain XcodeDefault -find clang`; - chomp $Clang; - if ($Clang eq "") { - DieDiag("No 'clang' executable found by 'xcrun'\n"); - } - } - else { - $Clang = $AnalyzerDiscoveryMethod; - if (!defined $Clang or not -x $Clang) { - DieDiag("Cannot find an executable clang at '$AnalyzerDiscoveryMethod'\n"); - } - } -} +my $ClangNotFoundErrMsg = FindClang(); if ($ForceDisplayHelp || $RequestDisplayHelp) { - DisplayHelp(); + DisplayHelp($ClangNotFoundErrMsg); exit $ForceDisplayHelp; } +DieDiag($ClangNotFoundErrMsg) if (defined $ClangNotFoundErrMsg); + $ClangCXX = $Clang; -# Determine operating system under which this copy of Perl was built. -my $IsWinBuild = ($^O =~/msys|cygwin|MSWin32/); -if($IsWinBuild) { - $ClangCXX =~ s/.exe$/++.exe/; -} -else { - $ClangCXX =~ s/\-\d+\.\d+$//; - $ClangCXX .= "++"; +if ($Clang !~ /\+\+(\.exe)?$/) { + # If $Clang holds the name of the clang++ executable then we leave + # $ClangCXX and $Clang equal, otherwise construct the name of the clang++ + # executable from the clang executable name. + + # Determine operating system under which this copy of Perl was built. + my $IsWinBuild = ($^O =~/msys|cygwin|MSWin32/); + if($IsWinBuild) { + $ClangCXX =~ s/.exe$/++.exe/; + } + else { + $ClangCXX =~ s/\-\d+\.\d+$//; + $ClangCXX .= "++"; + } } # Make sure to use "" to handle paths with spaces. @@ -1632,17 +1732,15 @@ $ClangVersion = HtmlEscape(`"$Clang" --version`); # Determine where results go. $CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV))); -$HtmlTitle = "${CurrentDirSuffix} - scan-build results" - unless (defined($HtmlTitle)); # Determine the output directory for the HTML reports. -my $BaseDir = $HtmlDir; -$HtmlDir = GetHTMLRunDir($HtmlDir); +my $BaseDir = $Options{OutputDir}; +$Options{OutputDir} = GetHTMLRunDir($Options{OutputDir}); # Determine the location of ccc-analyzer. my $AbsRealBin = Cwd::realpath($RealBin); -my $Cmd = "$AbsRealBin/libexec/ccc-analyzer"; -my $CmdCXX = "$AbsRealBin/libexec/c++-analyzer"; +my $Cmd = "$AbsRealBin/../libexec/ccc-analyzer"; +my $CmdCXX = "$AbsRealBin/../libexec/c++-analyzer"; # Portability: use less strict but portable check -e (file exists) instead of # non-portable -x (file is executable). On some windows ports -x just checks @@ -1659,63 +1757,72 @@ if (!defined $CmdCXX || ! -e $CmdCXX) { Diag("Using '$Clang' for static analysis\n"); -SetHtmlEnv(\@ARGV, $HtmlDir); -if ($AnalyzeHeaders) { push @AnalysesToRun,"-analyzer-opt-analyze-headers"; } -if ($AnalyzerStats) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; } -if ($MaxLoop > 0) { push @AnalysesToRun, "-analyzer-max-loop $MaxLoop"; } +SetHtmlEnv(\@ARGV, $Options{OutputDir}); + +my @AnalysesToRun; +foreach (sort { $Options{EnableCheckers}{$a} <=> $Options{EnableCheckers}{$b} } + keys %{$Options{EnableCheckers}}) { + # Push checkers in order they were enabled. + push @AnalysesToRun, "-analyzer-checker", $_; +} +foreach (sort { $Options{DisableCheckers}{$a} <=> $Options{DisableCheckers}{$b} } + keys %{$Options{DisableCheckers}}) { + # Push checkers in order they were disabled. + push @AnalysesToRun, "-analyzer-disable-checker", $_; +} +if ($Options{AnalyzeHeaders}) { push @AnalysesToRun, "-analyzer-opt-analyze-headers"; } +if ($Options{AnalyzerStats}) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; } +if ($Options{MaxLoop} > 0) { push @AnalysesToRun, "-analyzer-max-loop $Options{MaxLoop}"; } # Delay setting up other environment variables in case we can do true # interposition. -my $CCC_ANALYZER_ANALYSIS = join ' ',@AnalysesToRun; -my $CCC_ANALYZER_PLUGINS = join ' ',@PluginsToLoad; -my $CCC_ANALYZER_CONFIG = join ' ',@ConfigOptions; -my %Options = ( +my $CCC_ANALYZER_ANALYSIS = join ' ', @AnalysesToRun; +my $CCC_ANALYZER_PLUGINS = join ' ', map { "-load ".$_ } @{$Options{PluginsToLoad}}; +my $CCC_ANALYZER_CONFIG = join ' ', map { "-analyzer-config ".$_ } @{$Options{ConfigOptions}}; +my %EnvVars = ( 'CC' => $Cmd, 'CXX' => $CmdCXX, 'CLANG' => $Clang, 'CLANG_CXX' => $ClangCXX, - 'VERBOSE' => $Verbose, + 'VERBOSE' => $Options{Verbose}, 'CCC_ANALYZER_ANALYSIS' => $CCC_ANALYZER_ANALYSIS, 'CCC_ANALYZER_PLUGINS' => $CCC_ANALYZER_PLUGINS, 'CCC_ANALYZER_CONFIG' => $CCC_ANALYZER_CONFIG, - 'OUTPUT_DIR' => $HtmlDir + 'OUTPUT_DIR' => $Options{OutputDir}, + 'CCC_CC' => $Options{UseCC}, + 'CCC_CXX' => $Options{UseCXX}, + 'CCC_REPORT_FAILURES' => $Options{ReportFailures}, + 'CCC_ANALYZER_STORE_MODEL' => $Options{StoreModel}, + 'CCC_ANALYZER_CONSTRAINTS_MODEL' => $Options{ConstraintsModel}, + 'CCC_ANALYZER_INTERNAL_STATS' => $Options{InternalStats}, + 'CCC_ANALYZER_OUTPUT_FORMAT' => $Options{OutputFormat}, + 'CLANG_ANALYZER_TARGET' => $Options{AnalyzerTarget} ); -if (defined $StoreModel) { - $Options{'CCC_ANALYZER_STORE_MODEL'} = $StoreModel; -} -if (defined $ConstraintsModel) { - $Options{'CCC_ANALYZER_CONSTRAINTS_MODEL'} = $ConstraintsModel; -} -if (defined $InternalStats) { - $Options{'CCC_ANALYZER_INTERNAL_STATS'} = 1; -} -if (defined $OutputFormat) { - $Options{'CCC_ANALYZER_OUTPUT_FORMAT'} = $OutputFormat; -} - # Run the build. -my $ExitStatus = RunBuildCommand(\@ARGV, $IgnoreErrors, $Cmd, $CmdCXX, - \%Options); +my $ExitStatus = RunBuildCommand(\@ARGV, $Options{IgnoreErrors}, $Cmd, $CmdCXX, + \%EnvVars); -if (defined $OutputFormat) { - if ($OutputFormat =~ /plist/) { +if (defined $Options{OutputFormat}) { + if ($Options{OutputFormat} =~ /plist/) { Diag "Analysis run complete.\n"; - Diag "Analysis results (plist files) deposited in '$HtmlDir'\n"; + Diag "Analysis results (plist files) deposited in '$Options{OutputDir}'\n"; } - if ($OutputFormat =~ /html/) { + if ($Options{OutputFormat} =~ /html/) { # Postprocess the HTML directory. - my $NumBugs = Postprocess($HtmlDir, $BaseDir, $AnalyzerStats, $KeepEmpty); + my $NumBugs = Postprocess($Options{OutputDir}, $BaseDir, + $Options{AnalyzerStats}, $Options{KeepEmpty}); - if ($ViewResults and -r "$HtmlDir/index.html") { + if ($Options{ViewResults} and -r "$Options{OutputDir}/index.html") { Diag "Analysis run complete.\n"; - Diag "Viewing analysis results in '$HtmlDir' using scan-view.\n"; + Diag "Viewing analysis results in '$Options{OutputDir}' using scan-view.\n"; my $ScanView = Cwd::realpath("$RealBin/scan-view"); if (! -x $ScanView) { $ScanView = "scan-view"; } - exec $ScanView, "$HtmlDir"; + if (! -x $ScanView) { $ScanView = Cwd::realpath("$RealBin/../../scan-view/bin/scan-view"); } + exec $ScanView, "$Options{OutputDir}"; } - if ($ExitStatusFoundBugs) { + if ($Options{ExitStatusFoundBugs}) { exit 1 if ($NumBugs > 0); exit 0; } diff --git a/tools/scan-build/scan-build.bat b/tools/scan-build/bin/scan-build.bat index 77be6746318f1..77be6746318f1 100644 --- a/tools/scan-build/scan-build.bat +++ b/tools/scan-build/bin/scan-build.bat diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/bin/set-xcode-analyzer index 8e674823ba66c..8e674823ba66c 100755 --- a/tools/scan-build/set-xcode-analyzer +++ b/tools/scan-build/bin/set-xcode-analyzer diff --git a/tools/scan-build/c++-analyzer b/tools/scan-build/libexec/c++-analyzer index dda5db9c7d925..dda5db9c7d925 100755 --- a/tools/scan-build/c++-analyzer +++ b/tools/scan-build/libexec/c++-analyzer diff --git a/tools/scan-build/c++-analyzer.bat b/tools/scan-build/libexec/c++-analyzer.bat index 69f048a91671f..69f048a91671f 100644 --- a/tools/scan-build/c++-analyzer.bat +++ b/tools/scan-build/libexec/c++-analyzer.bat diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/libexec/ccc-analyzer index 14591aef57c87..831dd42e9c9c0 100755 --- a/tools/scan-build/ccc-analyzer +++ b/tools/scan-build/libexec/ccc-analyzer @@ -68,6 +68,7 @@ my $Clang; my $DefaultCCompiler; my $DefaultCXXCompiler; my $IsCXX; +my $AnalyzerTarget; # If on OSX, use xcrun to determine the SDK root. my $UseXCRUN = 0; @@ -104,6 +105,8 @@ else { $IsCXX = 0 } +$AnalyzerTarget = $ENV{'CLANG_ANALYZER_TARGET'}; + ##===----------------------------------------------------------------------===## # Cleanup. ##===----------------------------------------------------------------------===## @@ -245,6 +248,10 @@ sub Analyze { push @Args, "-Xclang", "-analyzer-viz-egraph-ubigraph"; } + if (defined $AnalyzerTarget) { + push @Args, "-target", $AnalyzerTarget; + } + my $AnalysisArgs = GetCCArgs($HtmlDir, "--analyze", \@Args); @CmdArgs = @$AnalysisArgs; } @@ -275,7 +282,7 @@ sub Analyze { # We save the output file in the 'crashes' directory if clang encounters # any problems with the file. my ($ofh, $ofile) = tempfile("clang_output_XXXXXX", DIR => $HtmlDir); - + my $OutputStream = silent_system($HtmlDir, $Cmd, @CmdArgs); while ( <$OutputStream> ) { print $ofh $_; @@ -579,7 +586,7 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) { } # Compile mode flags. - if ($Arg =~ /^-[D,I,U,isystem](.*)$/) { + if ($Arg =~ /^-(?:[DIU]|isystem)(.*)$/) { my $Tmp = $Arg; if ($1 eq '') { # FIXME: Check if we are going off the end. @@ -660,6 +667,15 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) { next; } + # Handle -Xclang some-arg. Add both arguments to the compiler options. + if ($Arg =~ /^-Xclang$/) { + # FIXME: Check if we are going off the end. + ++$i; + push @CompileOpts, $Arg; + push @CompileOpts, $ARGV[$i]; + next; + } + if (!($Arg =~ /^-/)) { push @Files, $Arg; next; diff --git a/tools/scan-build/ccc-analyzer.bat b/tools/scan-build/libexec/ccc-analyzer.bat index 2a85376eb82b1..2a85376eb82b1 100644 --- a/tools/scan-build/ccc-analyzer.bat +++ b/tools/scan-build/libexec/ccc-analyzer.bat diff --git a/tools/scan-build/scan-build.1 b/tools/scan-build/man/scan-build.1 index 57333642ce168..fd18d1f5c70a2 100644 --- a/tools/scan-build/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 201182 2014-02-11 21:37:27Z sylvestre $ +.\" $Id: scan-build.1 253074 2015-11-13 20:34:15Z jroelofs $ .Dd May 25, 2012 .Dt SCAN-BUILD 1 .Os "clang" "3.5" diff --git a/tools/scan-build/scanview.css b/tools/scan-build/share/scan-build/scanview.css index cf8a5a6ad470c..cf8a5a6ad470c 100644 --- a/tools/scan-build/scanview.css +++ b/tools/scan-build/share/scan-build/scanview.css diff --git a/tools/scan-build/sorttable.js b/tools/scan-build/share/scan-build/sorttable.js index 32faa078d8993..32faa078d8993 100644 --- a/tools/scan-build/sorttable.js +++ b/tools/scan-build/share/scan-build/sorttable.js diff --git a/tools/scan-view/CMakeLists.txt b/tools/scan-view/CMakeLists.txt new file mode 100644 index 0000000000000..b305ca562a72b --- /dev/null +++ b/tools/scan-view/CMakeLists.txt @@ -0,0 +1,41 @@ +option(CLANG_INSTALL_SCANVIEW "Install the scan-view tool" ON) + +set(BinFiles + scan-view) + +set(ShareFiles + ScanView.py + Reporter.py + startfile.py + FileRadar.scpt + GetRadarVersion.scpt + bugcatcher.ico) + +if(CLANG_INSTALL_SCANVIEW) + foreach(BinFile ${BinFiles}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/${BinFile} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/bin + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile} + ${CMAKE_BINARY_DIR}/bin/ + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bin/${BinFile}) + list(APPEND Depends ${CMAKE_BINARY_DIR}/bin/${BinFile}) + install(PROGRAMS bin/${BinFile} DESTINATION bin) + endforeach() + + foreach(ShareFile ${ShareFiles}) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/share/scan-view/${ShareFile} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/share/scan-view + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/share/${ShareFile} + ${CMAKE_BINARY_DIR}/share/scan-view/ + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/share/${ShareFile}) + list(APPEND Depends ${CMAKE_BINARY_DIR}/share/scan-view/${ShareFile}) + install(FILES share/${ShareFile} DESTINATION share/scan-view) + endforeach() + + add_custom_target(scan-view ALL DEPENDS ${Depends}) + set_target_properties(scan-view PROPERTIES FOLDER "Misc") +endif() diff --git a/tools/scan-view/Makefile b/tools/scan-view/Makefile new file mode 100644 index 0000000000000..37e4404d6f833 --- /dev/null +++ b/tools/scan-view/Makefile @@ -0,0 +1,37 @@ +##===- tools/scan-view/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. + +include $(CLANG_LEVEL)/../../Makefile.config +include $(CLANG_LEVEL)/Makefile + +CLANG_INSTALL_SCANVIEW ?= 1 + +ifeq ($(CLANG_INSTALL_SCANVIEW), 1) + InstallTargets := $(ToolDir)/scan-view \ + $(ShareDir)/scan-view/Reporter.py \ + $(ShareDir)/scan-view/ScanView.py \ + $(ShareDir)/scan-view/startfile.py \ + $(ShareDir)/scan-view/FileRadar.scpt \ + $(ShareDir)/scan-view/GetRadarVersion.scpt \ + $(ShareDir)/scan-view/bugcatcher.ico +endif + +all:: $(InstallTargets) + +$(ToolDir)/%: bin/% Makefile $(ToolDir)/.dir + $(Echo) "Copying $(notdir $<) to the 'bin' directory..." + $(Verb)cp $< $@ + $(Verb)chmod +x $@ + +$(ShareDir)/scan-view/%: share/% Makefile $(ShareDir)/scan-view/.dir + $(Echo) "Copying $(notdir $<) to the 'share' directory..." + $(Verb)cp $< $@ + diff --git a/tools/scan-view/bin/scan-view b/tools/scan-view/bin/scan-view new file mode 100755 index 0000000000000..1b6e8ba90dfac --- /dev/null +++ b/tools/scan-view/bin/scan-view @@ -0,0 +1,143 @@ +#!/usr/bin/env python + +"""The clang static analyzer results viewer. +""" + +import sys +import imp +import os +import posixpath +import thread +import time +import urllib +import webbrowser + +# How long to wait for server to start. +kSleepTimeout = .05 +kMaxSleeps = int(60 / kSleepTimeout) + +# Default server parameters + +kDefaultHost = '127.0.0.1' +kDefaultPort = 8181 +kMaxPortsToTry = 100 + +### + + +def url_is_up(url): + try: + o = urllib.urlopen(url) + except IOError: + return False + o.close() + return True + + +def start_browser(port, options): + import urllib + import webbrowser + + url = 'http://%s:%d' % (options.host, port) + + # Wait for server to start... + if options.debug: + sys.stderr.write('%s: Waiting for server.' % sys.argv[0]) + sys.stderr.flush() + for i in range(kMaxSleeps): + if url_is_up(url): + break + if options.debug: + sys.stderr.write('.') + sys.stderr.flush() + time.sleep(kSleepTimeout) + else: + print >> sys.stderr, 'WARNING: Unable to detect that server started.' + + if options.debug: + print >> sys.stderr, '%s: Starting webbrowser...' % sys.argv[0] + webbrowser.open(url) + + +def run(port, options, root): + # Prefer to look relative to the installed binary + share = os.path.dirname(__file__) + "/../share/scan-view" + if not os.path.isdir(share): + # Otherwise look relative to the source + share = os.path.dirname(__file__) + "/../../scan-view/share" + sys.path.append(share) + + import ScanView + try: + print 'Starting scan-view at: http://%s:%d' % (options.host, + port) + print ' Use Ctrl-C to exit.' + httpd = ScanView.create_server((options.host, port), + options, root) + httpd.serve_forever() + except KeyboardInterrupt: + pass + + +def port_is_open(port): + import SocketServer + try: + t = SocketServer.TCPServer((kDefaultHost, port), None) + except: + return False + t.server_close() + return True + + +def main(): + import argparse + parser = argparse.ArgumentParser(description="The clang static analyzer " + "results viewer.") + parser.add_argument("root", metavar="<results directory>", type=str) + parser.add_argument( + '--host', dest="host", default=kDefaultHost, type=str, + help="Host interface to listen on. (default=%s)" % kDefaultHost) + parser.add_argument('--port', dest="port", default=None, type=int, + help="Port to listen on. (default=%s)" % kDefaultPort) + parser.add_argument("--debug", dest="debug", default=0, + action="count", + help="Print additional debugging information.") + parser.add_argument("--auto-reload", dest="autoReload", default=False, + action="store_true", + help="Automatically update module for each request.") + parser.add_argument("--no-browser", dest="startBrowser", default=True, + action="store_false", + help="Don't open a webbrowser on startup.") + parser.add_argument("--allow-all-hosts", dest="onlyServeLocal", + default=True, action="store_false", + help='Allow connections from any host (access ' + 'restricted to "127.0.0.1" by default)') + args = parser.parse_args() + + # Make sure this directory is in a reasonable state to view. + if not posixpath.exists(posixpath.join(args.root, 'index.html')): + parser.error('Invalid directory, analysis results not found!') + + # Find an open port. We aren't particularly worried about race + # conditions here. Note that if the user specified a port we only + # use that one. + if args.port is not None: + port = args.port + else: + for i in range(kMaxPortsToTry): + if port_is_open(kDefaultPort + i): + port = kDefaultPort + i + break + else: + parser.error('Unable to find usable port in [%d,%d)' % + (kDefaultPort, kDefaultPort+kMaxPortsToTry)) + + # Kick off thread to wait for server and start web browser, if + # requested. + if args.startBrowser: + t = thread.start_new_thread(start_browser, (port, args)) + + run(port, args, args.root) + +if __name__ == '__main__': + main() diff --git a/tools/scan-view/scan-view b/tools/scan-view/scan-view deleted file mode 100755 index fb27da698882e..0000000000000 --- a/tools/scan-view/scan-view +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python - -"""The clang static analyzer results viewer. -""" - -import sys -import posixpath -import thread -import time -import urllib -import webbrowser - -# How long to wait for server to start. -kSleepTimeout = .05 -kMaxSleeps = int(60 / kSleepTimeout) - -# Default server parameters - -kDefaultHost = '127.0.0.1' -kDefaultPort = 8181 -kMaxPortsToTry = 100 - -### - -def url_is_up(url): - try: - o = urllib.urlopen(url) - except IOError: - return False - o.close() - return True - -def start_browser(port, options): - import urllib, webbrowser - - url = 'http://%s:%d'%(options.host, port) - - # Wait for server to start... - if options.debug: - sys.stderr.write('%s: Waiting for server.' % sys.argv[0]) - sys.stderr.flush() - for i in range(kMaxSleeps): - if url_is_up(url): - break - if options.debug: - sys.stderr.write('.') - sys.stderr.flush() - time.sleep(kSleepTimeout) - else: - print >>sys.stderr,'WARNING: Unable to detect that server started.' - - if options.debug: - print >>sys.stderr,'%s: Starting webbrowser...' % sys.argv[0] - webbrowser.open(url) - -def run(port, options, root): - import ScanView - try: - print 'Starting scan-view at: http://%s:%d'%(options.host, - port) - print ' Use Ctrl-C to exit.' - httpd = ScanView.create_server((options.host, port), - options, root) - httpd.serve_forever() - except KeyboardInterrupt: - pass - -def port_is_open(port): - import SocketServer - try: - t = SocketServer.TCPServer((kDefaultHost,port),None) - except: - return False - t.server_close() - return True - -def main(): - from optparse import OptionParser - parser = OptionParser('usage: %prog [options] <results directory>') - parser.set_description(__doc__) - parser.add_option( - '--host', dest="host", default=kDefaultHost, type="string", - help="Host interface to listen on. (default=%s)" % kDefaultHost) - parser.add_option( - '--port', dest="port", default=None, type="int", - help="Port to listen on. (default=%s)" % kDefaultPort) - parser.add_option("--debug", dest="debug", default=0, - action="count", - help="Print additional debugging information.") - parser.add_option("--auto-reload", dest="autoReload", default=False, - action="store_true", - help="Automatically update module for each request.") - parser.add_option("--no-browser", dest="startBrowser", default=True, - action="store_false", - help="Don't open a webbrowser on startup.") - parser.add_option("--allow-all-hosts", dest="onlyServeLocal", default=True, - action="store_false", - help='Allow connections from any host (access restricted to "127.0.0.1" by default)') - (options, args) = parser.parse_args() - - if len(args) != 1: - parser.error('No results directory specified.') - root, = args - - # Make sure this directory is in a reasonable state to view. - if not posixpath.exists(posixpath.join(root,'index.html')): - parser.error('Invalid directory, analysis results not found!') - - # Find an open port. We aren't particularly worried about race - # conditions here. Note that if the user specified a port we only - # use that one. - if options.port is not None: - port = options.port - else: - for i in range(kMaxPortsToTry): - if port_is_open(kDefaultPort + i): - port = kDefaultPort + i - break - else: - parser.error('Unable to find usable port in [%d,%d)'%(kDefaultPort, - kDefaultPort+kMaxPortsToTry)) - - # Kick off thread to wait for server and start web browser, if - # requested. - if options.startBrowser: - t = thread.start_new_thread(start_browser, (port,options)) - - run(port, options, root) - -if __name__ == '__main__': - main() diff --git a/tools/scan-view/Resources/FileRadar.scpt b/tools/scan-view/share/FileRadar.scpt Binary files differindex 1c7455285ccb0..1c7455285ccb0 100644 --- a/tools/scan-view/Resources/FileRadar.scpt +++ b/tools/scan-view/share/FileRadar.scpt diff --git a/tools/scan-view/Resources/GetRadarVersion.scpt b/tools/scan-view/share/GetRadarVersion.scpt index e69de29bb2d1d..e69de29bb2d1d 100644 --- a/tools/scan-view/Resources/GetRadarVersion.scpt +++ b/tools/scan-view/share/GetRadarVersion.scpt diff --git a/tools/scan-view/Reporter.py b/tools/scan-view/share/Reporter.py index 9560fc1aabbb3..294e05b44c251 100644 --- a/tools/scan-view/Reporter.py +++ b/tools/scan-view/share/Reporter.py @@ -175,7 +175,7 @@ class RadarReporter: @staticmethod def isAvailable(): # FIXME: Find this .scpt better - path = os.path.join(os.path.dirname(__file__),'Resources/GetRadarVersion.scpt') + path = os.path.join(os.path.dirname(__file__),'../share/scan-view/GetRadarVersion.scpt') try: p = subprocess.Popen(['osascript',path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -206,7 +206,7 @@ class RadarReporter: if not componentVersion.strip(): componentVersion = 'X' - script = os.path.join(os.path.dirname(__file__),'Resources/FileRadar.scpt') + script = os.path.join(os.path.dirname(__file__),'../share/scan-view/FileRadar.scpt') args = ['osascript', script, component, componentVersion, classification, personID, report.title, report.description, diagnosis, config] + map(os.path.abspath, report.files) # print >>sys.stderr, args diff --git a/tools/scan-view/ScanView.py b/tools/scan-view/share/ScanView.py index ee08baa8bad05..7dc0351ebe7f5 100644 --- a/tools/scan-view/ScanView.py +++ b/tools/scan-view/share/ScanView.py @@ -73,7 +73,7 @@ kReportReplacements.append((re.compile('<!-- REPORTSUMMARYEXTRA -->'), ### # Other simple parameters -kResources = posixpath.join(posixpath.dirname(__file__), 'Resources') +kShare = posixpath.join(posixpath.dirname(__file__), '../share/scan-view') kConfigPath = os.path.expanduser('~/.scanview.cfg') ### @@ -680,7 +680,7 @@ File Bug</h3> overrides['Radar']['Component Version'] = 'X' return self.send_report(None, overrides) elif name=='favicon.ico': - return self.send_path(posixpath.join(kResources,'bugcatcher.ico')) + return self.send_path(posixpath.join(kShare,'bugcatcher.ico')) # Match directory entries. if components[-1] == '': diff --git a/tools/scan-view/Resources/bugcatcher.ico b/tools/scan-view/share/bugcatcher.ico Binary files differindex 22d39b592036d..22d39b592036d 100644 --- a/tools/scan-view/Resources/bugcatcher.ico +++ b/tools/scan-view/share/bugcatcher.ico diff --git a/tools/scan-view/startfile.py b/tools/scan-view/share/startfile.py index e8fbe2d5a84ee..e8fbe2d5a84ee 100644 --- a/tools/scan-view/startfile.py +++ b/tools/scan-view/share/startfile.py |
