forked from OSchip/llvm-project
[flang][nfc] Tweak the FrontendAction class
This patch refactors the `FrontendAction` class. It merely moves code around so that re-using it is easier. No new functionality is introduced. 1. Three new member methods are introduced: `RunPrescan`, `RunParse`, `RunSemanticChecks`. 2. The following free functions are re-implemented as member methods: * `reportFatalSemanticErrors` * `reportFatalScanningErrors` * `reportFatalParsingErrors` * `reportFatalErrors` `reportFatalSemanticErrors` is updated to resemble the other error reporting functions and to make the API more consistent. 3. The `BeginSourceFileAction` methods are simplified and the unused input argument is deleted. Differential Revision: https://reviews.llvm.org/D108130
This commit is contained in:
parent
ce8272afb3
commit
4f21e6aedd
|
@ -43,7 +43,7 @@ protected:
|
|||
///
|
||||
/// \return True on success; on failure ExecutionAction() and
|
||||
/// EndSourceFileAction() will not be called.
|
||||
virtual bool BeginSourceFileAction(CompilerInstance &ci) { return true; }
|
||||
virtual bool BeginSourceFileAction() { return true; }
|
||||
|
||||
/// @}
|
||||
|
||||
|
@ -100,6 +100,34 @@ public:
|
|||
/// Perform any per-file post processing, deallocate per-file
|
||||
/// objects, and run statistics and output file cleanup code.
|
||||
void EndSourceFile();
|
||||
|
||||
/// @}
|
||||
protected:
|
||||
// Prescan the current input file. Return False if fatal errors are reported,
|
||||
// True otherwise.
|
||||
bool RunPrescan();
|
||||
// Parse the current input file. Return False if fatal errors are reported,
|
||||
// True otherwise.
|
||||
bool RunParse();
|
||||
// Run semantic checks for the current input file. Return False if fatal
|
||||
// errors are reported, True otherwise.
|
||||
bool RunSemanticChecks();
|
||||
|
||||
// Report fatal semantic errors. Return True if present, false otherwise.
|
||||
bool reportFatalSemanticErrors();
|
||||
|
||||
// Report fatal scanning errors. Return True if present, false otherwise.
|
||||
inline bool reportFatalScanningErrors() {
|
||||
return reportFatalErrors("Could not scan %0");
|
||||
}
|
||||
|
||||
// Report fatal parsing errors. Return True if present, false otherwise
|
||||
inline bool reportFatalParsingErrors() {
|
||||
return reportFatalErrors("Could not parse %0");
|
||||
}
|
||||
|
||||
private:
|
||||
template <unsigned N> bool reportFatalErrors(const char (&message)[N]);
|
||||
};
|
||||
|
||||
} // namespace Fortran::frontend
|
||||
|
|
|
@ -51,7 +51,7 @@ class InitOnlyAction : public FrontendAction {
|
|||
//===----------------------------------------------------------------------===//
|
||||
class PrescanAction : public FrontendAction {
|
||||
void ExecuteAction() override = 0;
|
||||
bool BeginSourceFileAction(CompilerInstance &ci) override;
|
||||
bool BeginSourceFileAction() override;
|
||||
};
|
||||
|
||||
class PrintPreprocessedAction : public PrescanAction {
|
||||
|
@ -75,7 +75,7 @@ class DebugMeasureParseTreeAction : public PrescanAction {
|
|||
//===----------------------------------------------------------------------===//
|
||||
class PrescanAndParseAction : public FrontendAction {
|
||||
void ExecuteAction() override = 0;
|
||||
bool BeginSourceFileAction(CompilerInstance &ci) override;
|
||||
bool BeginSourceFileAction() override;
|
||||
};
|
||||
|
||||
class DebugUnparseNoSemaAction : public PrescanAndParseAction {
|
||||
|
@ -92,7 +92,7 @@ class DebugDumpParseTreeNoSemaAction : public PrescanAndParseAction {
|
|||
class PrescanAndSemaAction : public FrontendAction {
|
||||
|
||||
void ExecuteAction() override = 0;
|
||||
bool BeginSourceFileAction(CompilerInstance &ci) override;
|
||||
bool BeginSourceFileAction() override;
|
||||
};
|
||||
|
||||
class DebugUnparseWithSymbolsAction : public PrescanAndSemaAction {
|
||||
|
|
|
@ -89,7 +89,7 @@ bool FrontendAction::BeginSourceFile(
|
|||
invoc.fortranOpts().isFixedForm = currentInput().IsFixedForm();
|
||||
}
|
||||
|
||||
if (!BeginSourceFileAction(ci)) {
|
||||
if (!BeginSourceFileAction()) {
|
||||
BeginSourceFileCleanUp(*this, ci);
|
||||
return false;
|
||||
}
|
||||
|
@ -117,3 +117,96 @@ void FrontendAction::EndSourceFile() {
|
|||
set_instance(nullptr);
|
||||
set_currentInput(FrontendInputFile());
|
||||
}
|
||||
|
||||
bool FrontendAction::RunPrescan() {
|
||||
CompilerInstance &ci = this->instance();
|
||||
std::string currentInputPath{GetCurrentFileOrBufferName()};
|
||||
Fortran::parser::Options parserOptions = ci.invocation().fortranOpts();
|
||||
|
||||
if (ci.invocation().frontendOpts().fortranForm == FortranForm::Unknown) {
|
||||
// Switch between fixed and free form format based on the input file
|
||||
// extension.
|
||||
//
|
||||
// Ideally we should have all Fortran options set before entering this
|
||||
// method (i.e. before processing any specific input files). However, we
|
||||
// can't decide between fixed and free form based on the file extension
|
||||
// earlier than this.
|
||||
parserOptions.isFixedForm = currentInput().IsFixedForm();
|
||||
}
|
||||
|
||||
// Prescan. In case of failure, report and return.
|
||||
ci.parsing().Prescan(currentInputPath, parserOptions);
|
||||
|
||||
return !reportFatalScanningErrors();
|
||||
}
|
||||
|
||||
bool FrontendAction::RunParse() {
|
||||
CompilerInstance &ci = this->instance();
|
||||
|
||||
// Parse. In case of failure, report and return.
|
||||
ci.parsing().Parse(llvm::outs());
|
||||
|
||||
if (reportFatalParsingErrors()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Report the diagnostics from parsing
|
||||
ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FrontendAction::RunSemanticChecks() {
|
||||
CompilerInstance &ci = this->instance();
|
||||
std::optional<parser::Program> &parseTree{ci.parsing().parseTree()};
|
||||
assert(parseTree && "Cannot run semantic checks without a parse tree!");
|
||||
|
||||
// Prepare semantics
|
||||
ci.setSemantics(std::make_unique<Fortran::semantics::Semantics>(
|
||||
ci.invocation().semanticsContext(), *parseTree,
|
||||
ci.invocation().debugModuleDir()));
|
||||
auto &semantics = ci.semantics();
|
||||
|
||||
// Run semantic checks
|
||||
semantics.Perform();
|
||||
|
||||
if (reportFatalSemanticErrors()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Report the diagnostics from the semantic checks
|
||||
semantics.EmitMessages(ci.semaOutputStream());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <unsigned N>
|
||||
bool FrontendAction::reportFatalErrors(const char (&message)[N]) {
|
||||
if (!instance_->parsing().messages().empty() &&
|
||||
(instance_->invocation().warnAsErr() ||
|
||||
instance_->parsing().messages().AnyFatalError())) {
|
||||
const unsigned diagID = instance_->diagnostics().getCustomDiagID(
|
||||
clang::DiagnosticsEngine::Error, message);
|
||||
instance_->diagnostics().Report(diagID) << GetCurrentFileOrBufferName();
|
||||
instance_->parsing().messages().Emit(
|
||||
llvm::errs(), instance_->allCookedSources());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FrontendAction::reportFatalSemanticErrors() {
|
||||
auto &diags = instance_->diagnostics();
|
||||
auto &sema = instance_->semantics();
|
||||
|
||||
if (instance_->semantics().AnyFatalError()) {
|
||||
unsigned DiagID = diags.getCustomDiagID(
|
||||
clang::DiagnosticsEngine::Error, "Semantic errors in %0");
|
||||
diags.Report(DiagID) << GetCurrentFileOrBufferName();
|
||||
sema.EmitMessages(instance_->semaOutputStream());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -27,132 +27,22 @@
|
|||
|
||||
using namespace Fortran::frontend;
|
||||
|
||||
/// Report fatal semantic errors if present.
|
||||
///
|
||||
/// \param semantics The semantics instance
|
||||
/// \param diags The diagnostics engine instance
|
||||
/// \param bufferName The file or buffer name
|
||||
///
|
||||
/// \return True if fatal semantic errors are present, false if not
|
||||
bool reportFatalSemanticErrors(const Fortran::semantics::Semantics &semantics,
|
||||
clang::DiagnosticsEngine &diags, const llvm::StringRef &bufferName) {
|
||||
if (semantics.AnyFatalError()) {
|
||||
unsigned DiagID = diags.getCustomDiagID(
|
||||
clang::DiagnosticsEngine::Error, "Semantic errors in %0");
|
||||
diags.Report(DiagID) << bufferName;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Custom BeginSourceFileAction
|
||||
//===----------------------------------------------------------------------===//
|
||||
bool PrescanAction::BeginSourceFileAction() { return RunPrescan(); }
|
||||
|
||||
bool PrescanAndParseAction::BeginSourceFileAction() {
|
||||
return RunPrescan() && RunParse();
|
||||
}
|
||||
|
||||
template <unsigned N>
|
||||
static bool reportFatalErrors(
|
||||
const FrontendAction *act, const char (&message)[N]) {
|
||||
CompilerInstance &ci = act->instance();
|
||||
if (!ci.parsing().messages().empty() &&
|
||||
(ci.invocation().warnAsErr() ||
|
||||
ci.parsing().messages().AnyFatalError())) {
|
||||
const unsigned diagID = ci.diagnostics().getCustomDiagID(
|
||||
clang::DiagnosticsEngine::Error, message);
|
||||
ci.diagnostics().Report(diagID) << act->GetCurrentFileOrBufferName();
|
||||
ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool reportFatalScanningErrors(const FrontendAction *act) {
|
||||
return reportFatalErrors(act, "Could not scan %0");
|
||||
}
|
||||
|
||||
inline bool reportFatalParsingErrors(const FrontendAction *act) {
|
||||
return reportFatalErrors(act, "Could not parse %0");
|
||||
}
|
||||
|
||||
bool PrescanAction::BeginSourceFileAction(CompilerInstance &c1) {
|
||||
CompilerInstance &ci = this->instance();
|
||||
std::string currentInputPath{GetCurrentFileOrBufferName()};
|
||||
Fortran::parser::Options parserOptions = ci.invocation().fortranOpts();
|
||||
|
||||
// Prescan. In case of failure, report and return.
|
||||
ci.parsing().Prescan(currentInputPath, parserOptions);
|
||||
|
||||
return !reportFatalScanningErrors(this);
|
||||
}
|
||||
|
||||
bool PrescanAndParseAction::BeginSourceFileAction(CompilerInstance &c1) {
|
||||
CompilerInstance &ci = this->instance();
|
||||
|
||||
std::string currentInputPath{GetCurrentFileOrBufferName()};
|
||||
|
||||
Fortran::parser::Options parserOptions = ci.invocation().fortranOpts();
|
||||
|
||||
if (ci.invocation().frontendOpts().fortranForm == FortranForm::Unknown) {
|
||||
// Switch between fixed and free form format based on the input file
|
||||
// extension.
|
||||
//
|
||||
// Ideally we should have all Fortran options set before entering this
|
||||
// method (i.e. before processing any specific input files). However, we
|
||||
// can't decide between fixed and free form based on the file extension
|
||||
// earlier than this.
|
||||
parserOptions.isFixedForm = currentInput().IsFixedForm();
|
||||
}
|
||||
|
||||
// Prescan. In case of failure, report and return.
|
||||
ci.parsing().Prescan(currentInputPath, parserOptions);
|
||||
|
||||
if (reportFatalScanningErrors(this))
|
||||
return false;
|
||||
|
||||
// Parse. In case of failure, report and return.
|
||||
ci.parsing().Parse(llvm::outs());
|
||||
|
||||
if (reportFatalParsingErrors(this))
|
||||
return false;
|
||||
|
||||
// Report the diagnostics from parsing
|
||||
ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PrescanAndSemaAction::BeginSourceFileAction(CompilerInstance &c1) {
|
||||
CompilerInstance &ci = this->instance();
|
||||
std::string currentInputPath{GetCurrentFileOrBufferName()};
|
||||
Fortran::parser::Options parserOptions = ci.invocation().fortranOpts();
|
||||
|
||||
// Prescan. In case of failure, report and return.
|
||||
ci.parsing().Prescan(currentInputPath, parserOptions);
|
||||
|
||||
if (reportFatalScanningErrors(this))
|
||||
return false;
|
||||
|
||||
// Parse. In case of failure, report and return.
|
||||
ci.parsing().Parse(llvm::outs());
|
||||
|
||||
if (reportFatalParsingErrors(this))
|
||||
return false;
|
||||
|
||||
// Report the diagnostics from parsing
|
||||
ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
|
||||
|
||||
auto &parseTree{*ci.parsing().parseTree()};
|
||||
|
||||
// Prepare semantics
|
||||
ci.setSemantics(std::make_unique<Fortran::semantics::Semantics>(
|
||||
ci.invocation().semanticsContext(), parseTree,
|
||||
ci.invocation().debugModuleDir()));
|
||||
auto &semantics = ci.semantics();
|
||||
|
||||
// Run semantic checks
|
||||
semantics.Perform();
|
||||
|
||||
// Report the diagnostics from the semantic checks
|
||||
semantics.EmitMessages(ci.semaOutputStream());
|
||||
|
||||
return true;
|
||||
bool PrescanAndSemaAction::BeginSourceFileAction() {
|
||||
return RunPrescan() & RunParse() && RunSemanticChecks();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Custom ExecuteAction
|
||||
//===----------------------------------------------------------------------===//
|
||||
void InputOutputTestAction::ExecuteAction() {
|
||||
CompilerInstance &ci = instance();
|
||||
|
||||
|
@ -224,10 +114,6 @@ void DebugDumpProvenanceAction::ExecuteAction() {
|
|||
}
|
||||
|
||||
void ParseSyntaxOnlyAction::ExecuteAction() {
|
||||
CompilerInstance &ci = this->instance();
|
||||
|
||||
reportFatalSemanticErrors(
|
||||
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName());
|
||||
}
|
||||
|
||||
void DebugUnparseNoSemaAction::ExecuteAction() {
|
||||
|
@ -258,20 +144,17 @@ void DebugUnparseAction::ExecuteAction() {
|
|||
invoc.useAnalyzedObjectsForUnparse() ? &invoc.asFortran() : nullptr);
|
||||
|
||||
// Report fatal semantic errors
|
||||
reportFatalSemanticErrors(ci.semantics(), this->instance().diagnostics(),
|
||||
GetCurrentFileOrBufferName());
|
||||
reportFatalSemanticErrors();
|
||||
}
|
||||
|
||||
void DebugUnparseWithSymbolsAction::ExecuteAction() {
|
||||
CompilerInstance &ci = this->instance();
|
||||
auto &parseTree{*instance().parsing().parseTree()};
|
||||
|
||||
Fortran::semantics::UnparseWithSymbols(
|
||||
llvm::outs(), parseTree, /*encoding=*/Fortran::parser::Encoding::UTF_8);
|
||||
|
||||
// Report fatal semantic errors
|
||||
reportFatalSemanticErrors(
|
||||
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName());
|
||||
reportFatalSemanticErrors();
|
||||
}
|
||||
|
||||
void DebugDumpSymbolsAction::ExecuteAction() {
|
||||
|
@ -283,8 +166,7 @@ void DebugDumpSymbolsAction::ExecuteAction() {
|
|||
// The runtime derived type information table builder may find and report
|
||||
// semantic errors. So it is important that we report them _after_
|
||||
// BuildRuntimeDerivedTypeTables is run.
|
||||
reportFatalSemanticErrors(
|
||||
semantics, this->instance().diagnostics(), GetCurrentFileOrBufferName());
|
||||
reportFatalSemanticErrors();
|
||||
|
||||
if (!tables.schemata) {
|
||||
unsigned DiagID =
|
||||
|
@ -315,8 +197,7 @@ void DebugDumpAllAction::ExecuteAction() {
|
|||
// The runtime derived type information table builder may find and report
|
||||
// semantic errors. So it is important that we report them _after_
|
||||
// BuildRuntimeDerivedTypeTables is run.
|
||||
reportFatalSemanticErrors(
|
||||
semantics, this->instance().diagnostics(), GetCurrentFileOrBufferName());
|
||||
reportFatalSemanticErrors();
|
||||
|
||||
if (!tables.schemata) {
|
||||
unsigned DiagID =
|
||||
|
@ -342,7 +223,6 @@ void DebugDumpParseTreeNoSemaAction::ExecuteAction() {
|
|||
}
|
||||
|
||||
void DebugDumpParseTreeAction::ExecuteAction() {
|
||||
CompilerInstance &ci = this->instance();
|
||||
auto &parseTree{instance().parsing().parseTree()};
|
||||
|
||||
// Dump parse tree
|
||||
|
@ -350,8 +230,7 @@ void DebugDumpParseTreeAction::ExecuteAction() {
|
|||
llvm::outs(), parseTree, &this->instance().invocation().asFortran());
|
||||
|
||||
// Report fatal semantic errors
|
||||
reportFatalSemanticErrors(
|
||||
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName());
|
||||
reportFatalSemanticErrors();
|
||||
}
|
||||
|
||||
void DebugMeasureParseTreeAction::ExecuteAction() {
|
||||
|
@ -388,8 +267,7 @@ void DebugMeasureParseTreeAction::ExecuteAction() {
|
|||
void DebugPreFIRTreeAction::ExecuteAction() {
|
||||
CompilerInstance &ci = this->instance();
|
||||
// Report and exit if fatal semantic errors are present
|
||||
if (reportFatalSemanticErrors(
|
||||
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName())) {
|
||||
if (reportFatalSemanticErrors()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -417,9 +295,9 @@ void GetDefinitionAction::ExecuteAction() {
|
|||
CompilerInstance &ci = this->instance();
|
||||
|
||||
// Report and exit if fatal semantic errors are present
|
||||
if (reportFatalSemanticErrors(
|
||||
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName()))
|
||||
if (reportFatalSemanticErrors()) {
|
||||
return;
|
||||
}
|
||||
|
||||
parser::AllCookedSources &cs = ci.allCookedSources();
|
||||
unsigned diagID = ci.diagnostics().getCustomDiagID(
|
||||
|
@ -465,9 +343,9 @@ void GetSymbolsSourcesAction::ExecuteAction() {
|
|||
CompilerInstance &ci = this->instance();
|
||||
|
||||
// Report and exit if fatal semantic errors are present
|
||||
if (reportFatalSemanticErrors(
|
||||
ci.semantics(), ci.diagnostics(), GetCurrentFileOrBufferName()))
|
||||
if (reportFatalSemanticErrors()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ci.semantics().DumpSymbolsSources(llvm::outs());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue