[clang] dc256a4 - [flang][driver] Add support for `-fget-definition`

Andrzej Warzynski via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 21 02:31:53 PDT 2021


Author: Andrzej Warzynski
Date: 2021-04-21T09:31:36Z
New Revision: dc256a443a456a8e0e4d72736fee1c9442bcf4bd

URL: https://github.com/llvm/llvm-project/commit/dc256a443a456a8e0e4d72736fee1c9442bcf4bd
DIFF: https://github.com/llvm/llvm-project/commit/dc256a443a456a8e0e4d72736fee1c9442bcf4bd.diff

LOG: [flang][driver] Add support for `-fget-definition`

This patch adds `-fget-definition` to `flang-new`. The semantics of this
option are identical in both drivers. The error message in the
"throwaway" driver is updated so that it matches the one from
`flang-new` (which is auto-generated and cannot be changed easily).

Tests are updated accordingly. A dedicated test for error handling was
added: get-definition.f90 (for the sake of simplicity,
getdefinition01.f90 no longer tests for errors).

The `ParseFrontendArgs` function is updated so that it can return
errors. This change is required in order to report invalid values
following `-fget-definition`.

The actual implementation of `GetDefinitionAction::ExecuteAction()` was
extracted from f18.cpp (i.e. the bit that deals with
`-fget-definition`).

Depends on: https://reviews.llvm.org/D100556

Differential Revision: https://reviews.llvm.org/D100558

Added: 
    flang/test/Driver/get-definition.f90

