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
18namespace 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.
24class SymbolDumpVisitor {
25public:
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
55private:
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
62void 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
78void SymbolDumpVisitor::Indent(llvm::raw_ostream &out, int indent) const {
79 for (int i{0}; i < indent; ++i) {
80 out << ' ';
81 }
82}
83
84void 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
92void 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

source code of flang/lib/Semantics/unparse-with-symbols.cpp