summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/clang/lib/Frontend/Rewrite/FrontendActions.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 14:31:31 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 14:31:31 +0000
commite5dd70708596ae51455a0ffa086a00c5b29f8583 (patch)
tree5d676f27b570bacf71e786c3b5cff3e6f6679b59 /gnu/llvm/clang/lib/Frontend/Rewrite/FrontendActions.cpp
parentImport LLVM 10.0.0 release including clang, lld and lldb. (diff)
downloadwireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.tar.xz
wireguard-openbsd-e5dd70708596ae51455a0ffa086a00c5b29f8583.zip
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu/llvm/clang/lib/Frontend/Rewrite/FrontendActions.cpp')
-rw-r--r--gnu/llvm/clang/lib/Frontend/Rewrite/FrontendActions.cpp323
1 files changed, 323 insertions, 0 deletions
diff --git a/gnu/llvm/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/gnu/llvm/clang/lib/Frontend/Rewrite/FrontendActions.cpp
new file mode 100644
index 00000000000..aaffbde3309
--- /dev/null
+++ b/gnu/llvm/clang/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -0,0 +1,323 @@
+//===--- FrontendActions.cpp ----------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Rewrite/Frontend/FrontendActions.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/LangStandard.h"
+#include "clang/Config/config.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Rewrite/Frontend/ASTConsumers.h"
+#include "clang/Rewrite/Frontend/FixItRewriter.h"
+#include "clang/Rewrite/Frontend/Rewriters.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/ModuleFile.h"
+#include "clang/Serialization/ModuleManager.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <utility>
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// AST Consumer Actions
+//===----------------------------------------------------------------------===//
+
+std::unique_ptr<ASTConsumer>
+HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+ if (std::unique_ptr<raw_ostream> OS =
+ CI.createDefaultOutputFile(false, InFile))
+ return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor());
+ return nullptr;
+}
+
+FixItAction::FixItAction() {}
+FixItAction::~FixItAction() {}
+
+std::unique_ptr<ASTConsumer>
+FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+ return std::make_unique<ASTConsumer>();
+}
+
+namespace {
+class FixItRewriteInPlace : public FixItOptions {
+public:
+ FixItRewriteInPlace() { InPlace = true; }
+
+ std::string RewriteFilename(const std::string &Filename, int &fd) override {
+ llvm_unreachable("don't call RewriteFilename for inplace rewrites");
+ }
+};
+
+class FixItActionSuffixInserter : public FixItOptions {
+ std::string NewSuffix;
+
+public:
+ FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
+ : NewSuffix(std::move(NewSuffix)) {
+ this->FixWhatYouCan = FixWhatYouCan;
+ }
+
+ std::string RewriteFilename(const std::string &Filename, int &fd) override {
+ fd = -1;
+ SmallString<128> Path(Filename);
+ llvm::sys::path::replace_extension(Path,
+ NewSuffix + llvm::sys::path::extension(Path));
+ return Path.str();
+ }
+};
+
+class FixItRewriteToTemp : public FixItOptions {
+public:
+ std::string RewriteFilename(const std::string &Filename, int &fd) override {
+ SmallString<128> Path;
+ llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
+ llvm::sys::path::extension(Filename).drop_front(), fd,
+ Path);
+ return Path.str();
+ }
+};
+} // end anonymous namespace
+
+bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
+ const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
+ if (!FEOpts.FixItSuffix.empty()) {
+ FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
+ FEOpts.FixWhatYouCan));
+ } else {
+ FixItOpts.reset(new FixItRewriteInPlace);
+ FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
+ }
+ Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
+ CI.getLangOpts(), FixItOpts.get()));
+ return true;
+}
+
+void FixItAction::EndSourceFileAction() {
+ // Otherwise rewrite all files.
+ Rewriter->WriteFixedFiles();
+}
+
+bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
+
+ std::vector<std::pair<std::string, std::string> > RewrittenFiles;
+ bool err = false;
+ {
+ const FrontendOptions &FEOpts = CI.getFrontendOpts();
+ std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
+ if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
+ std::unique_ptr<FixItOptions> FixItOpts;
+ if (FEOpts.FixToTemporaries)
+ FixItOpts.reset(new FixItRewriteToTemp());
+ else
+ FixItOpts.reset(new FixItRewriteInPlace());
+ FixItOpts->Silent = true;
+ FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
+ FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
+ FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
+ CI.getLangOpts(), FixItOpts.get());
+ if (llvm::Error Err = FixAction->Execute()) {
+ // FIXME this drops the error on the floor.
+ consumeError(std::move(Err));
+ return false;
+ }
+
+ err = Rewriter.WriteFixedFiles(&RewrittenFiles);
+
+ FixAction->EndSourceFile();
+ CI.setSourceManager(nullptr);
+ CI.setFileManager(nullptr);
+ } else {
+ err = true;
+ }
+ }
+ if (err)
+ return false;
+ CI.getDiagnosticClient().clear();
+ CI.getDiagnostics().Reset();
+
+ PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+ PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
+ RewrittenFiles.begin(), RewrittenFiles.end());
+ PPOpts.RemappedFilesKeepOriginalName = false;
+
+ return true;
+}
+
+#if CLANG_ENABLE_OBJC_REWRITER
+
+std::unique_ptr<ASTConsumer>
+RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
+ if (std::unique_ptr<raw_ostream> OS =
+ CI.createDefaultOutputFile(false, InFile, "cpp")) {
+ if (CI.getLangOpts().ObjCRuntime.isNonFragile())
+ return CreateModernObjCRewriter(
+ InFile, std::move(OS), CI.getDiagnostics(), CI.getLangOpts(),
+ CI.getDiagnosticOpts().NoRewriteMacros,
+ (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo));
+ return CreateObjCRewriter(InFile, std::move(OS), CI.getDiagnostics(),
+ CI.getLangOpts(),
+ CI.getDiagnosticOpts().NoRewriteMacros);
+ }
+ return nullptr;
+}
+
+#endif
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Actions
+//===----------------------------------------------------------------------===//
+
+void RewriteMacrosAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ std::unique_ptr<raw_ostream> OS =
+ CI.createDefaultOutputFile(true, getCurrentFileOrBufferName());
+ if (!OS) return;
+
+ RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
+}
+
+void RewriteTestAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ std::unique_ptr<raw_ostream> OS =
+ CI.createDefaultOutputFile(false, getCurrentFileOrBufferName());
+ if (!OS) return;
+
+ DoRewriteTest(CI.getPreprocessor(), OS.get());
+}
+
+class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
+ CompilerInstance &CI;
+ std::weak_ptr<raw_ostream> Out;
+
+ llvm::DenseSet<const FileEntry*> Rewritten;
+
+public:
+ RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
+ : CI(CI), Out(Out) {}
+
+ void visitModuleFile(StringRef Filename,
+ serialization::ModuleKind Kind) override {
+ auto File = CI.getFileManager().getFile(Filename);
+ assert(File && "missing file for loaded module?");
+
+ // Only rewrite each module file once.
+ if (!Rewritten.insert(*File).second)
+ return;
+
+ serialization::ModuleFile *MF =
+ CI.getASTReader()->getModuleManager().lookup(*File);
+ assert(MF && "missing module file for loaded module?");
+
+ // Not interested in PCH / preambles.
+ if (!MF->isModule())
+ return;
+
+ auto OS = Out.lock();
+ assert(OS && "loaded module file after finishing rewrite action?");
+
+ (*OS) << "#pragma clang module build ";
+ if (isValidIdentifier(MF->ModuleName))
+ (*OS) << MF->ModuleName;
+ else {
+ (*OS) << '"';
+ OS->write_escaped(MF->ModuleName);
+ (*OS) << '"';
+ }
+ (*OS) << '\n';
+
+ // Rewrite the contents of the module in a separate compiler instance.
+ CompilerInstance Instance(CI.getPCHContainerOperations(),
+ &CI.getModuleCache());
+ Instance.setInvocation(
+ std::make_shared<CompilerInvocation>(CI.getInvocation()));
+ Instance.createDiagnostics(
+ new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
+ /*ShouldOwnClient=*/true);
+ Instance.getFrontendOpts().DisableFree = false;
+ Instance.getFrontendOpts().Inputs.clear();
+ Instance.getFrontendOpts().Inputs.emplace_back(
+ Filename, InputKind(Language::Unknown, InputKind::Precompiled));
+ Instance.getFrontendOpts().ModuleFiles.clear();
+ Instance.getFrontendOpts().ModuleMapFiles.clear();
+ // Don't recursively rewrite imports. We handle them all at the top level.
+ Instance.getPreprocessorOutputOpts().RewriteImports = false;
+
+ llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
+ RewriteIncludesAction Action;
+ Action.OutputStream = OS;
+ Instance.ExecuteAction(Action);
+ });
+
+ (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
+ }
+};
+
+bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
+ if (!OutputStream) {
+ OutputStream =
+ CI.createDefaultOutputFile(true, getCurrentFileOrBufferName());
+ if (!OutputStream)
+ return false;
+ }
+
+ auto &OS = *OutputStream;
+
+ // If we're preprocessing a module map, start by dumping the contents of the
+ // module itself before switching to the input buffer.
+ auto &Input = getCurrentInput();
+ if (Input.getKind().getFormat() == InputKind::ModuleMap) {
+ if (Input.isFile()) {
+ OS << "# 1 \"";
+ OS.write_escaped(Input.getFile());
+ OS << "\"\n";
+ }
+ getCurrentModule()->print(OS);
+ OS << "#pragma clang module contents\n";
+ }
+
+ // If we're rewriting imports, set up a listener to track when we import
+ // module files.
+ if (CI.getPreprocessorOutputOpts().RewriteImports) {
+ CI.createASTReader();
+ CI.getASTReader()->addListener(
+ std::make_unique<RewriteImportsListener>(CI, OutputStream));
+ }
+
+ return true;
+}
+
+void RewriteIncludesAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+
+ // If we're rewriting imports, emit the module build output first rather
+ // than switching back and forth (potentially in the middle of a line).
+ if (CI.getPreprocessorOutputOpts().RewriteImports) {
+ std::string Buffer;
+ llvm::raw_string_ostream OS(Buffer);
+
+ RewriteIncludesInInput(CI.getPreprocessor(), &OS,
+ CI.getPreprocessorOutputOpts());
+
+ (*OutputStream) << OS.str();
+ } else {
+ RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
+ CI.getPreprocessorOutputOpts());
+ }
+
+ OutputStream.reset();
+}