Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,37 @@
create_subdirectory_options(CLANG TOOL)
add_clang_subdirectory(diagtool)
add_clang_subdirectory(driver)
add_clang_subdirectory(clang-diff)
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)
add_clang_subdirectory(clang-rename)
add_clang_subdirectory(clang-refactor)
if(CLANG_ENABLE_ARCMT)
add_clang_subdirectory(arcmt-test)
add_clang_subdirectory(c-arcmt-test)
endif()
if(CLANG_ENABLE_STATIC_ANALYZER)
add_clang_subdirectory(clang-check)
add_clang_subdirectory(clang-func-mapping)
add_clang_subdirectory(scan-build)
add_clang_subdirectory(scan-view)
endif()
# We support checking out the clang-tools-extra repository into the 'extra'
# subdirectory. It contains tools developed as part of the Clang/LLVM project
# on top of the Clang tooling platform. We keep them in a separate repository
# to keep the primary Clang repository small and focused.
# It also may be included by LLVM_EXTERNAL_CLANG_TOOLS_EXTRA_SOURCE_DIR.
add_llvm_external_project(clang-tools-extra extra)
# libclang may require clang-tidy in clang-tools-extra.
add_clang_subdirectory(libclang)

View File

@@ -0,0 +1,15 @@
set(LLVM_LINK_COMPONENTS
support
)
add_clang_executable(arcmt-test
arcmt-test.cpp
)
target_link_libraries(arcmt-test
PRIVATE
clangARCMigrate
clangBasic
clangFrontend
clangLex
)

View File

