xref: /llvm-project/flang/lib/Semantics/unparse-with-symbols.cpp (revision ec1e0c5ecd53e415b23d5bd40b8e44e3ef4b4d92)
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 "mod-file.h"
11 #include "flang/Parser/parse-tree-visitor.h"
12 #include "flang/Parser/parse-tree.h"
13 #include "flang/Parser/unparse.h"
14 #include "flang/Semantics/symbol.h"
15 #include "llvm/Support/raw_ostream.h"
16 #include <map>
17 #include <set>
18 
19 namespace Fortran::semantics {
20 
21 // Walk the parse tree and collection information about which statements
22 // reference symbols. Then PrintSymbols outputs information by statement.
23 // The first reference to a symbol is treated as its definition and more
24 // information is included.
25 class SymbolDumpVisitor {
26 public:
27   // Write out symbols referenced at this statement.
28   void PrintSymbols(const parser::CharBlock &, llvm::raw_ostream &, int);
29 
30   template <typename T> bool Pre(const T &) { return true; }
31   template <typename T> void Post(const T &) {}
32   template <typename T> bool Pre(const parser::Statement<T> &stmt) {
33     currStmt_ = stmt.source;
34     return true;
35   }
36   template <typename T> void Post(const parser::Statement<T> &) {
37     currStmt_ = std::nullopt;
38   }
39   bool Pre(const parser::AccClause &clause) {
40     currStmt_ = clause.source;
41     return true;
42   }
43   void Post(const parser::AccClause &) { currStmt_ = std::nullopt; }
44   bool Pre(const parser::OmpClause &clause) {
45     currStmt_ = clause.source;
46     return true;
47   }
48   void Post(const parser::OmpClause &) { currStmt_ = std::nullopt; }
49   bool Pre(const parser::OpenMPThreadprivate &dir) {
50     currStmt_ = dir.source;
51     return true;
52   }
53   void Post(const parser::OpenMPThreadprivate &) { currStmt_ = std::nullopt; }
54   void Post(const parser::Name &name);
55 
56   bool Pre(const parser::OpenMPDeclareMapperConstruct &x) {
57     currStmt_ = x.source;
58     return true;
59   }
60   void Post(const parser::OpenMPDeclareMapperConstruct &) {
61     currStmt_ = std::nullopt;
62   }
63 
64 private:
65   std::optional<SourceName> currStmt_; // current statement we are processing
66   std::multimap<const char *, const Symbol *> symbols_; // location to symbol
67   std::set<const Symbol *> symbolsDefined_; // symbols that have been processed
68   void Indent(llvm::raw_ostream &, int) const;
69 };
70 
71 void SymbolDumpVisitor::PrintSymbols(
72     const parser::CharBlock &location, llvm::raw_ostream &out, int indent) {
73   std::set<const Symbol *> done; // prevent duplicates on this line
74   auto range{symbols_.equal_range(location.begin())};
75   for (auto it{range.first}; it != range.second; ++it) {
76     const auto *symbol{it->second};
77     if (done.insert(symbol).second) {
78       bool firstTime{symbolsDefined_.insert(symbol).second};
79       Indent(out, indent);
80       out << '!' << (firstTime ? "DEF"s : "REF"s) << ": ";
81       DumpForUnparse(out, *symbol, firstTime);
82       out << '\n';
83     }
84   }
85 }
86 
87 void SymbolDumpVisitor::Indent(llvm::raw_ostream &out, int indent) const {
88   for (int i{0}; i < indent; ++i) {
89     out << ' ';
90   }
91 }
92 
93 void SymbolDumpVisitor::Post(const parser::Name &name) {
94   if (const auto *symbol{name.symbol}) {
95     if (!symbol->has<MiscDetails>()) {
96       symbols_.emplace(currStmt_.value().begin(), symbol);
97     }
98   }
99 }
100 
101 void UnparseWithSymbols(llvm::raw_ostream &out, const parser::Program &program,
102     parser::Encoding encoding) {
103   SymbolDumpVisitor visitor;
104   parser::Walk(program, visitor);
105   parser::preStatementType preStatement{
106       [&](const parser::CharBlock &location, llvm::raw_ostream &out,
107           int indent) { visitor.PrintSymbols(location, out, indent); }};
108   parser::Unparse(out, program, encoding, false, true, &preStatement);
109 }
110 
111 // UnparseWithModules()
112 
113 class UsedModuleVisitor {
114 public:
115   UnorderedSymbolSet &modulesUsed() { return modulesUsed_; }
116   UnorderedSymbolSet &modulesDefined() { return modulesDefined_; }
117   template <typename T> bool Pre(const T &) { return true; }
118   template <typename T> void Post(const T &) {}
119   void Post(const parser::ModuleStmt &module) {
120     if (module.v.symbol) {
121       modulesDefined_.insert(*module.v.symbol);
122     }
123   }
124   void Post(const parser::UseStmt &use) {
125     if (use.moduleName.symbol) {
126       modulesUsed_.insert(*use.moduleName.symbol);
127     }
128   }
129 
130 private:
131   UnorderedSymbolSet modulesUsed_;
132   UnorderedSymbolSet modulesDefined_;
133 };
134 
135 void UnparseWithModules(llvm::raw_ostream &out, SemanticsContext &context,
136     const parser::Program &program, parser::Encoding encoding) {
137   UsedModuleVisitor visitor;
138   parser::Walk(program, visitor);
139   UnorderedSymbolSet nonIntrinsicModulesWritten{
140       std::move(visitor.modulesDefined())};
141   ModFileWriter writer{context};
142   for (SymbolRef moduleRef : visitor.modulesUsed()) {
143     writer.WriteClosure(out, *moduleRef, nonIntrinsicModulesWritten);
144   }
145   parser::Unparse(out, program, encoding, false, true);
146 }
147 } // namespace Fortran::semantics
148