185 lines · cpp
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-exception6//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/semantics.h"15#include "flang/Semantics/symbol.h"16#include "llvm/Support/raw_ostream.h"17#include <map>18#include <set>19 20namespace Fortran::semantics {21 22// Walk the parse tree and collection information about which statements23// reference symbols. Then PrintSymbols outputs information by statement.24// The first reference to a symbol is treated as its definition and more25// information is included.26class SymbolDumpVisitor {27public:28 // Write out symbols referenced at this statement.29 void PrintSymbols(const parser::CharBlock &, llvm::raw_ostream &, int);30 31 template <typename T> bool Pre(const T &) { return true; }32 template <typename T> void Post(const T &) {}33 template <typename T> bool Pre(const parser::Statement<T> &stmt) {34 currStmt_ = stmt.source;35 return true;36 }37 template <typename T> void Post(const parser::Statement<T> &) {38 currStmt_ = std::nullopt;39 }40 void Post(const parser::Name &name);41 42 bool Pre(const parser::AccClause &clause) {43 currStmt_ = clause.source;44 return true;45 }46 void Post(const parser::AccClause &) { currStmt_ = std::nullopt; }47 bool Pre(const parser::OmpClause &clause) {48 currStmt_ = clause.source;49 return true;50 }51 void Post(const parser::OmpClause &) { currStmt_ = std::nullopt; }52 bool Pre(const parser::OpenMPGroupprivate &dir) {53 currStmt_ = dir.source;54 return true;55 }56 void Post(const parser::OpenMPGroupprivate &) { currStmt_ = std::nullopt; }57 bool Pre(const parser::OpenMPThreadprivate &dir) {58 currStmt_ = dir.source;59 return true;60 }61 void Post(const parser::OpenMPThreadprivate &) { currStmt_ = std::nullopt; }62 63 bool Pre(const parser::OpenMPDeclareMapperConstruct &x) {64 currStmt_ = x.source;65 return true;66 }67 void Post(const parser::OpenMPDeclareMapperConstruct &) {68 currStmt_ = std::nullopt;69 }70 71 bool Pre(const parser::OpenMPDeclareReductionConstruct &x) {72 currStmt_ = x.source;73 return true;74 }75 void Post(const parser::OpenMPDeclareReductionConstruct &) {76 currStmt_ = std::nullopt;77 }78 79 bool Pre(const parser::OpenMPDeclareTargetConstruct &x) {80 currStmt_ = x.source;81 return true;82 }83 void Post(const parser::OpenMPDeclareTargetConstruct &) {84 currStmt_ = std::nullopt;85 }86 87 // Directive arguments can be objects with symbols.88 bool Pre(const parser::OmpBeginDirective &x) {89 currStmt_ = x.source;90 return true;91 }92 void Post(const parser::OmpBeginDirective &) { currStmt_ = std::nullopt; }93 94 bool Pre(const parser::OmpEndDirective &x) {95 currStmt_ = x.source;96 return true;97 }98 void Post(const parser::OmpEndDirective &) { currStmt_ = std::nullopt; }99 100private:101 std::optional<SourceName> currStmt_; // current statement we are processing102 std::multimap<const char *, const Symbol *> symbols_; // location to symbol103 std::set<const Symbol *> symbolsDefined_; // symbols that have been processed104 void Indent(llvm::raw_ostream &, int) const;105};106 107void SymbolDumpVisitor::PrintSymbols(108 const parser::CharBlock &location, llvm::raw_ostream &out, int indent) {109 std::set<const Symbol *> done; // prevent duplicates on this line110 auto range{symbols_.equal_range(location.begin())};111 for (auto it{range.first}; it != range.second; ++it) {112 const auto *symbol{it->second};113 if (done.insert(symbol).second) {114 bool firstTime{symbolsDefined_.insert(symbol).second};115 Indent(out, indent);116 out << '!' << (firstTime ? "DEF"s : "REF"s) << ": ";117 DumpForUnparse(out, *symbol, firstTime);118 out << '\n';119 }120 }121}122 123void SymbolDumpVisitor::Indent(llvm::raw_ostream &out, int indent) const {124 for (int i{0}; i < indent; ++i) {125 out << ' ';126 }127}128 129void SymbolDumpVisitor::Post(const parser::Name &name) {130 if (const auto *symbol{name.symbol}) {131 if (!symbol->has<MiscDetails>()) {132 CHECK(currStmt_.has_value());133 symbols_.emplace(currStmt_.value().begin(), symbol);134 }135 }136}137 138void UnparseWithSymbols(llvm::raw_ostream &out, const parser::Program &program,139 const common::LangOptions &langOpts, parser::Encoding encoding) {140 SymbolDumpVisitor visitor;141 parser::Walk(program, visitor);142 parser::preStatementType preStatement{143 [&](const parser::CharBlock &location, llvm::raw_ostream &out,144 int indent) { visitor.PrintSymbols(location, out, indent); }};145 parser::Unparse(out, program, langOpts, encoding, false, true, &preStatement);146}147 148// UnparseWithModules()149 150class UsedModuleVisitor {151public:152 UnorderedSymbolSet &modulesUsed() { return modulesUsed_; }153 UnorderedSymbolSet &modulesDefined() { return modulesDefined_; }154 template <typename T> bool Pre(const T &) { return true; }155 template <typename T> void Post(const T &) {}156 void Post(const parser::ModuleStmt &module) {157 if (module.v.symbol) {158 modulesDefined_.insert(*module.v.symbol);159 }160 }161 void Post(const parser::UseStmt &use) {162 if (use.moduleName.symbol) {163 modulesUsed_.insert(*use.moduleName.symbol);164 }165 }166 167private:168 UnorderedSymbolSet modulesUsed_;169 UnorderedSymbolSet modulesDefined_;170};171 172void UnparseWithModules(llvm::raw_ostream &out, SemanticsContext &context,173 const parser::Program &program, parser::Encoding encoding) {174 UsedModuleVisitor visitor;175 parser::Walk(program, visitor);176 UnorderedSymbolSet nonIntrinsicModulesWritten{177 std::move(visitor.modulesDefined())};178 ModFileWriter writer{context};179 for (SymbolRef moduleRef : visitor.modulesUsed()) {180 writer.WriteClosure(out, *moduleRef, nonIntrinsicModulesWritten);181 }182 parser::Unparse(out, program, context.langOptions(), encoding, false, true);183}184} // namespace Fortran::semantics185