@@ -0,0 +1,377 @@
//===-- arcmt-test.cpp - ARC Migration Tool testbed -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/ARCMigrate/ARCMT.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>
using namespace clang;
using namespace arcmt;
static llvm::cl::opt<bool>
CheckOnly("check-only",
llvm::cl::desc("Just check for issues that need to be handled manually"));
//static llvm::cl::opt<bool>
//TestResultForARC("test-result",
//llvm::cl::desc("Test the result of transformations by parsing it in ARC mode"));
static llvm::cl::opt<bool>
OutputTransformations("output-transformations",
llvm::cl::desc("Print the source transformations"));
static llvm::cl::opt<bool>
VerifyDiags("verify",llvm::cl::desc("Verify emitted diagnostics and warnings"));
static llvm::cl::opt<bool>
VerboseOpt("v", llvm::cl::desc("Enable verbose output"));
static llvm::cl::opt<bool>
VerifyTransformedFiles("verify-transformed-files",
llvm::cl::desc("Read pairs of file mappings (typically the output of "
"c-arcmt-test) and compare their contents with the filenames "
"provided in command-line"));
static llvm::cl::opt<std::string>
RemappingsFile("remappings-file",
llvm::cl::desc("Pairs of file mappings (typically the output of "
"c-arcmt-test)"));
static llvm::cl::list<std::string>
ResultFiles(llvm::cl::Positional, llvm::cl::desc("<filename>..."));
static llvm::cl::extrahelp extraHelp(
"\nusage with compiler args: arcmt-test [options] --args [compiler flags]\n");
// This function isn't referenced outside its translation unit, but it
// can't use the "static" keyword because its address is used for
// GetMainExecutable (since some platforms don't support taking the
// address of main, and some platforms can't implement GetMainExecutable
// without being given the address of a function in the main executable).
std::string GetExecutablePath(const char *Argv0) {
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}
static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
raw_ostream &OS);
static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
raw_ostream &OS);
namespace {
class PrintTransforms : public MigrationProcess::RewriteListener {
ASTContext *Ctx;
raw_ostream &OS;
public:
PrintTransforms(raw_ostream &OS)
: Ctx(nullptr), OS(OS) {}
void start(ASTContext &ctx) override { Ctx = &ctx; }
void finish() override { Ctx = nullptr; }
void insert(SourceLocation loc, StringRef text) override {
assert(Ctx);
OS << "Insert: ";
printSourceLocation(loc, *Ctx, OS);
OS << " \"" << text << "\"\n";
}
void remove(CharSourceRange range) override {
assert(Ctx);
OS << "Remove: ";
printSourceRange(range, *Ctx, OS);
OS << '\n';
}
};
} // anonymous namespace
static bool checkForMigration(StringRef resourcesPath,
ArrayRef<const char *> Args) {
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
DiagnosticConsumer *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
// Chain in -verify checker, if requested.
VerifyDiagnosticConsumer *verifyDiag = nullptr;
if (VerifyDiags) {
verifyDiag = new VerifyDiagnosticConsumer(*Diags);
Diags->setClient(verifyDiag);
}
CompilerInvocation CI;
if (!CompilerInvocation::CreateFromArgs(CI, Args.begin(), Args.end(), *Diags))
return true;
if (CI.getFrontendOpts().Inputs.empty()) {
llvm::errs() << "error: no input files\n";
return true;
}
if (!CI.getLangOpts()->ObjC1)
return false;
arcmt::checkForManualIssues(CI, CI.getFrontendOpts().Inputs[0],
std::make_shared<PCHContainerOperations>(),
Diags->getClient());
return Diags->getClient()->getNumErrors() > 0;
}
static void printResult(FileRemapper &remapper, raw_ostream &OS) {
PreprocessorOptions PPOpts;
remapper.applyMappings(PPOpts);
// The changed files will be in memory buffers, print them.
for (const auto &RB : PPOpts.RemappedFileBuffers)
OS << RB.second->getBuffer();
}
static bool performTransformations(StringRef resourcesPath,
ArrayRef<const char *> Args) {
// Check first.
if (checkForMigration(resourcesPath, Args))
return true;
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
DiagnosticConsumer *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
IntrusiveRefCntPtr<DiagnosticsEngine> TopDiags(
new DiagnosticsEngine(DiagID, &*DiagOpts, &*DiagClient));
CompilerInvocation origCI;
if (!CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(),
*TopDiags))
return true;
if (origCI.getFrontendOpts().Inputs.empty()) {
llvm::errs() << "error: no input files\n";
return true;
}
if (!origCI.getLangOpts()->ObjC1)
return false;
MigrationProcess migration(origCI, std::make_shared<PCHContainerOperations>(),
DiagClient);
std::vector<TransformFn>
transforms = arcmt::getAllTransformations(origCI.getLangOpts()->getGC(),
origCI.getMigratorOpts().NoFinalizeRemoval);
assert(!transforms.empty());
std::unique_ptr<PrintTransforms> transformPrinter;
if (OutputTransformations)
transformPrinter.reset(new PrintTransforms(llvm::outs()));
for (unsigned i=0, e = transforms.size(); i != e; ++i) {
bool err = migration.applyTransform(transforms[i], transformPrinter.get());
if (err) return true;
if (VerboseOpt) {
if (i == e-1)
llvm::errs() << "\n##### FINAL RESULT #####\n";
else
llvm::errs() << "\n##### OUTPUT AFTER "<< i+1 <<". TRANSFORMATION #####\n";
printResult(migration.getRemapper(), llvm::errs());
llvm::errs() << "\n##########################\n\n";
}
}
if (!OutputTransformations)
printResult(migration.getRemapper(), llvm::outs());
// FIXME: TestResultForARC
return false;
}
static bool filesCompareEqual(StringRef fname1, StringRef fname2) {
using namespace llvm;
ErrorOr<std::unique_ptr<MemoryBuffer>> file1 = MemoryBuffer::getFile(fname1);
if (!file1)
return false;
ErrorOr<std::unique_ptr<MemoryBuffer>> file2 = MemoryBuffer::getFile(fname2);
if (!file2)
return false;
return file1.get()->getBuffer() == file2.get()->getBuffer();
}
static bool verifyTransformedFiles(ArrayRef<std::string> resultFiles) {
using namespace llvm;
assert(!resultFiles.empty());
std::map<StringRef, StringRef> resultMap;
for (ArrayRef<std::string>::iterator
I = resultFiles.begin(), E = resultFiles.end(); I != E; ++I) {
StringRef fname(*I);
if (!fname.endswith(".result")) {
errs() << "error: filename '" << fname
<< "' does not have '.result' extension\n";
return true;
}
resultMap[sys::path::stem(fname)] = fname;
}
ErrorOr<std::unique_ptr<MemoryBuffer>> inputBuf = std::error_code();
if (RemappingsFile.empty())
inputBuf = MemoryBuffer::getSTDIN();
else
inputBuf = MemoryBuffer::getFile(RemappingsFile);
if (!inputBuf) {
errs() << "error: could not read remappings input\n";
return true;
}
SmallVector<StringRef, 8> strs;
inputBuf.get()->getBuffer().split(strs, "\n", /*MaxSplit=*/-1,
/*KeepEmpty=*/false);
if (strs.empty()) {
errs() << "error: no files to verify from stdin\n";
return true;
}
if (strs.size() % 2 != 0) {
errs() << "error: files to verify are not original/result pairs\n";
return true;
}
for (unsigned i = 0, e = strs.size(); i != e; i += 2) {
StringRef inputOrigFname = strs[i];
StringRef inputResultFname = strs[i+1];
std::map<StringRef, StringRef>::iterator It;
It = resultMap.find(sys::path::filename(inputOrigFname));
if (It == resultMap.end()) {
errs() << "error: '" << inputOrigFname << "' is not in the list of "
<< "transformed files to verify\n";
return true;
}
if (!sys::fs::exists(It->second)) {
errs() << "error: '" << It->second << "' does not exist\n";
return true;
}
if (!sys::fs::exists(inputResultFname)) {
errs() << "error: '" << inputResultFname << "' does not exist\n";
return true;
}
if (!filesCompareEqual(It->second, inputResultFname)) {
errs() << "error: '" << It->second << "' is different than "
<< "'" << inputResultFname << "'\n";
return true;
}
resultMap.erase(It);
}
if (!resultMap.empty()) {
for (std::map<StringRef, StringRef>::iterator
I = resultMap.begin(), E = resultMap.end(); I != E; ++I)
errs() << "error: '" << I->second << "' was not verified!\n";
return true;
}
return false;
}
//===----------------------------------------------------------------------===//
// Misc. functions.
//===----------------------------------------------------------------------===//
static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
raw_ostream &OS) {
SourceManager &SM = Ctx.getSourceManager();
PresumedLoc PL = SM.getPresumedLoc(loc);
OS << llvm::sys::path::filename(PL.getFilename());
OS << ":" << PL.getLine() << ":"
<< PL.getColumn();
}
static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
raw_ostream &OS) {
SourceManager &SM = Ctx.getSourceManager();
const LangOptions &langOpts = Ctx.getLangOpts();
PresumedLoc PL = SM.getPresumedLoc(range.getBegin());
OS << llvm::sys::path::filename(PL.getFilename());
OS << " [" << PL.getLine() << ":"
<< PL.getColumn();
OS << " - ";
SourceLocation end = range.getEnd();
PL = SM.getPresumedLoc(end);
unsigned endCol = PL.getColumn() - 1;
if (!range.isTokenRange())
endCol += Lexer::MeasureTokenLength(end, SM, langOpts);
OS << PL.getLine() << ":" << endCol << "]";
}
//===----------------------------------------------------------------------===//
// Command line processing.
//===----------------------------------------------------------------------===//
int main(int argc, const char **argv) {
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
std::string
resourcesPath = CompilerInvocation::GetResourcesPath(argv[0], MainAddr);
int optargc = 0;
for (; optargc != argc; ++optargc) {
if (StringRef(argv[optargc]) == "--args")
break;
}
llvm::cl::ParseCommandLineOptions(optargc, argv, "arcmt-test");
if (VerifyTransformedFiles) {
if (ResultFiles.empty()) {
llvm::cl::PrintHelpMessage();
return 1;
}
return verifyTransformedFiles(ResultFiles);
}
if (optargc == argc) {
llvm::cl::PrintHelpMessage();
return 1;
}
ArrayRef<const char*> Args(argv+optargc+1, argc-optargc-1);
if (CheckOnly)
return checkForMigration(resourcesPath, Args);
return performTransformations(resourcesPath, Args);
}

View File

@@ -0,0 +1,19 @@
add_clang_executable(c-arcmt-test
c-arcmt-test.c
)
if (LLVM_BUILD_STATIC)
target_link_libraries(c-arcmt-test
PRIVATE
libclang_static
)
else()
target_link_libraries(c-arcmt-test
PRIVATE
libclang
)
endif()
set_target_properties(c-arcmt-test
PROPERTIES
LINKER_LANGUAGE CXX)

View File