Modified: 
    clang/include/clang/Driver/Options.td
    flang/include/flang/Frontend/FrontendActions.h
    flang/include/flang/Frontend/FrontendOptions.h
    flang/lib/Frontend/CompilerInvocation.cpp
    flang/lib/Frontend/FrontendActions.cpp
    flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
    flang/test/Driver/driver-help.f90
    flang/test/Semantics/getdefinition01.f90
    flang/test/Semantics/getdefinition02.f
    flang/test/Semantics/getdefinition03-a.f90
    flang/test/Semantics/getdefinition04.f90
    flang/test/Semantics/getdefinition05.f90
    flang/tools/f18/f18.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index f93b8a2496e07..648cfb0522e14 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4381,6 +4381,9 @@ def J : JoinedOrSeparate<["-"], "J">,
 //===----------------------------------------------------------------------===//
 let Flags = [FC1Option, FlangOnlyOption] in {
 
+def fget_definition : MultiArg<["-"], "fget-definition", 3>,
+  HelpText<"Get the symbol definition from <line> <start-column> <end-column>">,
+  Group<Action_Group>;
 def test_io : Flag<["-"], "test-io">, Group<Action_Group>,
   HelpText<"Run the InputOuputTest action. Use for development and testing only.">;
 def fdebug_unparse_no_sema : Flag<["-"], "fdebug-unparse-no-sema">, Group<Action_Group>,

diff  --git a/flang/include/flang/Frontend/FrontendActions.h b/flang/include/flang/Frontend/FrontendActions.h
index 83e9652153ae3..619e83ad88c77 100644
--- a/flang/include/flang/Frontend/FrontendActions.h
+++ b/flang/include/flang/Frontend/FrontendActions.h
@@ -116,6 +116,10 @@ class DebugPreFIRTreeAction : public PrescanAndSemaAction {
   void ExecuteAction() override;
 };
 
+class GetDefinitionAction : public PrescanAndSemaAction {
+  void ExecuteAction() override;
+};
+
 class GetSymbolsSourcesAction : public PrescanAndSemaAction {
   void ExecuteAction() override;
 };

diff  --git a/flang/include/flang/Frontend/FrontendOptions.h b/flang/include/flang/Frontend/FrontendOptions.h
index 24fbdd3aff2a9..e18fd961a55b0 100644
--- a/flang/include/flang/Frontend/FrontendOptions.h
+++ b/flang/include/flang/Frontend/FrontendOptions.h
@@ -67,6 +67,9 @@ enum ActionKind {
   /// Parse, run semantics and then output the pre-FIR tree
   DebugPreFIRTree,
 
+  /// `-fget-definition`
+  GetDefinition,
+
   /// Parse, run semantics and then dump symbol sources map
   GetSymbolsSources
 
@@ -206,6 +209,14 @@ class FrontendOptions {
   /// compilation.
   unsigned needProvenanceRangeToCharBlockMappings_ : 1;
 
+  /// Input values from `-fget-definition`
+  struct GetDefinitionVals {
+    unsigned line;
+    unsigned startColumn;
+    unsigned endColumn;
+  };
+  GetDefinitionVals getDefVals_;
+
   /// The input files and their types.
   std::vector<FrontendInputFile> inputs_;
 

diff  --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index a8879294eebf7..c79c2f2a0d939 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -95,12 +95,14 @@ static void setUpFrontendBasedOnAction(FrontendOptions &opts) {
   if (opts.programAction_ == DebugDumpParsingLog)
     opts.instrumentedParse_ = true;
 
-  if (opts.programAction_ == DebugDumpProvenance)
+  if (opts.programAction_ == DebugDumpProvenance ||
+      opts.programAction_ == Fortran::frontend::GetDefinition)
     opts.needProvenanceRangeToCharBlockMappings_ = true;
 }
 
-static void ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
+static bool ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
     clang::DiagnosticsEngine &diags) {
+  unsigned numErrorsBefore = diags.getNumErrors();
 
   // By default the frontend driver creates a ParseSyntaxOnly action.
   opts.programAction_ = ParseSyntaxOnly;
@@ -157,6 +159,9 @@ static void ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
     case clang::driver::options::OPT_fget_symbols_sources:
       opts.programAction_ = GetSymbolsSources;
       break;
+    case clang::driver::options::OPT_fget_definition:
+      opts.programAction_ = GetDefinition;
+      break;
 
       // TODO:
       // case calng::driver::options::OPT_emit_llvm:
@@ -165,6 +170,27 @@ static void ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
       // case clang::driver::options::OPT_emit_module:
       // (...)
     }
+
+    // Parse the values provided with `-fget-definition` (there should be 3
+    // integers)
+    if (llvm::opt::OptSpecifier(a->getOption().getID()) ==
+        clang::driver::options::OPT_fget_definition) {
+      unsigned optVals[3] = {0, 0, 0};
+
+      for (unsigned i = 0; i < 3; i++) {
+        llvm::StringRef val = a->getValue(i);
+
+        if (val.getAsInteger(10, optVals[i])) {
+          // A non-integer was encountered - that's an error.
+          diags.Report(clang::diag::err_drv_invalid_value)
+              << a->getOption().getName() << val;
+          break;
+        }
+      }
+      opts.getDefVals_.line = optVals[0];
+      opts.getDefVals_.startColumn = optVals[1];
+      opts.getDefVals_.endColumn = optVals[2];
+    }
   }
 
   opts.outputFile_ = args.getLastArgValue(clang::driver::options::OPT_o);
@@ -293,6 +319,8 @@ static void ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
 
   setUpFrontendBasedOnAction(opts);
   opts.dashX_ = dashX;
+
+  return diags.getNumErrors() == numErrorsBefore;
 }
 
 // Generate the path to look for intrinsic modules
@@ -481,8 +509,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &res,
     success = false;
   }
 
-  // Parse the frontend args
-  ParseFrontendArgs(res.frontendOpts(), args, diags);
+  success &= ParseFrontendArgs(res.frontendOpts(), args, diags);
   parsePreprocessorArgs(res.preprocessorOpts(), args);
   success &= parseSemaArgs(res, args, diags);
   success &= parseDialectArgs(res, args, diags);

diff  --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 00b46c90dfd1f..f35ee4ed58e65 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -21,6 +21,7 @@
 #include "flang/Semantics/semantics.h"
 #include "flang/Semantics/unparse-with-symbols.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
 #include <clang/Basic/Diagnostic.h>
 #include <memory>
 
@@ -371,6 +372,53 @@ void DebugDumpParsingLogAction::ExecuteAction() {
   ci.parsing().DumpParsingLog(llvm::outs());
 }
 
