1 //===-- lib/Semantics/unparse-with-symbols.cpp ----------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "flang/Semantics/unparse-with-symbols.h" 10 #include "flang/Parser/parse-tree-visitor.h" 11 #include "flang/Parser/parse-tree.h" 12 #include "flang/Parser/unparse.h" 13 #include "flang/Semantics/symbol.h" 14 #include "llvm/Support/raw_ostream.h" 15 #include <map> 16 #include <set> 17 18 namespace Fortran::semantics { 19 20 // Walk the parse tree and collection information about which statements 21 // reference symbols. Then PrintSymbols outputs information by statement. 22 // The first reference to a symbol is treated as its definition and more 23 // information is included. 24 class SymbolDumpVisitor { 25 public: 26 // Write out symbols referenced at this statement. 27 void PrintSymbols(const parser::CharBlock &, llvm::raw_ostream &, int); 28 29 template <typename T> bool Pre(const T &) { return true; } 30 template <typename T> void Post(const T &) {} 31 template <typename T> bool Pre(const parser::Statement<T> &stmt) { 32 currStmt_ = stmt.source; 33 return true; 34 } 35 template <typename T> void Post(const parser::Statement<T> &) { 36 currStmt_ = std::nullopt; 37 } 38 bool Pre(const parser::AccClause &clause) { 39 currStmt_ = clause.source; 40 return true; 41 } 42 void Post(const parser::AccClause &) { currStmt_ = std::nullopt; } 43 bool Pre(const parser::OmpClause &clause) { 44 currStmt_ = clause.source; 45 return true; 46 } 47 void Post(const parser::OmpClause &) { currStmt_ = std::nullopt; } 48 bool Pre(const parser::OpenMPThreadprivate &dir) { 49 currStmt_ = dir.source; 50 return true; 51 } 52 void Post(const parser::OpenMPThreadprivate &) { currStmt_ = std::nullopt; } 53 void Post(const parser::Name &name); 54 55 private: 56 std::optional<SourceName> currStmt_; // current statement we are processing 57 std::multimap<const char *, const Symbol *> symbols_; // location to symbol 58 std::set<const Symbol *> symbolsDefined_; // symbols that have been processed 59 void Indent(llvm::raw_ostream &, int) const; 60 }; 61 62 void SymbolDumpVisitor::PrintSymbols( 63 const parser::CharBlock &location, llvm::raw_ostream &out, int indent) { 64 std::set<const Symbol *> done; // prevent duplicates on this line 65 auto range{symbols_.equal_range(location.begin())}; 66 for (auto it{range.first}; it != range.second; ++it) { 67 const auto *symbol{it->second}; 68 if (done.insert(symbol).second) { 69 bool firstTime{symbolsDefined_.insert(symbol).second}; 70 Indent(out, indent); 71 out << '!' << (firstTime ? "DEF"s : "REF"s) << ": "; 72 DumpForUnparse(out, *symbol, firstTime); 73 out << '\n'; 74 } 75 } 76 } 77 78 void SymbolDumpVisitor::Indent(llvm::raw_ostream &out, int indent) const { 79 for (int i{0}; i < indent; ++i) { 80 out << ' '; 81 } 82 } 83 84 void SymbolDumpVisitor::Post(const parser::Name &name) { 85 if (const auto *symbol{name.symbol}) { 86 if (!symbol->has<MiscDetails>()) { 87 symbols_.emplace(currStmt_.value().begin(), symbol); 88 } 89 } 90 } 91 92 void UnparseWithSymbols(llvm::raw_ostream &out, const parser::Program &program, 93 parser::Encoding encoding) { 94 SymbolDumpVisitor visitor; 95 parser::Walk(program, visitor); 96 parser::preStatementType preStatement{ 97 [&](const parser::CharBlock &location, llvm::raw_ostream &out, 98 int indent) { visitor.PrintSymbols(location, out, indent); }}; 99 parser::Unparse(out, program, encoding, false, true, &preStatement); 100 } 101 } // namespace Fortran::semantics 102