Replacing Hello World example Plugin with one that counts and prints the names of
functions and subroutines.
This involves changing the `PluginParseTreeAction` Plugin base class to
inherit from `PrescanAndSemaAction` class to get access to the Parse Tree
so that the Plugin can walk it.
Additionally, there are tests of this new Plugin to check it prints the correct
things in different circumstances.
Depends on: D106137
Reviewed By: awarzynski
Differential Revision: https://reviews.llvm.org/D107089
FortranRuntime
)
-add_subdirectory(HelloWorld)
+add_subdirectory(PrintFlangFunctionNames)
+++ /dev/null
-//===-- HelloWorldPlugin.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
-//
-//===----------------------------------------------------------------------===//
-//
-// Basic example Flang plugin which simply prints a Hello World statement
-//
-//===----------------------------------------------------------------------===//
-
-#include "flang/Frontend/FrontendActions.h"
-#include "flang/Frontend/FrontendPluginRegistry.h"
-
-using namespace Fortran::frontend;
-
-class HelloWorldFlangPlugin : public PluginParseTreeAction {
- void ExecuteAction() override {
- llvm::outs() << "Hello World from your new Flang plugin\n";
- }
-};
-
-static FrontendPluginRegistry::Add<HelloWorldFlangPlugin> X(
- "-hello-world", "Hello World Plugin example");
# TODO: Note that this is currently only available on Linux.
# On Windows, we would also have to specify e.g. `PLUGIN_TOOL`.
add_llvm_library(
- flangHelloWorldPlugin
+ flangPrintFunctionNames
MODULE
- HelloWorldPlugin.cpp
+ PrintFlangFunctionNames.cpp
)
--- /dev/null
+//===-- PrintFlangFunctionNames.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Small example Flang plugin to count/print Functions & Subroutines names.
+// It walks the Parse Tree using a Visitor struct that has Post functions for
+// FunctionStmt and SubroutineStmt to access the names of functions &
+// subroutines. It also has Pre functions for FunctionSubprogram and
+// SubroutineSubprogram so a Bool can be set to show that it is the definition
+// of a function/subroutine, and not print those that are in an Interface.
+// This plugin does not recognise Statement Functions or Module Procedures,
+// which could be dealt with through StmtFunctionStmt and MpSubprogramStmt nodes
+// respectively.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Frontend/CompilerInstance.h"
+#include "flang/Frontend/FrontendActions.h"
+#include "flang/Frontend/FrontendPluginRegistry.h"
+#include "flang/Parser/dump-parse-tree.h"
+#include "flang/Parser/parsing.h"
+
+using namespace Fortran::frontend;
+
+class PrintFunctionNamesAction : public PluginParseTreeAction {
+
+ // Visitor struct that defines Pre/Post functions for different types of nodes
+ struct ParseTreeVisitor {
+ template <typename A> bool Pre(const A &) { return true; }
+ template <typename A> void Post(const A &) {}
+
+ bool Pre(const Fortran::parser::FunctionSubprogram &) {
+ isInSubprogram_ = true;
+ return true;
+ }
+ void Post(const Fortran::parser::FunctionStmt &f) {
+ if (isInSubprogram_) {
+ llvm::outs() << "Function:\t"
+ << std::get<Fortran::parser::Name>(f.t).ToString() << "\n";
+ fcounter++;
+ isInSubprogram_ = false;
+ }
+ }
+
+ bool Pre(const Fortran::parser::SubroutineSubprogram &) {
+ isInSubprogram_ = true;
+ return true;
+ }
+ void Post(const Fortran::parser::SubroutineStmt &s) {
+ if (isInSubprogram_) {
+ llvm::outs() << "Subroutine:\t"
+ << std::get<Fortran::parser::Name>(s.t).ToString() << "\n";
+ scounter++;
+ isInSubprogram_ = false;
+ }
+ }
+
+ int fcounter{0};
+ int scounter{0};
+
+ private:
+ bool isInSubprogram_{false};
+ };
+
+ void ExecuteAction() override {
+ auto &parseTree{instance().parsing().parseTree()};
+
+ ParseTreeVisitor visitor;
+ Fortran::parser::Walk(parseTree, visitor);
+
+ llvm::outs() << "\n==== Functions: " << visitor.fcounter << " ====\n";
+ llvm::outs() << "==== Subroutines: " << visitor.scounter << " ====\n";
+ }
+};
+
+static FrontendPluginRegistry::Add<PrintFunctionNamesAction> X(
+ "print-fns", "Print Function names");
// Custom Consumer Actions
//===----------------------------------------------------------------------===//
-class PluginParseTreeAction : public FrontendAction {
- void ExecuteAction() override;
-};
-
class InputOutputTestAction : public FrontendAction {
void ExecuteAction() override;
};
void ExecuteAction() override;
};
+class PluginParseTreeAction : public PrescanAndSemaAction {
+ void ExecuteAction() override;
+};
+
} // namespace Fortran::frontend
#endif // LLVM_FLANG_FRONTEND_FRONTENDACTIONS_H
endif()
if (FLANG_BUILD_EXAMPLES)
- list(APPEND FLANG_TEST_DEPENDS flangHelloWorldPlugin)
+ list(APPEND FLANG_TEST_DEPENDS
+ flangPrintFunctionNames
+ )
endif ()
add_custom_target(flang-test-depends DEPENDS ${FLANG_TEST_DEPENDS})
+++ /dev/null
-! Check that loading and running the Hello World plugin example results in the correct print statement
-! Also check that when a plugin name isn't found, the error diagnostic is correct
-! This requires that the examples are built (FLANG_BUILD_EXAMPLES=ON)
-
-! REQUIRES: plugins, examples, shell
-
-! RUN: %flang_fc1 -load %llvmshlibdir/flangHelloWorldPlugin%pluginext -plugin -hello-world %s 2>&1 | FileCheck %s
-! CHECK: Hello World from your new Flang plugin
-
-! RUN: not %flang_fc1 -load %llvmshlibdir/flangHelloWorldPlugin%pluginext -plugin -wrong-name %s 2>&1 | FileCheck %s --check-prefix=ERROR
-! ERROR: error: unable to find plugin '-wrong-name'
--- /dev/null
+! Check the correct error diagnostic is reported when a plugin name isn't found
+
+! REQUIRES: plugins, shell
+
+! RUN: not %flang_fc1 -plugin -wrong-name %s 2>&1 | FileCheck %s --check-prefix=ERROR
+
+! ERROR: error: unable to find plugin '-wrong-name'
--- /dev/null
+! Check the Flang Print Function Names example plugin doesn't count/print function/subroutine calls (should only count definitions)
+! This requires that the examples are built (FLANG_BUILD_EXAMPLES=ON) to access flangPrintFunctionNames.so
+
+! REQUIRES: plugins, examples, shell
+
+! RUN: %flang_fc1 -load %llvmshlibdir/flangPrintFunctionNames%pluginext -plugin print-fns %s 2>&1 | FileCheck %s
+
+!-----------------------------
+! EXPECTED OUTPUT: Counts == 0
+!-----------------------------
+! CHECK: ==== Functions: 0 ====
+! CHECK-NEXT: ==== Subroutines: 0 ====
+
+!-----------------------------
+! INPUT
+!-----------------------------
+program main
+ call subroutine1
+ fn1 = function1()
+ fn2 = function2()
+end program main
--- /dev/null
+! Check the Flang Print Function Names example plugin prints and counts function/subroutine definitions
+! This includes internal and external Function/Subroutines, but not Statement Functions
+! This requires that the examples are built (FLANG_BUILD_EXAMPLES=ON) to access flangPrintFunctionNames.so
+
+! REQUIRES: plugins, examples, shell
+
+! RUN: %flang_fc1 -load %llvmshlibdir/flangPrintFunctionNames%pluginext -plugin print-fns %s 2>&1 | FileCheck %s
+
+!-------------------------------------------------
+! EXPECTED OUTPUT: Names printed and counts != 0
+!-------------------------------------------------
+! CHECK: Function: external_func1
+! CHECK-NEXT: Function: external_func2
+! CHECK-NEXT: Subroutine: external_subr
+! CHECK-NEXT: Function: internal_func
+! CHECK-NEXT: Subroutine: internal_subr
+! CHECK-EMPTY:
+! CHECK-NEXT: ==== Functions: 3 ====
+! CHECK-NEXT: ==== Subroutines: 2 ====
+
+!--------------------------
+! INPUT
+!--------------------------
+function external_func1()
+end function
+
+function external_func2()
+end function
+
+subroutine external_subr
+end subroutine
+
+program main
+contains
+ function internal_func()
+ end function
+
+ subroutine internal_subr
+ end subroutine
+end program main
--- /dev/null
+! Check the Flang Print Function Names example plugin doesn't count/print Functions/Subroutines in interfaces
+! (It should only count definitions, which will appear elsewhere for interfaced functions/subroutines)
+! This requires that the examples are built (FLANG_BUILD_EXAMPLES=ON) to access flangPrintFunctionNames.so
+
+! REQUIRES: plugins, examples, shell
+
+! RUN: %flang_fc1 -load %llvmshlibdir/flangPrintFunctionNames%pluginext -plugin print-fns %s 2>&1 | FileCheck %s
+
+!-----------------------------
+! EXPECTED OUTPUT: Counts == 0
+!-----------------------------
+! CHECK: ==== Functions: 0 ====
+! CHECK-NEXT: ==== Subroutines: 0 ====
+
+!--------------------------
+! INPUT
+!--------------------------
+program main
+ interface
+ function interface_func()
+ end function
+
+ subroutine interface_subr()
+ end subroutine
+ end interface
+end program main