1 //===-- lib/Semantics/unparse-with-symbols.cpp ----------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "flang/Semantics/unparse-with-symbols.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"
19 namespace Fortran::semantics
{
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
{
27 // Write out symbols referenced at this statement.
28 void PrintSymbols(const parser::CharBlock
&, llvm::raw_ostream
&, int);
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
;
36 template <typename T
> void Post(const parser::Statement
<T
> &) {
37 currStmt_
= std::nullopt
;
39 bool Pre(const parser::AccClause
&clause
) {
40 currStmt_
= clause
.source
;
43 void Post(const parser::AccClause
&) { currStmt_
= std::nullopt
; }
44 bool Pre(const parser::OmpClause
&clause
) {
45 currStmt_
= clause
.source
;
48 void Post(const parser::OmpClause
&) { currStmt_
= std::nullopt
; }
49 bool Pre(const parser::OpenMPThreadprivate
&dir
) {
50 currStmt_
= dir
.source
;
53 void Post(const parser::OpenMPThreadprivate
&) { currStmt_
= std::nullopt
; }
54 void Post(const parser::Name
&name
);
56 bool Pre(const parser::OpenMPDeclareMapperConstruct
&x
) {
60 void Post(const parser::OpenMPDeclareMapperConstruct
&) {
61 currStmt_
= std::nullopt
;
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;
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
};
80 out
<< '!' << (firstTime
? "DEF"s
: "REF"s
) << ": ";
81 DumpForUnparse(out
, *symbol
, firstTime
);
87 void SymbolDumpVisitor::Indent(llvm::raw_ostream
&out
, int indent
) const {
88 for (int i
{0}; i
< indent
; ++i
) {
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
);
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
);
111 // UnparseWithModules()
113 class UsedModuleVisitor
{
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
);
124 void Post(const parser::UseStmt
&use
) {
125 if (use
.moduleName
.symbol
) {
126 modulesUsed_
.insert(*use
.moduleName
.symbol
);
131 UnorderedSymbolSet modulesUsed_
;
132 UnorderedSymbolSet modulesDefined_
;
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
);
145 parser::Unparse(out
, program
, encoding
, false, true);
147 } // namespace Fortran::semantics