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 | |