[flang] Add mapping of source location to Scope
authorTim Keith <tkeith@nvidia.com>
Wed, 28 Nov 2018 23:55:55 +0000 (15:55 -0800)
committerTim Keith <tkeith@nvidia.com>
Wed, 28 Nov 2018 23:55:55 +0000 (15:55 -0800)
Each Scope now tracks the source locations that it and its nested scopes
span. This is achieved by extending the source range of a scope for each
statement encountered while it is the current scope.

Semantics::FindScope maps a source location (from the cooked character
stream) to the narrowest scope that contains it.

Original-commit: flang-compiler/f18@7b4d2bb113e4a1018c5f6aa740b02e423ff61799
Reviewed-on: https://github.com/flang-compiler/f18/pull/230
Tree-same-pre-rewrite: false

flang/lib/parser/char-block.h
flang/lib/semantics/resolve-names.cc
flang/lib/semantics/scope.cc
flang/lib/semantics/scope.h
flang/lib/semantics/semantics.cc
flang/lib/semantics/semantics.h

index 3fc0cd4..ae829de 100644 (file)
@@ -48,6 +48,10 @@ public:
     return interval_.start()[j];
   }
 
+  bool Contains(const CharBlock &that) const {
+    return interval_.Contains(that.interval_);
+  }
+
   bool IsBlank() const {
     for (char ch : *this) {
       if (ch != ' ' && ch != '\t') {
index 1dccfc8..b39a3ea 100644 (file)
@@ -199,15 +199,8 @@ public:
 
   void set_messages(parser::Messages &messages) { messages_ = &messages; }
 
-  template<typename T> bool Pre(const parser::Statement<T> &x) {
-    currStmtSource_ = &x.source;
-    return true;
-  }
-  template<typename T> void Post(const parser::Statement<T> &) {
-    currStmtSource_ = nullptr;
-  }
-
   const SourceName *currStmtSource() { return currStmtSource_; }
+  void set_currStmtSource(const SourceName *x) { currStmtSource_ = x; }
 
   // Add a message to the messages to be emitted.
   Message &Say(Message &&);
@@ -240,8 +233,6 @@ class ImplicitRulesVisitor : public DeclTypeSpecVisitor, public MessageHandler {
 public:
   using DeclTypeSpecVisitor::Post;
   using DeclTypeSpecVisitor::Pre;
-  using MessageHandler::Post;
-  using MessageHandler::Pre;
   using ImplicitNoneNameSpec = parser::ImplicitStmt::ImplicitNoneNameSpec;
 
   void Post(const parser::ParameterStmt &);
@@ -338,6 +329,15 @@ public:
     ImplicitRulesVisitor::ClearScopes();
   }
 
+  template<typename T> bool Pre(const parser::Statement<T> &x) {
+    set_currStmtSource(&x.source);
+    currScope_->AddSourceRange(x.source);
+    return true;
+  }
+  template<typename T> void Post(const parser::Statement<T> &) {
+    set_currStmtSource(nullptr);
+  }
+
   Symbol *FindSymbol(const SourceName &name);
   void EraseSymbol(const SourceName &name);
 
@@ -765,6 +765,8 @@ public:
   using InterfaceVisitor::Pre;
   using ModuleVisitor::Post;
   using ModuleVisitor::Pre;
+  using ScopeHandler::Post;
+  using ScopeHandler::Pre;
   using SubprogramVisitor::Post;
   using SubprogramVisitor::Pre;
 
index 2f583b2..ae275b4 100644 (file)
@@ -134,6 +134,28 @@ bool Scope::CanImport(const SourceName &name) const {
   }
 }
 
+const Scope *Scope::FindScope(const parser::CharBlock &source) const {
+  if (!sourceRange_.Contains(source)) {
+    return nullptr;
+  }
+  for (const auto &child : children_) {
+    if (const auto *scope{child.FindScope(source)}) {
+      return scope;
+    }
+  }
+  return this;
+}
+
+void Scope::AddSourceRange(const parser::CharBlock &source) {
+  if (sourceRange_.empty()) {
+    sourceRange_ = source;
+  } else if (!source.empty()) {
+    sourceRange_ =
+        parser::CharBlock(std::min(sourceRange_.begin(), source.begin()),
+            std::max(sourceRange_.end(), source.end()));
+  }
+}
+
 std::ostream &operator<<(std::ostream &os, const Scope &scope) {
   os << Scope::EnumToString(scope.kind()) << " scope: ";
   if (auto *symbol{scope.symbol()}) {
index b60239d..fd5404a 100644 (file)
@@ -137,9 +137,16 @@ public:
 
   bool add_importName(const SourceName &);
 
+  // The range of the source of this and nested scopes.
+  const parser::CharBlock &sourceRange() const { return sourceRange_; }
+  void AddSourceRange(const parser::CharBlock &);
+  // Find the smallest scope under this one that contains source
+  const Scope *FindScope(const parser::CharBlock &) const;
+
 private:
   Scope &parent_;
   const Kind kind_;
+  parser::CharBlock sourceRange_;
   Symbol *const symbol_;
   std::list<Scope> children_;
   mapType symbols_;
index 51feee5..117d39c 100644 (file)
@@ -74,6 +74,14 @@ bool Semantics::Perform() {
   return !AnyFatalError();
 }
 
+const Scope &Semantics::FindScope(const parser::CharBlock &source) const {
+  if (const auto *scope{context_.globalScope().FindScope(source)}) {
+    return *scope;
+  } else {
+    common::die("invalid source location");
+  }
+}
+
 void Semantics::EmitMessages(std::ostream &os) const {
   context_.messages().Emit(os, cooked_);
 }
index f66c1f8..d64a0df 100644 (file)
@@ -89,10 +89,13 @@ class Semantics {
 public:
   explicit Semantics(SemanticsContext &context, parser::Program &program,
       parser::CookedSource &cooked)
-    : context_{context}, program_{program}, cooked_{cooked} {}
+    : context_{context}, program_{program}, cooked_{cooked} {
+    context.globalScope().AddSourceRange(parser::CharBlock{cooked.data()});
+  }
 
   SemanticsContext &context() const { return context_; }
   bool Perform();
+  const Scope &FindScope(const parser::CharBlock &) const;
   bool AnyFatalError() const { return context_.AnyFatalError(); }
   void EmitMessages(std::ostream &) const;
   void DumpSymbols(std::ostream &);