aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:18:08 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:18:08 +0000
commitbab175ec4b075c8076ba14c762900392533f6ee4 (patch)
tree01f4f29419a2cb10abe13c1e63cd2a66068b0137 /tools
parent8b7a8012d223fac5d17d16a66bb39168a9a1dfc0 (diff)
downloadsrc-bab175ec4b075c8076ba14c762900392533f6ee4.tar.gz
src-bab175ec4b075c8076ba14c762900392533f6ee4.zip
Vendor import of clang trunk r290819:vendor/clang/clang-trunk-r290819
Notes
Notes: svn path=/vendor/clang/dist/; revision=311118 svn path=/vendor/clang/clang-trunk-r290819/; revision=311119; tag=vendor/clang/clang-trunk-r290819
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt2
-rw-r--r--tools/arcmt-test/arcmt-test.cpp6
-rw-r--r--tools/c-index-test/c-index-test.c54
-rw-r--r--tools/c-index-test/core_main.cpp7
-rw-r--r--tools/clang-format-vs/.gitignore12
-rw-r--r--tools/clang-format-vs/CMakeLists.txt14
-rw-r--r--tools/clang-format-vs/ClangFormat.sln4
-rw-r--r--tools/clang-format-vs/ClangFormat/ClangFormat.csproj102
-rw-r--r--tools/clang-format-vs/ClangFormat/ClangFormat.vsct18
-rw-r--r--tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs92
-rw-r--r--tools/clang-format-vs/ClangFormat/PkgCmdID.cs3
-rw-r--r--tools/clang-format-vs/ClangFormat/Resources.Designer.cs2
-rw-r--r--tools/clang-format-vs/ClangFormat/packages.config22
-rw-r--r--tools/clang-format-vs/README.txt46
-rw-r--r--tools/clang-format/ClangFormat.cpp18
-rwxr-xr-xtools/clang-format/clang-format-diff.py2
-rw-r--r--tools/clang-format/clang-format.el89
-rw-r--r--tools/clang-format/clang-format.py28
-rwxr-xr-xtools/clang-format/git-clang-format159
-rw-r--r--tools/clang-fuzzer/ClangFuzzer.cpp1
-rw-r--r--tools/clang-import-test/CMakeLists.txt27
-rw-r--r--tools/clang-import-test/clang-import-test.cpp319
-rw-r--r--tools/clang-offload-bundler/CMakeLists.txt24
-rw-r--r--tools/clang-offload-bundler/ClangOffloadBundler.cpp1012
-rw-r--r--tools/diagtool/DiagTool.cpp1
-rw-r--r--tools/diagtool/TreeView.cpp1
-rw-r--r--tools/driver/CMakeLists.txt27
-rw-r--r--tools/driver/Info.plist.in2
-rw-r--r--tools/driver/cc1_main.cpp105
-rw-r--r--tools/driver/cc1as_main.cpp21
-rw-r--r--tools/driver/driver.cpp6
-rw-r--r--tools/libclang/ARCMigrate.cpp4
-rw-r--r--tools/libclang/BuildSystem.cpp4
-rw-r--r--tools/libclang/CIndex.cpp222
-rw-r--r--tools/libclang/CIndexCXX.cpp4
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp15
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp10
-rw-r--r--tools/libclang/CIndexHigh.cpp5
-rw-r--r--tools/libclang/CIndexInclusionStack.cpp4
-rw-r--r--tools/libclang/CIndexUSRs.cpp4
-rw-r--r--tools/libclang/CIndexer.cpp15
-rw-r--r--tools/libclang/CIndexer.h5
-rw-r--r--tools/libclang/CLog.h2
-rw-r--r--tools/libclang/CMakeLists.txt1
-rw-r--r--tools/libclang/CXComment.cpp7
-rw-r--r--tools/libclang/CXCompilationDatabase.cpp4
-rw-r--r--tools/libclang/CXCursor.cpp35
-rw-r--r--tools/libclang/CXIndexDataConsumer.cpp20
-rw-r--r--tools/libclang/CXIndexDataConsumer.h1
-rw-r--r--tools/libclang/CXLoadedDiagnostic.cpp4
-rw-r--r--tools/libclang/CXLoadedDiagnostic.h1
-rw-r--r--tools/libclang/CXSourceLocation.cpp21
-rw-r--r--tools/libclang/CXStoredDiagnostic.cpp3
-rw-r--r--tools/libclang/CXString.cpp4
-rw-r--r--tools/libclang/CXType.cpp90
-rw-r--r--tools/libclang/CursorVisitor.h3
-rw-r--r--tools/libclang/Indexing.cpp6
-rw-r--r--tools/libclang/libclang.exports4
-rw-r--r--tools/scan-build-py/libscanbuild/analyze.py3
-rw-r--r--tools/scan-build-py/libscanbuild/clang.py191
-rw-r--r--tools/scan-build-py/libscanbuild/report.py4
-rw-r--r--tools/scan-build-py/libscanbuild/runner.py13
-rw-r--r--tools/scan-build-py/tests/unit/test_clang.py62
-rw-r--r--tools/scan-build-py/tests/unit/test_report.py13
-rw-r--r--tools/scan-build-py/tests/unit/test_runner.py14
-rwxr-xr-xtools/scan-build/bin/scan-build32
66 files changed, 2528 insertions, 528 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index d734493c619e..b0c97f0f1e4c 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -5,6 +5,8 @@ add_clang_subdirectory(driver)
add_clang_subdirectory(clang-format)
add_clang_subdirectory(clang-format-vs)
add_clang_subdirectory(clang-fuzzer)
+add_clang_subdirectory(clang-import-test)
+add_clang_subdirectory(clang-offload-bundler)
add_clang_subdirectory(c-index-test)
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
index 900358ec1fe9..e57d69fddbe2 100644
--- a/tools/arcmt-test/arcmt-test.cpp
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -7,15 +7,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/PCHContainerOperations.h"
#include "clang/ARCMigrate/ARCMT.h"
-#include "clang/Frontend/ASTUnit.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Frontend/PCHContainerOperations.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include <system_error>
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 007af9e252a8..dfb4b27bce61 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -838,8 +838,11 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
if (Cursor.kind == CXCursor_FunctionDecl) {
/* Collect the template parameter kinds from the base template. */
- unsigned NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
- unsigned I;
+ int NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
+ int I;
+ if (NumTemplateArgs < 0) {
+ printf(" [no template arg info]");
+ }
for (I = 0; I < NumTemplateArgs; I++) {
enum CXTemplateArgumentKind TAK =
clang_Cursor_getTemplateArgumentKind(Cursor, I);
@@ -1313,6 +1316,25 @@ static enum CXVisitorResult FieldVisitor(CXCursor C,
return CXVisit_Continue;
}
+static void PrintTypeTemplateArgs(CXType T, const char *Format) {
+ int NumTArgs = clang_Type_getNumTemplateArguments(T);
+ if (NumTArgs != -1 && NumTArgs != 0) {
+ int i;
+ CXType TArg;
+ printf(Format, NumTArgs);
+ for (i = 0; i < NumTArgs; ++i) {
+ TArg = clang_Type_getTemplateArgumentAsType(T, i);
+ if (TArg.kind != CXType_Invalid) {
+ PrintTypeAndTypeKind(TArg, " [type=%s] [typekind=%s]");
+ }
+ }
+ /* Ensure that the returned type is invalid when indexing off-by-one. */
+ TArg = clang_Type_getTemplateArgumentAsType(T, i);
+ assert(TArg.kind == CXType_Invalid);
+ printf("]");
+ }
+}
+
static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
CXClientData d) {
if (!clang_isInvalid(clang_getCursorKind(cursor))) {
@@ -1330,11 +1352,14 @@ static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
printf(" lvalue-ref-qualifier");
if (RQ == CXRefQualifier_RValue)
printf(" rvalue-ref-qualifier");
+ /* Print the template argument types if they exist. */
+ PrintTypeTemplateArgs(T, " [templateargs/%d=");
/* Print the canonical type if it is different. */
{
CXType CT = clang_getCanonicalType(T);
if (!clang_equalTypes(T, CT)) {
PrintTypeAndTypeKind(CT, " [canonicaltype=%s] [canonicaltypekind=%s]");
+ PrintTypeTemplateArgs(CT, " [canonicaltemplateargs/%d=");
}
}
/* Print the return type if it exists. */
@@ -1359,21 +1384,6 @@ static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
printf("]");
}
}
- /* Print the template argument types if they exist. */
- {
- int NumTArgs = clang_Type_getNumTemplateArguments(T);
- if (NumTArgs != -1 && NumTArgs != 0) {
- int i;
- printf(" [templateargs/%d=", NumTArgs);
- for (i = 0; i < NumTArgs; ++i) {
- CXType TArg = clang_Type_getTemplateArgumentAsType(T, i);
- if (TArg.kind != CXType_Invalid) {
- PrintTypeAndTypeKind(TArg, " [type=%s] [typekind=%s]");
- }
- }
- printf("]");
- }
- }
/* Print if this is a non-POD type. */
printf(" [isPOD=%d]", clang_isPODType(T));
/* Print the pointee type. */
@@ -2459,8 +2469,14 @@ static void display_evaluate_results(CXEvalResult result) {
switch (clang_EvalResult_getKind(result)) {
case CXEval_Int:
{
- int val = clang_EvalResult_getAsInt(result);
- printf("Kind: Int , Value: %d", val);
+ printf("Kind: Int, ");
+ if (clang_EvalResult_isUnsignedInt(result)) {
+ unsigned long long val = clang_EvalResult_getAsUnsigned(result);
+ printf("unsigned, Value: %llu", val);
+ } else {
+ long long val = clang_EvalResult_getAsLongLong(result);
+ printf("Value: %lld", val);
+ }
break;
}
case CXEval_Float:
diff --git a/tools/c-index-test/core_main.cpp b/tools/c-index-test/core_main.cpp
index e64dae726fe3..3e4052c93ef5 100644
--- a/tools/c-index-test/core_main.cpp
+++ b/tools/c-index-test/core_main.cpp
@@ -41,8 +41,7 @@ static cl::opt<ActionType>
Action(cl::desc("Action:"), cl::init(ActionType::None),
cl::values(
clEnumValN(ActionType::PrintSourceSymbols,
- "print-source-symbols", "Print symbols from source"),
- clEnumValEnd),
+ "print-source-symbols", "Print symbols from source")),
cl::cat(IndexTestCoreCategory));
static cl::extrahelp MoreHelp(
@@ -168,9 +167,9 @@ static bool printSourceSymbols(ArrayRef<const char *> Args) {
static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS) {
OS << getSymbolKindString(SymInfo.Kind);
- if (SymInfo.SubKinds) {
+ if (SymInfo.Properties) {
OS << '(';
- printSymbolSubKinds(SymInfo.SubKinds, OS);
+ printSymbolProperties(SymInfo.Properties, OS);
OS << ')';
}
OS << '/' << getSymbolLanguageString(SymInfo.Lang);
diff --git a/tools/clang-format-vs/.gitignore b/tools/clang-format-vs/.gitignore
new file mode 100644
index 000000000000..c9d25d96c8ec
--- /dev/null
+++ b/tools/clang-format-vs/.gitignore
@@ -0,0 +1,12 @@
+# Visual Studio files
+.vs/
+*.user
+/packages/
+/ClangFormat/obj/
+/ClangFormat/bin/
+
+# Generated and copied files
+/ClangFormat/Key.snk
+/ClangFormat/license.txt
+/ClangFormat/clang-format.exe
+/ClangFormat/source.extension.vsixmanifest
diff --git a/tools/clang-format-vs/CMakeLists.txt b/tools/clang-format-vs/CMakeLists.txt
index fd0d6b028c66..d07a4f6ed5da 100644
--- a/tools/clang-format-vs/CMakeLists.txt
+++ b/tools/clang-format-vs/CMakeLists.txt
@@ -11,15 +11,25 @@ if (BUILD_CLANG_FORMAT_VS_PLUGIN)
"${CLANG_SOURCE_DIR}/LICENSE.TXT"
"${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat/license.txt")
+ # Build number added to Clang version to ensure that new VSIX can be upgraded
+ string(TIMESTAMP CLANG_FORMAT_VSIX_BUILD %y%m%d%H%M UTC)
+
if (NOT CLANG_FORMAT_VS_VERSION)
- set(CLANG_FORMAT_VS_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
+ set(CLANG_FORMAT_VS_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}.${CLANG_FORMAT_VSIX_BUILD}")
endif()
configure_file("source.extension.vsixmanifest.in"
"${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat/source.extension.vsixmanifest")
+ find_program(NUGET_EXE nuget PATHS ${NUGET_EXE_DIR})
+ if (NOT NUGET_EXE)
+ message(FATAL_ERROR "Could not find nuget.exe. Download from https://www.nuget.org/nuget.exe"
+ " and add parent directory to PATH or pass it via NUGET_EXE_DIR var.")
+ endif()
+
add_custom_target(clang_format_vsix ALL
- devenv "${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat.sln" /Build Release
+ COMMAND ${NUGET_EXE} restore "${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat.sln"
+ COMMAND devenv "${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat.sln" /Build Release
DEPENDS clang_format_exe_for_vsix "${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat/source.extension.vsixmanifest"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat/bin/Release/ClangFormat.vsix"
diff --git a/tools/clang-format-vs/ClangFormat.sln b/tools/clang-format-vs/ClangFormat.sln
index d6b211fe506f..73bf84e02858 100644
--- a/tools/clang-format-vs/ClangFormat.sln
+++ b/tools/clang-format-vs/ClangFormat.sln
@@ -1,6 +1,8 @@

Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClangFormat", "ClangFormat\ClangFormat.csproj", "{7FD1783E-2D31-4D05-BF23-6EBE1B42B608}"
EndProject
Global
diff --git a/tools/clang-format-vs/ClangFormat/ClangFormat.csproj b/tools/clang-format-vs/ClangFormat/ClangFormat.csproj
index a61e431cc0b9..5ce601d649bf 100644
--- a/tools/clang-format-vs/ClangFormat/ClangFormat.csproj
+++ b/tools/clang-format-vs/ClangFormat/ClangFormat.csproj
@@ -14,7 +14,7 @@
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>Key.snk</AssemblyOriginatorKeyFile>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
- <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
+ <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
@@ -35,6 +35,7 @@
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
+ <TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -44,6 +45,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
+ <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -53,27 +55,87 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<RunCodeAnalysis>true</RunCodeAnalysis>
+ <Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="envdte, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <HintPath>..\packages\VSSDK.DTE.7.0.3\lib\net20\envdte.dll</HintPath>
+ <EmbedInteropTypes>False</EmbedInteropTypes>
+ </Reference>
<Reference Include="Microsoft.CSharp" />
- <Reference Include="Microsoft.VisualStudio.CoreUtility, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
- <Reference Include="Microsoft.VisualStudio.Editor, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
- <Reference Include="Microsoft.VisualStudio.OLE.Interop" />
- <Reference Include="Microsoft.VisualStudio.Shell.Interop" />
- <Reference Include="Microsoft.VisualStudio.Shell.Interop.8.0" />
- <Reference Include="Microsoft.VisualStudio.Shell.Interop.9.0" />
+ <Reference Include="Microsoft.VisualStudio.CoreUtility, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\packages\VSSDK.CoreUtility.10.0.4\lib\net40\Microsoft.VisualStudio.CoreUtility.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.Editor, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\packages\VSSDK.Editor.10.0.4\lib\net40\Microsoft.VisualStudio.Editor.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.OLE.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <HintPath>..\packages\VSSDK.OLE.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.OLE.Interop.dll</HintPath>
+ <Private>True</Private>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.Shell.10.0, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\packages\VSSDK.Shell.10.10.0.3\lib\net40\Microsoft.VisualStudio.Shell.10.0.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.Shell.Immutable.10.0, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\packages\VSSDK.Shell.Immutable.10.10.0.3\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.Shell.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <HintPath>..\packages\VSSDK.Shell.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.Shell.Interop.dll</HintPath>
+ <Private>True</Private>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.Shell.Interop.8.0, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <HintPath>..\packages\VSSDK.Shell.Interop.8.8.0.3\lib\net20\Microsoft.VisualStudio.Shell.Interop.8.0.dll</HintPath>
+ <Private>True</Private>
+ <Private>False</Private>
+ </Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Interop.10.0" />
- <Reference Include="Microsoft.VisualStudio.TextManager.Interop" />
- <Reference Include="Microsoft.VisualStudio.Shell.10.0">
- <Private>false</Private>
- </Reference>
- <Reference Include="Microsoft.VisualStudio.Text.Data, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
- <Reference Include="Microsoft.VisualStudio.Text.Logic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
- <Reference Include="Microsoft.VisualStudio.Text.UI, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
- <Reference Include="Microsoft.VisualStudio.Text.UI.Wpf, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
- <Reference Include="Microsoft.VisualStudio.TextManager.Interop" />
- <Reference Include="Microsoft.VisualStudio.Shell.Immutable.10.0" />
+ <Reference Include="Microsoft.VisualStudio.Shell.Interop.9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <HintPath>..\packages\VSSDK.Shell.Interop.9.9.0.3\lib\net20\Microsoft.VisualStudio.Shell.Interop.9.0.dll</HintPath>
+ <Private>True</Private>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.Text.Data, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\packages\VSSDK.Text.10.0.4\lib\net40\Microsoft.VisualStudio.Text.Data.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.Text.Logic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\packages\VSSDK.Text.10.0.4\lib\net40\Microsoft.VisualStudio.Text.Logic.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.Text.UI, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\packages\VSSDK.Text.10.0.4\lib\net40\Microsoft.VisualStudio.Text.UI.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.Text.UI.Wpf, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\packages\VSSDK.Text.10.0.4\lib\net40\Microsoft.VisualStudio.Text.UI.Wpf.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.TextManager.Interop">
+ <HintPath>..\packages\VSSDK.TextManager.Interop.7.0.4\lib\net20\Microsoft.VisualStudio.TextManager.Interop.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.TextManager.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.TextManager.Interop.8.0, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <HintPath>..\packages\VSSDK.TextManager.Interop.8.8.0.4\lib\net20\Microsoft.VisualStudio.TextManager.Interop.8.0.dll</HintPath>
+ <Private>True</Private>
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ <Reference Include="stdole, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+ <HintPath>..\packages\VSSDK.DTE.7.0.3\lib\net20\stdole.dll</HintPath>
+ <EmbedInteropTypes>False</EmbedInteropTypes>
+ </Reference>
<Reference Include="System" />
+ <Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Design" />
@@ -81,6 +143,7 @@
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
+ <Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<COMReference Include="EnvDTE">
@@ -165,6 +228,7 @@
</ItemGroup>
<ItemGroup>
<None Include="Key.snk" />
+ <None Include="packages.config" />
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
</None>
@@ -219,7 +283,7 @@
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\VSSDK\Microsoft.VsSDK.targets" Condition="false" />
<PropertyGroup>
- <PreBuildEvent>if not exist $(ProjectDir)Key.snk ("$(FrameworkSDKDir)Bin\NETFX 4.5.1 Tools\sn.exe" -k $(ProjectDir)Key.snk)</PreBuildEvent>
+ <PreBuildEvent>if not exist $(ProjectDir)Key.snk ("$(FrameworkSDKDir)Bin\NETFX 4.6 Tools\sn.exe" -k $(ProjectDir)Key.snk)</PreBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
@@ -228,4 +292,4 @@
<Target Name="AfterBuild">
</Target>
-->
-</Project>
+</Project> \ No newline at end of file
diff --git a/tools/clang-format-vs/ClangFormat/ClangFormat.vsct b/tools/clang-format-vs/ClangFormat/ClangFormat.vsct
index 3e3e22e67d42..798957740d54 100644
--- a/tools/clang-format-vs/ClangFormat/ClangFormat.vsct
+++ b/tools/clang-format-vs/ClangFormat/ClangFormat.vsct
@@ -61,15 +61,21 @@
<CommandFlag>DynamicVisibility</CommandFlag>
If you do not want an image next to your command, remove the Icon node /> -->
- <Button guid="guidClangFormatCmdSet" id="cmdidClangFormat" priority="0x0100" type="Button">
+ <Button guid="guidClangFormatCmdSet" id="cmdidClangFormatSelection" priority="0x0100" type="Button">
<Parent guid="guidClangFormatCmdSet" id="MyMenuGroup" />
<Icon guid="guidImages" id="bmpPic1" />
<Strings>
- <ButtonText>ClangFormat</ButtonText>
+ <ButtonText>Clang Format Selection</ButtonText>
</Strings>
</Button>
-
+ <Button guid="guidClangFormatCmdSet" id="cmdidClangFormatDocument" priority="0x0101" type="Button">
+ <Parent guid="guidClangFormatCmdSet" id="MyMenuGroup" />
+ <Icon guid="guidImages" id="bmpPic2" />
+ <Strings>
+ <ButtonText>Clang Format Document</ButtonText>
+ </Strings>
+ </Button>
</Buttons>
@@ -88,7 +94,8 @@
<KeyBindings>
- <KeyBinding guid="guidClangFormatCmdSet" id="cmdidClangFormat" editor="guidTextEditor" key1="R" mod1="Control" key2="F" mod2="Control"/>
+ <KeyBinding guid="guidClangFormatCmdSet" id="cmdidClangFormatSelection" editor="guidTextEditor" key1="R" mod1="Control" key2="F" mod2="Control"/>
+ <KeyBinding guid="guidClangFormatCmdSet" id="cmdidClangFormatDocument" editor="guidTextEditor" key1="R" mod1="Control" key2="D" mod2="Control"/>
</KeyBindings>
@@ -101,7 +108,8 @@
<GuidSymbol name="guidClangFormatCmdSet" value="{e39cbab1-0f96-4022-a2bc-da5a9db7eb78}">
<IDSymbol name="MyMenuGroup" value="0x1020" />
- <IDSymbol name="cmdidClangFormat" value="0x0100" />
+ <IDSymbol name="cmdidClangFormatSelection" value="0x0100" />
+ <IDSymbol name="cmdidClangFormatDocument" value="0x0101" />
</GuidSymbol>
<GuidSymbol name="guidTextEditor" value="{8B382828-6202-11d1-8870-0000F87579D2}" />
diff --git a/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
index 6af2fd177f0f..c7eac42211ad 100644
--- a/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
+++ b/tools/clang-format-vs/ClangFormat/ClangFormatPackage.cs
@@ -180,15 +180,44 @@ namespace LLVM.ClangFormat
var commandService = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (commandService != null)
{
- var menuCommandID = new CommandID(GuidList.guidClangFormatCmdSet, (int)PkgCmdIDList.cmdidClangFormat);
- var menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
- commandService.AddCommand(menuItem);
+ {
+ var menuCommandID = new CommandID(GuidList.guidClangFormatCmdSet, (int)PkgCmdIDList.cmdidClangFormatSelection);
+ var menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
+ commandService.AddCommand(menuItem);
+ }
+
+ {
+ var menuCommandID = new CommandID(GuidList.guidClangFormatCmdSet, (int)PkgCmdIDList.cmdidClangFormatDocument);
+ var menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
+ commandService.AddCommand(menuItem);
+ }
}
}
#endregion
private void MenuItemCallback(object sender, EventArgs args)
{
+ var mc = sender as System.ComponentModel.Design.MenuCommand;
+ if (mc == null)
+ return;
+
+ switch (mc.CommandID.ID)
+ {
+ case (int)PkgCmdIDList.cmdidClangFormatSelection:
+ FormatSelection();
+ break;
+
+ case (int)PkgCmdIDList.cmdidClangFormatDocument:
+ FormatDocument();
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Runs clang-format on the current selection
+ /// </summary>
+ private void FormatSelection()
+ {
IWpfTextView view = GetCurrentView();
if (view == null)
// We're not in a text view.
@@ -197,24 +226,40 @@ namespace LLVM.ClangFormat
int start = view.Selection.Start.Position.GetContainingLine().Start.Position;
int end = view.Selection.End.Position.GetContainingLine().End.Position;
int length = end - start;
+
// clang-format doesn't support formatting a range that starts at the end
// of the file.
if (start >= text.Length && text.Length > 0)
start = text.Length - 1;
string path = GetDocumentParent(view);
string filePath = GetDocumentPath(view);
+
+ RunClangFormatAndApplyReplacements(text, start, length, path, filePath, view);
+ }
+
+ /// <summary>
+ /// Runs clang-format on the current document
+ /// </summary>
+ private void FormatDocument()
+ {
+ IWpfTextView view = GetCurrentView();
+ if (view == null)
+ // We're not in a text view.
+ return;
+
+ string filePath = GetDocumentPath(view);
+ var path = Path.GetDirectoryName(filePath);
+ string text = view.TextBuffer.CurrentSnapshot.GetText();
+
+ RunClangFormatAndApplyReplacements(text, 0, text.Length, path, filePath, view);
+ }
+
+ private void RunClangFormatAndApplyReplacements(string text, int offset, int length, string path, string filePath, IWpfTextView view)
+ {
try
{
- var root = XElement.Parse(RunClangFormat(text, start, length, path, filePath));
- var edit = view.TextBuffer.CreateEdit();
- foreach (XElement replacement in root.Descendants("replacement"))
- {
- var span = new Span(
- int.Parse(replacement.Attribute("offset").Value),
- int.Parse(replacement.Attribute("length").Value));
- edit.Replace(span, replacement.Value);
- }
- edit.Apply();
+ string replacements = RunClangFormat(text, offset, length, path, filePath);
+ ApplyClangFormatReplacements(replacements, view);
}
catch (Exception e)
{
@@ -305,6 +350,27 @@ namespace LLVM.ClangFormat
}
/// <summary>
+ /// Applies the clang-format replacements (xml) to the current view
+ /// </summary>
+ private void ApplyClangFormatReplacements(string replacements, IWpfTextView view)
+ {
+ // clang-format returns no replacements if input text is empty
+ if (replacements.Length == 0)
+ return;
+
+ var root = XElement.Parse(replacements);
+ var edit = view.TextBuffer.CreateEdit();
+ foreach (XElement replacement in root.Descendants("replacement"))
+ {
+ var span = new Span(
+ int.Parse(replacement.Attribute("offset").Value),
+ int.Parse(replacement.Attribute("length").Value));
+ edit.Replace(span, replacement.Value);
+ }
+ edit.Apply();
+ }
+
+ /// <summary>
/// Returns the currently active view if it is a IWpfTextView.
/// </summary>
private IWpfTextView GetCurrentView()
diff --git a/tools/clang-format-vs/ClangFormat/PkgCmdID.cs b/tools/clang-format-vs/ClangFormat/PkgCmdID.cs
index bb6b4559a98d..fcc31ee95b1e 100644
--- a/tools/clang-format-vs/ClangFormat/PkgCmdID.cs
+++ b/tools/clang-format-vs/ClangFormat/PkgCmdID.cs
@@ -2,6 +2,7 @@
{
static class PkgCmdIDList
{
- public const uint cmdidClangFormat = 0x100;
+ public const uint cmdidClangFormatSelection = 0x100;
+ public const uint cmdidClangFormatDocument = 0x101;
};
} \ No newline at end of file
diff --git a/tools/clang-format-vs/ClangFormat/Resources.Designer.cs b/tools/clang-format-vs/ClangFormat/Resources.Designer.cs
index a90251771da9..e3129b3db83a 100644
--- a/tools/clang-format-vs/ClangFormat/Resources.Designer.cs
+++ b/tools/clang-format-vs/ClangFormat/Resources.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.34209
+// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
diff --git a/tools/clang-format-vs/ClangFormat/packages.config b/tools/clang-format-vs/ClangFormat/packages.config
new file mode 100644
index 000000000000..38f64ed3a615
--- /dev/null
+++ b/tools/clang-format-vs/ClangFormat/packages.config
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="VSSDK.CoreUtility" version="10.0.4" targetFramework="net40" />
+ <package id="VSSDK.CoreUtility.10" version="10.0.4" targetFramework="net40" />
+ <package id="VSSDK.DTE" version="7.0.3" targetFramework="net40" />
+ <package id="VSSDK.Editor" version="10.0.4" targetFramework="net40" />
+ <package id="VSSDK.Editor.10" version="10.0.4" targetFramework="net40" />
+ <package id="VSSDK.IDE" version="7.0.4" targetFramework="net40" />
+ <package id="VSSDK.IDE.10" version="10.0.4" targetFramework="net40" />
+ <package id="VSSDK.IDE.8" version="8.0.4" targetFramework="net40" />
+ <package id="VSSDK.IDE.9" version="9.0.3" targetFramework="net40" />
+ <package id="VSSDK.OLE.Interop" version="7.0.4" targetFramework="net40" />
+ <package id="VSSDK.Shell.10" version="10.0.3" targetFramework="net40" />
+ <package id="VSSDK.Shell.Immutable.10" version="10.0.3" targetFramework="net40" />
+ <package id="VSSDK.Shell.Interop" version="7.0.4" targetFramework="net40" />
+ <package id="VSSDK.Shell.Interop.8" version="8.0.3" targetFramework="net40" />
+ <package id="VSSDK.Shell.Interop.9" version="9.0.3" targetFramework="net40" />
+ <package id="VSSDK.Text" version="10.0.4" targetFramework="net40" />
+ <package id="VSSDK.Text.10" version="10.0.4" targetFramework="net40" />
+ <package id="VSSDK.TextManager.Interop" version="7.0.4" targetFramework="net40" />
+ <package id="VSSDK.TextManager.Interop.8" version="8.0.4" targetFramework="net40" />
+</packages> \ No newline at end of file
diff --git a/tools/clang-format-vs/README.txt b/tools/clang-format-vs/README.txt
index b23355d0cebc..84e0b451f018 100644
--- a/tools/clang-format-vs/README.txt
+++ b/tools/clang-format-vs/README.txt
@@ -2,16 +2,50 @@ This directory contains a VSPackage project to generate a Visual Studio extensio
for clang-format.
Build prerequisites are:
-- Visual Studio 2013 Professional
-- Visual Studio 2013 SDK
-- Visual Studio 2010 Professional (?)
-- Visual Studio 2010 SDK (?)
+- Visual Studio 2015
+- Extensions SDK (you'll be prompted to install it if you open ClangFormat.sln)
-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.
+The extension is built using CMake to generate the usual LLVM.sln by setting
+the following CMake vars:
+
+- BUILD_CLANG_FORMAT_VS_PLUGIN=ON
+
+- NUGET_EXE_PATH=path/to/nuget_dir (unless nuget.exe is already available in PATH)
+
+example:
+ cd /d C:\code\llvm
+ mkdir build & cd build
+ cmake -DBUILD_CLANG_FORMAT_VS_PLUGIN=ON -DNUGET_EXE_PATH=C:\nuget ..
+
+Once LLVM.sln is generated, build the clang_format_vsix target, which will build
+ClangFormat.sln, the C# extension application.
The CMake build will copy clang-format.exe and LICENSE.TXT into the ClangFormat/
directory so they can be bundled with the plug-in, as well as creating
ClangFormat/source.extension.vsixmanifest. Once the plug-in has been built with
CMake once, it can be built manually from the ClangFormat.sln solution in Visual
Studio.
+
+===========
+ Debugging
+===========
+
+Once you've built the clang_format_vsix project from LLVM.sln at least once,
+open ClangFormat.sln in Visual Studio, then:
+
+- Make sure the "Debug" target is selected
+- Open the ClangFormat project properties
+- Select the Debug tab
+- Set "Start external program:" to where your devenv.exe is installed. Typically
+ it's "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe"
+- Set "Command line arguments" to: /rootsuffix Exp
+- You can now set breakpoints if you like
+- Press F5 to build and run with debugger
+
+If all goes well, a new instance of Visual Studio will be launched in a special
+mode where it uses the experimental hive instead of the normal configuration hive.
+By default, when you build a VSIX project in Visual Studio, it auto-registers the
+extension in the experimental hive, allowing you to test it. In the new Visual Studio
+instance, open or create a C++ solution, and you should now see the Clang Format
+entries in the Tool menu. You can test it out, and any breakpoints you set will be
+hit where you can debug as usual.
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp
index 27577a5a336a..6c50daf53834 100644
--- a/tools/clang-format/ClangFormat.cpp
+++ b/tools/clang-format/ClangFormat.cpp
@@ -20,9 +20,7 @@
#include "clang/Basic/Version.h"
#include "clang/Format/Format.h"
#include "clang/Rewrite/Core/Rewriter.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Signals.h"
@@ -251,7 +249,8 @@ static bool format(StringRef FileName) {
if (fillRanges(Code.get(), Ranges))
return true;
StringRef AssumedFileName = (FileName == "-") ? AssumeFileName : FileName;
- FormatStyle FormatStyle = getStyle(Style, AssumedFileName, FallbackStyle);
+ FormatStyle FormatStyle =
+ getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer());
if (SortIncludes.getNumOccurrences() != 0)
FormatStyle.SortIncludes = SortIncludes;
unsigned CursorPosition = Cursor;
@@ -262,23 +261,22 @@ static bool format(StringRef FileName) {
llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
return true;
}
- for (const auto &R : Replaces)
- Ranges.push_back({R.getOffset(), R.getLength()});
-
+ // Get new affected ranges after sorting `#includes`.
+ Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
bool IncompleteFormat = false;
Replacements FormatChanges = reformat(FormatStyle, *ChangedCode, Ranges,
AssumedFileName, &IncompleteFormat);
- Replaces = tooling::mergeReplacements(Replaces, FormatChanges);
+ Replaces = Replaces.merge(FormatChanges);
if (OutputXML) {
outs() << "<?xml version='1.0'?>\n<replacements "
"xml:space='preserve' incomplete_format='"
<< (IncompleteFormat ? "true" : "false") << "'>\n";
if (Cursor.getNumOccurrences() != 0)
outs() << "<cursor>"
- << tooling::shiftedCodePosition(FormatChanges, CursorPosition)
+ << FormatChanges.getShiftedCodePosition(CursorPosition)
<< "</cursor>\n";
- outputReplacementsXML(Replaces);
+ outputReplacementsXML(Replaces);
outs() << "</replacements>\n";
} else {
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
@@ -300,7 +298,7 @@ static bool format(StringRef FileName) {
} else {
if (Cursor.getNumOccurrences() != 0)
outs() << "{ \"Cursor\": "
- << tooling::shiftedCodePosition(FormatChanges, CursorPosition)
+ << FormatChanges.getShiftedCodePosition(CursorPosition)
<< ", \"IncompleteFormat\": "
<< (IncompleteFormat ? "true" : "false") << " }\n";
Rewrite.getEditBuffer(ID).write(outs());
diff --git a/tools/clang-format/clang-format-diff.py b/tools/clang-format/clang-format-diff.py
index 5e728f547169..ffa30e70ddc3 100755
--- a/tools/clang-format/clang-format-diff.py
+++ b/tools/clang-format/clang-format-diff.py
@@ -17,7 +17,7 @@ This script reads input from a unified diff and reformats all the changed
lines. This is useful to reformat all the lines touched by a specific patch.
Example usage for git/svn users:
- git diff -U0 HEAD^ | clang-format-diff.py -p1 -i
+ git diff -U0 --no-color HEAD^ | clang-format-diff.py -p1 -i
svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i
"""
diff --git a/tools/clang-format/clang-format.el b/tools/clang-format/clang-format.el
index ca461444e226..0ac2da3ad29a 100644
--- a/tools/clang-format/clang-format.el
+++ b/tools/clang-format/clang-format.el
@@ -1,4 +1,4 @@
-;;; clang-format.el --- Format code using clang-format
+;;; clang-format.el --- Format code using clang-format -*- lexical-binding: t; -*-
;; Keywords: tools, c
;; Package-Requires: ((cl-lib "0.3"))
@@ -15,7 +15,7 @@
;; M-x package-install clang-format
;;
;; when ("melpa" . "http://melpa.org/packages/") is included in
-;; `package-archives'. Alternatively, ensure the directory of this
+;; `package-archives'. Alternatively, ensure the directory of this
;; file is in your `load-path' and add
;;
;; (require 'clang-format)
@@ -42,7 +42,7 @@
A string containing the name or the full path of the executable."
:group 'clang-format
- :type 'string
+ :type '(file :must-match t)
:risky t)
(defcustom clang-format-style "file"
@@ -93,15 +93,32 @@ of the buffer."
(list replacements cursor (string= incomplete-format "true"))))
(defun clang-format--replace (offset length &optional text)
- (let ((start (byte-to-position (1+ offset)))
- (end (byte-to-position (+ 1 offset length))))
+ "Replace the region defined by OFFSET and LENGTH with TEXT.
+OFFSET and LENGTH are measured in bytes, not characters. OFFSET
+is a zero-based file offset."
+ (let ((start (clang-format--filepos-to-bufferpos offset 'exact))
+ (end (clang-format--filepos-to-bufferpos (+ offset length) 'exact)))
(goto-char start)
(delete-region start end)
(when text
(insert text))))
+;; ‘bufferpos-to-filepos’ and ‘filepos-to-bufferpos’ are new in Emacs 25.1.
+;; Provide fallbacks for older versions.
+(defalias 'clang-format--bufferpos-to-filepos
+ (if (fboundp 'bufferpos-to-filepos)
+ 'bufferpos-to-filepos
+ (lambda (position &optional _quality _coding-system)
+ (1- (position-bytes position)))))
+
+(defalias 'clang-format--filepos-to-bufferpos
+ (if (fboundp 'filepos-to-bufferpos)
+ 'filepos-to-bufferpos
+ (lambda (byte &optional _quality _coding-system)
+ (byte-to-position (1+ byte)))))
+
;;;###autoload
-(defun clang-format-region (char-start char-end &optional style)
+(defun clang-format-region (start end &optional style)
"Use clang-format to format the code between START and END according to STYLE.
If called interactively uses the region or the current statement if there
is no active region. If no style is given uses `clang-format-style'."
@@ -113,51 +130,41 @@ is no active region. If no style is given uses `clang-format-style'."
(unless style
(setq style clang-format-style))
- (let ((start (1- (position-bytes char-start)))
- (end (1- (position-bytes char-end)))
- (cursor (1- (position-bytes (point))))
+ (let ((file-start (clang-format--bufferpos-to-filepos start 'approximate))
+ (file-end (clang-format--bufferpos-to-filepos end 'approximate))
+ (cursor (clang-format--bufferpos-to-filepos (point) 'exact))
(temp-buffer (generate-new-buffer " *clang-format-temp*"))
(temp-file (make-temp-file "clang-format")))
(unwind-protect
- (let (status stderr operations)
- (setq status
- (call-process-region
- (point-min) (point-max) clang-format-executable
- nil `(,temp-buffer ,temp-file) nil
-
- "-output-replacements-xml"
- "-assume-filename" (or (buffer-file-name) "")
- "-style" style
- "-offset" (number-to-string start)
- "-length" (number-to-string (- end start))
- "-cursor" (number-to-string cursor)))
- (setq stderr
- (with-temp-buffer
- (insert-file-contents temp-file)
- (when (> (point-max) (point-min))
- (insert ": "))
- (buffer-substring-no-properties
- (point-min) (line-end-position))))
-
+ (let ((status (call-process-region
+ nil nil clang-format-executable
+ nil `(,temp-buffer ,temp-file) nil
+
+ "-output-replacements-xml"
+ "-assume-filename" (or (buffer-file-name) "")
+ "-style" style
+ "-offset" (number-to-string file-start)
+ "-length" (number-to-string (- file-end file-start))
+ "-cursor" (number-to-string cursor)))
+ (stderr (with-temp-buffer
+ (unless (zerop (cadr (insert-file-contents temp-file)))
+ (insert ": "))
+ (buffer-substring-no-properties
+ (point-min) (line-end-position)))))
(cond
((stringp status)
(error "(clang-format killed by signal %s%s)" status stderr))
- ((not (equal 0 status))
+ ((not (zerop status))
(error "(clang-format failed with code %d%s)" status stderr)))
- (with-current-buffer temp-buffer
- (setq operations (clang-format--extract (car (xml-parse-region)))))
-
- (let ((replacements (nth 0 operations))
- (cursor (nth 1 operations))
- (incomplete-format (nth 2 operations)))
+ (cl-destructuring-bind (replacements cursor incomplete-format)
+ (with-current-buffer temp-buffer
+ (clang-format--extract (car (xml-parse-region))))
(save-excursion
- (mapc (lambda (rpl)
- (apply #'clang-format--replace rpl))
- replacements))
+ (dolist (rpl replacements)
+ (apply #'clang-format--replace rpl)))
(when cursor
- (goto-char (byte-to-position (1+ cursor))))
- (message "%s" incomplete-format)
+ (goto-char (clang-format--filepos-to-bufferpos cursor 'exact)))
(if incomplete-format
(message "(clang-format: incomplete (syntax errors)%s)" stderr)
(message "(clang-format: success%s)" stderr))))
diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py
index 5cb41fcfa371..ae8a6ebf74e9 100644
--- a/tools/clang-format/clang-format.py
+++ b/tools/clang-format/clang-format.py
@@ -25,9 +25,11 @@
#
# It operates on the current, potentially unsaved buffer and does not create
# or save any files. To revert a formatting, just undo.
+from __future__ import print_function
import difflib
import json
+import platform
import subprocess
import sys
import vim
@@ -47,9 +49,15 @@ fallback_style = None
if vim.eval('exists("g:clang_format_fallback_style")') == "1":
fallback_style = vim.eval('g:clang_format_fallback_style')
+def get_buffer(encoding):
+ if platform.python_version_tuple()[0] == '3':
+ return vim.current.buffer
+ return [ line.decode(encoding) for line in vim.current.buffer ]
+
def main():
# Get the current text.
- buf = vim.current.buffer
+ encoding = vim.eval("&encoding")
+ buf = get_buffer(encoding)
text = '\n'.join(buf)
# Determine range to format.
@@ -61,7 +69,7 @@ def main():
# Determine the cursor position.
cursor = int(vim.eval('line2byte(line("."))+col(".")')) - 2
if cursor < 0:
- print 'Couldn\'t determine cursor position. Is your file empty?'
+ print('Couldn\'t determine cursor position. Is your file empty?')
return
# Avoid flashing an ugly, ugly cmd prompt on Windows when invoking clang-format.
@@ -82,25 +90,27 @@ def main():
p = subprocess.Popen(command,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
stdin=subprocess.PIPE, startupinfo=startupinfo)
- stdout, stderr = p.communicate(input=text)
+ stdout, stderr = p.communicate(input=text.encode(encoding))
# If successful, replace buffer contents.
if stderr:
- print stderr
+ print(stderr)
if not stdout:
- print ('No output from clang-format (crashed?).\n' +
- 'Please report to bugs.llvm.org.')
+ print(
+ 'No output from clang-format (crashed?).\n'
+ 'Please report to bugs.llvm.org.'
+ )
else:
- lines = stdout.split('\n')
+ lines = stdout.decode(encoding).split('\n')
output = json.loads(lines[0])
lines = lines[1:]
- sequence = difflib.SequenceMatcher(None, vim.current.buffer, lines)
+ sequence = difflib.SequenceMatcher(None, buf, lines)
for op in reversed(sequence.get_opcodes()):
if op[0] is not 'equal':
vim.current.buffer[op[1]:op[2]] = lines[op[3]:op[4]]
if output.get('IncompleteFormat'):
- print 'clang-format: incomplete (syntax errors)'
+ print('clang-format: incomplete (syntax errors)')
vim.command('goto %d' % (output['Cursor'] + 1))
main()
diff --git a/tools/clang-format/git-clang-format b/tools/clang-format/git-clang-format
index 0c45762ea515..74fd451a847b 100755
--- a/tools/clang-format/git-clang-format
+++ b/tools/clang-format/git-clang-format
@@ -32,12 +32,15 @@ import re
import subprocess
import sys
-usage = 'git clang-format [OPTIONS] [<commit>] [--] [<file>...]'
+usage = 'git clang-format [OPTIONS] [<commit>] [<commit>] [--] [<file>...]'
desc = '''
-Run clang-format on all lines that differ between the working directory
-and <commit>, which defaults to HEAD. Changes are only applied to the working
-directory.
+If zero or one commits are given, run clang-format on all lines that differ
+between the working directory and <commit>, which defaults to HEAD. Changes are
+only applied to the working directory.
+
+If two commits are given (requires --diff), run clang-format on all lines in the
+second <commit> that differ from the first <commit>.
The following git-config settings set the default of the corresponding option:
clangFormat.binary
@@ -77,6 +80,7 @@ def main():
'cc', 'cp', 'cpp', 'c++', 'cxx', 'hpp', # C++
# Other languages that clang-format supports
'proto', 'protodevel', # Protocol Buffers
+ 'java', # Java
'js', # JavaScript
'ts', # TypeScript
])
@@ -120,8 +124,14 @@ def main():
opts.verbose -= opts.quiet
del opts.quiet
- commit, files = interpret_args(opts.args, dash_dash, opts.commit)
- changed_lines = compute_diff_and_extract_lines(commit, files)
+ commits, files = interpret_args(opts.args, dash_dash, opts.commit)
+ if len(commits) > 1:
+ if not opts.diff:
+ die('--diff is required when two commits are given')
+ else:
+ if len(commits) > 2:
+ die('at most two commits allowed; %d given' % len(commits))
+ changed_lines = compute_diff_and_extract_lines(commits, files)
if opts.verbose >= 1:
ignored_files = set(changed_lines)
filter_by_extension(changed_lines, opts.extensions.lower().split(','))
@@ -141,10 +151,17 @@ def main():
# The computed diff outputs absolute paths, so we must cd before accessing
# those files.
cd_to_toplevel()
- old_tree = create_tree_from_workdir(changed_lines)
- new_tree = run_clang_format_and_save_to_tree(changed_lines,
- binary=opts.binary,
- style=opts.style)
+ if len(commits) > 1:
+ old_tree = commits[1]
+ new_tree = run_clang_format_and_save_to_tree(changed_lines,
+ revision=commits[1],
+ binary=opts.binary,
+ style=opts.style)
+ else:
+ old_tree = create_tree_from_workdir(changed_lines)
+ new_tree = run_clang_format_and_save_to_tree(changed_lines,
+ binary=opts.binary,
+ style=opts.style)
if opts.verbose >= 1:
print 'old tree:', old_tree
print 'new tree:', new_tree
@@ -181,40 +198,41 @@ def load_git_config(non_string_options=None):
def interpret_args(args, dash_dash, default_commit):
- """Interpret `args` as "[commit] [--] [files...]" and return (commit, files).
+ """Interpret `args` as "[commits] [--] [files]" and return (commits, files).
It is assumed that "--" and everything that follows has been removed from
args and placed in `dash_dash`.
- If "--" is present (i.e., `dash_dash` is non-empty), the argument to its
- left (if present) is taken as commit. Otherwise, the first argument is
- checked if it is a commit or a file. If commit is not given,
- `default_commit` is used."""
+ If "--" is present (i.e., `dash_dash` is non-empty), the arguments to its
+ left (if present) are taken as commits. Otherwise, the arguments are checked
+ from left to right if they are commits or files. If commits are not given,
+ a list with `default_commit` is used."""
if dash_dash:
if len(args) == 0:
- commit = default_commit
- elif len(args) > 1:
- die('at most one commit allowed; %d given' % len(args))
+ commits = [default_commit]
else:
- commit = args[0]
- object_type = get_object_type(commit)
- if object_type not in ('commit', 'tag'):
- if object_type is None:
- die("'%s' is not a commit" % commit)
- else:
- die("'%s' is a %s, but a commit was expected" % (commit, object_type))
+ commits = args
+ for commit in commits:
+ object_type = get_object_type(commit)
+ if object_type not in ('commit', 'tag'):
+ if object_type is None:
+ die("'%s' is not a commit" % commit)
+ else:
+ die("'%s' is a %s, but a commit was expected" % (commit, object_type))
files = dash_dash[1:]
elif args:
- if disambiguate_revision(args[0]):
- commit = args[0]
- files = args[1:]
- else:
- commit = default_commit
- files = args
+ commits = []
+ while args:
+ if not disambiguate_revision(args[0]):
+ break
+ commits.append(args.pop(0))
+ if not commits:
+ commits = [default_commit]
+ files = args
else:
- commit = default_commit
+ commits = [default_commit]
files = []
- return commit, files
+ return commits, files
def disambiguate_revision(value):
@@ -242,9 +260,9 @@ def get_object_type(value):
return stdout.strip()
-def compute_diff_and_extract_lines(commit, files):
+def compute_diff_and_extract_lines(commits, files):
"""Calls compute_diff() followed by extract_lines()."""
- diff_process = compute_diff(commit, files)
+ diff_process = compute_diff(commits, files)
changed_lines = extract_lines(diff_process.stdout)
diff_process.stdout.close()
diff_process.wait()
@@ -254,13 +272,17 @@ def compute_diff_and_extract_lines(commit, files):
return changed_lines
-def compute_diff(commit, files):
- """Return a subprocess object producing the diff from `commit`.
+def compute_diff(commits, files):
+ """Return a subprocess object producing the diff from `commits`.
The return value's `stdin` file object will produce a patch with the
- differences between the working directory and `commit`, filtered on `files`
- (if non-empty). Zero context lines are used in the patch."""
- cmd = ['git', 'diff-index', '-p', '-U0', commit, '--']
+ differences between the working directory and the first commit if a single
+ one was specified, or the difference between both specified commits, filtered
+ on `files` (if non-empty). Zero context lines are used in the patch."""
+ git_tool = 'diff-index'
+ if len(commits) > 1:
+ git_tool = 'diff-tree'
+ cmd = ['git', git_tool, '-p', '-U0'] + commits + ['--']
cmd.extend(files)
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p.stdin.close()
@@ -317,15 +339,26 @@ def create_tree_from_workdir(filenames):
return create_tree(filenames, '--stdin')
-def run_clang_format_and_save_to_tree(changed_lines, binary='clang-format',
- style=None):
+def run_clang_format_and_save_to_tree(changed_lines, revision=None,
+ binary='clang-format', style=None):
"""Run clang-format on each file and save the result to a git tree.
Returns the object ID (SHA-1) of the created tree."""
def index_info_generator():
for filename, line_ranges in changed_lines.iteritems():
- mode = oct(os.stat(filename).st_mode)
- blob_id = clang_format_to_blob(filename, line_ranges, binary=binary,
+ if revision:
+ git_metadata_cmd = ['git', 'ls-tree',
+ '%s:%s' % (revision, os.path.dirname(filename)),
+ os.path.basename(filename)]
+ git_metadata = subprocess.Popen(git_metadata_cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ stdout = git_metadata.communicate()[0]
+ mode = oct(int(stdout.split()[0], 8))
+ else:
+ mode = oct(os.stat(filename).st_mode)
+ blob_id = clang_format_to_blob(filename, line_ranges,
+ revision=revision,
+ binary=binary,
style=style)
yield '%s %s\t%s' % (mode, blob_id, filename)
return create_tree(index_info_generator(), '--index-info')
@@ -351,26 +384,42 @@ def create_tree(input_lines, mode):
return tree_id
-def clang_format_to_blob(filename, line_ranges, binary='clang-format',
- style=None):
+def clang_format_to_blob(filename, line_ranges, revision=None,
+ binary='clang-format', style=None):
"""Run clang-format on the given file and save the result to a git blob.
+ Runs on the file in `revision` if not None, or on the file in the working
+ directory if `revision` is None.
+
Returns the object ID (SHA-1) of the created blob."""
- clang_format_cmd = [binary, filename]
+ clang_format_cmd = [binary]
if style:
clang_format_cmd.extend(['-style='+style])
clang_format_cmd.extend([
'-lines=%s:%s' % (start_line, start_line+line_count-1)
for start_line, line_count in line_ranges])
+ if revision:
+ clang_format_cmd.extend(['-assume-filename='+filename])
+ git_show_cmd = ['git', 'cat-file', 'blob', '%s:%s' % (revision, filename)]
+ git_show = subprocess.Popen(git_show_cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ git_show.stdin.close()
+ clang_format_stdin = git_show.stdout
+ else:
+ clang_format_cmd.extend([filename])
+ git_show = None
+ clang_format_stdin = subprocess.PIPE
try:
- clang_format = subprocess.Popen(clang_format_cmd, stdin=subprocess.PIPE,
+ clang_format = subprocess.Popen(clang_format_cmd, stdin=clang_format_stdin,
stdout=subprocess.PIPE)
+ if clang_format_stdin == subprocess.PIPE:
+ clang_format_stdin = clang_format.stdin
except OSError as e:
if e.errno == errno.ENOENT:
die('cannot find executable "%s"' % binary)
else:
raise
- clang_format.stdin.close()
+ clang_format_stdin.close()
hash_object_cmd = ['git', 'hash-object', '-w', '--path='+filename, '--stdin']
hash_object = subprocess.Popen(hash_object_cmd, stdin=clang_format.stdout,
stdout=subprocess.PIPE)
@@ -380,6 +429,8 @@ def clang_format_to_blob(filename, line_ranges, binary='clang-format',
die('`%s` failed' % ' '.join(hash_object_cmd))
if clang_format.wait() != 0:
die('`%s` failed' % ' '.join(clang_format_cmd))
+ if git_show and git_show.wait() != 0:
+ die('`%s` failed' % ' '.join(git_show_cmd))
return stdout.rstrip('\r\n')
@@ -418,7 +469,12 @@ def print_diff(old_tree, new_tree):
# We use the porcelain 'diff' and not plumbing 'diff-tree' because the output
# is expected to be viewed by the user, and only the former does nice things
# like color and pagination.
- subprocess.check_call(['git', 'diff', old_tree, new_tree, '--'])
+ #
+ # We also only print modified files since `new_tree` only contains the files
+ # that were modified, so unmodified files would show as deleted without the
+ # filter.
+ subprocess.check_call(['git', 'diff', '--diff-filter=M', old_tree, new_tree,
+ '--'])
def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
@@ -426,7 +482,8 @@ def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
Bails if there are local changes in those files and not `force`. If
`patch_mode`, runs `git checkout --patch` to select hunks interactively."""
- changed_files = run('git', 'diff-tree', '-r', '-z', '--name-only', old_tree,
+ changed_files = run('git', 'diff-tree', '--diff-filter=M', '-r', '-z',
+ '--name-only', old_tree,
new_tree).rstrip('\0').split('\0')
if not force:
unstaged_files = run('git', 'diff-files', '--name-status', *changed_files)
diff --git a/tools/clang-fuzzer/ClangFuzzer.cpp b/tools/clang-fuzzer/ClangFuzzer.cpp
index d07cf5027b2a..afe57d4a666c 100644
--- a/tools/clang-fuzzer/ClangFuzzer.cpp
+++ b/tools/clang-fuzzer/ClangFuzzer.cpp
@@ -16,6 +16,7 @@
#include "clang/Tooling/Tooling.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/Option/Option.h"
using namespace clang;
diff --git a/tools/clang-import-test/CMakeLists.txt b/tools/clang-import-test/CMakeLists.txt
new file mode 100644
index 000000000000..bd4919694a27
--- /dev/null
+++ b/tools/clang-import-test/CMakeLists.txt
@@ -0,0 +1,27 @@
+set(LLVM_LINK_COMPONENTS
+ core
+ support
+)
+
+if(NOT CLANG_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
+add_clang_tool(clang-import-test
+ clang-import-test.cpp
+ DEPENDS
+ ${tablegen_deps}
+ )
+
+set(CLANG_IMPORT_TEST_LIB_DEPS
+ clangAST
+ clangBasic
+ clangCodeGen
+ clangFrontend
+ clangLex
+ clangParse
+ )
+
+target_link_libraries(clang-import-test
+ ${CLANG_IMPORT_TEST_LIB_DEPS}
+ )
diff --git a/tools/clang-import-test/clang-import-test.cpp b/tools/clang-import-test/clang-import-test.cpp
new file mode 100644
index 000000000000..47598fc91813
--- /dev/null
+++ b/tools/clang-import-test/clang-import-test.cpp
@@ -0,0 +1,319 @@
+//===-- import-test.cpp - ASTImporter/ExternalASTSource testbed -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Signals.h"
+
+#include <memory>
+#include <string>
+
+using namespace clang;
+
+static llvm::cl::opt<std::string> Expression(
+ "expression", llvm::cl::Required,
+ llvm::cl::desc("Path to a file containing the expression to parse"));
+
+static llvm::cl::list<std::string>
+ Imports("import", llvm::cl::ZeroOrMore,
+ llvm::cl::desc("Path to a file containing declarations to import"));
+
+static llvm::cl::list<std::string>
+ ClangArgs("Xcc", llvm::cl::ZeroOrMore,
+ llvm::cl::desc("Argument to pass to the CompilerInvocation"),
+ llvm::cl::CommaSeparated);
+
+namespace init_convenience {
+class TestDiagnosticConsumer : public DiagnosticConsumer {
+private:
+ std::unique_ptr<TextDiagnosticBuffer> Passthrough;
+ const LangOptions *LangOpts = nullptr;
+
+public:
+ TestDiagnosticConsumer()
+ : Passthrough(llvm::make_unique<TextDiagnosticBuffer>()) {}
+
+ virtual void BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP = nullptr) override {
+ this->LangOpts = &LangOpts;
+ return Passthrough->BeginSourceFile(LangOpts, PP);
+ }
+
+ virtual void EndSourceFile() override {
+ this->LangOpts = nullptr;
+ Passthrough->EndSourceFile();
+ }
+
+ virtual bool IncludeInDiagnosticCounts() const override {
+ return Passthrough->IncludeInDiagnosticCounts();
+ }
+
+private:
+ static void PrintSourceForLocation(const SourceLocation &Loc,
+ SourceManager &SM) {
+ const char *LocData = SM.getCharacterData(Loc, /*Invalid=*/nullptr);
+ unsigned LocColumn =
+ SM.getSpellingColumnNumber(Loc, /*Invalid=*/nullptr) - 1;
+ FileID FID = SM.getFileID(Loc);
+ llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, Loc, /*Invalid=*/nullptr);
+
+ assert(LocData >= Buffer->getBufferStart() &&
+ LocData < Buffer->getBufferEnd());
+
+ const char *LineBegin = LocData - LocColumn;
+
+ assert(LineBegin >= Buffer->getBufferStart());
+
+ const char *LineEnd = nullptr;
+
+ for (LineEnd = LineBegin; *LineEnd != '\n' && *LineEnd != '\r' &&
+ LineEnd < Buffer->getBufferEnd();
+ ++LineEnd)
+ ;
+
+ llvm::StringRef LineString(LineBegin, LineEnd - LineBegin);
+
+ llvm::errs() << LineString << '\n';
+ llvm::errs().indent(LocColumn);
+ llvm::errs() << '^';
+ }
+
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) override {
+ if (Info.hasSourceManager() && LangOpts) {
+ SourceManager &SM = Info.getSourceManager();
+
+ if (Info.getLocation().isValid()) {
+ Info.getLocation().print(llvm::errs(), SM);
+ llvm::errs() << ": ";
+ }
+
+ SmallString<16> DiagText;
+ Info.FormatDiagnostic(DiagText);
+ llvm::errs() << DiagText << '\n';
+
+ if (Info.getLocation().isValid()) {
+ PrintSourceForLocation(Info.getLocation(), SM);
+ }
+
+ for (const CharSourceRange &Range : Info.getRanges()) {
+ bool Invalid = true;
+ StringRef Ref = Lexer::getSourceText(Range, SM, *LangOpts, &Invalid);
+ if (!Invalid) {
+ llvm::errs() << Ref << '\n';
+ }
+ }
+ }
+ DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
+ }
+};
+
+std::unique_ptr<CompilerInstance>
+BuildCompilerInstance(ArrayRef<const char *> ClangArgv) {
+ auto Ins = llvm::make_unique<CompilerInstance>();
+ auto DC = llvm::make_unique<TestDiagnosticConsumer>();
+ const bool ShouldOwnClient = true;
+ Ins->createDiagnostics(DC.release(), ShouldOwnClient);
+
+ auto Inv = llvm::make_unique<CompilerInvocation>();
+
+ CompilerInvocation::CreateFromArgs(*Inv, ClangArgv.data(),
+ &ClangArgv.data()[ClangArgv.size()],
+ Ins->getDiagnostics());
+
+ Inv->getLangOpts()->CPlusPlus = true;
+ Inv->getLangOpts()->CPlusPlus11 = true;
+ Inv->getHeaderSearchOpts().UseLibcxx = true;
+ Inv->getLangOpts()->Bool = true;
+ Inv->getLangOpts()->WChar = true;
+ Inv->getLangOpts()->Blocks = true;
+ Inv->getLangOpts()->DebuggerSupport = true;
+ Inv->getLangOpts()->SpellChecking = false;
+ Inv->getLangOpts()->ThreadsafeStatics = false;
+ Inv->getLangOpts()->AccessControl = false;
+ Inv->getLangOpts()->DollarIdents = true;
+ Inv->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo);
+ Inv->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
+
+ Ins->setInvocation(Inv.release());
+
+ TargetInfo *TI = TargetInfo::CreateTargetInfo(
+ Ins->getDiagnostics(), Ins->getInvocation().TargetOpts);
+ Ins->setTarget(TI);
+ Ins->getTarget().adjust(Ins->getLangOpts());
+ Ins->createFileManager();
+ Ins->createSourceManager(Ins->getFileManager());
+ Ins->createPreprocessor(TU_Complete);
+
+ return Ins;
+}
+
+std::unique_ptr<ASTContext>
+BuildASTContext(CompilerInstance &CI, SelectorTable &ST, Builtin::Context &BC) {
+ auto AST = llvm::make_unique<ASTContext>(
+ CI.getLangOpts(), CI.getSourceManager(),
+ CI.getPreprocessor().getIdentifierTable(), ST, BC);
+ AST->InitBuiltinTypes(CI.getTarget());
+ return AST;
+}
+
+std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
+ llvm::LLVMContext &LLVMCtx) {
+ StringRef ModuleName("$__module");
+ return std::unique_ptr<CodeGenerator>(CreateLLVMCodeGen(
+ CI.getDiagnostics(), ModuleName, CI.getHeaderSearchOpts(),
+ CI.getPreprocessorOpts(), CI.getCodeGenOpts(), LLVMCtx));
+}
+} // end namespace
+
+namespace {
+class TestExternalASTSource : public ExternalASTSource {
+private:
+ llvm::ArrayRef<std::unique_ptr<CompilerInstance>> ImportCIs;
+ std::map<CompilerInstance *, std::unique_ptr<ASTImporter>> ForwardImporters;
+ std::map<CompilerInstance *, std::unique_ptr<ASTImporter>> ReverseImporters;
+
+public:
+ TestExternalASTSource(
+ CompilerInstance &ExpressionCI,
+ llvm::ArrayRef<std::unique_ptr<CompilerInstance>> ImportCIs)
+ : ImportCIs(ImportCIs) {
+ for (const std::unique_ptr<CompilerInstance> &ImportCI : ImportCIs) {
+ ForwardImporters[ImportCI.get()] = llvm::make_unique<ASTImporter>(
+ ExpressionCI.getASTContext(), ExpressionCI.getFileManager(),
+ ImportCI->getASTContext(), ImportCI->getFileManager(),
+ /*MinimalImport=*/true);
+ ReverseImporters[ImportCI.get()] = llvm::make_unique<ASTImporter>(
+ ImportCI->getASTContext(), ImportCI->getFileManager(),
+ ExpressionCI.getASTContext(), ExpressionCI.getFileManager(),
+ /*MinimalImport=*/true);
+ }
+ }
+
+ bool FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) override {
+ llvm::SmallVector<NamedDecl *, 1> Decls;
+
+ if (isa<TranslationUnitDecl>(DC)) {
+ for (const std::unique_ptr<CompilerInstance> &I : ImportCIs) {
+ DeclarationName FromName = ReverseImporters[I.get()]->Import(Name);
+ DeclContextLookupResult Result =
+ I->getASTContext().getTranslationUnitDecl()->lookup(FromName);
+ for (NamedDecl *FromD : Result) {
+ NamedDecl *D =
+ llvm::cast<NamedDecl>(ForwardImporters[I.get()]->Import(FromD));
+ Decls.push_back(D);
+ }
+ }
+ }
+ if (Decls.empty()) {
+ return false;
+ } else {
+ SetExternalVisibleDeclsForName(DC, Name, Decls);
+ return true;
+ }
+ }
+};
+
+void AddExternalSource(
+ CompilerInstance &CI,
+ llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
+ ASTContext &AST = CI.getASTContext();
+ auto ES = llvm::make_unique<TestExternalASTSource>(CI, Imports);
+ AST.setExternalSource(ES.release());
+ AST.getTranslationUnitDecl()->setHasExternalVisibleStorage();
+}
+
+llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI,
+ CodeGenerator &CG) {
+ SourceManager &SM = CI.getSourceManager();
+ const FileEntry *FE = CI.getFileManager().getFile(Path);
+ if (!FE) {
+ return llvm::make_error<llvm::StringError>(
+ llvm::Twine("Couldn't open ", Path), std::error_code());
+ }
+ SM.setMainFileID(SM.createFileID(FE, SourceLocation(), SrcMgr::C_User));
+ ParseAST(CI.getPreprocessor(), &CG, CI.getASTContext());
+ return llvm::Error::success();
+}
+
+llvm::Expected<std::unique_ptr<CompilerInstance>>
+Parse(const std::string &Path,
+ llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
+ std::vector<const char *> ClangArgv(ClangArgs.size());
+ std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
+ [](const std::string &s) -> const char * { return s.data(); });
+ std::unique_ptr<CompilerInstance> CI =
+ init_convenience::BuildCompilerInstance(ClangArgv);
+ auto ST = llvm::make_unique<SelectorTable>();
+ auto BC = llvm::make_unique<Builtin::Context>();
+ std::unique_ptr<ASTContext> AST =
+ init_convenience::BuildASTContext(*CI, *ST, *BC);
+ CI->setASTContext(AST.release());
+ AddExternalSource(*CI, Imports);
+
+ auto LLVMCtx = llvm::make_unique<llvm::LLVMContext>();
+ std::unique_ptr<CodeGenerator> CG =
+ init_convenience::BuildCodeGen(*CI, *LLVMCtx);
+ CG->Initialize(CI->getASTContext());
+
+ CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(),
+ &CI->getPreprocessor());
+ if (llvm::Error PE = ParseSource(Path, *CI, *CG)) {
+ return std::move(PE);
+ }
+ CI->getDiagnosticClient().EndSourceFile();
+ if (CI->getDiagnosticClient().getNumErrors()) {
+ return llvm::make_error<llvm::StringError>(
+ "Errors occured while parsing the expression.", std::error_code());
+ } else {
+ return std::move(CI);
+ }
+}
+} // end namespace
+
+int main(int argc, const char **argv) {
+ const bool DisableCrashReporting = true;
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting);
+ llvm::cl::ParseCommandLineOptions(argc, argv);
+ std::vector<std::unique_ptr<CompilerInstance>> ImportCIs;
+ for (auto I : Imports) {
+ llvm::Expected<std::unique_ptr<CompilerInstance>> ImportCI = Parse(I, {});
+ if (auto E = ImportCI.takeError()) {
+ llvm::errs() << llvm::toString(std::move(E));
+ exit(-1);
+ } else {
+ ImportCIs.push_back(std::move(*ImportCI));
+ }
+ }
+ llvm::Expected<std::unique_ptr<CompilerInstance>> ExpressionCI =
+ Parse(Expression, ImportCIs);
+ if (auto E = ExpressionCI.takeError()) {
+ llvm::errs() << llvm::toString(std::move(E));
+ exit(-1);
+ } else {
+ return 0;
+ }
+}
diff --git a/tools/clang-offload-bundler/CMakeLists.txt b/tools/clang-offload-bundler/CMakeLists.txt
new file mode 100644
index 000000000000..6161d08ae587
--- /dev/null
+++ b/tools/clang-offload-bundler/CMakeLists.txt
@@ -0,0 +1,24 @@
+set(LLVM_LINK_COMPONENTS BitWriter Core Object Support)
+
+if(NOT CLANG_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
+add_clang_executable(clang-offload-bundler
+ ClangOffloadBundler.cpp
+
+ DEPENDS
+ ${tablegen_deps}
+ )
+
+set(CLANG_OFFLOAD_BUNDLER_LIB_DEPS
+ clangBasic
+ )
+
+add_dependencies(clang clang-offload-bundler)
+
+target_link_libraries(clang-offload-bundler
+ ${CLANG_OFFLOAD_BUNDLER_LIB_DEPS}
+ )
+
+install(TARGETS clang-offload-bundler RUNTIME DESTINATION bin)
diff --git a/tools/clang-offload-bundler/ClangOffloadBundler.cpp b/tools/clang-offload-bundler/ClangOffloadBundler.cpp
new file mode 100644
index 000000000000..20988b48ede1
--- /dev/null
+++ b/tools/clang-offload-bundler/ClangOffloadBundler.cpp
@@ -0,0 +1,1012 @@
+//===-- clang-offload-bundler/ClangOffloadBundler.cpp ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements a clang-offload-bundler that bundles different
+/// files that relate with the same source code but different targets into a
+/// single one. Also the implements the opposite functionality, i.e. unbundle
+/// files previous created by this tool.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::object;
+
+static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
+
+// Mark all our options with this category, everything else (except for -version
+// and -help) will be hidden.
+static cl::OptionCategory
+ ClangOffloadBundlerCategory("clang-offload-bundler options");
+
+static cl::list<std::string>
+ InputFileNames("inputs", cl::CommaSeparated, cl::OneOrMore,
+ cl::desc("[<input file>,...]"),
+ cl::cat(ClangOffloadBundlerCategory));
+static cl::list<std::string>
+ OutputFileNames("outputs", cl::CommaSeparated, cl::OneOrMore,
+ cl::desc("[<output file>,...]"),
+ cl::cat(ClangOffloadBundlerCategory));
+static cl::list<std::string>
+ TargetNames("targets", cl::CommaSeparated, cl::OneOrMore,
+ cl::desc("[<offload kind>-<target triple>,...]"),
+ cl::cat(ClangOffloadBundlerCategory));
+static cl::opt<std::string>
+ FilesType("type", cl::Required,
+ cl::desc("Type of the files to be bundled/unbundled.\n"
+ "Current supported types are:\n"
+ " i - cpp-output\n"
+ " ii - c++-cpp-output\n"
+ " ll - llvm\n"
+ " bc - llvm-bc\n"
+ " s - assembler\n"
+ " o - object\n"
+ " gch - precompiled-header\n"
+ " ast - clang AST file"),
+ cl::cat(ClangOffloadBundlerCategory));
+static cl::opt<bool>
+ Unbundle("unbundle",
+ cl::desc("Unbundle bundled file into several output files.\n"),
+ cl::init(false), cl::cat(ClangOffloadBundlerCategory));
+
+static cl::opt<bool> PrintExternalCommands(
+ "###",
+ cl::desc("Print any external commands that are to be executed "
+ "instead of actually executing them - for testing purposes.\n"),
+ cl::init(false), cl::cat(ClangOffloadBundlerCategory));
+
+static cl::opt<bool> DumpTemporaryFiles(
+ "dump-temporary-files",
+ cl::desc("Dumps any temporary files created - for testing purposes.\n"),
+ cl::init(false), cl::cat(ClangOffloadBundlerCategory));
+
+/// Magic string that marks the existence of offloading data.
+#define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
+
+/// The index of the host input in the list of inputs.
+static unsigned HostInputIndex = ~0u;
+
+/// Path to the current binary.
+static std::string BundlerExecutable;
+
+/// Obtain the offload kind and real machine triple out of the target
+/// information specified by the user.
+static void getOffloadKindAndTriple(StringRef Target, StringRef &OffloadKind,
+ StringRef &Triple) {
+ auto KindTriplePair = Target.split('-');
+ OffloadKind = KindTriplePair.first;
+ Triple = KindTriplePair.second;
+}
+static StringRef getTriple(StringRef Target) {
+ StringRef OffloadKind;
+ StringRef Triple;
+ getOffloadKindAndTriple(Target, OffloadKind, Triple);
+ return Triple;
+}
+static bool hasHostKind(StringRef Target) {
+ StringRef OffloadKind;
+ StringRef Triple;
+ getOffloadKindAndTriple(Target, OffloadKind, Triple);
+ return OffloadKind == "host";
+}
+
+/// Generic file handler interface.
+class FileHandler {
+public:
+ FileHandler() {}
+
+ virtual ~FileHandler() {}
+
+ /// Update the file handler with information from the header of the bundled
+ /// file
+ virtual void ReadHeader(MemoryBuffer &Input) = 0;
+
+ /// Read the marker of the next bundled to be read in the file. The triple of
+ /// the target associated with that bundle is returned. An empty string is
+ /// returned if there are no more bundles to be read.
+ virtual StringRef ReadBundleStart(MemoryBuffer &Input) = 0;
+
+ /// Read the marker that closes the current bundle.
+ virtual void ReadBundleEnd(MemoryBuffer &Input) = 0;
+
+ /// Read the current bundle and write the result into the stream \a OS.
+ virtual void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
+
+ /// Write the header of the bundled file to \a OS based on the information
+ /// gathered from \a Inputs.
+ virtual void WriteHeader(raw_fd_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
+
+ /// Write the marker that initiates a bundle for the triple \a TargetTriple to
+ /// \a OS.
+ virtual void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
+
+ /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
+ /// OS. Return true if any error was found.
+
+ virtual bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
+
+ /// Write the bundle from \a Input into \a OS.
+ virtual void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
+};
+
+/// Handler for binary files. The bundled file will have the following format
+/// (all integers are stored in little-endian format):
+///
+/// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string)
+///
+/// NumberOfOffloadBundles (8-byte integer)
+///
+/// OffsetOfBundle1 (8-byte integer)
+/// SizeOfBundle1 (8-byte integer)
+/// NumberOfBytesInTripleOfBundle1 (8-byte integer)
+/// TripleOfBundle1 (byte length defined before)
+///
+/// ...
+///
+/// OffsetOfBundleN (8-byte integer)
+/// SizeOfBundleN (8-byte integer)
+/// NumberOfBytesInTripleOfBundleN (8-byte integer)
+/// TripleOfBundleN (byte length defined before)
+///
+/// Bundle1
+/// ...
+/// BundleN
+
+/// Read 8-byte integers from a buffer in little-endian format.
+static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {
+ uint64_t Res = 0;
+ const char *Data = Buffer.data();
+
+ for (unsigned i = 0; i < 8; ++i) {
+ Res <<= 8;
+ uint64_t Char = (uint64_t)Data[pos + 7 - i];
+ Res |= 0xffu & Char;
+ }
+ return Res;
+}
+
+/// Write 8-byte integers to a buffer in little-endian format.
+static void Write8byteIntegerToBuffer(raw_fd_ostream &OS, uint64_t Val) {
+ for (unsigned i = 0; i < 8; ++i) {
+ char Char = (char)(Val & 0xffu);
+ OS.write(&Char, 1);
+ Val >>= 8;
+ }
+}
+
+class BinaryFileHandler final : public FileHandler {
+ /// Information about the bundles extracted from the header.
+ struct BundleInfo final {
+ /// Size of the bundle.
+ uint64_t Size = 0u;
+ /// Offset at which the bundle starts in the bundled file.
+ uint64_t Offset = 0u;
+
+ BundleInfo() {}
+ BundleInfo(uint64_t Size, uint64_t Offset) : Size(Size), Offset(Offset) {}
+ };
+
+ /// Map between a triple and the corresponding bundle information.
+ StringMap<BundleInfo> BundlesInfo;
+
+ /// Iterator for the bundle information that is being read.
+ StringMap<BundleInfo>::iterator CurBundleInfo;
+
+public:
+ BinaryFileHandler() : FileHandler() {}
+
+ ~BinaryFileHandler() final {}
+
+ void ReadHeader(MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+
+ // Initialize the current bundle with the end of the container.
+ CurBundleInfo = BundlesInfo.end();
+
+ // Check if buffer is smaller than magic string.
+ size_t ReadChars = sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
+ if (ReadChars > FC.size())
+ return;
+
+ // Check if no magic was found.
+ StringRef Magic(FC.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
+ if (!Magic.equals(OFFLOAD_BUNDLER_MAGIC_STR))
+ return;
+
+ // Read number of bundles.
+ if (ReadChars + 8 > FC.size())
+ return;
+
+ uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read bundle offsets, sizes and triples.
+ for (uint64_t i = 0; i < NumberOfBundles; ++i) {
+
+ // Read offset.
+ if (ReadChars + 8 > FC.size())
+ return;
+
+ uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read size.
+ if (ReadChars + 8 > FC.size())
+ return;
+
+ uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read triple size.
+ if (ReadChars + 8 > FC.size())
+ return;
+
+ uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read triple.
+ if (ReadChars + TripleSize > FC.size())
+ return;
+
+ StringRef Triple(&FC.data()[ReadChars], TripleSize);
+ ReadChars += TripleSize;
+
+ // Check if the offset and size make sense.
+ if (!Size || !Offset || Offset + Size > FC.size())
+ return;
+
+ assert(BundlesInfo.find(Triple) == BundlesInfo.end() &&
+ "Triple is duplicated??");
+ BundlesInfo[Triple] = BundleInfo(Size, Offset);
+ }
+ // Set the iterator to where we will start to read.
+ CurBundleInfo = BundlesInfo.begin();
+ }
+
+ StringRef ReadBundleStart(MemoryBuffer &Input) final {
+ if (CurBundleInfo == BundlesInfo.end())
+ return StringRef();
+
+ return CurBundleInfo->first();
+ }
+
+ void ReadBundleEnd(MemoryBuffer &Input) final {
+ assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
+ ++CurBundleInfo;
+ }
+
+ void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+ assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
+ StringRef FC = Input.getBuffer();
+ OS.write(FC.data() + CurBundleInfo->second.Offset,
+ CurBundleInfo->second.Size);
+ }
+
+ void WriteHeader(raw_fd_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
+ // Compute size of the header.
+ uint64_t HeaderSize = 0;
+
+ HeaderSize += sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
+ HeaderSize += 8; // Number of Bundles
+
+ for (auto &T : TargetNames) {
+ HeaderSize += 3 * 8; // Bundle offset, Size of bundle and size of triple.
+ HeaderSize += T.size(); // The triple.
+ }
+
+ // Write to the buffer the header.
+ OS << OFFLOAD_BUNDLER_MAGIC_STR;
+
+ Write8byteIntegerToBuffer(OS, TargetNames.size());
+
+ unsigned Idx = 0;
+ for (auto &T : TargetNames) {
+ MemoryBuffer &MB = *Inputs[Idx++].get();
+ // Bundle offset.
+ Write8byteIntegerToBuffer(OS, HeaderSize);
+ // Size of the bundle (adds to the next bundle's offset)
+ Write8byteIntegerToBuffer(OS, MB.getBufferSize());
+ HeaderSize += MB.getBufferSize();
+ // Size of the triple
+ Write8byteIntegerToBuffer(OS, T.size());
+ // Triple
+ OS << T;
+ }
+ }
+
+ void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {}
+
+ bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
+ return false;
+ }
+
+ void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+ OS.write(Input.getBufferStart(), Input.getBufferSize());
+ }
+};
+
+/// Handler for object files. The bundles are organized by sections with a
+/// designated name.
+///
+/// In order to bundle we create an IR file with the content of each section and
+/// use incremental linking to produce the resulting object. We also add section
+/// with a single byte to state the name of the component the main object file
+/// (the one we are bundling into) refers to.
+///
+/// To unbundle, we use just copy the contents of the designated section. If the
+/// requested bundle refer to the main object file, we just copy it with no
+/// changes.
+class ObjectFileHandler final : public FileHandler {
+
+ /// The object file we are currently dealing with.
+ std::unique_ptr<ObjectFile> Obj;
+
+ /// Return the input file contents.
+ StringRef getInputFileContents() const { return Obj->getData(); }
+
+ /// Return true if the provided section is an offload section and return the
+ /// triple by reference.
+ static bool IsOffloadSection(SectionRef CurSection,
+ StringRef &OffloadTriple) {
+ StringRef SectionName;
+ CurSection.getName(SectionName);
+
+ if (SectionName.empty())
+ return false;
+
+ // If it does not start with the reserved suffix, just skip this section.
+ if (!SectionName.startswith(OFFLOAD_BUNDLER_MAGIC_STR))
+ return false;
+
+ // Return the triple that is right after the reserved prefix.
+ OffloadTriple = SectionName.substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
+ return true;
+ }
+
+ /// Total number of inputs.
+ unsigned NumberOfInputs = 0;
+
+ /// Total number of processed inputs, i.e, inputs that were already
+ /// read from the buffers.
+ unsigned NumberOfProcessedInputs = 0;
+
+ /// LLVM context used to to create the auxiliar modules.
+ LLVMContext VMContext;
+
+ /// LLVM module used to create an object with all the bundle
+ /// components.
+ std::unique_ptr<Module> AuxModule;
+
+ /// The current triple we are working with.
+ StringRef CurrentTriple;
+
+ /// The name of the main input file.
+ StringRef MainInputFileName;
+
+ /// Iterator of the current and next section.
+ section_iterator CurrentSection;
+ section_iterator NextSection;
+
+public:
+ ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn)
+ : FileHandler(), Obj(std::move(ObjIn)),
+ CurrentSection(Obj->section_begin()),
+ NextSection(Obj->section_begin()) {}
+
+ ~ObjectFileHandler() final {}
+
+ void ReadHeader(MemoryBuffer &Input) final {}
+
+ StringRef ReadBundleStart(MemoryBuffer &Input) final {
+ while (NextSection != Obj->section_end()) {
+ CurrentSection = NextSection;
+ ++NextSection;
+
+ StringRef OffloadTriple;
+ // Check if the current section name starts with the reserved prefix. If
+ // so, return the triple.
+ if (IsOffloadSection(*CurrentSection, OffloadTriple))
+ return OffloadTriple;
+ }
+ return StringRef();
+ }
+
+ void ReadBundleEnd(MemoryBuffer &Input) final {}
+
+ void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+ // If the current section has size one, that means that the content we are
+ // interested in is the file itself. Otherwise it is the content of the
+ // section.
+ //
+ // TODO: Instead of copying the input file as is, deactivate the section
+ // that is no longer needed.
+
+ StringRef Content;
+ CurrentSection->getContents(Content);
+
+ if (Content.size() < 2)
+ OS.write(Input.getBufferStart(), Input.getBufferSize());
+ else
+ OS.write(Content.data(), Content.size());
+ }
+
+ void WriteHeader(raw_fd_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
+ assert(HostInputIndex != ~0u && "Host input index not defined.");
+
+ // Record number of inputs.
+ NumberOfInputs = Inputs.size();
+
+ // Create an LLVM module to have the content we need to bundle.
+ auto *M = new Module("clang-offload-bundle", VMContext);
+ M->setTargetTriple(getTriple(TargetNames[HostInputIndex]));
+ AuxModule.reset(M);
+ }
+
+ void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
+ ++NumberOfProcessedInputs;
+
+ // Record the triple we are using, that will be used to name the section we
+ // will create.
+ CurrentTriple = TargetTriple;
+ }
+
+ bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
+ assert(NumberOfProcessedInputs <= NumberOfInputs &&
+ "Processing more inputs that actually exist!");
+ assert(HostInputIndex != ~0u && "Host input index not defined.");
+
+ // If this is not the last output, we don't have to do anything.
+ if (NumberOfProcessedInputs != NumberOfInputs)
+ return false;
+
+ // Create the bitcode file name to write the resulting code to. Keep it if
+ // save-temps is active.
+ SmallString<128> BitcodeFileName;
+ if (sys::fs::createTemporaryFile("clang-offload-bundler", "bc",
+ BitcodeFileName)) {
+ errs() << "error: unable to create temporary file.\n";
+ return true;
+ }
+
+ // Dump the contents of the temporary file if that was requested.
+ if (DumpTemporaryFiles) {
+ errs() << ";\n; Object file bundler IR file.\n;\n";
+ AuxModule.get()->dump();
+ }
+
+ // Find clang in order to create the bundle binary.
+ StringRef Dir = sys::path::parent_path(BundlerExecutable);
+
+ auto ClangBinary = sys::findProgramByName("clang", Dir);
+ if (ClangBinary.getError()) {
+ // Remove bitcode file.
+ sys::fs::remove(BitcodeFileName);
+
+ errs() << "error: unable to find 'clang' in path.\n";
+ return true;
+ }
+
+ // Do the incremental linking. We write to the output file directly. So, we
+ // close it and use the name to pass down to clang.
+ OS.close();
+ SmallString<128> TargetName = getTriple(TargetNames[HostInputIndex]);
+ const char *ClangArgs[] = {"clang",
+ "-r",
+ "-target",
+ TargetName.c_str(),
+ "-o",
+ OutputFileNames.front().c_str(),
+ InputFileNames[HostInputIndex].c_str(),
+ BitcodeFileName.c_str(),
+ "-nostdlib",
+ nullptr};
+
+ // If the user asked for the commands to be printed out, we do that instead
+ // of executing it.
+ if (PrintExternalCommands) {
+ errs() << "\"" << ClangBinary.get() << "\"";
+ for (unsigned I = 1; ClangArgs[I]; ++I)
+ errs() << " \"" << ClangArgs[I] << "\"";
+ errs() << "\n";
+ } else {
+ // Write the bitcode contents to the temporary file.
+ {
+ std::error_code EC;
+ raw_fd_ostream BitcodeFile(BitcodeFileName, EC, sys::fs::F_None);
+ if (EC) {
+ errs() << "error: unable to open temporary file.\n";
+ return true;
+ }
+ WriteBitcodeToFile(AuxModule.get(), BitcodeFile);
+ }
+
+ bool Failed = sys::ExecuteAndWait(ClangBinary.get(), ClangArgs);
+
+ // Remove bitcode file.
+ sys::fs::remove(BitcodeFileName);
+
+ if (Failed) {
+ errs() << "error: incremental linking by external tool failed.\n";
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+ Module *M = AuxModule.get();
+
+ // Create the new section name, it will consist of the reserved prefix
+ // concatenated with the triple.
+ std::string SectionName = OFFLOAD_BUNDLER_MAGIC_STR;
+ SectionName += CurrentTriple;
+
+ // Create the constant with the content of the section. For the input we are
+ // bundling into (the host input), this is just a place-holder, so a single
+ // byte is sufficient.
+ assert(HostInputIndex != ~0u && "Host input index undefined??");
+ Constant *Content;
+ if (NumberOfProcessedInputs == HostInputIndex + 1) {
+ uint8_t Byte[] = {0};
+ Content = ConstantDataArray::get(VMContext, Byte);
+ } else
+ Content = ConstantDataArray::get(
+ VMContext, ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(
+ Input.getBufferStart()),
+ Input.getBufferSize()));
+
+ // Create the global in the desired section. We don't want these globals in
+ // the symbol table, so we mark them private.
+ auto *GV = new GlobalVariable(*M, Content->getType(), /*IsConstant=*/true,
+ GlobalVariable::PrivateLinkage, Content);
+ GV->setSection(SectionName);
+ }
+};
+
+/// Handler for text files. The bundled file will have the following format.
+///
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
+/// Bundle 1
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
+/// ...
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
+/// Bundle N
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
+class TextFileHandler final : public FileHandler {
+ /// String that begins a line comment.
+ StringRef Comment;
+
+ /// String that initiates a bundle.
+ std::string BundleStartString;
+
+ /// String that closes a bundle.
+ std::string BundleEndString;
+
+ /// Number of chars read from input.
+ size_t ReadChars = 0u;
+
+protected:
+ void ReadHeader(MemoryBuffer &Input) final {}
+
+ StringRef ReadBundleStart(MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+
+ // Find start of the bundle.
+ ReadChars = FC.find(BundleStartString, ReadChars);
+ if (ReadChars == FC.npos)
+ return StringRef();
+
+ // Get position of the triple.
+ size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
+
+ // Get position that closes the triple.
+ size_t TripleEnd = ReadChars = FC.find("\n", ReadChars);
+ if (TripleEnd == FC.npos)
+ return StringRef();
+
+ // Next time we read after the new line.
+ ++ReadChars;
+
+ return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
+ }
+
+ void ReadBundleEnd(MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+
+ // Read up to the next new line.
+ assert(FC[ReadChars] == '\n' && "The bundle should end with a new line.");
+
+ size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1);
+ if (TripleEnd == FC.npos)
+ return;
+
+ // Next time we read after the new line.
+ ++ReadChars;
+ }
+
+ void ReadBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+ size_t BundleStart = ReadChars;
+
+ // Find end of the bundle.
+ size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
+
+ StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
+ OS << Bundle;
+ }
+
+ void WriteHeader(raw_fd_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {}
+
+ void WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
+ OS << BundleStartString << TargetTriple << "\n";
+ }
+
+ bool WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
+ OS << BundleEndString << TargetTriple << "\n";
+ return false;
+ }
+
+ void WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+ OS << Input.getBuffer();
+ }
+
+public:
+ TextFileHandler(StringRef Comment)
+ : FileHandler(), Comment(Comment), ReadChars(0) {
+ BundleStartString =
+ "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ ";
+ BundleEndString =
+ "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__END__ ";
+ }
+};
+
+/// Return an appropriate object file handler. We use the specific object
+/// handler if we know how to deal with that format, otherwise we use a default
+/// binary file handler.
+static FileHandler *CreateObjectFileHandler(MemoryBuffer &FirstInput) {
+ // Check if the input file format is one that we know how to deal with.
+ Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput);
+
+ // Failed to open the input as a known binary. Use the default binary handler.
+ if (!BinaryOrErr) {
+ // We don't really care about the error (we just consume it), if we could
+ // not get a valid device binary object we use the default binary handler.
+ consumeError(BinaryOrErr.takeError());
+ return new BinaryFileHandler();
+ }
+
+ // We only support regular object files. If this is not an object file,
+ // default to the binary handler. The handler will be owned by the client of
+ // this function.
+ std::unique_ptr<ObjectFile> Obj(
+ dyn_cast<ObjectFile>(BinaryOrErr.get().release()));
+
+ if (!Obj)
+ return new BinaryFileHandler();
+
+ return new ObjectFileHandler(std::move(Obj));
+}
+
+/// Return an appropriate handler given the input files and options.
+static FileHandler *CreateFileHandler(MemoryBuffer &FirstInput) {
+ if (FilesType == "i")
+ return new TextFileHandler(/*Comment=*/"//");
+ if (FilesType == "ii")
+ return new TextFileHandler(/*Comment=*/"//");
+ if (FilesType == "ll")
+ return new TextFileHandler(/*Comment=*/";");
+ if (FilesType == "bc")
+ return new BinaryFileHandler();
+ if (FilesType == "s")
+ return new TextFileHandler(/*Comment=*/"#");
+ if (FilesType == "o")
+ return CreateObjectFileHandler(FirstInput);
+ if (FilesType == "gch")
+ return new BinaryFileHandler();
+ if (FilesType == "ast")
+ return new BinaryFileHandler();
+
+ errs() << "error: invalid file type specified.\n";
+ return nullptr;
+}
+
+/// Bundle the files. Return true if an error was found.
+static bool BundleFiles() {
+ std::error_code EC;
+
+ // Create output file.
+ raw_fd_ostream OutputFile(OutputFileNames.front(), EC, sys::fs::F_None);
+
+ if (EC) {
+ errs() << "error: Can't open file " << OutputFileNames.front() << ".\n";
+ return true;
+ }
+
+ // Open input files.
+ std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers(
+ InputFileNames.size());
+
+ unsigned Idx = 0;
+ for (auto &I : InputFileNames) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getFileOrSTDIN(I);
+ if (std::error_code EC = CodeOrErr.getError()) {
+ errs() << "error: Can't open file " << I << ": " << EC.message() << "\n";
+ return true;
+ }
+ InputBuffers[Idx++] = std::move(CodeOrErr.get());
+ }
+
+ // Get the file handler. We use the host buffer as reference.
+ assert(HostInputIndex != ~0u && "Host input index undefined??");
+ std::unique_ptr<FileHandler> FH;
+ FH.reset(CreateFileHandler(*InputBuffers[HostInputIndex].get()));
+
+ // Quit if we don't have a handler.
+ if (!FH.get())
+ return true;
+
+ // Write header.
+ FH.get()->WriteHeader(OutputFile, InputBuffers);
+
+ // Write all bundles along with the start/end markers. If an error was found
+ // writing the end of the bundle component, abort the bundle writing.
+ auto Input = InputBuffers.begin();
+ for (auto &Triple : TargetNames) {
+ FH.get()->WriteBundleStart(OutputFile, Triple);
+ FH.get()->WriteBundle(OutputFile, *Input->get());
+ if (FH.get()->WriteBundleEnd(OutputFile, Triple))
+ return true;
+ ++Input;
+ }
+ return false;
+}
+
+// Unbundle the files. Return true if an error was found.
+static bool UnbundleFiles() {
+ // Open Input file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getFileOrSTDIN(InputFileNames.front());
+ if (std::error_code EC = CodeOrErr.getError()) {
+ errs() << "error: Can't open file " << InputFileNames.front() << ": "
+ << EC.message() << "\n";
+ return true;
+ }
+
+ MemoryBuffer &Input = *CodeOrErr.get();
+
+ // Select the right files handler.
+ std::unique_ptr<FileHandler> FH;
+ FH.reset(CreateFileHandler(Input));
+
+ // Quit if we don't have a handler.
+ if (!FH.get())
+ return true;
+
+ // Read the header of the bundled file.
+ FH.get()->ReadHeader(Input);
+
+ // Create a work list that consist of the map triple/output file.
+ StringMap<StringRef> Worklist;
+ auto Output = OutputFileNames.begin();
+ for (auto &Triple : TargetNames) {
+ Worklist[Triple] = *Output;
+ ++Output;
+ }
+
+ // Read all the bundles that are in the work list. If we find no bundles we
+ // assume the file is meant for the host target.
+ bool FoundHostBundle = false;
+ while (!Worklist.empty()) {
+ StringRef CurTriple = FH.get()->ReadBundleStart(Input);
+
+ // We don't have more bundles.
+ if (CurTriple.empty())
+ break;
+
+ auto Output = Worklist.find(CurTriple);
+ // The file may have more bundles for other targets, that we don't care
+ // about. Therefore, move on to the next triple
+ if (Output == Worklist.end()) {
+ continue;
+ }
+
+ // Check if the output file can be opened and copy the bundle to it.
+ std::error_code EC;
+ raw_fd_ostream OutputFile(Output->second, EC, sys::fs::F_None);
+ if (EC) {
+ errs() << "error: Can't open file " << Output->second << ": "
+ << EC.message() << "\n";
+ return true;
+ }
+ FH.get()->ReadBundle(OutputFile, Input);
+ FH.get()->ReadBundleEnd(Input);
+ Worklist.erase(Output);
+
+ // Record if we found the host bundle.
+ if (hasHostKind(CurTriple))
+ FoundHostBundle = true;
+ }
+
+ // If no bundles were found, assume the input file is the host bundle and
+ // create empty files for the remaining targets.
+ if (Worklist.size() == TargetNames.size()) {
+ for (auto &E : Worklist) {
+ std::error_code EC;
+ raw_fd_ostream OutputFile(E.second, EC, sys::fs::F_None);
+ if (EC) {
+ errs() << "error: Can't open file " << E.second << ": " << EC.message()
+ << "\n";
+ return true;
+ }
+
+ // If this entry has a host kind, copy the input file to the output file.
+ if (hasHostKind(E.first()))
+ OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
+ }
+ return false;
+ }
+
+ // If we found elements, we emit an error if none of those were for the host.
+ if (!FoundHostBundle) {
+ errs() << "error: Can't find bundle for the host target\n";
+ return true;
+ }
+
+ // If we still have any elements in the worklist, create empty files for them.
+ for (auto &E : Worklist) {
+ std::error_code EC;
+ raw_fd_ostream OutputFile(E.second, EC, sys::fs::F_None);
+ if (EC) {
+ errs() << "error: Can't open file " << E.second << ": " << EC.message()
+ << "\n";
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void PrintVersion() {
+ raw_ostream &OS = outs();
+ OS << clang::getClangToolFullVersion("clang-offload-bundler") << '\n';
+}
+
+int main(int argc, const char **argv) {
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
+
+ cl::HideUnrelatedOptions(ClangOffloadBundlerCategory);
+ cl::SetVersionPrinter(PrintVersion);
+ cl::ParseCommandLineOptions(
+ argc, argv,
+ "A tool to bundle several input files of the specified type <type> \n"
+ "referring to the same source file but different targets into a single \n"
+ "one. The resulting file can also be unbundled into different files by \n"
+ "this tool if -unbundle is provided.\n");
+
+ if (Help)
+ cl::PrintHelpMessage();
+
+ bool Error = false;
+ if (Unbundle) {
+ if (InputFileNames.size() != 1) {
+ Error = true;
+ errs() << "error: only one input file supported in unbundling mode.\n";
+ }
+ if (OutputFileNames.size() != TargetNames.size()) {
+ Error = true;
+ errs() << "error: number of output files and targets should match in "
+ "unbundling mode.\n";
+ }
+ } else {
+ if (OutputFileNames.size() != 1) {
+ Error = true;
+ errs() << "error: only one output file supported in bundling mode.\n";
+ }
+ if (InputFileNames.size() != TargetNames.size()) {
+ Error = true;
+ errs() << "error: number of input files and targets should match in "
+ "bundling mode.\n";
+ }
+ }
+
+ // Verify that the offload kinds and triples are known. We also check that we
+ // have exactly one host target.
+ unsigned Index = 0u;
+ unsigned HostTargetNum = 0u;
+ for (StringRef Target : TargetNames) {
+ StringRef Kind;
+ StringRef Triple;
+ getOffloadKindAndTriple(Target, Kind, Triple);
+
+ bool KindIsValid = !Kind.empty();
+ KindIsValid = KindIsValid &&
+ StringSwitch<bool>(Kind)
+ .Case("host", true)
+ .Case("openmp", true)
+ .Default(false);
+
+ bool TripleIsValid = !Triple.empty();
+ llvm::Triple T(Triple);
+ TripleIsValid &= T.getArch() != Triple::UnknownArch;
+
+ if (!KindIsValid || !TripleIsValid) {
+ Error = true;
+ errs() << "error: invalid target '" << Target << "'";
+
+ if (!KindIsValid)
+ errs() << ", unknown offloading kind '" << Kind << "'";
+ if (!TripleIsValid)
+ errs() << ", unknown target triple '" << Triple << "'";
+ errs() << ".\n";
+ }
+
+ if (KindIsValid && Kind == "host") {
+ ++HostTargetNum;
+ // Save the index of the input that refers to the host.
+ HostInputIndex = Index;
+ }
+
+ ++Index;
+ }
+
+ if (HostTargetNum != 1) {
+ Error = true;
+ errs() << "error: expecting exactly one host target but got "
+ << HostTargetNum << ".\n";
+ }
+
+ if (Error)
+ return 1;
+
+ // Save the current executable directory as it will be useful to find other
+ // tools.
+ BundlerExecutable = sys::fs::getMainExecutable(argv[0], &BundlerExecutable);
+
+ return Unbundle ? UnbundleFiles() : BundleFiles();
+}
diff --git a/tools/diagtool/DiagTool.cpp b/tools/diagtool/DiagTool.cpp
index 0e4d8088c6c2..7582d51ae4f5 100644
--- a/tools/diagtool/DiagTool.cpp
+++ b/tools/diagtool/DiagTool.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "DiagTool.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include <vector>
diff --git a/tools/diagtool/TreeView.cpp b/tools/diagtool/TreeView.cpp
index 3647e393b869..07af944ffc4e 100644
--- a/tools/diagtool/TreeView.cpp
+++ b/tools/diagtool/TreeView.cpp
@@ -14,7 +14,6 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/Process.h"
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index e03b3fa3951e..49bde947f4c6 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -24,10 +24,17 @@ if(CLANG_PLUGIN_SUPPORT)
set(LLVM_NO_DEAD_STRIP 1)
endif()
+if(NOT CLANG_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
add_clang_tool(clang
driver.cpp
cc1_main.cpp
cc1as_main.cpp
+
+ DEPENDS
+ ${tablegen_deps}
)
target_link_libraries(clang
@@ -52,7 +59,7 @@ endif()
add_dependencies(clang clang-headers)
if(NOT CLANG_LINKS_TO_CREATE)
- set(CLANG_LINKS_TO_CREATE clang++ clang-cl)
+ set(CLANG_LINKS_TO_CREATE clang++ clang-cl clang-cpp)
if (WIN32)
list(APPEND CLANG_LINKS_TO_CREATE ../msbuild-bin/cl)
@@ -74,7 +81,7 @@ if (APPLE)
set(TOOL_INFO_UTI "${CLANG_VENDOR_UTI}")
set(TOOL_INFO_VERSION "${CLANG_VERSION}")
- set(TOOL_INFO_BUILD_VERSION "${LLVM_MAJOR_VERSION}.${LLVM_MINOR_VERSION}")
+ set(TOOL_INFO_BUILD_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
set(TOOL_INFO_PLIST_OUT "${CMAKE_CURRENT_BINARY_DIR}/${TOOL_INFO_PLIST}")
target_link_libraries(clang
@@ -101,8 +108,15 @@ if(LD64_EXECUTABLE AND CLANG_ORDER_FILE)
# This is a test to ensure the actual order file works with the linker.
check_linker_flag("-Wl,-order_file,${CLANG_ORDER_FILE}"
LINKER_ORDER_FILE_WORKS)
-
- if(LINKER_ORDER_FILE_WORKS)
+
+ # Passing an empty order file disables some linker layout optimizations.
+ # To work around this and enable workflows for re-linking when the order file
+ # changes we check during configuration if the file is empty, and make it a
+ # configuration dependency.
+ file(READ ${CLANG_ORDER_FILE} ORDER_FILE LIMIT 20)
+ if("${ORDER_FILE}" STREQUAL "\n")
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CLANG_ORDER_FILE})
+ elseif(LINKER_ORDER_FILE_WORKS)
target_link_libraries(clang "-Wl,-order_file,${CLANG_ORDER_FILE}")
set_target_properties(clang PROPERTIES LINK_DEPENDS ${CLANG_ORDER_FILE})
endif()
@@ -110,9 +124,4 @@ endif()
if(WITH_POLLY AND LINK_POLLY_INTO_TOOLS)
target_link_libraries(clang Polly)
- if(POLLY_LINK_LIBS)
- foreach(lib ${POLLY_LINK_LIBS})
- target_link_libraries(clang ${lib})
- endforeach(lib)
- endif(POLLY_LINK_LIBS)
endif(WITH_POLLY AND LINK_POLLY_INTO_TOOLS)
diff --git a/tools/driver/Info.plist.in b/tools/driver/Info.plist.in
index c938fb053d92..c2b157021df4 100644
--- a/tools/driver/Info.plist.in
+++ b/tools/driver/Info.plist.in
@@ -7,7 +7,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
- <string>@TOOL_INFO_NAME</string>
+ <string>@TOOL_INFO_NAME@</string>
<key>CFBundleShortVersionString</key>
<string>@TOOL_INFO_VERSION@</string>
<key>CFBundleVersion</key>
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index d78a31e67a2f..1a16746d589d 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -15,6 +15,7 @@
#include "llvm/Option/Arg.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
+#include "clang/Config/config.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -28,6 +29,7 @@
#include "llvm/LinkAllPasses.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Signals.h"
@@ -35,6 +37,11 @@
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
+
+#ifdef CLANG_HAVE_RLIMITS
+#include <sys/resource.h>
+#endif
+
using namespace clang;
using namespace llvm::opt;
@@ -64,7 +71,105 @@ void initializePollyPasses(llvm::PassRegistry &Registry);
}
#endif
+#ifdef CLANG_HAVE_RLIMITS
+// The amount of stack we think is "sufficient". If less than this much is
+// available, we may be unable to reach our template instantiation depth
+// limit and other similar limits.
+// FIXME: Unify this with the stack we request when spawning a thread to build
+// a module.
+static const int kSufficientStack = 8 << 20;
+
+#if defined(__linux__) && defined(__PIE__)
+static size_t getCurrentStackAllocation() {
+ // If we can't compute the current stack usage, allow for 512K of command
+ // line arguments and environment.
+ size_t Usage = 512 * 1024;
+ if (FILE *StatFile = fopen("/proc/self/stat", "r")) {
+ // We assume that the stack extends from its current address to the end of
+ // the environment space. In reality, there is another string literal (the
+ // program name) after the environment, but this is close enough (we only
+ // need to be within 100K or so).
+ unsigned long StackPtr, EnvEnd;
+ // Disable silly GCC -Wformat warning that complains about length
+ // modifiers on ignored format specifiers. We want to retain these
+ // for documentation purposes even though they have no effect.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#endif
+ if (fscanf(StatFile,
+ "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %*lu "
+ "%*lu %*ld %*ld %*ld %*ld %*ld %*ld %*llu %*lu %*ld %*lu %*lu "
+ "%*lu %*lu %lu %*lu %*lu %*lu %*lu %*lu %*llu %*lu %*lu %*d %*d "
+ "%*u %*u %*llu %*lu %*ld %*lu %*lu %*lu %*lu %*lu %*lu %lu %*d",
+ &StackPtr, &EnvEnd) == 2) {
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+ Usage = StackPtr < EnvEnd ? EnvEnd - StackPtr : StackPtr - EnvEnd;
+ }
+ fclose(StatFile);
+ }
+ return Usage;
+}
+
+#include <alloca.h>
+
+LLVM_ATTRIBUTE_NOINLINE
+static void ensureStackAddressSpace(int ExtraChunks = 0) {
+ // Linux kernels prior to 4.1 will sometimes locate the heap of a PIE binary
+ // relatively close to the stack (they are only guaranteed to be 128MiB
+ // apart). This results in crashes if we happen to heap-allocate more than
+ // 128MiB before we reach our stack high-water mark.
+ //
+ // To avoid these crashes, ensure that we have sufficient virtual memory
+ // pages allocated before we start running.
+ size_t Curr = getCurrentStackAllocation();
+ const int kTargetStack = kSufficientStack - 256 * 1024;
+ if (Curr < kTargetStack) {
+ volatile char *volatile Alloc =
+ static_cast<volatile char *>(alloca(kTargetStack - Curr));
+ Alloc[0] = 0;
+ Alloc[kTargetStack - Curr - 1] = 0;
+ }
+}
+#else
+static void ensureStackAddressSpace() {}
+#endif
+
+/// Attempt to ensure that we have at least 8MiB of usable stack space.
+static void ensureSufficientStack() {
+ struct rlimit rlim;
+ if (getrlimit(RLIMIT_STACK, &rlim) != 0)
+ return;
+
+ // Increase the soft stack limit to our desired level, if necessary and
+ // possible.
+ if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur < kSufficientStack) {
+ // Try to allocate sufficient stack.
+ if (rlim.rlim_max == RLIM_INFINITY || rlim.rlim_max >= kSufficientStack)
+ rlim.rlim_cur = kSufficientStack;
+ else if (rlim.rlim_cur == rlim.rlim_max)
+ return;
+ else
+ rlim.rlim_cur = rlim.rlim_max;
+
+ if (setrlimit(RLIMIT_STACK, &rlim) != 0 ||
+ rlim.rlim_cur != kSufficientStack)
+ return;
+ }
+
+ // We should now have a stack of size at least kSufficientStack. Ensure
+ // that we can actually use that much, if necessary.
+ ensureStackAddressSpace();
+}
+#else
+static void ensureSufficientStack() {}
+#endif
+
int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
+ ensureSufficientStack();
+
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 2d17be99e2d5..263751346b80 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -77,6 +77,9 @@ struct AssemblerInvocation {
/// be a list of strings starting with '+' or '-'.
std::vector<std::string> Features;
+ /// The list of symbol definitions.
+ std::vector<std::string> SymbolDefs;
+
/// @}
/// @name Language Options
/// @{
@@ -252,6 +255,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
Opts.IncrementalLinkerCompatible =
Args.hasArg(OPT_mincremental_linker_compatible);
+ Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym);
return Success;
}
@@ -379,7 +383,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
MCAsmBackend *MAB = nullptr;
if (Opts.ShowEncoding) {
CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
- MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple, Opts.CPU);
+ MCTargetOptions Options;
+ MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple, Opts.CPU, Options);
}
auto FOut = llvm::make_unique<formatted_raw_ostream>(*Out);
Str.reset(TheTarget->createAsmStreamer(
@@ -396,8 +401,9 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
}
MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
+ MCTargetOptions Options;
MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, Opts.Triple,
- Opts.CPU);
+ Opts.CPU, Options);
Triple T(Opts.Triple);
Str.reset(TheTarget->createMCObjectStreamer(
T, Ctx, *MAB, *Out, CE, *STI, Opts.RelaxAll,
@@ -418,6 +424,17 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
if (!TAP)
Failed = Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
+ // Set values for symbols, if any.
+ for (auto &S : Opts.SymbolDefs) {
+ auto Pair = StringRef(S).split('=');
+ auto Sym = Pair.first;
+ auto Val = Pair.second;
+ int64_t Value;
+ // We have already error checked this in the driver.
+ Val.getAsInteger(0, Value);
+ Ctx.setSymbolValue(Parser->getStreamer(), Sym, Value);
+ }
+
if (!Failed) {
Parser->setTargetParser(*TAP.get());
Failed = Parser->Run(Opts.NoInitialTextSection);
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 4d69aaffba23..61613028625b 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/CharInfo.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
@@ -25,7 +24,6 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Config/llvm-config.h"
@@ -37,7 +35,6 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
@@ -49,6 +46,7 @@
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
+#include <set>
#include <system_error>
using namespace clang;
using namespace clang::driver;
@@ -395,7 +393,7 @@ 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) {
+ if (ClangCLMode) {
// Arguments in "CL" are prepended.
llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
if (OptCL.hasValue()) {
diff --git a/tools/libclang/ARCMigrate.cpp b/tools/libclang/ARCMigrate.cpp
index b597383dfd2b..44a60c4e3e2c 100644
--- a/tools/libclang/ARCMigrate.cpp
+++ b/tools/libclang/ARCMigrate.cpp
@@ -32,8 +32,6 @@ struct Remap {
// libClang public APIs.
//===----------------------------------------------------------------------===//
-extern "C" {
-
CXRemapping clang_getRemappings(const char *migrate_dir_path) {
#ifndef CLANG_ENABLE_ARCMT
llvm::errs() << "error: feature not enabled in this build\n";
@@ -138,5 +136,3 @@ void clang_remap_getFilenames(CXRemapping map, unsigned index,
void clang_remap_dispose(CXRemapping map) {
delete static_cast<Remap *>(map);
}
-
-} // end: extern "C"
diff --git a/tools/libclang/BuildSystem.cpp b/tools/libclang/BuildSystem.cpp
index fe3db755eba8..99aa5b6f2ff0 100644
--- a/tools/libclang/BuildSystem.cpp
+++ b/tools/libclang/BuildSystem.cpp
@@ -16,15 +16,15 @@
#include "clang/Basic/VirtualFileSystem.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/CBindingWrapping.h"
+#include "llvm/Support/Chrono.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/TimeValue.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace llvm::sys;
unsigned long long clang_getBuildSessionTimestamp(void) {
- return llvm::sys::TimeValue::now().toEpochTime();
+ return llvm::sys::toTimeT(std::chrono::system_clock::now());
}
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(clang::vfs::YAMLVFSWriter,
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index deb4cc551b8a..b26cd754128a 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#include "CIndexer.h"
#include "CIndexDiagnostic.h"
+#include "CIndexer.h"
#include "CLog.h"
#include "CXCursor.h"
#include "CXSourceLocation.h"
@@ -1249,6 +1249,17 @@ bool CursorVisitor::VisitStaticAssertDecl(StaticAssertDecl *D) {
return false;
}
+bool CursorVisitor::VisitFriendDecl(FriendDecl *D) {
+ if (NamedDecl *FriendD = D->getFriendDecl()) {
+ if (Visit(MakeCXCursor(FriendD, TU, RegionOfInterest)))
+ return true;
+ } else if (TypeSourceInfo *TI = D->getFriendType()) {
+ if (Visit(TI->getTypeLoc()))
+ return true;
+ }
+ return false;
+}
+
bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) {
switch (Name.getName().getNameKind()) {
case clang::DeclarationName::Identifier:
@@ -1535,6 +1546,18 @@ bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
return Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU));
}
+bool CursorVisitor::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) {
+ if (Visit(MakeCursorTypeRef(TL.getDecl(), TL.getLocStart(), TU)))
+ return true;
+ for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) {
+ if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I),
+ TU)))
+ return true;
+ }
+
+ return false;
+}
+
bool CursorVisitor::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc()))
return true;
@@ -1977,6 +2000,19 @@ public:
void VisitOMPDistributeSimdDirective(const OMPDistributeSimdDirective *D);
void VisitOMPTargetParallelForSimdDirective(
const OMPTargetParallelForSimdDirective *D);
+ void VisitOMPTargetSimdDirective(const OMPTargetSimdDirective *D);
+ void VisitOMPTeamsDistributeDirective(const OMPTeamsDistributeDirective *D);
+ void VisitOMPTeamsDistributeSimdDirective(
+ const OMPTeamsDistributeSimdDirective *D);
+ void VisitOMPTeamsDistributeParallelForSimdDirective(
+ const OMPTeamsDistributeParallelForSimdDirective *D);
+ void VisitOMPTeamsDistributeParallelForDirective(
+ const OMPTeamsDistributeParallelForDirective *D);
+ void VisitOMPTargetTeamsDirective(const OMPTargetTeamsDirective *D);
+ void VisitOMPTargetTeamsDistributeDirective(
+ const OMPTargetTeamsDistributeDirective *D);
+ void VisitOMPTargetTeamsDistributeParallelForDirective(
+ const OMPTargetTeamsDistributeParallelForDirective *D);
private:
void AddDeclarationNameInfo(const Stmt *S);
@@ -2756,6 +2792,46 @@ void EnqueueVisitor::VisitOMPTargetParallelForSimdDirective(
VisitOMPLoopDirective(D);
}
+void EnqueueVisitor::VisitOMPTargetSimdDirective(
+ const OMPTargetSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPTeamsDistributeDirective(
+ const OMPTeamsDistributeDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPTeamsDistributeSimdDirective(
+ const OMPTeamsDistributeSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPTeamsDistributeParallelForSimdDirective(
+ const OMPTeamsDistributeParallelForSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPTeamsDistributeParallelForDirective(
+ const OMPTeamsDistributeParallelForDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPTargetTeamsDirective(
+ const OMPTargetTeamsDirective *D) {
+ VisitOMPExecutableDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPTargetTeamsDistributeDirective(
+ const OMPTargetTeamsDistributeDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void EnqueueVisitor::VisitOMPTargetTeamsDistributeParallelForDirective(
+ const OMPTargetTeamsDistributeParallelForDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) {
EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
}
@@ -3054,7 +3130,6 @@ struct RegisterFatalErrorHandler {
static llvm::ManagedStatic<RegisterFatalErrorHandler> RegisterFatalErrorHandlerOnce;
-extern "C" {
CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
int displayDiagnostics) {
// We use crash recovery to make some of our APIs more reliable, implicitly
@@ -3469,10 +3544,12 @@ static StringLiteral* getCFSTR_value(CallExpr *callExpr) {
struct ExprEvalResult {
CXEvalResultKind EvalType;
union {
- int intVal;
+ unsigned long long unsignedVal;
+ long long intVal;
double floatVal;
char *stringVal;
} EvalData;
+ bool IsUnsignedInt;
~ExprEvalResult() {
if (EvalType != CXEval_UnExposed && EvalType != CXEval_Float &&
EvalType != CXEval_Int) {
@@ -3493,10 +3570,32 @@ CXEvalResultKind clang_EvalResult_getKind(CXEvalResult E) {
}
int clang_EvalResult_getAsInt(CXEvalResult E) {
+ return clang_EvalResult_getAsLongLong(E);
+}
+
+long long clang_EvalResult_getAsLongLong(CXEvalResult E) {
if (!E) {
return 0;
}
- return ((ExprEvalResult *)E)->EvalData.intVal;
+ ExprEvalResult *Result = (ExprEvalResult*)E;
+ if (Result->IsUnsignedInt)
+ return Result->EvalData.unsignedVal;
+ return Result->EvalData.intVal;
+}
+
+unsigned clang_EvalResult_isUnsignedInt(CXEvalResult E) {
+ return ((ExprEvalResult *)E)->IsUnsignedInt;
+}
+
+unsigned long long clang_EvalResult_getAsUnsigned(CXEvalResult E) {
+ if (!E) {
+ return 0;
+ }
+
+ ExprEvalResult *Result = (ExprEvalResult*)E;
+ if (Result->IsUnsignedInt)
+ return Result->EvalData.unsignedVal;
+ return Result->EvalData.intVal;
}
double clang_EvalResult_getAsDouble(CXEvalResult E) {
@@ -3527,10 +3626,19 @@ static const ExprEvalResult* evaluateExpr(Expr *expr, CXCursor C) {
CallExpr *callExpr;
auto result = llvm::make_unique<ExprEvalResult>();
result->EvalType = CXEval_UnExposed;
+ result->IsUnsignedInt = false;
if (ER.Val.isInt()) {
result->EvalType = CXEval_Int;
- result->EvalData.intVal = ER.Val.getInt().getExtValue();
+
+ auto& val = ER.Val.getInt();
+ if (val.isUnsigned()) {
+ result->IsUnsignedInt = true;
+ result->EvalData.unsignedVal = val.getZExtValue();
+ } else {
+ result->EvalData.intVal = val.getExtValue();
+ }
+
return result.release();
}
@@ -3541,7 +3649,7 @@ static const ExprEvalResult* evaluateExpr(Expr *expr, CXCursor C) {
result->EvalType = CXEval_Float;
bool ignored;
llvm::APFloat apFloat = ER.Val.getFloat();
- apFloat.convert(llvm::APFloat::IEEEdouble,
+ apFloat.convert(llvm::APFloat::IEEEdouble(),
llvm::APFloat::rmNearestTiesToEven, &ignored);
result->EvalData.floatVal = apFloat.convertToDouble();
return result.release();
@@ -3879,13 +3987,10 @@ CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
return MakeCXCursor(CXXUnit->getASTContext().getTranslationUnitDecl(), TU);
}
-} // end: extern "C"
-
//===----------------------------------------------------------------------===//
// CXFile Operations.
//===----------------------------------------------------------------------===//
-extern "C" {
CXString clang_getFileName(CXFile SFile) {
if (!SFile)
return cxstring::createNull();
@@ -3954,8 +4059,6 @@ int clang_File_isEqual(CXFile file1, CXFile file2) {
return FEnt1->getUniqueID() == FEnt2->getUniqueID();
}
-} // end: extern "C"
-
//===----------------------------------------------------------------------===//
// CXCursor Operations.
//===----------------------------------------------------------------------===//
@@ -4340,7 +4443,8 @@ CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
}
if (C.kind == CXCursor_CXXMethod || C.kind == CXCursor_Destructor ||
- C.kind == CXCursor_ConversionFunction) {
+ C.kind == CXCursor_ConversionFunction ||
+ C.kind == CXCursor_FunctionDecl) {
if (pieceIndex > 0)
return clang_getNullRange();
if (const FunctionDecl *FD =
@@ -4880,12 +4984,30 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPDistributeSimdDirective");
case CXCursor_OMPTargetParallelForSimdDirective:
return cxstring::createRef("OMPTargetParallelForSimdDirective");
+ case CXCursor_OMPTargetSimdDirective:
+ return cxstring::createRef("OMPTargetSimdDirective");
+ case CXCursor_OMPTeamsDistributeDirective:
+ return cxstring::createRef("OMPTeamsDistributeDirective");
+ case CXCursor_OMPTeamsDistributeSimdDirective:
+ return cxstring::createRef("OMPTeamsDistributeSimdDirective");
+ case CXCursor_OMPTeamsDistributeParallelForSimdDirective:
+ return cxstring::createRef("OMPTeamsDistributeParallelForSimdDirective");
+ case CXCursor_OMPTeamsDistributeParallelForDirective:
+ return cxstring::createRef("OMPTeamsDistributeParallelForDirective");
+ case CXCursor_OMPTargetTeamsDirective:
+ return cxstring::createRef("OMPTargetTeamsDirective");
+ case CXCursor_OMPTargetTeamsDistributeDirective:
+ return cxstring::createRef("OMPTargetTeamsDistributeDirective");
+ case CXCursor_OMPTargetTeamsDistributeParallelForDirective:
+ return cxstring::createRef("OMPTargetTeamsDistributeParallelForDirective");
case CXCursor_OverloadCandidate:
return cxstring::createRef("OverloadCandidate");
case CXCursor_TypeAliasTemplateDecl:
return cxstring::createRef("TypeAliasTemplateDecl");
case CXCursor_StaticAssert:
return cxstring::createRef("StaticAssert");
+ case CXCursor_FriendDecl:
+ return cxstring::createRef("FriendDecl");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -5453,8 +5575,6 @@ static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
return getRawCursorExtent(C);
}
-extern "C" {
-
CXSourceRange clang_getCursorExtent(CXCursor C) {
SourceRange R = getRawCursorExtent(C);
if (R.isInvalid())
@@ -5607,6 +5727,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::TemplateTypeParm:
case Decl::EnumConstant:
case Decl::Field:
+ case Decl::Binding:
case Decl::MSProperty:
case Decl::IndirectField:
case Decl::ObjCIvar:
@@ -5619,6 +5740,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::ObjCImplementation:
case Decl::AccessSpec:
case Decl::LinkageSpec:
+ case Decl::Export:
case Decl::ObjCPropertyImpl:
case Decl::FileScopeAsm:
case Decl::StaticAssert:
@@ -5634,6 +5756,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::BuiltinTemplate:
case Decl::PragmaComment:
case Decl::PragmaDetectMismatch:
+ case Decl::UsingPack:
return C;
// Declaration kinds that don't make any sense here, but are
@@ -5677,7 +5800,8 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Var:
case Decl::VarTemplateSpecialization:
- case Decl::VarTemplatePartialSpecialization: {
+ case Decl::VarTemplatePartialSpecialization:
+ case Decl::Decomposition: {
// Ask the variable if it has a definition.
if (const VarDecl *Def = cast<VarDecl>(D)->getDefinition())
return MakeCXCursor(Def, TU);
@@ -5944,8 +6068,6 @@ void clang_executeOnThread(void (*fn)(void*), void *user_data,
llvm::llvm_execute_on_thread(fn, user_data, stack_size);
}
-} // end: extern "C"
-
//===----------------------------------------------------------------------===//
// Token-based Operations.
//===----------------------------------------------------------------------===//
@@ -5958,8 +6080,6 @@ void clang_executeOnThread(void (*fn)(void*), void *user_data,
* ptr_data: for identifiers and keywords, an IdentifierInfo*.
* otherwise unused.
*/
-extern "C" {
-
CXTokenKind clang_getTokenKind(CXToken CXTok) {
return static_cast<CXTokenKind>(CXTok.int_data[0]);
}
@@ -6103,7 +6223,7 @@ static void getTokens(ASTUnit *CXXUnit, SourceRange Range,
}
CXTokens.push_back(CXTok);
previousWasAt = Tok.is(tok::at);
- } while (Lex.getBufferLocation() <= EffectiveBufferEnd);
+ } while (Lex.getBufferLocation() < EffectiveBufferEnd);
}
void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
@@ -6148,8 +6268,6 @@ void clang_disposeTokens(CXTranslationUnit TU,
free(Tokens);
}
-} // end: extern "C"
-
//===----------------------------------------------------------------------===//
// Token annotation APIs.
//===----------------------------------------------------------------------===//
@@ -6817,8 +6935,6 @@ static void clang_annotateTokensImpl(CXTranslationUnit TU, ASTUnit *CXXUnit,
}
}
-extern "C" {
-
void clang_annotateTokens(CXTranslationUnit TU,
CXToken *Tokens, unsigned NumTokens,
CXCursor *Cursors) {
@@ -6858,13 +6974,10 @@ void clang_annotateTokens(CXTranslationUnit TU,
}
}
-} // end: extern "C"
-
//===----------------------------------------------------------------------===//
// Operations for querying linkage of a cursor.
//===----------------------------------------------------------------------===//
-extern "C" {
CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
if (!clang_isDeclaration(cursor.kind))
return CXLinkage_Invalid;
@@ -6881,13 +6994,11 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
return CXLinkage_Invalid;
}
-} // 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;
@@ -6902,7 +7013,6 @@ CXVisibilityKind clang_getCursorVisibility(CXCursor cursor) {
return CXVisibility_Invalid;
}
-} // end: extern "C"
//===----------------------------------------------------------------------===//
// Operations for querying language of a cursor.
@@ -6958,8 +7068,6 @@ static CXLanguageKind getDeclLanguage(const Decl *D) {
return CXLanguage_C;
}
-extern "C" {
-
static CXAvailabilityKind getCursorAvailabilityForDecl(const Decl *D) {
if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted())
return CXAvailability_NotAvailable;
@@ -7429,14 +7537,10 @@ CXFile clang_Module_getTopLevelHeader(CXTranslationUnit TU,
return nullptr;
}
-} // end: extern "C"
-
//===----------------------------------------------------------------------===//
// C++ AST instrospection.
//===----------------------------------------------------------------------===//
-extern "C" {
-
unsigned clang_CXXConstructor_isDefaultConstructor(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
@@ -7537,13 +7641,11 @@ unsigned clang_CXXMethod_isVirtual(CXCursor C) {
D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : nullptr;
return (Method && Method->isVirtual()) ? 1 : 0;
}
-} // end: extern "C"
//===----------------------------------------------------------------------===//
// Attribute introspection.
//===----------------------------------------------------------------------===//
-extern "C" {
CXType clang_getIBOutletCollectionType(CXCursor C) {
if (C.kind != CXCursor_IBOutletCollectionAttr)
return cxtype::MakeCXType(QualType(), cxcursor::getCursorTU(C));
@@ -7553,7 +7655,6 @@ CXType clang_getIBOutletCollectionType(CXCursor C) {
return cxtype::MakeCXType(A->getInterface(), cxcursor::getCursorTU(C));
}
-} // end: extern "C"
//===----------------------------------------------------------------------===//
// Inspecting memory usage.
@@ -7568,8 +7669,6 @@ static inline void createCXTUResourceUsageEntry(MemUsageEntries &entries,
entries.push_back(entry);
}
-extern "C" {
-
const char *clang_getTUResourceUsageName(CXTUResourceUsageKind kind) {
const char *str = "";
switch (kind) {
@@ -7708,7 +7807,7 @@ CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) {
CXTUResourceUsage usage = { (void*) entries.get(),
(unsigned) entries->size(),
!entries->empty() ? &(*entries)[0] : nullptr };
- entries.release();
+ (void)entries.release();
return usage;
}
@@ -7756,6 +7855,33 @@ CXSourceRangeList *clang_getSkippedRanges(CXTranslationUnit TU, CXFile file) {
return skipped;
}
+CXSourceRangeList *clang_getAllSkippedRanges(CXTranslationUnit TU) {
+ CXSourceRangeList *skipped = new CXSourceRangeList;
+ skipped->count = 0;
+ skipped->ranges = nullptr;
+
+ if (isNotUsableTU(TU)) {
+ LOG_BAD_TU(TU);
+ return skipped;
+ }
+
+ ASTUnit *astUnit = cxtu::getASTUnit(TU);
+ PreprocessingRecord *ppRec = astUnit->getPreprocessor().getPreprocessingRecord();
+ if (!ppRec)
+ return skipped;
+
+ ASTContext &Ctx = astUnit->getASTContext();
+
+ const std::vector<SourceRange> &SkippedRanges = ppRec->getSkippedRanges();
+
+ skipped->count = SkippedRanges.size();
+ skipped->ranges = new CXSourceRange[skipped->count];
+ for (unsigned i = 0, ei = skipped->count; i != ei; ++i)
+ skipped->ranges[i] = cxloc::translateSourceRange(Ctx, SkippedRanges[i]);
+
+ return skipped;
+}
+
void clang_disposeSourceRangeList(CXSourceRangeList *ranges) {
if (ranges) {
delete[] ranges->ranges;
@@ -7763,8 +7889,6 @@ void clang_disposeSourceRangeList(CXSourceRangeList *ranges) {
}
}
-} // end extern "C"
-
void clang::PrintLibclangResourceUsage(CXTranslationUnit TU) {
CXTUResourceUsage Usage = clang_getCXTUResourceUsage(TU);
for (unsigned I = 0; I != Usage.numEntries; ++I)
@@ -7927,14 +8051,10 @@ cxindex::checkForMacroInMacroDefinition(const MacroInfo *MI, SourceLocation Loc,
return checkForMacroInMacroDefinition(MI, Tok, TU);
}
-extern "C" {
-
CXString clang_getClangVersion() {
return cxstring::createDup(getClangFullVersion());
}
-} // end: extern "C"
-
Logger &cxindex::Logger::operator<<(CXTranslationUnit TU) {
if (TU) {
if (ASTUnit *Unit = cxtu::getASTUnit(TU)) {
@@ -8040,4 +8160,10 @@ cxindex::Logger::~Logger() {
extern volatile int ClangTidyPluginAnchorSource;
static int LLVM_ATTRIBUTE_UNUSED ClangTidyPluginAnchorDestination =
ClangTidyPluginAnchorSource;
+
+// This anchor is used to force the linker to link the clang-include-fixer
+// plugin.
+extern volatile int ClangIncludeFixerPluginAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED ClangIncludeFixerPluginAnchorDestination =
+ ClangIncludeFixerPluginAnchorSource;
#endif
diff --git a/tools/libclang/CIndexCXX.cpp b/tools/libclang/CIndexCXX.cpp
index 78e89d94d3c1..028b64a2b2d9 100644
--- a/tools/libclang/CIndexCXX.cpp
+++ b/tools/libclang/CIndexCXX.cpp
@@ -20,8 +20,6 @@
using namespace clang;
using namespace clang::cxcursor;
-extern "C" {
-
unsigned clang_isVirtualBase(CXCursor C) {
if (C.kind != CXCursor_CXXBaseSpecifier)
return 0;
@@ -123,5 +121,3 @@ CXCursor clang_getSpecializedCursorTemplate(CXCursor C) {
return MakeCXCursor(Template, getCursorTU(C));
}
-
-} // end extern "C"
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 344ed27021a1..12895c4a9b7a 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -53,8 +53,6 @@
using namespace clang;
using namespace clang::cxindex;
-extern "C" {
-
enum CXCompletionChunkKind
clang_getCompletionChunkKind(CXCompletionString completion_string,
unsigned chunk_number) {
@@ -346,8 +344,6 @@ AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
fprintf(stderr, "--- %u completion results\n",
--CodeCompletionResultObjects);
}
-
-} // end extern "C"
static unsigned long long getContextsForContextKind(
enum CodeCompletionContext::Kind kind,
@@ -794,7 +790,6 @@ clang_codeCompleteAt_Impl(CXTranslationUnit TU, const char *complete_filename,
return Results;
}
-extern "C" {
CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU,
const char *complete_filename,
unsigned complete_line,
@@ -916,8 +911,6 @@ CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *ResultsIn) {
return cxstring::createDup(Results->Selector);
}
-} // end extern "C"
-
/// \brief Simple utility function that appends a \p New string to the given
/// \p Old string, using the \p Buffer for storage.
///
@@ -990,9 +983,7 @@ namespace {
};
}
-extern "C" {
- void clang_sortCodeCompletionResults(CXCompletionResult *Results,
- unsigned NumResults) {
- std::stable_sort(Results, Results + NumResults, OrderCompletionResults());
- }
+void clang_sortCodeCompletionResults(CXCompletionResult *Results,
+ unsigned NumResults) {
+ std::stable_sort(Results, Results + NumResults, OrderCompletionResults());
}
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index 9ba36a6a0f8a..de223d3043a3 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -16,13 +16,11 @@
#include "CXSourceLocation.h"
#include "CXString.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/ASTUnit.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/DiagnosticRenderer.h"
-#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -207,8 +205,6 @@ CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
//-----------------------------------------------------------------------------
// C Interface Routines
//-----------------------------------------------------------------------------
-extern "C" {
-
unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
if (cxtu::isNotUsableTU(Unit)) {
LOG_BAD_TU(Unit);
@@ -479,5 +475,3 @@ unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
return D->getNumDiagnostics();
return 0;
}
-
-} // end extern "C"
diff --git a/tools/libclang/CIndexHigh.cpp b/tools/libclang/CIndexHigh.cpp
index d2baa13be9dd..d4666c2288c9 100644
--- a/tools/libclang/CIndexHigh.cpp
+++ b/tools/libclang/CIndexHigh.cpp
@@ -411,7 +411,7 @@ extern "C" {
CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file,
CXCursorAndRangeVisitor visitor) {
- LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
+ LogRef Log = Logger::make(__func__);
if (clang_Cursor_isNull(cursor)) {
if (Log)
@@ -485,7 +485,7 @@ CXResult clang_findIncludesInFile(CXTranslationUnit TU, CXFile file,
return CXResult_Invalid;
}
- LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
+ LogRef Log = Logger::make(__func__);
if (!file) {
if (Log)
*Log << "Null file";
@@ -535,4 +535,3 @@ CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit TU,
}
} // end: extern "C"
-
diff --git a/tools/libclang/CIndexInclusionStack.cpp b/tools/libclang/CIndexInclusionStack.cpp
index 095937453351..4b021fc4cbeb 100644
--- a/tools/libclang/CIndexInclusionStack.cpp
+++ b/tools/libclang/CIndexInclusionStack.cpp
@@ -17,8 +17,6 @@
#include "CXTranslationUnit.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Frontend/ASTUnit.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/raw_ostream.h"
using namespace clang;
static void getInclusions(const SrcMgr::SLocEntry &(SourceManager::*Getter)(unsigned, bool*) const, unsigned n,
@@ -70,7 +68,6 @@ static void getInclusions(const SrcMgr::SLocEntry &(SourceManager::*Getter)(unsi
}
-extern "C" {
void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
CXClientData clientData) {
if (cxtu::isNotUsableTU(TU)) {
@@ -98,4 +95,3 @@ void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
getInclusions(&SourceManager::getLocalSLocEntry, n, TU, CB, clientData);
}
-} // end extern C
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index 69d60c9d44f2..7cd7b6f1cd9e 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -36,8 +36,6 @@ bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf) {
return generateUSRForDecl(D, Buf);
}
-extern "C" {
-
CXString clang_getCursorUSR(CXCursor C) {
const CXCursorKind &K = clang_getCursorKind(C);
@@ -140,5 +138,3 @@ CXString clang_constructUSR_ObjCProperty(const char *property,
generateUSRForObjCProperty(property, /*isClassProp=*/false, OS);
return cxstring::createDup(OS.str());
}
-
-} // end extern "C"
diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp
index 91154cc1c3a0..694ed606306c 100644
--- a/tools/libclang/CIndexer.cpp
+++ b/tools/libclang/CIndexer.cpp
@@ -12,22 +12,13 @@
//===----------------------------------------------------------------------===//
#include "CIndexer.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclVisitor.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/Version.h"
-#include "clang/Sema/CodeCompleteConsumer.h"
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Config/llvm-config.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
-#include "llvm/Support/raw_ostream.h"
#include <cstdio>
-#include <sstream>
-#include <vector>
#ifdef __CYGWIN__
#include <cygwin/version.h>
diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h
index 47e30c30ba11..b227f943f7b3 100644
--- a/tools/libclang/CIndexer.h
+++ b/tools/libclang/CIndexer.h
@@ -17,11 +17,8 @@
#include "clang-c/Index.h"
#include "clang/Frontend/PCHContainerOperations.h"
-#include "clang/Lex/ModuleLoader.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Path.h"
+#include "llvm/ADT/STLExtras.h"
#include <utility>
-#include <vector>
namespace llvm {
class CrashRecoveryContext;
diff --git a/tools/libclang/CLog.h b/tools/libclang/CLog.h
index b9309ed19239..e1d6a57e4a01 100644
--- a/tools/libclang/CLog.h
+++ b/tools/libclang/CLog.h
@@ -98,6 +98,6 @@ public:
/// \endcode
#define LOG_SECTION(NAME) \
if (clang::cxindex::LogRef Log = clang::cxindex::Logger::make(NAME))
-#define LOG_FUNC_SECTION LOG_SECTION(LLVM_FUNCTION_NAME)
+#define LOG_FUNC_SECTION LOG_SECTION(__func__)
#endif
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index 630be124660d..2dd670307636 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -50,6 +50,7 @@ endif ()
if (TARGET clangTidyPlugin)
add_definitions(-DCLANG_TOOL_EXTRA_BUILD)
list(APPEND LIBS clangTidyPlugin)
+ list(APPEND LIBS clangIncludeFixerPlugin)
endif ()
find_library(DL_LIBRARY_PATH dl)
diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp
index 9cc05ed4e127..028fdf1d3a8b 100644
--- a/tools/libclang/CXComment.cpp
+++ b/tools/libclang/CXComment.cpp
@@ -11,15 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#include "clang-c/Index.h"
#include "CXComment.h"
#include "CXCursor.h"
#include "CXString.h"
#include "clang-c/Documentation.h"
+#include "clang-c/Index.h"
#include "clang/AST/Decl.h"
#include "clang/Index/CommentToXML.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include <climits>
@@ -27,8 +26,6 @@ using namespace clang;
using namespace clang::comments;
using namespace clang::cxcomment;
-extern "C" {
-
CXComment clang_Cursor_getParsedComment(CXCursor C) {
using namespace clang::cxcursor;
@@ -407,5 +404,3 @@ CXString clang_FullComment_getAsXML(CXComment CXC) {
return cxstring::createDup(XML.str());
}
-} // end extern "C"
-
diff --git a/tools/libclang/CXCompilationDatabase.cpp b/tools/libclang/CXCompilationDatabase.cpp
index 82498bf54c74..c122ec8a6db4 100644
--- a/tools/libclang/CXCompilationDatabase.cpp
+++ b/tools/libclang/CXCompilationDatabase.cpp
@@ -6,8 +6,6 @@
using namespace clang;
using namespace clang::tooling;
-extern "C" {
-
// FIXME: do something more useful with the error message
CXCompilationDatabase
clang_CompilationDatabase_fromDirectory(const char *BuildDir,
@@ -180,5 +178,3 @@ clang_CompileCommand_getMappedSourceContent(CXCompileCommand CCmd, unsigned I)
return cxstring::createRef(Cmd->MappedSources[I].second.c_str());
}
-
-} // end: extern "C"
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 19ab0f929c85..9344bfa6a60f 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -243,6 +243,8 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::ChooseExprClass:
case Stmt::DesignatedInitExprClass:
case Stmt::DesignatedInitUpdateExprClass:
+ case Stmt::ArrayInitLoopExprClass:
+ case Stmt::ArrayInitIndexExprClass:
case Stmt::ExprWithCleanupsClass:
case Stmt::ExpressionTraitExprClass:
case Stmt::ExtVectorElementExprClass:
@@ -650,6 +652,30 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::OMPTargetParallelForSimdDirectiveClass:
K = CXCursor_OMPTargetParallelForSimdDirective;
break;
+ case Stmt::OMPTargetSimdDirectiveClass:
+ K = CXCursor_OMPTargetSimdDirective;
+ break;
+ case Stmt::OMPTeamsDistributeDirectiveClass:
+ K = CXCursor_OMPTeamsDistributeDirective;
+ break;
+ case Stmt::OMPTeamsDistributeSimdDirectiveClass:
+ K = CXCursor_OMPTeamsDistributeSimdDirective;
+ break;
+ case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
+ K = CXCursor_OMPTeamsDistributeParallelForSimdDirective;
+ break;
+ case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
+ K = CXCursor_OMPTeamsDistributeParallelForDirective;
+ break;
+ case Stmt::OMPTargetTeamsDirectiveClass:
+ K = CXCursor_OMPTargetTeamsDirective;
+ break;
+ case Stmt::OMPTargetTeamsDistributeDirectiveClass:
+ K = CXCursor_OMPTargetTeamsDistributeDirective;
+ break;
+ case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
+ K = CXCursor_OMPTargetTeamsDistributeParallelForDirective;
+ break;
}
CXCursor C = { K, 0, { Parent, S, TU } };
@@ -1087,8 +1113,6 @@ bool cxcursor::isFirstInDeclGroup(CXCursor C) {
// libclang CXCursor APIs
//===----------------------------------------------------------------------===//
-extern "C" {
-
int clang_Cursor_isNull(CXCursor cursor) {
return clang_equalCursors(cursor, clang_getNullCursor());
}
@@ -1278,8 +1302,6 @@ unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C,
return TA.getAsIntegral().getZExtValue();
}
-} // end: extern "C"
-
//===----------------------------------------------------------------------===//
// CXCursorSet.
//===----------------------------------------------------------------------===//
@@ -1313,7 +1335,6 @@ public:
};
}
-extern "C" {
CXCursorSet clang_createCXCursorSet() {
return packCXCursorSet(new CXCursorSet_Impl());
}
@@ -1376,7 +1397,6 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
}
return nullptr;
}
-} // end: extern C.
namespace {
struct OverridenCursorsPool {
@@ -1401,7 +1421,6 @@ void cxcursor::disposeOverridenCXCursorsPool(void *pool) {
delete static_cast<OverridenCursorsPool*>(pool);
}
-extern "C" {
void clang_getOverriddenCursors(CXCursor cursor,
CXCursor **overridden,
unsigned *num_overridden) {
@@ -1523,5 +1542,3 @@ CXType clang_Cursor_getReceiverType(CXCursor C) {
return cxtype::MakeCXType(QualType(), TU);
}
-
-} // end: extern "C"
diff --git a/tools/libclang/CXIndexDataConsumer.cpp b/tools/libclang/CXIndexDataConsumer.cpp
index 59fa92bb21e2..45198dd1b168 100644
--- a/tools/libclang/CXIndexDataConsumer.cpp
+++ b/tools/libclang/CXIndexDataConsumer.cpp
@@ -478,6 +478,14 @@ void CXIndexDataConsumer::importedModule(const ImportDecl *ImportD) {
if (!Mod)
return;
+ // If the imported module is part of the top-level module that we're
+ // indexing, it doesn't correspond to an imported AST file.
+ // FIXME: This assumes that AST files and top-level modules directly
+ // correspond, which is unlikely to remain true forever.
+ if (Module *SrcMod = ImportD->getImportedOwningModule())
+ if (SrcMod->getTopLevelModule() == Mod->getTopLevelModule())
+ return;
+
CXIdxImportedASTFileInfo Info = {
static_cast<CXFile>(
const_cast<FileEntry *>(Mod->getASTFile())),
@@ -1134,7 +1142,7 @@ void CXIndexDataConsumer::translateLoc(SourceLocation Loc,
static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage L);
static CXIdxEntityCXXTemplateKind
-getEntityKindFromSymbolSubKinds(SymbolSubKindSet K);
+getEntityKindFromSymbolProperties(SymbolPropertySet K);
static CXIdxEntityLanguage getEntityLangFromSymbolLang(SymbolLanguage L);
void CXIndexDataConsumer::getEntityInfo(const NamedDecl *D,
@@ -1150,7 +1158,7 @@ void CXIndexDataConsumer::getEntityInfo(const NamedDecl *D,
SymbolInfo SymInfo = getSymbolInfo(D);
EntityInfo.kind = getEntityKindFromSymbolKind(SymInfo.Kind, SymInfo.Lang);
- EntityInfo.templateKind = getEntityKindFromSymbolSubKinds(SymInfo.SubKinds);
+ EntityInfo.templateKind = getEntityKindFromSymbolProperties(SymInfo.Properties);
EntityInfo.lang = getEntityLangFromSymbolLang(SymInfo.Lang);
if (D->hasAttrs()) {
@@ -1290,12 +1298,12 @@ static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage
}
static CXIdxEntityCXXTemplateKind
-getEntityKindFromSymbolSubKinds(SymbolSubKindSet K) {
- if (K & (unsigned)SymbolSubKind::TemplatePartialSpecialization)
+getEntityKindFromSymbolProperties(SymbolPropertySet K) {
+ if (K & (unsigned)SymbolProperty::TemplatePartialSpecialization)
return CXIdxEntity_TemplatePartialSpecialization;
- if (K & (unsigned)SymbolSubKind::TemplateSpecialization)
+ if (K & (unsigned)SymbolProperty::TemplateSpecialization)
return CXIdxEntity_TemplateSpecialization;
- if (K & (unsigned)SymbolSubKind::Generic)
+ if (K & (unsigned)SymbolProperty::Generic)
return CXIdxEntity_Template;
return CXIdxEntity_NonTemplate;
}
diff --git a/tools/libclang/CXIndexDataConsumer.h b/tools/libclang/CXIndexDataConsumer.h
index 308fa79488de..406831f1ddce 100644
--- a/tools/libclang/CXIndexDataConsumer.h
+++ b/tools/libclang/CXIndexDataConsumer.h
@@ -16,7 +16,6 @@
#include "clang/AST/DeclGroup.h"
#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/DenseSet.h"
-#include <deque>
namespace clang {
class FileEntry;
diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp
index 2c10d34844b7..36c3dcabb924 100644
--- a/tools/libclang/CXLoadedDiagnostic.cpp
+++ b/tools/libclang/CXLoadedDiagnostic.cpp
@@ -18,13 +18,11 @@
#include "clang/Basic/LLVM.h"
#include "clang/Frontend/SerializedDiagnosticReader.h"
#include "clang/Frontend/SerializedDiagnostics.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MemoryBuffer.h"
using namespace clang;
@@ -389,11 +387,9 @@ std::error_code DiagLoader::visitDiagnosticRecord(
return std::error_code();
}
-extern "C" {
CXDiagnosticSet clang_loadDiagnostics(const char *file,
enum CXLoadDiag_Error *error,
CXString *errorString) {
DiagLoader L(error, errorString);
return L.load(file);
}
-} // end extern 'C'.
diff --git a/tools/libclang/CXLoadedDiagnostic.h b/tools/libclang/CXLoadedDiagnostic.h
index d5006a4444a4..1209d76669f8 100644
--- a/tools/libclang/CXLoadedDiagnostic.h
+++ b/tools/libclang/CXLoadedDiagnostic.h
@@ -17,7 +17,6 @@
#include "CIndexDiagnostic.h"
#include "llvm/ADT/StringRef.h"
#include "clang/Basic/LLVM.h"
-#include <string>
#include <vector>
namespace clang {
diff --git a/tools/libclang/CXSourceLocation.cpp b/tools/libclang/CXSourceLocation.cpp
index 1b7464b25af9..2e0ea4e44099 100644
--- a/tools/libclang/CXSourceLocation.cpp
+++ b/tools/libclang/CXSourceLocation.cpp
@@ -38,8 +38,6 @@ static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
// Basic construction and comparison of CXSourceLocations and CXSourceRanges.
//===----------------------------------------------------------------------===//
-extern "C" {
-
CXSourceLocation clang_getNullLocation() {
CXSourceLocation Result = { { nullptr, nullptr }, 0 };
return Result;
@@ -110,14 +108,10 @@ CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
return Result;
}
-} // end extern "C"
-
//===----------------------------------------------------------------------===//
// Getting CXSourceLocations and CXSourceRanges from a translation unit.
//===----------------------------------------------------------------------===//
-extern "C" {
-
CXSourceLocation clang_getLocation(CXTranslationUnit TU,
CXFile file,
unsigned line,
@@ -131,7 +125,7 @@ CXSourceLocation clang_getLocation(CXTranslationUnit TU,
if (line == 0 || column == 0)
return clang_getNullLocation();
- LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
+ LogRef Log = Logger::make(__func__);
ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
const FileEntry *File = static_cast<const FileEntry *>(file);
@@ -139,16 +133,17 @@ CXSourceLocation clang_getLocation(CXTranslationUnit TU,
if (SLoc.isInvalid()) {
if (Log)
*Log << llvm::format("(\"%s\", %d, %d) = invalid",
- File->getName(), line, column);
+ File->getName().str().c_str(), line, column);
return clang_getNullLocation();
}
CXSourceLocation CXLoc =
cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
if (Log)
- *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column)
+ *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName().str().c_str(),
+ line, column)
<< CXLoc;
-
+
return CXLoc;
}
@@ -173,8 +168,6 @@ CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
}
-} // end extern "C"
-
//===----------------------------------------------------------------------===//
// Routines for expanding and manipulating CXSourceLocations, regardless
// of their origin.
@@ -204,8 +197,6 @@ static void createNullLocation(CXString *filename, unsigned *line,
*offset = 0;
}
-extern "C" {
-
int clang_Location_isInSystemHeader(CXSourceLocation location) {
const SourceLocation Loc =
SourceLocation::getFromRawEncoding(location.int_data);
@@ -381,5 +372,3 @@ void clang_getFileLocation(CXSourceLocation location,
if (offset)
*offset = FileOffset;
}
-
-} // end extern "C"
diff --git a/tools/libclang/CXStoredDiagnostic.cpp b/tools/libclang/CXStoredDiagnostic.cpp
index faaf746a1e70..f2e9c1da28f6 100644
--- a/tools/libclang/CXStoredDiagnostic.cpp
+++ b/tools/libclang/CXStoredDiagnostic.cpp
@@ -19,10 +19,7 @@
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace clang::cxloc;
diff --git a/tools/libclang/CXString.cpp b/tools/libclang/CXString.cpp
index 1ccbed3b5c24..448603179203 100644
--- a/tools/libclang/CXString.cpp
+++ b/tools/libclang/CXString.cpp
@@ -17,7 +17,6 @@
#include "CXTranslationUnit.h"
#include "clang-c/Index.h"
#include "clang/Frontend/ASTUnit.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -162,7 +161,6 @@ bool isManagedByPool(CXString str) {
// libClang public APIs.
//===----------------------------------------------------------------------===//
-extern "C" {
const char *clang_getCString(CXString string) {
if (string.private_flags == (unsigned) CXS_StringBuf) {
return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data();
@@ -192,5 +190,3 @@ void clang_disposeStringSet(CXStringSet *set) {
delete set;
}
-} // end: extern "C"
-
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 4fcd8864cd37..66caf340d195 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -143,7 +143,44 @@ static inline CXTranslationUnit GetTU(CXType CT) {
return static_cast<CXTranslationUnit>(CT.data[1]);
}
-extern "C" {
+static Optional<ArrayRef<TemplateArgument>>
+GetTemplateArguments(QualType Type) {
+ assert(!Type.isNull());
+ if (const auto *Specialization = Type->getAs<TemplateSpecializationType>())
+ return Specialization->template_arguments();
+
+ if (const auto *RecordDecl = Type->getAsCXXRecordDecl()) {
+ const auto *TemplateDecl =
+ dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl);
+ if (TemplateDecl)
+ return TemplateDecl->getTemplateArgs().asArray();
+ }
+
+ return None;
+}
+
+static Optional<QualType> TemplateArgumentToQualType(const TemplateArgument &A) {
+ if (A.getKind() == TemplateArgument::Type)
+ return A.getAsType();
+ return None;
+}
+
+static Optional<QualType>
+FindTemplateArgumentTypeAt(ArrayRef<TemplateArgument> TA, unsigned index) {
+ unsigned current = 0;
+ for (const auto &A : TA) {
+ if (A.getKind() == TemplateArgument::Pack) {
+ if (index < current + A.pack_size())
+ return TemplateArgumentToQualType(A.getPackAsArray()[index - current]);
+ current += A.pack_size();
+ continue;
+ }
+ if (current == index)
+ return TemplateArgumentToQualType(A);
+ current++;
+ }
+ return None;
+}
CXType clang_getCursorType(CXCursor C) {
using namespace cxcursor;
@@ -531,6 +568,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
TCALLINGCONV(X86FastCall);
TCALLINGCONV(X86ThisCall);
TCALLINGCONV(X86Pascal);
+ TCALLINGCONV(X86RegCall);
TCALLINGCONV(X86VectorCall);
TCALLINGCONV(X86_64Win64);
TCALLINGCONV(X86_64SysV);
@@ -901,12 +939,11 @@ CXString clang_getDeclObjCTypeEncoding(CXCursor C) {
std::string encoding;
if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
- if (Ctx.getObjCEncodingForMethodDecl(OMD, encoding))
- return cxstring::createRef("?");
+ encoding = Ctx.getObjCEncodingForMethodDecl(OMD);
} else if (const ObjCPropertyDecl *OPD = dyn_cast<ObjCPropertyDecl>(D))
- Ctx.getObjCEncodingForPropertyDecl(OPD, nullptr, encoding);
+ encoding = Ctx.getObjCEncodingForPropertyDecl(OPD, nullptr);
else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- Ctx.getObjCEncodingForFunctionDecl(FD, encoding);
+ encoding = Ctx.getObjCEncodingForFunctionDecl(FD);
else {
QualType Ty;
if (const TypeDecl *TD = dyn_cast<TypeDecl>(D))
@@ -920,38 +957,37 @@ CXString clang_getDeclObjCTypeEncoding(CXCursor C) {
return cxstring::createDup(encoding);
}
+static unsigned GetTemplateArgumentArraySize(ArrayRef<TemplateArgument> TA) {
+ unsigned size = TA.size();
+ for (const auto &Arg : TA)
+ if (Arg.getKind() == TemplateArgument::Pack)
+ size += Arg.pack_size() - 1;
+ return size;
+}
+
int clang_Type_getNumTemplateArguments(CXType CT) {
QualType T = GetQualType(CT);
if (T.isNull())
return -1;
- const CXXRecordDecl *RecordDecl = T->getAsCXXRecordDecl();
- if (!RecordDecl)
- return -1;
- const ClassTemplateSpecializationDecl *TemplateDecl =
- dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl);
- if (!TemplateDecl)
+
+ auto TA = GetTemplateArguments(T);
+ if (!TA)
return -1;
- return TemplateDecl->getTemplateArgs().size();
+
+ return GetTemplateArgumentArraySize(TA.getValue());
}
-CXType clang_Type_getTemplateArgumentAsType(CXType CT, unsigned i) {
+CXType clang_Type_getTemplateArgumentAsType(CXType CT, unsigned index) {
QualType T = GetQualType(CT);
if (T.isNull())
return MakeCXType(QualType(), GetTU(CT));
- const CXXRecordDecl *RecordDecl = T->getAsCXXRecordDecl();
- if (!RecordDecl)
- return MakeCXType(QualType(), GetTU(CT));
- const ClassTemplateSpecializationDecl *TemplateDecl =
- dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl);
- if (!TemplateDecl)
- return MakeCXType(QualType(), GetTU(CT));
- const TemplateArgumentList &TA = TemplateDecl->getTemplateArgs();
- if (TA.size() <= i)
- return MakeCXType(QualType(), GetTU(CT));
- const TemplateArgument &A = TA.get(i);
- if (A.getKind() != TemplateArgument::Type)
+
+ auto TA = GetTemplateArguments(T);
+ if (!TA)
return MakeCXType(QualType(), GetTU(CT));
- return MakeCXType(A.getAsType(), GetTU(CT));
+
+ Optional<QualType> QT = FindTemplateArgumentTypeAt(TA.getValue(), index);
+ return MakeCXType(QT.getValueOr(QualType()), GetTU(CT));
}
unsigned clang_Type_visitFields(CXType PT,
@@ -1000,5 +1036,3 @@ CXType clang_Type_getNamedType(CXType CT){
return MakeCXType(QualType(), GetTU(CT));
}
-
-} // end: extern "C"
diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h
index a2dfaeedccc8..82f251a348f0 100644
--- a/tools/libclang/CursorVisitor.h
+++ b/tools/libclang/CursorVisitor.h
@@ -239,7 +239,8 @@ public:
bool VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
bool VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
bool VisitStaticAssertDecl(StaticAssertDecl *D);
-
+ bool VisitFriendDecl(FriendDecl *D);
+
// Name visitor
bool VisitDeclarationNameInfo(DeclarationNameInfo Name);
bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range);
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
index fe14cb2664af..c18b5402aa71 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -26,7 +26,7 @@
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/PPConditionalDirectiveRecord.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Sema/SemaConsumer.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Mutex.h"
@@ -687,8 +687,6 @@ static CXErrorCode clang_indexTranslationUnit_Impl(
// libclang public APIs.
//===----------------------------------------------------------------------===//
-extern "C" {
-
int clang_index_isEntityObjCContainerKind(CXIdxEntityKind K) {
return CXIdxEntity_ObjCClass <= K && K <= CXIdxEntity_ObjCCategory;
}
@@ -978,5 +976,3 @@ CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc location) {
return cxloc::translateSourceLocation(DataConsumer.getASTContext(), Loc);
}
-} // end: extern "C"
-
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index c8fe0a21d09d..222cb678395e 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -142,6 +142,7 @@ clang_findReferencesInFile
clang_findReferencesInFileWithBlock
clang_formatDiagnostic
clang_free
+clang_getAllSkippedRanges
clang_getArgType
clang_getArrayElementType
clang_getArraySize
@@ -334,6 +335,9 @@ clang_Cursor_hasAttrs
clang_Cursor_Evaluate
clang_EvalResult_getKind
clang_EvalResult_getAsInt
+clang_EvalResult_getAsLongLong
+clang_EvalResult_getAsUnsigned
+clang_EvalResult_isUnsignedInt
clang_EvalResult_getAsDouble
clang_EvalResult_getAsStr
clang_EvalResult_dispose
diff --git a/tools/scan-build-py/libscanbuild/analyze.py b/tools/scan-build-py/libscanbuild/analyze.py
index 0ed0aef83873..244c34b75837 100644
--- a/tools/scan-build-py/libscanbuild/analyze.py
+++ b/tools/scan-build-py/libscanbuild/analyze.py
@@ -269,6 +269,9 @@ def validate(parser, args, from_build_command):
""" Validation done by the parser itself, but semantic check still
needs to be done. This method is doing that. """
+ # Make plugins always a list. (It might be None when not specified.)
+ args.plugins = args.plugins if args.plugins else []
+
if args.help_checkers_verbose:
print_checkers(get_checkers(args.clang, args.plugins))
parser.exit()
diff --git a/tools/scan-build-py/libscanbuild/clang.py b/tools/scan-build-py/libscanbuild/clang.py
index 0c3454b16a76..833e77d28bbe 100644
--- a/tools/scan-build-py/libscanbuild/clang.py
+++ b/tools/scan-build-py/libscanbuild/clang.py
@@ -15,142 +15,143 @@ from libscanbuild.shell import decode
__all__ = ['get_version', 'get_arguments', 'get_checkers']
+# regex for activated checker
+ACTIVE_CHECKER_PATTERN = re.compile(r'^-analyzer-checker=(.*)$')
-def get_version(cmd):
- """ Returns the compiler version as string. """
- lines = subprocess.check_output([cmd, '-v'], stderr=subprocess.STDOUT)
- return lines.decode('ascii').splitlines()[0]
+def get_version(clang):
+ """ Returns the compiler version as string.
+
+ :param clang: the compiler we are using
+ :return: the version string printed to stderr """
+
+ output = subprocess.check_output([clang, '-v'], stderr=subprocess.STDOUT)
+ return output.decode('utf-8').splitlines()[0]
def get_arguments(command, cwd):
""" Capture Clang invocation.
- This method returns the front-end invocation that would be executed as
- a result of the given driver invocation. """
-
- def lastline(stream):
- last = None
- for line in stream:
- last = line
- if last is None:
- raise Exception("output not found")
- return last
+ :param command: the compilation command
+ :param cwd: the current working directory
+ :return: the detailed front-end invocation command """
cmd = command[:]
cmd.insert(1, '-###')
logging.debug('exec command in %s: %s', cwd, ' '.join(cmd))
- child = subprocess.Popen(cmd,
- cwd=cwd,
- universal_newlines=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- line = lastline(child.stdout)
- child.stdout.close()
- child.wait()
- if child.returncode == 0:
- if re.search(r'clang(.*): error:', line):
- raise Exception(line)
- return decode(line)
- else:
- raise Exception(line)
+
+ output = subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT)
+ # The relevant information is in the last line of the output.
+ # Don't check if finding last line fails, would throw exception anyway.
+ last_line = output.decode('utf-8').splitlines()[-1]
+ if re.search(r'clang(.*): error:', last_line):
+ raise Exception(last_line)
+ return decode(last_line)
def get_active_checkers(clang, plugins):
- """ To get the default plugins we execute Clang to print how this
- compilation would be called.
+ """ Get the active checker list.
- For input file we specify stdin and pass only language information. """
+ :param clang: the compiler we are using
+ :param plugins: list of plugins which was requested by the user
+ :return: list of checker names which are active
- def checkers(language):
+ To get the default checkers we execute Clang to print how this
+ compilation would be called. And take out the enabled checker from the
+ arguments. For input file we specify stdin and pass only language
+ information. """
+
+ def get_active_checkers_for(language):
""" Returns a list of active checkers for the given language. """
- load = [elem
- for plugin in plugins
- for elem in ['-Xclang', '-load', '-Xclang', plugin]]
- cmd = [clang, '--analyze'] + load + ['-x', language, '-']
- pattern = re.compile(r'^-analyzer-checker=(.*)$')
- return [pattern.match(arg).group(1)
- for arg in get_arguments(cmd, '.') if pattern.match(arg)]
+ load_args = [arg
+ for plugin in plugins
+ for arg in ['-Xclang', '-load', '-Xclang', plugin]]
+ cmd = [clang, '--analyze'] + load_args + ['-x', language, '-']
+ return [ACTIVE_CHECKER_PATTERN.match(arg).group(1)
+ for arg in get_arguments(cmd, '.')
+ if ACTIVE_CHECKER_PATTERN.match(arg)]
result = set()
for language in ['c', 'c++', 'objective-c', 'objective-c++']:
- result.update(checkers(language))
- return result
+ result.update(get_active_checkers_for(language))
+ return frozenset(result)
-def get_checkers(clang, plugins):
- """ Get all the available checkers from default and from the plugins.
+def is_active(checkers):
+ """ Returns a method, which classifies the checker active or not,
+ based on the received checker name list. """
- clang -- the compiler we are using
- plugins -- list of plugins which was requested by the user
+ def predicate(checker):
+ """ Returns True if the given checker is active. """
- This method returns a dictionary of all available checkers and status.
+ return any(pattern.match(checker) for pattern in predicate.patterns)
- {<plugin name>: (<plugin description>, <is active by default>)} """
+ predicate.patterns = [re.compile(r'^' + a + r'(\.|$)') for a in checkers]
+ return predicate
- plugins = plugins if plugins else []
- def parse_checkers(stream):
- """ Parse clang -analyzer-checker-help output.
+def parse_checkers(stream):
+ """ Parse clang -analyzer-checker-help output.
- Below the line 'CHECKERS:' are there the name description pairs.
- Many of them are in one line, but some long named plugins has the
- name and the description in separate lines.
+ Below the line 'CHECKERS:' are there the name description pairs.
+ Many of them are in one line, but some long named checker has the
+ name and the description in separate lines.
- The plugin name is always prefixed with two space character. The
- name contains no whitespaces. Then followed by newline (if it's
- too long) or other space characters comes the description of the
- plugin. The description ends with a newline character. """
+ The checker name is always prefixed with two space character. The
+ name contains no whitespaces. Then followed by newline (if it's
+ too long) or other space characters comes the description of the
+ checker. The description ends with a newline character.
- # find checkers header
- for line in stream:
- if re.match(r'^CHECKERS:', line):
- break
- # find entries
- state = None
- for line in stream:
- if state and not re.match(r'^\s\s\S', line):
- yield (state, line.strip())
- state = None
- elif re.match(r'^\s\s\S+$', line.rstrip()):
- state = line.strip()
- else:
- pattern = re.compile(r'^\s\s(?P<key>\S*)\s*(?P<value>.*)')
- match = pattern.match(line.rstrip())
- if match:
- current = match.groupdict()
- yield (current['key'], current['value'])
+ :param stream: list of lines to parse
+ :return: generator of tuples
- def is_active(actives, entry):
- """ Returns true if plugin name is matching the active plugin names.
+ (<checker name>, <checker description>) """
- actives -- set of active plugin names (or prefixes).
- entry -- the current plugin name to judge.
+ lines = iter(stream)
+ # find checkers header
+ for line in lines:
+ if re.match(r'^CHECKERS:', line):
+ break
+ # find entries
+ state = None
+ for line in lines:
+ if state and not re.match(r'^\s\s\S', line):
+ yield (state, line.strip())
+ state = None
+ elif re.match(r'^\s\s\S+$', line.rstrip()):
+ state = line.strip()
+ else:
+ pattern = re.compile(r'^\s\s(?P<key>\S*)\s*(?P<value>.*)')
+ match = pattern.match(line.rstrip())
+ if match:
+ current = match.groupdict()
+ yield (current['key'], current['value'])
- The active plugin names are specific plugin names or prefix of some
- names. One example for prefix, when it say 'unix' and it shall match
- on 'unix.API', 'unix.Malloc' and 'unix.MallocSizeof'. """
- return any(re.match(r'^' + a + r'(\.|$)', entry) for a in actives)
+def get_checkers(clang, plugins):
+ """ Get all the available checkers from default and from the plugins.
+
+ :param clang: the compiler we are using
+ :param plugins: list of plugins which was requested by the user
+ :return: a dictionary of all available checkers and its status
- actives = get_active_checkers(clang, plugins)
+ {<checker name>: (<checker description>, <is active by default>)} """
load = [elem for plugin in plugins for elem in ['-load', plugin]]
cmd = [clang, '-cc1'] + load + ['-analyzer-checker-help']
logging.debug('exec command: %s', ' '.join(cmd))
- child = subprocess.Popen(cmd,
- universal_newlines=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
+ output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+ lines = output.decode('utf-8').splitlines()
+
+ is_active_checker = is_active(get_active_checkers(clang, plugins))
+
checkers = {
- k: (v, is_active(actives, k))
- for k, v in parse_checkers(child.stdout)
+ name: (description, is_active_checker(name))
+ for name, description in parse_checkers(lines)
}
- child.stdout.close()
- child.wait()
- if child.returncode == 0 and len(checkers):
- return checkers
- else:
+ if not checkers:
raise Exception('Could not query Clang for available checkers.')
+
+ return checkers
diff --git a/tools/scan-build-py/libscanbuild/report.py b/tools/scan-build-py/libscanbuild/report.py
index 5c33319e206d..766ddef71990 100644
--- a/tools/scan-build-py/libscanbuild/report.py
+++ b/tools/scan-build-py/libscanbuild/report.py
@@ -21,6 +21,7 @@ import glob
import json
import logging
import contextlib
+import datetime
from libscanbuild import duplicate_check
from libscanbuild.clang import get_version
@@ -34,7 +35,8 @@ def report_directory(hint, keep):
hint -- could specify the parent directory of the output directory.
keep -- a boolean value to keep or delete the empty report directory. """
- stamp = time.strftime('scan-build-%Y-%m-%d-%H%M%S-', time.localtime())
+ stamp_format = 'scan-build-%Y-%m-%d-%H-%M-%S-%f-'
+ stamp = datetime.datetime.now().strftime(stamp_format)
parentdir = os.path.abspath(hint)
if not os.path.exists(parentdir):
diff --git a/tools/scan-build-py/libscanbuild/runner.py b/tools/scan-build-py/libscanbuild/runner.py
index 628ad90d627a..72d02c85fed1 100644
--- a/tools/scan-build-py/libscanbuild/runner.py
+++ b/tools/scan-build-py/libscanbuild/runner.py
@@ -205,19 +205,8 @@ def filter_debug_flags(opts, continuation=run_analyzer):
return continuation(opts)
-@require(['file', 'directory'])
-def set_file_path_relative(opts, continuation=filter_debug_flags):
- """ Set source file path to relative to the working directory.
-
- The only purpose of this function is to pass the SATestBuild.py tests. """
-
- opts.update({'file': os.path.relpath(opts['file'], opts['directory'])})
-
- return continuation(opts)
-
-
@require(['language', 'compiler', 'file', 'flags'])
-def language_check(opts, continuation=set_file_path_relative):
+def language_check(opts, continuation=filter_debug_flags):
""" Find out the language from command line parameters or file name
extension. The decision also influenced by the compiler invocation. """
diff --git a/tools/scan-build-py/tests/unit/test_clang.py b/tools/scan-build-py/tests/unit/test_clang.py
index 04414a85b828..eef8c26bbd19 100644
--- a/tools/scan-build-py/tests/unit/test_clang.py
+++ b/tools/scan-build-py/tests/unit/test_clang.py
@@ -8,9 +8,19 @@ import libear
import libscanbuild.clang as sut
import unittest
import os.path
+import sys
-class GetClangArgumentsTest(unittest.TestCase):
+class ClangGetVersion(unittest.TestCase):
+ def test_get_version_is_not_empty(self):
+ self.assertTrue(sut.get_version('clang'))
+
+ def test_get_version_throws(self):
+ with self.assertRaises(OSError):
+ sut.get_version('notexists')
+
+
+class ClangGetArgumentsTest(unittest.TestCase):
def test_get_clang_arguments(self):
with libear.TemporaryDirectory() as tmpdir:
filename = os.path.join(tmpdir, 'test.c')
@@ -25,18 +35,60 @@ class GetClangArgumentsTest(unittest.TestCase):
self.assertTrue('var="this is it"' in result)
def test_get_clang_arguments_fails(self):
- self.assertRaises(
- Exception, sut.get_arguments,
- ['clang', '-###', '-fsyntax-only', '-x', 'c', 'notexist.c'], '.')
+ with self.assertRaises(Exception):
+ sut.get_arguments(['clang', '-x', 'c', 'notexist.c'], '.')
+
+ def test_get_clang_arguments_fails_badly(self):
+ with self.assertRaises(OSError):
+ sut.get_arguments(['notexist'], '.')
-class GetCheckersTest(unittest.TestCase):
+class ClangGetCheckersTest(unittest.TestCase):
def test_get_checkers(self):
# this test is only to see is not crashing
result = sut.get_checkers('clang', [])
self.assertTrue(len(result))
+ # do check result types
+ string_type = unicode if sys.version_info < (3,) else str
+ for key, value in result.items():
+ self.assertEqual(string_type, type(key))
+ self.assertEqual(string_type, type(value[0]))
+ self.assertEqual(bool, type(value[1]))
def test_get_active_checkers(self):
# this test is only to see is not crashing
result = sut.get_active_checkers('clang', [])
self.assertTrue(len(result))
+ # do check result types
+ for value in result:
+ self.assertEqual(str, type(value))
+
+ def test_is_active(self):
+ test = sut.is_active(['a', 'b.b', 'c.c.c'])
+
+ self.assertTrue(test('a'))
+ self.assertTrue(test('a.b'))
+ self.assertTrue(test('b.b'))
+ self.assertTrue(test('b.b.c'))
+ self.assertTrue(test('c.c.c.p'))
+
+ self.assertFalse(test('ab'))
+ self.assertFalse(test('ba'))
+ self.assertFalse(test('bb'))
+ self.assertFalse(test('c.c'))
+ self.assertFalse(test('b'))
+ self.assertFalse(test('d'))
+
+ def test_parse_checkers(self):
+ lines = [
+ 'OVERVIEW: Clang Static Analyzer Checkers List',
+ '',
+ 'CHECKERS:',
+ ' checker.one Checker One description',
+ ' checker.two',
+ ' Checker Two description']
+ result = dict(sut.parse_checkers(lines))
+ self.assertTrue('checker.one' in result)
+ self.assertEqual('Checker One description', result.get('checker.one'))
+ self.assertTrue('checker.two' in result)
+ self.assertEqual('Checker Two description', result.get('checker.two'))
diff --git a/tools/scan-build-py/tests/unit/test_report.py b/tools/scan-build-py/tests/unit/test_report.py
index 3f249ce2aa0c..c82b5593e0dc 100644
--- a/tools/scan-build-py/tests/unit/test_report.py
+++ b/tools/scan-build-py/tests/unit/test_report.py
@@ -146,3 +146,16 @@ class GetPrefixFromCompilationDatabaseTest(unittest.TestCase):
def test_empty(self):
self.assertEqual(
sut.commonprefix([]), '')
+
+class ReportDirectoryTest(unittest.TestCase):
+
+ # Test that successive report directory names ascend in lexicographic
+ # order. This is required so that report directories from two runs of
+ # scan-build can be easily matched up to compare results.
+ def test_directory_name_comparison(self):
+ with libear.TemporaryDirectory() as tmpdir, \
+ sut.report_directory(tmpdir, False) as report_dir1, \
+ sut.report_directory(tmpdir, False) as report_dir2, \
+ sut.report_directory(tmpdir, False) as report_dir3:
+ self.assertLess(report_dir1, report_dir2)
+ self.assertLess(report_dir2, report_dir3)
diff --git a/tools/scan-build-py/tests/unit/test_runner.py b/tools/scan-build-py/tests/unit/test_runner.py
index b4730a1c5191..2d0906223329 100644
--- a/tools/scan-build-py/tests/unit/test_runner.py
+++ b/tools/scan-build-py/tests/unit/test_runner.py
@@ -219,20 +219,6 @@ class AnalyzerTest(unittest.TestCase):
self.assertEqual(['-DNDEBUG', '-UNDEBUG'], test(['-DNDEBUG']))
self.assertEqual(['-DSomething', '-UNDEBUG'], test(['-DSomething']))
- def test_set_file_relative_path(self):
- def test(expected, input):
- spy = Spy()
- self.assertEqual(spy.success,
- sut.set_file_path_relative(input, spy.call))
- self.assertEqual(expected, spy.arg['file'])
-
- test('source.c',
- {'file': '/home/me/source.c', 'directory': '/home/me'})
- test('me/source.c',
- {'file': '/home/me/source.c', 'directory': '/home'})
- test('../home/me/source.c',
- {'file': '/home/me/source.c', 'directory': '/tmp'})
-
def test_set_language_fall_through(self):
def language(expected, input):
spy = Spy()
diff --git a/tools/scan-build/bin/scan-build b/tools/scan-build/bin/scan-build
index 3182a29767b9..cbf3bf3d6f0b 100755
--- a/tools/scan-build/bin/scan-build
+++ b/tools/scan-build/bin/scan-build
@@ -53,6 +53,7 @@ my %Options = (
IgnoreErrors => 0, # Ignore build errors.
ViewResults => 0, # View results when the build terminates.
ExitStatusFoundBugs => 0, # Exit status reflects whether bugs were found
+ ShowDescription => 0, # Display the description of the defect in the list
KeepEmpty => 0, # Don't remove output directory even with 0 results.
EnableCheckers => {},
DisableCheckers => {},
@@ -453,6 +454,10 @@ sub ScanFile {
push @$Index,[ $FName, $BugCategory, $BugType, $BugFile, $BugFunction, $BugLine,
$BugPathLength ];
+
+ if ($Options{ShowDescription}) {
+ push @{ $Index->[-1] }, $BugDescription
+ }
}
##----------------------------------------------------------------------------##
@@ -746,6 +751,15 @@ print OUT <<ENDTEXT;
<td>Function/Method</td>
<td class="Q">Line</td>
<td class="Q">Path Length</td>
+ENDTEXT
+
+if ($Options{ShowDescription}) {
+print OUT <<ENDTEXT;
+ <td class="Q">Description</td>
+ENDTEXT
+}
+
+print OUT <<ENDTEXT;
<td class="sorttable_nosort"></td>
<!-- REPORTBUGCOL -->
</tr></thead>
@@ -771,10 +785,10 @@ ENDTEXT
print OUT "<tr class=\"bt_$x\">";
print OUT "<td class=\"DESC\">";
- print OUT $row->[1];
+ print OUT $row->[1]; # $BugCategory
print OUT "</td>";
print OUT "<td class=\"DESC\">";
- print OUT $row->[2];
+ print OUT $row->[2]; # $BugType
print OUT "</td>";
# Update the file prefix.
@@ -802,11 +816,11 @@ ENDTEXT
print OUT "</td>";
print OUT "<td class=\"DESC\">";
- print OUT $row->[4];
+ print OUT $row->[4]; # Function
print OUT "</td>";
# Print out the quantities.
- for my $j ( 5 .. 6 ) {
+ for my $j ( 5 .. 6 ) { # Line & Path length
print OUT "<td class=\"Q\">$row->[$j]</td>";
}
@@ -1150,6 +1164,10 @@ OPTIONS:
Specify the title used on generated HTML pages. If not specified, a default
title will be used.
+ --show-description
+
+ Display the description of defects in the list
+
-plist
By default the output of scan-build is a set of HTML files. This option
@@ -1586,6 +1604,12 @@ sub ProcessArgs {
next;
}
+ if ($arg eq "--show-description") {
+ shift @$Args;
+ $Options{ShowDescription} = 1;
+ next;
+ }
+
if ($arg eq "-store") {
shift @$Args;
$Options{StoreModel} = shift @$Args;