1 //===--- FrontendAction.cpp -----------------------------------------------===//
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "flang/Frontend/FrontendAction.h"
10 #include "flang/Frontend/CompilerInstance.h"
11 #include "flang/Frontend/FrontendActions.h"
12 #include "flang/Frontend/FrontendOptions.h"
13 #include "flang/FrontendTool/Utils.h"
14 #include "llvm/Support/Errc.h"
15 
16 using namespace Fortran::frontend;
17 
18 void FrontendAction::set_currentInput(const FrontendInputFile &currentInput) {
19   this->currentInput_ = currentInput;
20 }
21 
22 // Call this method if BeginSourceFile fails.
23 // Deallocate compiler instance, input and output descriptors
24 static void BeginSourceFileCleanUp(FrontendAction &fa, CompilerInstance &ci) {
25   ci.ClearOutputFiles(/*EraseFiles=*/true);
26   fa.set_currentInput(FrontendInputFile());
27   fa.set_instance(nullptr);
28 }
29 
30 bool FrontendAction::BeginSourceFile(
31     CompilerInstance &ci, const FrontendInputFile &realInput) {
32 
33   FrontendInputFile input(realInput);
34   assert(!instance_ && "Already processing a source file!");
35   assert(!realInput.IsEmpty() && "Unexpected empty filename!");
36   set_currentInput(realInput);
37   set_instance(&ci);
38   if (!ci.HasAllSources()) {
39     BeginSourceFileCleanUp(*this, ci);
40     return false;
41   }
42   return true;
43 }
44 
45 bool FrontendAction::ShouldEraseOutputFiles() {
46   return instance().diagnostics().hasErrorOccurred();
47 }
48 
49 llvm::Error FrontendAction::Execute() {
50   CompilerInstance &ci = this->instance();
51 
52   std::string currentInputPath{GetCurrentFileOrBufferName()};
53 
54   Fortran::parser::Options parserOptions =
55       this->instance().invocation().fortranOpts();
56   // Set the fixed form flag based on the file extension
57   auto pathDotIndex{currentInputPath.rfind(".")};
58   if (pathDotIndex != std::string::npos) {
59     std::string pathSuffix{currentInputPath.substr(pathDotIndex + 1)};
60     parserOptions.isFixedForm = isFixedFormSuffix(pathSuffix);
61   }
62 
63   // Prescan. In case of failure, report and return.
64   ci.parsing().Prescan(currentInputPath, parserOptions);
65 
66   if (ci.parsing().messages().AnyFatalError()) {
67     const unsigned diagID = ci.diagnostics().getCustomDiagID(
68         clang::DiagnosticsEngine::Error, "Could not scan %0");
69     ci.diagnostics().Report(diagID) << GetCurrentFileOrBufferName();
70     ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources());
71 
72     return llvm::Error::success();
73   }
74 
75   ExecuteAction();
76 
77   return llvm::Error::success();
78 }
79 
80 void FrontendAction::EndSourceFile() {
81   CompilerInstance &ci = instance();
82 
83   // Cleanup the output streams, and erase the output files if instructed by the
84   // FrontendAction.
85   ci.ClearOutputFiles(/*EraseFiles=*/ShouldEraseOutputFiles());
86 
87   set_instance(nullptr);
88   set_currentInput(FrontendInputFile());
89 }
90