mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-07 22:26:05 +00:00

To support this, an optional marker "#pragma clang module contents" is recognized in module map files, and the rest of the module map file from that point onwards is treated as the source of the module. Preprocessing a module map produces the input module followed by the marker and then the preprocessed contents of the module. Ignoring line markers, a preprocessed module might look like this: module A { header "a.h" } #pragma clang module contents #pragma clang module begin A // ... a.h ... #pragma clang module end The preprocessed output generates line markers, which are not accepted by the module map parser, so -x c++-module-map-cpp-output should be used to compile such outputs. A couple of major parts do not work yet: 1) The files that are listed in the module map must exist on disk, in order to build the on-disk header -> module lookup table in the PCM file. To fix this, we need the preprocessed output to track the file size and other stat information we might use to build the lookup table. 2) Declaration ownership semantics don't work properly yet, since mapping from a source location to a module relies on mapping from FileIDs to modules, which we can't do if module transitions can occur in the middle of a file. llvm-svn: 302309
214 lines
7.2 KiB
C++
214 lines
7.2 KiB
C++
//===--- FrontendActions.cpp ----------------------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Rewrite/Frontend/FrontendActions.h"
|
|
#include "clang/AST/ASTConsumer.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 "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 llvm::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,
|
|
StringRef Filename) {
|
|
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());
|
|
FixAction->Execute();
|
|
|
|
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;
|
|
}
|
|
|
|
#ifdef 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, getCurrentFile());
|
|
if (!OS) return;
|
|
|
|
RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
|
|
}
|
|
|
|
void RewriteTestAction::ExecuteAction() {
|
|
CompilerInstance &CI = getCompilerInstance();
|
|
std::unique_ptr<raw_ostream> OS =
|
|
CI.createDefaultOutputFile(false, getCurrentFile());
|
|
if (!OS) return;
|
|
|
|
DoRewriteTest(CI.getPreprocessor(), OS.get());
|
|
}
|
|
|
|
void RewriteIncludesAction::ExecuteAction() {
|
|
CompilerInstance &CI = getCompilerInstance();
|
|
std::unique_ptr<raw_ostream> OS =
|
|
CI.createDefaultOutputFile(true, getCurrentFile());
|
|
if (!OS) return;
|
|
|
|
// 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 \"" << Input.getFile() << "\"\n";
|
|
// FIXME: Include additional information here so that we don't need the
|
|
// original source files to exist on disk.
|
|
getCurrentModule()->print(*OS);
|
|
(*OS) << "#pragma clang module contents\n";
|
|
}
|
|
|
|
RewriteIncludesInInput(CI.getPreprocessor(), OS.get(),
|
|
CI.getPreprocessorOutputOpts());
|
|
}
|