| //===-- lib/Semantics/unparse-with-symbols.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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "flang/Semantics/unparse-with-symbols.h" |
| #include "flang/Parser/parse-tree-visitor.h" |
| #include "flang/Parser/parse-tree.h" |
| #include "flang/Parser/unparse.h" |
| #include "flang/Semantics/symbol.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <map> |
| #include <set> |
| |
| namespace Fortran::semantics { |
| |
| // Walk the parse tree and collection information about which statements |
| // reference symbols. Then PrintSymbols outputs information by statement. |
| // The first reference to a symbol is treated as its definition and more |
| // information is included. |
| class SymbolDumpVisitor { |
| public: |
| // Write out symbols referenced at this statement. |
| void PrintSymbols(const parser::CharBlock &, llvm::raw_ostream &, int); |
| |
| template <typename T> bool Pre(const T &) { return true; } |
| template <typename T> void Post(const T &) {} |
| template <typename T> bool Pre(const parser::Statement<T> &stmt) { |
| currStmt_ = stmt.source; |
| return true; |
| } |
| template <typename T> void Post(const parser::Statement<T> &) { |
| currStmt_ = std::nullopt; |
| } |
| bool Pre(const parser::AccClause &clause) { |
| currStmt_ = clause.source; |
| return true; |
| } |
| void Post(const parser::AccClause &) { currStmt_ = std::nullopt; } |
| bool Pre(const parser::OmpClause &clause) { |
| currStmt_ = clause.source; |
| return true; |
| } |
| void Post(const parser::OmpClause &) { currStmt_ = std::nullopt; } |
| bool Pre(const parser::OpenMPThreadprivate &dir) { |
| currStmt_ = dir.source; |
| return true; |
| } |
| void Post(const parser::OpenMPThreadprivate &) { currStmt_ = std::nullopt; } |
| void Post(const parser::Name &name); |
| |
| private: |
| std::optional<SourceName> currStmt_; // current statement we are processing |
| std::multimap<const char *, const Symbol *> symbols_; // location to symbol |
| std::set<const Symbol *> symbolsDefined_; // symbols that have been processed |
| void Indent(llvm::raw_ostream &, int) const; |
| }; |
| |
| void SymbolDumpVisitor::PrintSymbols( |
| const parser::CharBlock &location, llvm::raw_ostream &out, int indent) { |
| std::set<const Symbol *> done; // prevent duplicates on this line |
| auto range{symbols_.equal_range(location.begin())}; |
| for (auto it{range.first}; it != range.second; ++it) { |
| const auto *symbol{it->second}; |
| if (done.insert(symbol).second) { |
| bool firstTime{symbolsDefined_.insert(symbol).second}; |
| Indent(out, indent); |
| out << '!' << (firstTime ? "DEF"s : "REF"s) << ": "; |
| DumpForUnparse(out, *symbol, firstTime); |
| out << '\n'; |
| } |
| } |
| } |
| |
| void SymbolDumpVisitor::Indent(llvm::raw_ostream &out, int indent) const { |
| for (int i{0}; i < indent; ++i) { |
| out << ' '; |
| } |
| } |
| |
| void SymbolDumpVisitor::Post(const parser::Name &name) { |
| if (const auto *symbol{name.symbol}) { |
| if (!symbol->has<MiscDetails>()) { |
| symbols_.emplace(currStmt_.value().begin(), symbol); |
| } |
| } |
| } |
| |
| void UnparseWithSymbols(llvm::raw_ostream &out, const parser::Program &program, |
| parser::Encoding encoding) { |
| SymbolDumpVisitor visitor; |
| parser::Walk(program, visitor); |
| parser::preStatementType preStatement{ |
| [&](const parser::CharBlock &location, llvm::raw_ostream &out, |
| int indent) { visitor.PrintSymbols(location, out, indent); }}; |
| parser::Unparse(out, program, encoding, false, true, &preStatement); |
| } |
| } // namespace Fortran::semantics |