@@ -0,0 +1,129 @@
/* c-arcmt-test.c */
#include "clang-c/Index.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if defined(_WIN32)
#include <io.h>
#include <fcntl.h>
#endif
static int print_remappings(const char *path) {
CXRemapping remap;
unsigned i, N;
CXString origFname;
CXString transFname;
remap = clang_getRemappings(path);
if (!remap)
return 1;
N = clang_remap_getNumFiles(remap);
for (i = 0; i != N; ++i) {
clang_remap_getFilenames(remap, i, &origFname, &transFname);
fprintf(stdout, "%s\n", clang_getCString(origFname));
fprintf(stdout, "%s\n", clang_getCString(transFname));
clang_disposeString(origFname);
clang_disposeString(transFname);
}
clang_remap_dispose(remap);
return 0;
}
static int print_remappings_filelist(const char **files, unsigned numFiles) {
CXRemapping remap;
unsigned i, N;
CXString origFname;
CXString transFname;
remap = clang_getRemappingsFromFileList(files, numFiles);
if (!remap)
return 1;
N = clang_remap_getNumFiles(remap);
for (i = 0; i != N; ++i) {
clang_remap_getFilenames(remap, i, &origFname, &transFname);
fprintf(stdout, "%s\n", clang_getCString(origFname));
fprintf(stdout, "%s\n", clang_getCString(transFname));
clang_disposeString(origFname);
clang_disposeString(transFname);
}
clang_remap_dispose(remap);
return 0;
}
/******************************************************************************/
/* Command line processing. */
/******************************************************************************/
static void print_usage(void) {
fprintf(stderr,
"usage: c-arcmt-test -mt-migrate-directory <path>\n"
" c-arcmt-test <remap-file-path1> <remap-file-path2> ...\n\n\n");
}
/***/
int carcmttest_main(int argc, const char **argv) {
clang_enableStackTraces();
if (argc == 3 && strncmp(argv[1], "-mt-migrate-directory", 21) == 0)
return print_remappings(argv[2]);
if (argc > 1)
return print_remappings_filelist(argv+1, argc-1);
print_usage();
return 1;
}
/***/
/* We intentionally run in a separate thread to ensure we at least minimal
* testing of a multithreaded environment (for example, having a reduced stack
* size). */
typedef struct thread_info {
int argc;
const char **argv;
int result;
} thread_info;
void thread_runner(void *client_data_v) {
thread_info *client_data = client_data_v;
client_data->result = carcmttest_main(client_data->argc, client_data->argv);
}
static void flush_atexit(void) {
/* stdout, and surprisingly even stderr, are not always flushed on process
* and thread exit, particularly when the system is under heavy load. */
fflush(stdout);
fflush(stderr);
}
int main(int argc, const char **argv) {
thread_info client_data;
atexit(flush_atexit);
#if defined(_WIN32)
if (getenv("LIBCLANG_LOGGING") == NULL)
putenv("LIBCLANG_LOGGING=1");
_setmode( _fileno(stdout), _O_BINARY );
#else
setenv("LIBCLANG_LOGGING", "1", /*overwrite=*/0);
#endif
if (getenv("CINDEXTEST_NOTHREADS"))
return carcmttest_main(argc, argv);
client_data.argc = argc;
client_data.argv = argv;
clang_executeOnThread(thread_runner, &client_data, 0);
return client_data.result;
}

View File

@@ -0,0 +1,65 @@
set(LLVM_LINK_COMPONENTS
support
)
add_clang_executable(c-index-test
c-index-test.c
core_main.cpp
)
if(NOT MSVC)
set_property(
SOURCE c-index-test.c
PROPERTY COMPILE_FLAGS "-std=gnu89"
)
endif()
if (LLVM_BUILD_STATIC)
target_link_libraries(c-index-test
PRIVATE
libclang_static
clangCodeGen
clangIndex
)
else()
target_link_libraries(c-index-test
PRIVATE
libclang
clangAST
clangBasic
clangCodeGen
clangFrontend
clangIndex
clangSerialization
)
endif()
set_target_properties(c-index-test
PROPERTIES
LINKER_LANGUAGE CXX)
# If libxml2 is available, make it available for c-index-test.
if (CLANG_HAVE_LIBXML)
include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR})
target_link_libraries(c-index-test PRIVATE ${LIBXML2_LIBRARIES})
endif()
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
if(INTERNAL_INSTALL_PREFIX)
set(INSTALL_DESTINATION "${INTERNAL_INSTALL_PREFIX}/bin")
set_property(TARGET c-index-test APPEND PROPERTY INSTALL_RPATH
"@executable_path/../../lib")
else()
set(INSTALL_DESTINATION bin)
endif()
install(TARGETS c-index-test
RUNTIME DESTINATION "${INSTALL_DESTINATION}"
COMPONENT c-index-test)
if (NOT CMAKE_CONFIGURATION_TYPES) # don't add this for IDE's.
add_llvm_install_targets(install-c-index-test
DEPENDS c-index-test
COMPONENT c-index-test)
endif()
endif()

View File

@@ -0,0 +1 @@
99f05669b64c748fe88e0cca09ce73efb64db73b

View File

