brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · 9ea7df1 Raw
165 lines · cpp
1//===--- Compiler.cpp --------------------------------------------*- C++-*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Compiler.h"10#include "support/Logger.h"11#include "clang/Basic/TargetInfo.h"12#include "clang/Driver/CreateInvocationFromArgs.h"13#include "clang/Frontend/CompilerInvocation.h"14#include "clang/Lex/PreprocessorOptions.h"15#include "clang/Serialization/PCHContainerOperations.h"16#include "llvm/ADT/StringRef.h"17 18namespace clang {19namespace clangd {20 21void IgnoreDiagnostics::log(DiagnosticsEngine::Level DiagLevel,22                            const clang::Diagnostic &Info) {23  // FIXME: format lazily, in case vlog is off.24  llvm::SmallString<64> Message;25  Info.FormatDiagnostic(Message);26 27  llvm::SmallString<64> Location;28  if (Info.hasSourceManager() && Info.getLocation().isValid()) {29    auto &SourceMgr = Info.getSourceManager();30    auto Loc = SourceMgr.getFileLoc(Info.getLocation());31    llvm::raw_svector_ostream OS(Location);32    Loc.print(OS, SourceMgr);33    OS << ":";34  }35 36  clangd::vlog("Ignored diagnostic. {0}{1}", Location, Message);37}38 39void IgnoreDiagnostics::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,40                                         const clang::Diagnostic &Info) {41  IgnoreDiagnostics::log(DiagLevel, Info);42}43 44static bool AllowCrashPragmasForTest = false;45void allowCrashPragmasForTest() { AllowCrashPragmasForTest = true; }46 47void disableUnsupportedOptions(CompilerInvocation &CI) {48  // Disable "clang -verify" diagnostics, they are rarely useful in clangd, and49  // our compiler invocation set-up doesn't seem to work with it (leading50  // assertions in VerifyDiagnosticConsumer).51  CI.getDiagnosticOpts().VerifyDiagnostics = false;52  CI.getDiagnosticOpts().ShowColors = false;53 54  // Disable any dependency outputting, we don't want to generate files or write55  // to stdout/stderr.56  CI.getDependencyOutputOpts().ShowIncludesDest = ShowIncludesDestination::None;57  CI.getDependencyOutputOpts().OutputFile.clear();58  CI.getDependencyOutputOpts().HeaderIncludeOutputFile.clear();59  CI.getDependencyOutputOpts().DOTOutputFile.clear();60  CI.getDependencyOutputOpts().ModuleDependencyOutputDir.clear();61 62  // Disable any pch generation/usage operations. Since serialized preamble63  // format is unstable, using an incompatible one might result in unexpected64  // behaviours, including crashes.65  CI.getPreprocessorOpts().ImplicitPCHInclude.clear();66  CI.getPreprocessorOpts().PrecompiledPreambleBytes = {0, false};67  CI.getPreprocessorOpts().PCHThroughHeader.clear();68  CI.getPreprocessorOpts().PCHWithHdrStop = false;69  CI.getPreprocessorOpts().PCHWithHdrStopCreate = false;70  // Don't crash on `#pragma clang __debug parser_crash`71  if (!AllowCrashPragmasForTest)72    CI.getPreprocessorOpts().DisablePragmaDebugCrash = true;73 74  // Always default to raw container format as clangd doesn't registry any other75  // and clang dies when faced with unknown formats.76  CI.getHeaderSearchOpts().ModuleFormat =77      PCHContainerOperations().getRawReader().getFormats().front().str();78 79  CI.getFrontendOpts().Plugins.clear();80  CI.getFrontendOpts().AddPluginActions.clear();81  CI.getFrontendOpts().PluginArgs.clear();82  CI.getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;83  CI.getFrontendOpts().ActionName.clear();84 85  // These options mostly affect codegen, and aren't relevant to clangd. And86  // clang will die immediately when these files are not existed.87  // Disable these uninteresting options to make clangd more robust.88  CI.getLangOpts().NoSanitizeFiles.clear();89  CI.getLangOpts().XRayAttrListFiles.clear();90  CI.getLangOpts().ProfileListFiles.clear();91  CI.getLangOpts().XRayAlwaysInstrumentFiles.clear();92  CI.getLangOpts().XRayNeverInstrumentFiles.clear();93}94 95std::unique_ptr<CompilerInvocation>96buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,97                        std::vector<std::string> *CC1Args) {98  llvm::ArrayRef<std::string> Argv = Inputs.CompileCommand.CommandLine;99  if (Argv.empty())100    return nullptr;101  std::vector<const char *> ArgStrs;102  ArgStrs.reserve(Argv.size() + 1);103  // In asserts builds, CompilerInvocation redundantly reads/parses cc1 args as104  // a sanity test. This is not useful to clangd, and costs 10% of test time.105  // To avoid mismatches between assert/production builds, disable it always.106  ArgStrs = {Argv.front().c_str(), "-Xclang", "-no-round-trip-args"};107  for (const auto &S : Argv.drop_front())108    ArgStrs.push_back(S.c_str());109 110  CreateInvocationOptions CIOpts;111  CIOpts.VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);112  CIOpts.CC1Args = CC1Args;113  CIOpts.RecoverOnError = true;114  DiagnosticOptions DiagOpts;115  CIOpts.Diags =116      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts, &D, false);117  CIOpts.ProbePrecompiled = false;118  std::unique_ptr<CompilerInvocation> CI = createInvocation(ArgStrs, CIOpts);119  if (!CI)120    return nullptr;121  // createInvocationFromCommandLine sets DisableFree.122  CI->getFrontendOpts().DisableFree = false;123  CI->getLangOpts().CommentOpts.ParseAllComments = true;124  CI->getLangOpts().RetainCommentsFromSystemHeaders = true;125 126  disableUnsupportedOptions(*CI);127  return CI;128}129 130std::unique_ptr<CompilerInstance>131prepareCompilerInstance(std::unique_ptr<clang::CompilerInvocation> CI,132                        const PrecompiledPreamble *Preamble,133                        std::unique_ptr<llvm::MemoryBuffer> Buffer,134                        llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,135                        DiagnosticConsumer &DiagsClient) {136  assert(VFS && "VFS is null");137  assert(!CI->getPreprocessorOpts().RetainRemappedFileBuffers &&138         "Setting RetainRemappedFileBuffers to true will cause a memory leak "139         "of ContentsBuffer");140 141  // NOTE: we use Buffer.get() when adding remapped files, so we have to make142  // sure it will be released if no error is emitted.143  if (Preamble) {144    Preamble->OverridePreamble(*CI, VFS, Buffer.get());145  } else {146    CI->getPreprocessorOpts().addRemappedFile(147        CI->getFrontendOpts().Inputs[0].getFile(), Buffer.get());148  }149 150  auto Clang = std::make_unique<CompilerInstance>(std::move(CI));151  Clang->createVirtualFileSystem(VFS, &DiagsClient);152  Clang->createDiagnostics(&DiagsClient, false);153  Clang->createFileManager();154  if (!Clang->createTarget())155    return nullptr;156 157  // RemappedFileBuffers will handle the lifetime of the Buffer pointer,158  // release it.159  Buffer.release();160  return Clang;161}162 163} // namespace clangd164} // namespace clang165