2018-08-15 00:03:32 +08:00
|
|
|
//===--- Compiler.cpp --------------------------------------------*- C++-*-===//
|
2017-12-04 21:49:59 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2017-12-04 21:49:59 +08:00
|
|
|
//
|
2018-08-15 00:03:32 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2017-12-15 05:22:03 +08:00
|
|
|
|
2017-12-04 21:49:59 +08:00
|
|
|
#include "Compiler.h"
|
2018-02-12 20:48:51 +08:00
|
|
|
#include "Logger.h"
|
2017-12-04 21:49:59 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
|
|
|
#include "clang/Lex/PreprocessorOptions.h"
|
2018-02-12 20:48:51 +08:00
|
|
|
#include "llvm/Support/Format.h"
|
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
2017-12-04 21:49:59 +08:00
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
|
2018-02-12 20:48:51 +08:00
|
|
|
void IgnoreDiagnostics::log(DiagnosticsEngine::Level DiagLevel,
|
|
|
|
const clang::Diagnostic &Info) {
|
2018-11-02 20:51:26 +08:00
|
|
|
// FIXME: format lazily, in case vlog is off.
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::SmallString<64> Message;
|
2018-02-12 20:48:51 +08:00
|
|
|
Info.FormatDiagnostic(Message);
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::SmallString<64> Location;
|
2018-02-12 20:48:51 +08:00
|
|
|
if (Info.hasSourceManager() && Info.getLocation().isValid()) {
|
|
|
|
auto &SourceMgr = Info.getSourceManager();
|
|
|
|
auto Loc = SourceMgr.getFileLoc(Info.getLocation());
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::raw_svector_ostream OS(Location);
|
2018-02-12 20:48:51 +08:00
|
|
|
Loc.print(OS, SourceMgr);
|
|
|
|
OS << ":";
|
|
|
|
}
|
|
|
|
|
2018-11-02 20:51:26 +08:00
|
|
|
clangd::vlog("Ignored diagnostic. {0}{1}", Location, Message);
|
2018-02-12 20:48:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void IgnoreDiagnostics::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
|
|
|
|
const clang::Diagnostic &Info) {
|
|
|
|
IgnoreDiagnostics::log(DiagLevel, Info);
|
|
|
|
}
|
|
|
|
|
2019-01-22 17:58:53 +08:00
|
|
|
std::unique_ptr<CompilerInvocation>
|
|
|
|
buildCompilerInvocation(const ParseInputs &Inputs) {
|
|
|
|
std::vector<const char *> ArgStrs;
|
|
|
|
for (const auto &S : Inputs.CompileCommand.CommandLine)
|
|
|
|
ArgStrs.push_back(S.c_str());
|
|
|
|
|
|
|
|
if (Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
|
|
|
|
log("Couldn't set working directory when creating compiler invocation.");
|
|
|
|
// We proceed anyway, our lit-tests rely on results for non-existing working
|
|
|
|
// dirs.
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME(ibiryukov): store diagnostics from CommandLine when we start
|
|
|
|
// reporting them.
|
|
|
|
IgnoreDiagnostics IgnoreDiagnostics;
|
|
|
|
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
|
|
|
|
CompilerInstance::createDiagnostics(new DiagnosticOptions,
|
|
|
|
&IgnoreDiagnostics, false);
|
|
|
|
std::unique_ptr<CompilerInvocation> CI = createInvocationFromCommandLine(
|
|
|
|
ArgStrs, CommandLineDiagsEngine, Inputs.FS);
|
|
|
|
if (!CI)
|
|
|
|
return nullptr;
|
|
|
|
// createInvocationFromCommandLine sets DisableFree.
|
|
|
|
CI->getFrontendOpts().DisableFree = false;
|
|
|
|
CI->getLangOpts()->CommentOpts.ParseAllComments = true;
|
|
|
|
return CI;
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
std::unique_ptr<CompilerInstance>
|
|
|
|
prepareCompilerInstance(std::unique_ptr<clang::CompilerInvocation> CI,
|
|
|
|
const PrecompiledPreamble *Preamble,
|
|
|
|
std::unique_ptr<llvm::MemoryBuffer> Buffer,
|
|
|
|
std::shared_ptr<PCHContainerOperations> PCHs,
|
|
|
|
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
|
|
|
|
DiagnosticConsumer &DiagsClient) {
|
2017-12-04 21:49:59 +08:00
|
|
|
assert(VFS && "VFS is null");
|
|
|
|
assert(!CI->getPreprocessorOpts().RetainRemappedFileBuffers &&
|
|
|
|
"Setting RetainRemappedFileBuffers to true will cause a memory leak "
|
|
|
|
"of ContentsBuffer");
|
|
|
|
|
|
|
|
// NOTE: we use Buffer.get() when adding remapped files, so we have to make
|
|
|
|
// sure it will be released if no error is emitted.
|
|
|
|
if (Preamble) {
|
2018-01-18 23:17:00 +08:00
|
|
|
Preamble->OverridePreamble(*CI, VFS, Buffer.get());
|
2017-12-04 21:49:59 +08:00
|
|
|
} else {
|
|
|
|
CI->getPreprocessorOpts().addRemappedFile(
|
|
|
|
CI->getFrontendOpts().Inputs[0].getFile(), Buffer.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Clang = llvm::make_unique<CompilerInstance>(PCHs);
|
|
|
|
Clang->setInvocation(std::move(CI));
|
|
|
|
Clang->createDiagnostics(&DiagsClient, false);
|
|
|
|
|
|
|
|
if (auto VFSWithRemapping = createVFSFromCompilerInvocation(
|
|
|
|
Clang->getInvocation(), Clang->getDiagnostics(), VFS))
|
|
|
|
VFS = VFSWithRemapping;
|
|
|
|
Clang->setVirtualFileSystem(VFS);
|
|
|
|
|
|
|
|
Clang->setTarget(TargetInfo::CreateTargetInfo(
|
|
|
|
Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
|
|
|
|
if (!Clang->hasTarget())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
// RemappedFileBuffers will handle the lifetime of the Buffer pointer,
|
|
|
|
// release it.
|
|
|
|
Buffer.release();
|
|
|
|
return Clang;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|