@@ -0,0 +1,309 @@
//===-- core_main.cpp - Core Index Tool testbed ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Index/IndexingAction.h"
#include "clang/Index/IndexDataConsumer.h"
#include "clang/Index/USRGeneration.h"
#include "clang/Index/CodegenNameGenerator.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/PrettyStackTrace.h"
using namespace clang;
using namespace clang::index;
using namespace llvm;
extern "C" int indextest_core_main(int argc, const char **argv);
namespace {
enum class ActionType {
None,
PrintSourceSymbols,
};
namespace options {
static cl::OptionCategory IndexTestCoreCategory("index-test-core options");
static cl::opt<ActionType>
Action(cl::desc("Action:"), cl::init(ActionType::None),
cl::values(
clEnumValN(ActionType::PrintSourceSymbols,
"print-source-symbols", "Print symbols from source")),
cl::cat(IndexTestCoreCategory));
static cl::extrahelp MoreHelp(
"\nAdd \"-- <compiler arguments>\" at the end to setup the compiler "
"invocation\n"
);
static cl::opt<bool>
DumpModuleImports("dump-imported-module-files",
cl::desc("Print symbols and input files from imported modules"));
static cl::opt<bool>
IncludeLocals("include-locals", cl::desc("Print local symbols"));
static cl::opt<std::string>
ModuleFilePath("module-file",
cl::desc("Path to module file to print symbols from"));
static cl::opt<std::string>
ModuleFormat("fmodule-format", cl::init("raw"),
cl::desc("Container format for clang modules and PCH, 'raw' or 'obj'"));
}
} // anonymous namespace
static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS);
static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx,
raw_ostream &OS);
namespace {
class PrintIndexDataConsumer : public IndexDataConsumer {
raw_ostream &OS;
std::unique_ptr<CodegenNameGenerator> CGNameGen;
public:
PrintIndexDataConsumer(raw_ostream &OS) : OS(OS) {
}
void initialize(ASTContext &Ctx) override {
CGNameGen.reset(new CodegenNameGenerator(Ctx));
}
bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles,
ArrayRef<SymbolRelation> Relations,
FileID FID, unsigned Offset,
ASTNodeInfo ASTNode) override {
ASTContext &Ctx = D->getASTContext();
SourceManager &SM = Ctx.getSourceManager();
unsigned Line = SM.getLineNumber(FID, Offset);
unsigned Col = SM.getColumnNumber(FID, Offset);
OS << Line << ':' << Col << " | ";
printSymbolInfo(getSymbolInfo(D), OS);
OS << " | ";
printSymbolNameAndUSR(D, Ctx, OS);
OS << " | ";
if (CGNameGen->writeName(D, OS))
OS << "<no-cgname>";
OS << " | ";
printSymbolRoles(Roles, OS);
OS << " | ";
OS << "rel: " << Relations.size() << '\n';
for (auto &SymRel : Relations) {
OS << '\t';
printSymbolRoles(SymRel.Roles, OS);
OS << " | ";
printSymbolNameAndUSR(SymRel.RelatedSymbol, Ctx, OS);
OS << '\n';
}
return true;
}
bool handleModuleOccurence(const ImportDecl *ImportD, SymbolRoleSet Roles,
FileID FID, unsigned Offset) override {
ASTContext &Ctx = ImportD->getASTContext();
SourceManager &SM = Ctx.getSourceManager();
unsigned Line = SM.getLineNumber(FID, Offset);
unsigned Col = SM.getColumnNumber(FID, Offset);
OS << Line << ':' << Col << " | ";
printSymbolInfo(getSymbolInfo(ImportD), OS);
OS << " | ";
OS << ImportD->getImportedModule()->getFullModuleName() << " | ";
printSymbolRoles(Roles, OS);
OS << " |\n";
return true;
}
};
} // anonymous namespace
//===----------------------------------------------------------------------===//
// Print Source Symbols
//===----------------------------------------------------------------------===//
static void dumpModuleFileInputs(serialization::ModuleFile &Mod,
ASTReader &Reader,
raw_ostream &OS) {
OS << "---- Module Inputs ----\n";
Reader.visitInputFiles(Mod, /*IncludeSystem=*/true, /*Complain=*/false,
[&](const serialization::InputFile &IF, bool isSystem) {
OS << (isSystem ? "system" : "user") << " | ";
OS << IF.getFile()->getName() << '\n';
});
}
static bool printSourceSymbols(ArrayRef<const char *> Args,
bool dumpModuleImports,
bool indexLocals) {
SmallVector<const char *, 4> ArgsWithProgName;
ArgsWithProgName.push_back("clang");
ArgsWithProgName.append(Args.begin(), Args.end());
IntrusiveRefCntPtr<DiagnosticsEngine>
Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
auto CInvok = createInvocationFromCommandLine(ArgsWithProgName, Diags);
if (!CInvok)
return true;
raw_ostream &OS = outs();
auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(OS);
IndexingOptions IndexOpts;
IndexOpts.IndexFunctionLocals = indexLocals;
std::unique_ptr<FrontendAction> IndexAction;
IndexAction = createIndexingAction(DataConsumer, IndexOpts,
/*WrappedAction=*/nullptr);
auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
std::move(CInvok), PCHContainerOps, Diags, IndexAction.get()));
if (!Unit)
return true;
if (dumpModuleImports) {
if (auto Reader = Unit->getASTReader()) {
Reader->getModuleManager().visit([&](serialization::ModuleFile &Mod) -> bool {
OS << "==== Module " << Mod.ModuleName << " ====\n";
indexModuleFile(Mod, *Reader, DataConsumer, IndexOpts);
dumpModuleFileInputs(Mod, *Reader, OS);
return true; // skip module dependencies.
});
}
}
return false;
}
static bool printSourceSymbolsFromModule(StringRef modulePath,
StringRef format) {
FileSystemOptions FileSystemOpts;
auto pchContOps = std::make_shared<PCHContainerOperations>();
// Register the support for object-file-wrapped Clang modules.
pchContOps->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>());
auto pchRdr = pchContOps->getReaderOrNull(format);
if (!pchRdr) {
errs() << "unknown module format: " << format << '\n';
return true;
}
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
CompilerInstance::createDiagnostics(new DiagnosticOptions());
std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
modulePath, *pchRdr, ASTUnit::LoadASTOnly, Diags,
FileSystemOpts, /*UseDebugInfo=*/false,
/*OnlyLocalDecls=*/true, None,
/*CaptureDiagnostics=*/false,
/*AllowPCHWithCompilerErrors=*/true,
/*UserFilesAreVolatile=*/false);
if (!AU) {
errs() << "failed to create TU for: " << modulePath << '\n';
return true;
}
auto DataConsumer = std::make_shared<PrintIndexDataConsumer>(outs());
IndexingOptions IndexOpts;
indexASTUnit(*AU, DataConsumer, IndexOpts);
return false;
}
//===----------------------------------------------------------------------===//
// Helper Utils
//===----------------------------------------------------------------------===//
static void printSymbolInfo(SymbolInfo SymInfo, raw_ostream &OS) {
OS << getSymbolKindString(SymInfo.Kind);
if (SymInfo.SubKind != SymbolSubKind::None)
OS << '/' << getSymbolSubKindString(SymInfo.SubKind);
if (SymInfo.Properties) {
OS << '(';
printSymbolProperties(SymInfo.Properties, OS);
OS << ')';
}
OS << '/' << getSymbolLanguageString(SymInfo.Lang);
}
static void printSymbolNameAndUSR(const Decl *D, ASTContext &Ctx,
raw_ostream &OS) {
if (printSymbolName(D, Ctx.getLangOpts(), OS)) {
OS << "<no-name>";
}
OS << " | ";
SmallString<256> USRBuf;
if (generateUSRForDecl(D, USRBuf)) {
OS << "<no-usr>";
} else {
OS << USRBuf;
}
}
//===----------------------------------------------------------------------===//
// Command line processing.
//===----------------------------------------------------------------------===//
int indextest_core_main(int argc, const char **argv) {
sys::PrintStackTraceOnErrorSignal(argv[0]);
PrettyStackTraceProgram X(argc, argv);
assert(argv[1] == StringRef("core"));
++argv;
--argc;
std::vector<const char *> CompArgs;
const char **DoubleDash = std::find(argv, argv + argc, StringRef("--"));
if (DoubleDash != argv + argc) {
CompArgs = std::vector<const char *>(DoubleDash + 1, argv + argc);
argc = DoubleDash - argv;
}
cl::HideUnrelatedOptions(options::IndexTestCoreCategory);
cl::ParseCommandLineOptions(argc, argv, "index-test-core");
if (options::Action == ActionType::None) {
errs() << "error: action required; pass '-help' for options\n";
return 1;
}
if (options::Action == ActionType::PrintSourceSymbols) {
if (!options::ModuleFilePath.empty()) {
return printSourceSymbolsFromModule(options::ModuleFilePath,
options::ModuleFormat);
}
if (CompArgs.empty()) {
errs() << "error: missing compiler args; pass '-- <compiler arguments>'\n";
return 1;
}
return printSourceSymbols(CompArgs, options::DumpModuleImports, options::IncludeLocals);
}
return 0;
}

