diff --git a/flang/docs/FlangDriver.md b/flang/docs/FlangDriver.md --- a/flang/docs/FlangDriver.md +++ b/flang/docs/FlangDriver.md @@ -395,25 +395,30 @@ the `ExecuteAction` method in your plugin class. This method will contain the implementation of what the plugin actually does, for example: ```cpp +// Forward declaration +struct ParseTreeVisitor; + void ExecuteAction() override { - auto &parseTree{instance().parsing().parseTree()}; ParseTreeVisitor visitor; - Fortran::parser::Walk(parseTree, visitor); + Fortran::parser::Walk(getParsing().parseTree(), visitor); } ``` -In the example plugin, the `ExecuteAction` method first gets a reference to the -parse tree, `instance().parsing().parseTree()`, then declares a `visitor` -struct, before passing both of these to the `Fortran::parser::Walk` function -that will traverse the parse tree. Implementation and details of the `Walk` -function can be found in `flang/include/flang/Parser/parse-tree-visitor.h`. - -A `visitor` struct should define different `Pre` and `Post` functions that take -the type of a specific `ParseTree` node as an argument. When the `Walk` function -is traversing the parse tree, these functions will be run before/after a node -of that type is visited. Template functions for `Pre`/`Post` are defined so that -when a node is visited that you have not defined a function for, it will still -be able to continue. `Pre` returns a `bool` indicating whether to visit that -node's children or not. For example: +In the example plugin, the `ExecuteAction` method first creates an instance of +`visitor` struct, before passing it together with the parse tree to the +`Fortran::parser::Walk` function that will traverse the parse tree. The parse +tree will normally be generated by the frontend driver and can be retrieved in +your plugin through the `getParsing()` member method. Implementation and +details of the `Walk` function can be found in +`flang/include/flang/Parser/parse-tree-visitor.h`. + +You will have to define your own `visitor` struct. It should define different +`Pre` and `Post` functions that take the type of a specific `ParseTree` node as +an argument. When the `Walk` function is traversing the parse tree, these +functions will be run before/after a node of that type is visited. Template +functions for `Pre`/`Post` are defined so that when a node is visited that you +have not defined a function for, it will still be able to continue. `Pre` +returns a `bool` indicating whether to visit that node's children or not. For +example: ```cpp struct ParseTreeVisitor { template bool Pre(const A&) { return true; } diff --git a/flang/examples/FlangOmpReport/FlangOmpReport.cpp b/flang/examples/FlangOmpReport/FlangOmpReport.cpp --- a/flang/examples/FlangOmpReport/FlangOmpReport.cpp +++ b/flang/examples/FlangOmpReport/FlangOmpReport.cpp @@ -5,19 +5,17 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -// This plugin parses a Fortran source file and generates a YAML -// report with all the OpenMP constructs and clauses and which -// line they're located on. +// This plugin parses a Fortran source file and generates a YAML report with +// all the OpenMP constructs and clauses and which line they're located on. // // The plugin may be invoked as: -// ./bin/flang-new -fc1 -load lib/flangOmpReport.so -plugin -// flang-omp-report -fopenmp -o - +// ./bin/flang-new -fc1 -load lib/flangOmpReport.so -plugin flang-omp-report +// -fopenmp // //===----------------------------------------------------------------------===// #include "FlangOmpReportVisitor.h" -#include "flang/Frontend/CompilerInstance.h" #include "flang/Frontend/FrontendActions.h" #include "flang/Frontend/FrontendPluginRegistry.h" #include "flang/Parser/dump-parse-tree.h" @@ -53,20 +51,18 @@ class FlangOmpReport : public PluginParseTreeAction { void ExecuteAction() override { // Prepare the parse tree and the visitor - CompilerInstance &ci = this->instance(); - Parsing &parsing = ci.parsing(); - const Program &parseTree = *parsing.parseTree(); + Parsing &parsing = getParsing(); OpenMPCounterVisitor visitor; visitor.parsing = &parsing; // Walk the parse tree - Walk(parseTree, visitor); + Walk(parsing.parseTree(), visitor); // Dump the output - std::unique_ptr OS{ci.CreateDefaultOutputFile( - /*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName(), - /*Extension=*/".yaml")}; + std::unique_ptr OS{ + createOutputFile(/*extension=*/"yaml")}; llvm::yaml::Output yout(*OS); + yout << visitor.constructClauses; } }; diff --git a/flang/examples/FlangOmpReport/yaml_summarizer.py b/flang/examples/FlangOmpReport/yaml_summarizer.py --- a/flang/examples/FlangOmpReport/yaml_summarizer.py +++ b/flang/examples/FlangOmpReport/yaml_summarizer.py @@ -1,6 +1,6 @@ """YAML Summariser -The flang plugin ``flang-omp-report`` takes one fortran +The flang plugin ``flang-omp-report`` takes one Fortran file in and returns a YAML report file of the input file. This becomes an issue when you want to analyse an entire project into one final report. diff --git a/flang/examples/PrintFlangFunctionNames/PrintFlangFunctionNames.cpp b/flang/examples/PrintFlangFunctionNames/PrintFlangFunctionNames.cpp --- a/flang/examples/PrintFlangFunctionNames/PrintFlangFunctionNames.cpp +++ b/flang/examples/PrintFlangFunctionNames/PrintFlangFunctionNames.cpp @@ -18,7 +18,6 @@ // //===----------------------------------------------------------------------===// -#include "flang/Frontend/CompilerInstance.h" #include "flang/Frontend/FrontendActions.h" #include "flang/Frontend/FrontendPluginRegistry.h" #include "flang/Parser/dump-parse-tree.h" @@ -67,10 +66,8 @@ }; void ExecuteAction() override { - auto &parseTree{instance().parsing().parseTree()}; - ParseTreeVisitor visitor; - Fortran::parser::Walk(parseTree, visitor); + Fortran::parser::Walk(getParsing().parseTree(), visitor); llvm::outs() << "\n==== Functions: " << visitor.fcounter << " ====\n"; llvm::outs() << "==== Subroutines: " << visitor.scounter << " ====\n"; diff --git a/flang/include/flang/Frontend/FrontendActions.h b/flang/include/flang/Frontend/FrontendActions.h --- a/flang/include/flang/Frontend/FrontendActions.h +++ b/flang/include/flang/Frontend/FrontendActions.h @@ -10,9 +10,11 @@ #define LLVM_FLANG_FRONTEND_FRONTENDACTIONS_H #include "flang/Frontend/FrontendAction.h" +#include "flang/Parser/parsing.h" #include "flang/Semantics/semantics.h" #include "mlir/IR/BuiltinOps.h" +#include "llvm/ADT/StringRef.h" #include "llvm/IR/Module.h" #include @@ -131,6 +133,17 @@ class PluginParseTreeAction : public PrescanAndSemaAction { void ExecuteAction() override = 0; + +public: + Fortran::parser::Parsing &getParsing(); + /// Creates an output file. This is just a wrapper for calling + /// CreateDefaultOutputFile from CompilerInstance. Use it to make sure that + /// your plugin respects driver's `-o` flag. + /// \param extension The extension to use for the output file (ignored when + /// the user decides to print to stdout via `-o -`) + /// \return Null on error, ostream for the output file otherwise + std::unique_ptr createOutputFile( + llvm::StringRef extension); }; //===----------------------------------------------------------------------===// diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -648,3 +648,17 @@ clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); ci.diagnostics().Report(DiagID); } + +Fortran::parser::Parsing &PluginParseTreeAction::getParsing() { + return instance().parsing(); +} + +std::unique_ptr +PluginParseTreeAction::createOutputFile(llvm::StringRef extension = "") { + + std::unique_ptr OS{ + instance().CreateDefaultOutputFile( + /*Binary=*/false, /*InFile=*/GetCurrentFileOrBufferName(), + extension)}; + return OS; +}