+void GetDefinitionAction::ExecuteAction() {
+  // Report and exit if fatal semantic errors are present
+  if (reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),
+          GetCurrentFileOrBufferName()))
+    return;
+
+  CompilerInstance &ci = this->instance();
+  parser::AllCookedSources &cs = ci.allCookedSources();
+  unsigned diagID = ci.diagnostics().getCustomDiagID(
+      clang::DiagnosticsEngine::Error, "Symbol not found");
+
+  auto gdv = ci.invocation().frontendOpts().getDefVals_;
+  auto charBlock{cs.GetCharBlockFromLineAndColumns(
+      gdv.line, gdv.startColumn, gdv.endColumn)};
+  if (!charBlock) {
+    ci.diagnostics().Report(diagID);
+    return;
+  }
+
+  llvm::outs() << "String range: >" << charBlock->ToString() << "<\n";
+
+  auto *symbol{ci.invocation()
+                   .semanticsContext()
+                   .FindScope(*charBlock)
+                   .FindSymbol(*charBlock)};
+  if (!symbol) {
+    ci.diagnostics().Report(diagID);
+    return;
+  }
+
+  llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n";
+
+  auto sourceInfo{cs.GetSourcePositionRange(symbol->name())};
+  if (!sourceInfo) {
+    llvm_unreachable(
+        "Failed to obtain SourcePosition."
+        "TODO: Please, write a test and replace this with a diagnostic!");
+    return;
+  }
+
+  llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n";
+  llvm::outs() << symbol->name().ToString() << ": "
+               << sourceInfo->first.file.path() << ", "
+               << sourceInfo->first.line << ", " << sourceInfo->first.column
+               << "-" << sourceInfo->second.column << "\n";
+}
+
 void GetSymbolsSourcesAction::ExecuteAction() {
   // Report and exit if fatal semantic errors are present
   if (reportFatalSemanticErrors(semantics(), this->instance().diagnostics(),

diff  --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 462de5241f3e6..93bbf4fc9a06f 100644
--- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -67,6 +67,9 @@ static std::unique_ptr<FrontendAction> CreateFrontendBaseAction(
   case DebugPreFIRTree:
     return std::make_unique<DebugPreFIRTreeAction>();
     break;
+  case GetDefinition:
+    return std::make_unique<GetDefinitionAction>();
+    break;
   case GetSymbolsSources:
     return std::make_unique<GetSymbolsSourcesAction>();
     break;

diff  --git a/flang/test/Driver/driver-help.f90 b/flang/test/Driver/driver-help.f90
index b1b698b99b9bb..9783751a2c9e7 100644
--- a/flang/test/Driver/driver-help.f90
+++ b/flang/test/Driver/driver-help.f90
@@ -91,6 +91,8 @@
 ! HELP-FC1-NEXT: -ffixed-line-length=<value>
 ! HELP-FC1-NEXT: Use <value> as character line width in fixed mode
 ! HELP-FC1-NEXT: -ffree-form            Process source files in free form
+! HELP-FC1-NEXT: -fget-definition <value> <value> <value>
+! HELP-FC1-NEXT:                        Get the symbol definition from <line> <start-column> <end-column>
 ! HELP-FC1-NEXT: -fget-symbols-sources   Dump symbols and their source code locations
 ! HELP-FC1-NEXT: -fimplicit-none        No implicit typing allowed unless overridden by IMPLICIT statements
 ! HELP-FC1-NEXT: -finput-charset=<value> Specify the default character set for source files

diff  --git a/flang/test/Driver/get-definition.f90 b/flang/test/Driver/get-definition.f90
new file mode 100644
index 0000000000000..5e6d5ff2345fe
--- /dev/null
+++ b/flang/test/Driver/get-definition.f90
@@ -0,0 +1,46 @@
+! Verify that the driver correctly rejects invalid values for -fget-definition
+
+!-----------
+! RUN LINES
+!-----------
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition 45 1 2 %s 2>&1 | FileCheck --check-prefix=OK %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition a 1 1 %s 2>&1 | FileCheck --check-prefix=ERROR-a %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition 1 b 1 %s 2>&1 | FileCheck --check-prefix=ERROR-b %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition 1 1 c %s 2>&1 | FileCheck --check-prefix=ERROR-c %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition a b 1 %s 2>&1 | FileCheck --check-prefix=ERROR-ab %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition a b c %s 2>&1 | FileCheck --check-prefix=ERROR-abc %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition 1 b c %s 2>&1 | FileCheck --check-prefix=ERROR-bc %s
+! RUN: not %flang_fc1 -fsyntax-only -fget-definition a 1 c %s 2>&1 | FileCheck --check-prefix=ERROR-ac %s
+
+!-----------------
+! EXPECTED OUTPUT
+!-----------------
+! OK: String range: >m<
+! OK-NOT: error
+
+! ERROR-a: error: invalid value 'a' in 'fget-definition'
+! ERROR-a-NOT: String range: >m<
+
+! ERROR-b: error: invalid value 'b' in 'fget-definition'
+! ERROR-b-NOT: String range: >m<
+
+! ERROR-c: error: invalid value 'c' in 'fget-definition'
+! ERROR-c-NOT: String range: >m<
+
+! ERROR-ab: error: invalid value 'a' in 'fget-definition'
+! ERROR-ab-NOT: String range: >m<
+
+! ERROR-ac: error: invalid value 'a' in 'fget-definition'
+! ERROR-ac-NOT: String range: >m<
+
+! ERROR-bc: error: invalid value 'b' in 'fget-definition'
+! ERROR-bc-NOT: String range: >m<
+
+! ERROR-abc: error: invalid value 'a' in 'fget-definition'
+! ERROR-abc-NOT: String range: >m<
+
+!-------
+! INPUT
+!-------
+module m
+end module

diff  --git a/flang/test/Semantics/getdefinition01.f90 b/flang/test/Semantics/getdefinition01.f90
index 06f2cc0f8ddab..b5149e84f6e36 100644
--- a/flang/test/Semantics/getdefinition01.f90
+++ b/flang/test/Semantics/getdefinition01.f90
@@ -16,12 +16,9 @@ recursive pure function f() result(x)
 end module
 
 ! RUN and CHECK lines at the bottom as this test is sensitive to line numbers
-! RUN: %f18 -fget-definition 6 17 18 -fsyntax-only %s | FileCheck --check-prefix=CHECK1 %s
-! RUN: %f18 -fget-definition 7 20 23 -fsyntax-only %s | FileCheck --check-prefix=CHECK2 %s
-! RUN: %f18 -fget-definition 14 3 4 -fsyntax-only %s | FileCheck --check-prefix=CHECK3 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 6 17 18 %s | FileCheck --check-prefix=CHECK1 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 7 20 23 %s | FileCheck --check-prefix=CHECK2 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 14 3 4 %s | FileCheck --check-prefix=CHECK3 %s
 ! CHECK1: x:{{.*}}getdefinition01.f90, 5, 21-22
 ! CHECK2: yyy:{{.*}}getdefinition01.f90, 5, 24-27
 ! CHECK3: x:{{.*}}getdefinition01.f90, 13, 24-25
-
-! RUN: not %f18 -fget-definition -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
-! CHECK-ERROR: Invalid argument to -fget-definitions

diff  --git a/flang/test/Semantics/getdefinition02.f b/flang/test/Semantics/getdefinition02.f
index b32536968dc04..29f13ef1b5099 100644
--- a/flang/test/Semantics/getdefinition02.f
+++ b/flang/test/Semantics/getdefinition02.f
@@ -17,9 +17,9 @@ recursive pure function f() result(x)
       end module
 
 ! RUN and CHECK lines here as test is sensitive to line numbers
-! RUN: %f18 -fget-definition 7 9 10 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK1 %s
-! RUN: %f18 -fget-definition 8 26 29 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK2 %s
-! RUN: %f18 -fget-definition 15 9 10 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK3 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 7 9 10 %s 2>&1 | FileCheck --check-prefix=CHECK1 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 8 26 29 %s 2>&1 | FileCheck --check-prefix=CHECK2 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 15 9 10 %s 2>&1 | FileCheck --check-prefix=CHECK3 %s
 ! CHECK1: x:{{.*}}getdefinition02.f, 5, 27-28
 ! CHECK2: yyy:{{.*}}getdefinition02.f, 5, 30-33
 ! CHECK3: x:{{.*}}getdefinition02.f, 14, 30-31

diff  --git a/flang/test/Semantics/getdefinition03-a.f90 b/flang/test/Semantics/getdefinition03-a.f90
index 6e61637b3546b..3c0ba61c1f793 100644
--- a/flang/test/Semantics/getdefinition03-a.f90
+++ b/flang/test/Semantics/getdefinition03-a.f90
@@ -7,7 +7,7 @@ program main
  x = f
 end program
 
-! RUN: %f18 -fget-definition 7 6 7 -fsyntax-only %s | FileCheck --check-prefix=CHECK1 %s
-! RUN: %f18 -fget-definition 7 2 3 -fsyntax-only %s | FileCheck --check-prefix=CHECK2 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 7 6 7 %s | FileCheck --check-prefix=CHECK1 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 7 2 3 %s | FileCheck --check-prefix=CHECK2 %s
 ! CHECK1: f:{{.*}}getdefinition03-b.f90, 2, 12-13
 ! CHECK2: x:{{.*}}getdefinition03-a.f90, 6, 13-14

diff  --git a/flang/test/Semantics/getdefinition04.f90 b/flang/test/Semantics/getdefinition04.f90
index bc01f7979b421..6084f69e7fe1a 100644
--- a/flang/test/Semantics/getdefinition04.f90
+++ b/flang/test/Semantics/getdefinition04.f90
@@ -6,5 +6,5 @@ program main
   x = y
 end program
 
-! RUN: %f18 -fget-definition 6 3 4 -fsyntax-only %s | FileCheck %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 6 3 4 %s | FileCheck %s
 ! CHECK: x:{{.*}}getdefinition04.f90, 3, 14-15

diff  --git a/flang/test/Semantics/getdefinition05.f90 b/flang/test/Semantics/getdefinition05.f90
index 91952bb7fcc33..74e3d71b6a279 100644
--- a/flang/test/Semantics/getdefinition05.f90
+++ b/flang/test/Semantics/getdefinition05.f90
@@ -12,8 +12,8 @@ program main
 end program
 
 !! Inner x
-! RUN: %f18 -fget-definition 9 5 6 -fsyntax-only %s | FileCheck --check-prefix=CHECK1 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 9 5 6 %s | FileCheck --check-prefix=CHECK1 %s
 ! CHECK1: x:{{.*}}getdefinition05.f90, 7, 16-17
 !! Outer y
-! RUN: %f18 -fget-definition 11 7 8 -fsyntax-only %s | FileCheck --check-prefix=CHECK2 %s
+! RUN: %flang_fc1 -fsyntax-only -fget-definition 11 7 8 %s | FileCheck --check-prefix=CHECK2 %s
 ! CHECK2: y:{{.*}}getdefinition05.f90, 5, 14-15

diff  --git a/flang/tools/f18/f18.cpp b/flang/tools/f18/f18.cpp
index 1a658781d263b..691d4378928a3 100644
--- a/flang/tools/f18/f18.cpp
+++ b/flang/tools/f18/f18.cpp
@@ -658,8 +658,8 @@ int main(int argc, char *const argv[]) {
         }
         arguments[i] = std::strtol(args.front().c_str(), &endptr, 10);
         if (*endptr != '\0') {
-          llvm::errs() << "Invalid argument to -fget-definitions: "
-                       << args.front() << '\n';
+          llvm::errs() << "error: invalid value '" << args.front()
+                       << "' in 'fget-definition'" << '\n';
           return EXIT_FAILURE;
         }
         args.pop_front();


        


More information about the cfe-commits mailing list