View File

@@ -0,0 +1,23 @@
set( LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
Option
Support
)
add_clang_executable(clang-check
ClangCheck.cpp
)
target_link_libraries(clang-check
PRIVATE
clangAST
clangBasic
clangDriver
clangFrontend
clangRewriteFrontend
clangStaticAnalyzerFrontend
clangTooling
)
install(TARGETS clang-check
RUNTIME DESTINATION bin)

View File

@@ -0,0 +1,186 @@
//===--- tools/clang-check/ClangCheck.cpp - Clang check tool --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a clang-check tool that runs clang based on the info
// stored in a compilation database.
//
// This tool uses the Clang Tooling infrastructure, see
// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
// for details on setting it up with LLVM source tree.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Rewrite/Frontend/FixItRewriter.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"
using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::extrahelp MoreHelp(
"\tFor example, to run clang-check on all files in a subtree of the\n"
"\tsource tree, use:\n"
"\n"
"\t find path/in/subtree -name '*.cpp'|xargs clang-check\n"
"\n"
"\tor using a specific build path:\n"
"\n"
"\t find path/in/subtree -name '*.cpp'|xargs clang-check -p build/path\n"
"\n"
"\tNote, that path/in/subtree and current directory should follow the\n"
"\trules described above.\n"
"\n"
);
static cl::OptionCategory ClangCheckCategory("clang-check options");
static std::unique_ptr<opt::OptTable> Options(createDriverOptTable());
static cl::opt<bool>
ASTDump("ast-dump", cl::desc(Options->getOptionHelpText(options::OPT_ast_dump)),
cl::cat(ClangCheckCategory));
static cl::opt<bool>
ASTList("ast-list", cl::desc(Options->getOptionHelpText(options::OPT_ast_list)),
cl::cat(ClangCheckCategory));
static cl::opt<bool>
ASTPrint("ast-print",
cl::desc(Options->getOptionHelpText(options::OPT_ast_print)),
cl::cat(ClangCheckCategory));
static cl::opt<std::string> ASTDumpFilter(
"ast-dump-filter",
cl::desc(Options->getOptionHelpText(options::OPT_ast_dump_filter)),
cl::cat(ClangCheckCategory));
static cl::opt<bool>
Analyze("analyze", cl::desc(Options->getOptionHelpText(options::OPT_analyze)),
cl::cat(ClangCheckCategory));
static cl::opt<bool>
Fixit("fixit", cl::desc(Options->getOptionHelpText(options::OPT_fixit)),
cl::cat(ClangCheckCategory));
static cl::opt<bool> FixWhatYouCan(
"fix-what-you-can",
cl::desc(Options->getOptionHelpText(options::OPT_fix_what_you_can)),
cl::cat(ClangCheckCategory));
namespace {
// FIXME: Move FixItRewriteInPlace from lib/Rewrite/Frontend/FrontendActions.cpp
// into a header file and reuse that.
class FixItOptions : public clang::FixItOptions {
public:
FixItOptions() {
FixWhatYouCan = ::FixWhatYouCan;
}
std::string RewriteFilename(const std::string& filename, int &fd) override {
assert(llvm::sys::path::is_absolute(filename) &&
"clang-fixit expects absolute paths only.");
// We don't need to do permission checking here since clang will diagnose
// any I/O errors itself.
fd = -1; // No file descriptor for file.
return filename;
}
};
/// \brief Subclasses \c clang::FixItRewriter to not count fixed errors/warnings
/// in the final error counts.
///
/// This has the side-effect that clang-check -fixit exits with code 0 on
/// successfully fixing all errors.
class FixItRewriter : public clang::FixItRewriter {
public:
FixItRewriter(clang::DiagnosticsEngine& Diags,
clang::SourceManager& SourceMgr,
const clang::LangOptions& LangOpts,
clang::FixItOptions* FixItOpts)
: clang::FixItRewriter(Diags, SourceMgr, LangOpts, FixItOpts) {
}
bool IncludeInDiagnosticCounts() const override { return false; }
};
/// \brief Subclasses \c clang::FixItAction so that we can install the custom
/// \c FixItRewriter.
class FixItAction : public clang::FixItAction {
public:
bool BeginSourceFileAction(clang::CompilerInstance& CI) override {
FixItOpts.reset(new FixItOptions);
Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
CI.getLangOpts(), FixItOpts.get()));
return true;
}
};
class ClangCheckActionFactory {
public:
std::unique_ptr<clang::ASTConsumer> newASTConsumer() {
if (ASTList)
return clang::CreateASTDeclNodeLister();
if (ASTDump)
return clang::CreateASTDumper(ASTDumpFilter, /*DumpDecls=*/true,
/*Deserialize=*/false,
/*DumpLookups=*/false);
if (ASTPrint)
return clang::CreateASTPrinter(nullptr, ASTDumpFilter);
return llvm::make_unique<clang::ASTConsumer>();
}
};
} // namespace
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
// Initialize targets for clang module support.
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();
CommonOptionsParser OptionsParser(argc, argv, ClangCheckCategory);
ClangTool Tool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
// Clear adjusters because -fsyntax-only is inserted by the default chain.
Tool.clearArgumentsAdjusters();
Tool.appendArgumentsAdjuster(getClangStripOutputAdjuster());
// Running the analyzer requires --analyze. Other modes can work with the
// -fsyntax-only option.
Tool.appendArgumentsAdjuster(getInsertArgumentAdjuster(
Analyze ? "--analyze" : "-fsyntax-only", ArgumentInsertPosition::BEGIN));
ClangCheckActionFactory CheckFactory;
std::unique_ptr<FrontendActionFactory> FrontendFactory;
// Choose the correct factory based on the selected mode.
if (Analyze)
FrontendFactory = newFrontendActionFactory<clang::ento::AnalysisAction>();
else if (Fixit)
FrontendFactory = newFrontendActionFactory<FixItAction>();
else
FrontendFactory = newFrontendActionFactory(&CheckFactory);
return Tool.run(FrontendFactory.get());
}

View File

@@ -0,0 +1,15 @@
set(LLVM_LINK_COMPONENTS
Support
)
add_clang_executable(clang-diff
ClangDiff.cpp
)
target_link_libraries(clang-diff
PRIVATE
clangBasic
clangFrontend
clangTooling
clangToolingASTDiff
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
# Visual Studio files
.vs/
*.user
/packages/
/ClangFormat/obj/
/ClangFormat/bin/
# Generated and copied files
/ClangFormat/Key.snk
/ClangFormat/clang-format.exe
/ClangFormat/source.extension.vsixmanifest

View File

@@ -0,0 +1,33 @@
option(BUILD_CLANG_FORMAT_VS_PLUGIN "Build clang-format VS plugin" OFF)
if (BUILD_CLANG_FORMAT_VS_PLUGIN)
add_custom_target(clang_format_exe_for_vsix
${CMAKE_COMMAND} -E copy_if_different
"${LLVM_TOOLS_BINARY_DIR}/clang-format.exe"
"${CMAKE_CURRENT_SOURCE_DIR}/ClangFormat/clang-format.exe"
DEPENDS clang-format)
# 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}.${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
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"
"${LLVM_TOOLS_BINARY_DIR}/ClangFormat.vsix"
DEPENDS clang_format_exe_for_vsix)
endif()

View File

@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClangFormat", "ClangFormat\ClangFormat.csproj", "{7FD1783E-2D31-4D05-BF23-6EBE1B42B608}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7FD1783E-2D31-4D05-BF23-6EBE1B42B608}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7FD1783E-2D31-4D05-BF23-6EBE1B42B608}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7FD1783E-2D31-4D05-BF23-6EBE1B42B608}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7FD1783E-2D31-4D05-BF23-6EBE1B42B608}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,261 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{7FD1783E-2D31-4D05-BF23-6EBE1B42B608}</ProjectGuid>
<ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>LLVM.ClangFormat</RootNamespace>
<AssemblyName>ClangFormat</AssemblyName>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>Key.snk</AssemblyOriginatorKeyFile>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>4.0</OldToolsVersion>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<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">
<EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
<Reference Include="envdte80, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
<Reference Include="Microsoft.CSharp" />
<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.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, 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" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<COMReference Include="Microsoft.VisualStudio.CommandBars">
<Guid>{1CBA492E-7263-47BB-87FE-639000619B15}</Guid>
<VersionMajor>8</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
<COMReference Include="stdole">
<Guid>{00020430-0000-0000-C000-000000000046}</Guid>
<VersionMajor>2</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Guids.cs" />
<Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="ClangFormatPackage.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PkgCmdID.cs" />
<Compile Include="RunningDocTableEventsDispatcher.cs" />
<Compile Include="Vsix.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="VSPackage.resx">
<MergeWithCTO>true</MergeWithCTO>
<ManifestResourceName>VSPackage</ManifestResourceName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="Key.snk" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<VSCTCompile Include="ClangFormat.vsct">
<ResourceName>Menus.ctmenu</ResourceName>
</VSCTCompile>
</ItemGroup>
<ItemGroup>
<None Include="Resources\Images_32bit.bmp" />
</ItemGroup>
<ItemGroup>
<Content Include="clang-format.exe">
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
<Content Include="license.txt">
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
<Content Include="Resources\Package.ico" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.0">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
<Visible>False</Visible>
<ProductName>Windows Installer 4.5</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<PropertyGroup>
<UseCodebase>true</UseCodebase>
</PropertyGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<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.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.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This is the file that defines the actual layout and type of the commands.
It is divided in different sections (e.g. command definition, command
placement, ...), with each defining a specific set of properties.
See the comment before each section for more details about how to
use it. -->
<!-- The VSCT compiler (the tool that translates this file into the binary
format that VisualStudio will consume) has the ability to run a preprocessor
on the vsct file; this preprocessor is (usually) the C++ preprocessor, so
it is possible to define includes and macros with the same syntax used
in C++ files. Using this ability of the compiler here, we include some files
defining some of the constants that we will use inside the file. -->
<!--This is the file that defines the IDs for all the commands exposed by VisualStudio. -->
<Extern href="stdidcmd.h"/>
<!--This header contains the command ids for the menus provided by the shell. -->
<Extern href="vsshlids.h"/>
<!--The Commands section is where we the commands, menus and menu groups are defined.
This section uses a Guid to identify the package that provides the command defined inside it. -->
<Commands package="guidClangFormatPkg">
<!-- Inside this section we have different sub-sections: one for the menus, another
for the menu groups, one for the buttons (the actual commands), one for the combos
and the last one for the bitmaps used. Each element is identified by a command id that
is a unique pair of guid and numeric identifier; the guid part of the identifier is usually
called "command set" and is used to group different command inside a logically related
group; your package should define its own command set in order to avoid collisions
with command ids defined by other packages. -->
<!-- In this section you can define new menu groups. A menu group is a container for
other menus or buttons (commands); from a visual point of view you can see the
group as the part of a menu contained between two lines. The parent of a group
must be a menu. -->
<Groups>
<Group guid="guidClangFormatCmdSet" id="MyMenuGroup" priority="0x0600">
<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
</Group>
</Groups>
<!--Buttons section. -->
<!--This section defines the elements the user can interact with, like a menu command or a button
or combo box in a toolbar. -->
<Buttons>
<!--To define a menu group you have to specify its ID, the parent menu and its display priority.
The command is visible and enabled by default. If you need to change the visibility, status, etc, you can use
the CommandFlag node.
You can add more than one CommandFlag node e.g.:
<CommandFlag>DefaultInvisible</CommandFlag>
<CommandFlag>DynamicVisibility</CommandFlag>
If you do not want an image next to your command, remove the Icon node /> -->
<Button guid="guidClangFormatCmdSet" id="cmdidClangFormatSelection" priority="0x0100" type="Button">
<Parent guid="guidClangFormatCmdSet" id="MyMenuGroup" />
<Icon guid="guidImages" id="bmpPic1" />
<Strings>
<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>
<!--The bitmaps section is used to define the bitmaps that are used for the commands.-->
<Bitmaps>
<!-- The bitmap id is defined in a way that is a little bit different from the others:
the declaration starts with a guid for the bitmap strip, then there is the resource id of the
bitmap strip containing the bitmaps and then there are the numeric ids of the elements used
inside a button definition. An important aspect of this declaration is that the element id
must be the actual index (1-based) of the bitmap inside the bitmap strip. -->
<Bitmap guid="guidImages" href="Resources\Images_32bit.bmp" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>
</Bitmaps>
</Commands>
<KeyBindings>
<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>
<Symbols>
<!-- This is the package guid. -->
<GuidSymbol name="guidClangFormatPkg" value="{c5286038-25d3-4f65-83a8-51fa2df4a146}" />
<!-- This is the guid used to group the menu commands together -->
<GuidSymbol name="guidClangFormatCmdSet" value="{e39cbab1-0f96-4022-a2bc-da5a9db7eb78}">
<IDSymbol name="MyMenuGroup" value="0x1020" />
<IDSymbol name="cmdidClangFormatSelection" value="0x0100" />
<IDSymbol name="cmdidClangFormatDocument" value="0x0101" />
</GuidSymbol>
<GuidSymbol name="guidTextEditor" value="{8B382828-6202-11d1-8870-0000F87579D2}" />
<GuidSymbol name="guidImages" value="{6d53937b-9ae1-42e1-8849-d876dcdbad7b}" >
<IDSymbol name="bmpPic1" value="1" />
<IDSymbol name="bmpPic2" value="2" />
<IDSymbol name="bmpPicSearch" value="3" />
<IDSymbol name="bmpPicX" value="4" />
<IDSymbol name="bmpPicArrows" value="5" />
</GuidSymbol>
</Symbols>
</CommandTable>

View File

@@ -0,0 +1,456 @@
//===-- ClangFormatPackages.cs - VSPackage for clang-format ------*- C# -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This class contains a VS extension package that runs clang-format over a
// selection in a VS text editor.
//
//===----------------------------------------------------------------------===//
using EnvDTE;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.IO;
using System.Runtime.InteropServices;
using System.Xml.Linq;
using System.Linq;
namespace LLVM.ClangFormat
{
[ClassInterface(ClassInterfaceType.AutoDual)]
[CLSCompliant(false), ComVisible(true)]
public class OptionPageGrid : DialogPage
{
private string assumeFilename = "";
private string fallbackStyle = "LLVM";
private bool sortIncludes = false;
private string style = "file";
private bool formatOnSave = false;
private string formatOnSaveFileExtensions =
".c;.cpp;.cxx;.cc;.tli;.tlh;.h;.hh;.hpp;.hxx;.hh;.inl" +
".java;.js;.ts;.m;.mm;.proto;.protodevel;.td";
public OptionPageGrid Clone()
{
// Use MemberwiseClone to copy value types.
var clone = (OptionPageGrid)MemberwiseClone();
return clone;
}
public class StyleConverter : TypeConverter
{
protected ArrayList values;
public StyleConverter()
{
// Initializes the standard values list with defaults.
values = new ArrayList(new string[] { "file", "Chromium", "Google", "LLVM", "Mozilla", "WebKit" });
}
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
return new StandardValuesCollection(values);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
string s = value as string;
if (s == null)
return base.ConvertFrom(context, culture, value);
return value;
}
}
[Category("Format Options")]
[DisplayName("Style")]
[Description("Coding style, currently supports:\n" +
" - Predefined styles ('LLVM', 'Google', 'Chromium', 'Mozilla', 'WebKit').\n" +
" - 'file' to search for a YAML .clang-format or _clang-format\n" +
" configuration file.\n" +
" - A YAML configuration snippet.\n\n" +
"'File':\n" +
" Searches for a .clang-format or _clang-format configuration file\n" +
" in the source file's directory and its parents.\n\n" +
"YAML configuration snippet:\n" +
" The content of a .clang-format configuration file, as string.\n" +
" Example: '{BasedOnStyle: \"LLVM\", IndentWidth: 8}'\n\n" +
"See also: http://clang.llvm.org/docs/ClangFormatStyleOptions.html.")]
[TypeConverter(typeof(StyleConverter))]
public string Style
{
get { return style; }
set { style = value; }
}
public sealed class FilenameConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
string s = value as string;
if (s == null)
return base.ConvertFrom(context, culture, value);
// Check if string contains quotes. On Windows, file names cannot contain quotes.
// We do not accept them however to avoid hard-to-debug problems.
// A quote in user input would end the parameter quote and so break the command invocation.
if (s.IndexOf('\"') != -1)
throw new NotSupportedException("Filename cannot contain quotes");
return value;
}
}
[Category("Format Options")]
[DisplayName("Assume Filename")]
[Description("When reading from stdin, clang-format assumes this " +
"filename to look for a style config file (with 'file' style) " +
"and to determine the language.")]
[TypeConverter(typeof(FilenameConverter))]
public string AssumeFilename
{
get { return assumeFilename; }
set { assumeFilename = value; }
}
public sealed class FallbackStyleConverter : StyleConverter
{
public FallbackStyleConverter()
{
// Add "none" to the list of styles.
values.Insert(0, "none");
}
}
[Category("Format Options")]
[DisplayName("Fallback Style")]
[Description("The name of the predefined style used as a fallback in case clang-format " +
"is invoked with 'file' style, but can not find the configuration file.\n" +
"Use 'none' fallback style to skip formatting.")]
[TypeConverter(typeof(FallbackStyleConverter))]
public string FallbackStyle
{
get { return fallbackStyle; }
set { fallbackStyle = value; }
}
[Category("Format Options")]
[DisplayName("Sort includes")]
[Description("Sort touched include lines.\n\n" +
"See also: http://clang.llvm.org/docs/ClangFormat.html.")]
public bool SortIncludes
{
get { return sortIncludes; }
set { sortIncludes = value; }
}
[Category("Format On Save")]
[DisplayName("Enable")]
[Description("Enable running clang-format when modified files are saved. " +
"Will only format if Style is found (ignores Fallback Style)."
)]
public bool FormatOnSave
{
get { return formatOnSave; }
set { formatOnSave = value; }
}
[Category("Format On Save")]
[DisplayName("File extensions")]
[Description("When formatting on save, clang-format will be applied only to " +
"files with these extensions.")]
public string FormatOnSaveFileExtensions
{
get { return formatOnSaveFileExtensions; }
set { formatOnSaveFileExtensions = value; }
}
}
[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
[ProvideMenuResource("Menus.ctmenu", 1)]
[ProvideAutoLoad(UIContextGuids80.SolutionExists)] // Load package on solution load
[Guid(GuidList.guidClangFormatPkgString)]
[ProvideOptionPage(typeof(OptionPageGrid), "LLVM/Clang", "ClangFormat", 0, 0, true)]
public sealed class ClangFormatPackage : Package
{
#region Package Members
RunningDocTableEventsDispatcher _runningDocTableEventsDispatcher;
protected override void Initialize()
{
base.Initialize();
_runningDocTableEventsDispatcher = new RunningDocTableEventsDispatcher(this);
_runningDocTableEventsDispatcher.BeforeSave += OnBeforeSave;
var commandService = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (commandService != null)
{
{
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
OptionPageGrid GetUserOptions()
{
return (OptionPageGrid)GetDialogPage(typeof(OptionPageGrid));
}
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(GetUserOptions());
break;
case (int)PkgCmdIDList.cmdidClangFormatDocument:
FormatDocument(GetUserOptions());
break;
}
}
private static bool FileHasExtension(string filePath, string fileExtensions)
{
var extensions = fileExtensions.ToLower().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
return extensions.Contains(Path.GetExtension(filePath).ToLower());
}
private void OnBeforeSave(object sender, Document document)
{
var options = GetUserOptions();
if (!options.FormatOnSave)
return;
if (!FileHasExtension(document.FullName, options.FormatOnSaveFileExtensions))
return;
if (!Vsix.IsDocumentDirty(document))
return;
var optionsWithNoFallbackStyle = GetUserOptions().Clone();
optionsWithNoFallbackStyle.FallbackStyle = "none";
FormatDocument(document, optionsWithNoFallbackStyle);
}
/// <summary>
/// Runs clang-format on the current selection
/// </summary>
private void FormatSelection(OptionPageGrid options)
{
IWpfTextView view = Vsix.GetCurrentView();
if (view == null)
// We're not in a text view.
return;
string text = view.TextBuffer.CurrentSnapshot.GetText();
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 = Vsix.GetDocumentParent(view);
string filePath = Vsix.GetDocumentPath(view);
RunClangFormatAndApplyReplacements(text, start, length, path, filePath, options, view);
}
/// <summary>
/// Runs clang-format on the current document
/// </summary>
private void FormatDocument(OptionPageGrid options)
{
FormatView(Vsix.GetCurrentView(), options);
}
private void FormatDocument(Document document, OptionPageGrid options)
{
FormatView(Vsix.GetDocumentView(document), options);
}
private void FormatView(IWpfTextView view, OptionPageGrid options)
{
if (view == null)
// We're not in a text view.
return;
string filePath = Vsix.GetDocumentPath(view);
var path = Path.GetDirectoryName(filePath);
string text = view.TextBuffer.CurrentSnapshot.GetText();
if (!text.EndsWith(Environment.NewLine))
{
view.TextBuffer.Insert(view.TextBuffer.CurrentSnapshot.Length, Environment.NewLine);
text += Environment.NewLine;
}
RunClangFormatAndApplyReplacements(text, 0, text.Length, path, filePath, options, view);
}
private void RunClangFormatAndApplyReplacements(string text, int offset, int length, string path, string filePath, OptionPageGrid options, IWpfTextView view)
{
try
{
string replacements = RunClangFormat(text, offset, length, path, filePath, options);
ApplyClangFormatReplacements(replacements, view);
}
catch (Exception e)
{
var uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
var id = Guid.Empty;
int result;
uiShell.ShowMessageBox(
0, ref id,
"Error while running clang-format:",
e.Message,
string.Empty, 0,
OLEMSGBUTTON.OLEMSGBUTTON_OK,
OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
OLEMSGICON.OLEMSGICON_INFO,
0, out result);
}
}
/// <summary>
/// Runs the given text through clang-format and returns the replacements as XML.
///
/// Formats the text range starting at offset of the given length.
/// </summary>
private static string RunClangFormat(string text, int offset, int length, string path, string filePath, OptionPageGrid options)
{
string vsixPath = Path.GetDirectoryName(
typeof(ClangFormatPackage).Assembly.Location);
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = vsixPath + "\\clang-format.exe";
// Poor man's escaping - this will not work when quotes are already escaped
// in the input (but we don't need more).
string style = options.Style.Replace("\"", "\\\"");
string fallbackStyle = options.FallbackStyle.Replace("\"", "\\\"");
process.StartInfo.Arguments = " -offset " + offset +
" -length " + length +
" -output-replacements-xml " +
" -style \"" + style + "\"" +
" -fallback-style \"" + fallbackStyle + "\"";
if (options.SortIncludes)
process.StartInfo.Arguments += " -sort-includes ";
string assumeFilename = options.AssumeFilename;
if (string.IsNullOrEmpty(assumeFilename))
assumeFilename = filePath;
if (!string.IsNullOrEmpty(assumeFilename))
process.StartInfo.Arguments += " -assume-filename \"" + assumeFilename + "\"";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
if (path != null)
process.StartInfo.WorkingDirectory = path;
// We have to be careful when communicating via standard input / output,
// as writes to the buffers will block until they are read from the other side.
// Thus, we:
// 1. Start the process - clang-format.exe will start to read the input from the
// standard input.
try
{
process.Start();
}
catch (Exception e)
{
throw new Exception(
"Cannot execute " + process.StartInfo.FileName + ".\n\"" +
e.Message + "\".\nPlease make sure it is on the PATH.");
}
// 2. We write everything to the standard output - this cannot block, as clang-format
// reads the full standard input before analyzing it without writing anything to the
// standard output.
process.StandardInput.Write(text);
// 3. We notify clang-format that the input is done - after this point clang-format
// will start analyzing the input and eventually write the output.
process.StandardInput.Close();
// 4. We must read clang-format's output before waiting for it to exit; clang-format
// will close the channel by exiting.
string output = process.StandardOutput.ReadToEnd();
// 5. clang-format is done, wait until it is fully shut down.
process.WaitForExit();
if (process.ExitCode != 0)
{
// FIXME: If clang-format writes enough to the standard error stream to block,
// we will never reach this point; instead, read the standard error asynchronously.
throw new Exception(process.StandardError.ReadToEnd());
}
return output;
}
/// <summary>
/// Applies the clang-format replacements (xml) to the current view
/// </summary>
private static 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();
}
}
}

View File

@@ -0,0 +1,11 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project. Project-level
// suppressions either have no target or are given a specific target
// and scoped to a namespace, type, member, etc.
//
// To add a suppression to this file, right-click the message in the
// Error List, point to "Suppress Message(s)", and click "In Project
// Suppression File". You do not need to add suppressions to this
// file manually.
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")]

View File

@@ -0,0 +1,12 @@
using System;
namespace LLVM.ClangFormat
{
static class GuidList
{
public const string guidClangFormatPkgString = "c5286038-25d3-4f65-83a8-51fa2df4a146";
public const string guidClangFormatCmdSetString = "e39cbab1-0f96-4022-a2bc-da5a9db7eb78";
public static readonly Guid guidClangFormatCmdSet = new Guid(guidClangFormatCmdSetString);
};
}

Some files were not shown because too many files have changed in this diff Show More