164ab3302SCarolineConcatto //===-- lib/Parser/message.cpp --------------------------------------------===// 264ab3302SCarolineConcatto // 364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information. 564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 664ab3302SCarolineConcatto // 764ab3302SCarolineConcatto //===----------------------------------------------------------------------===// 864ab3302SCarolineConcatto 964ab3302SCarolineConcatto #include "flang/Parser/message.h" 1064ab3302SCarolineConcatto #include "flang/Common/idioms.h" 1164ab3302SCarolineConcatto #include "flang/Parser/char-set.h" 128670e499SCaroline Concatto #include "llvm/Support/raw_ostream.h" 1364ab3302SCarolineConcatto #include <algorithm> 1464ab3302SCarolineConcatto #include <cstdarg> 1564ab3302SCarolineConcatto #include <cstddef> 1664ab3302SCarolineConcatto #include <cstdio> 1764ab3302SCarolineConcatto #include <cstring> 1864ab3302SCarolineConcatto #include <string> 1964ab3302SCarolineConcatto #include <vector> 2064ab3302SCarolineConcatto 2164ab3302SCarolineConcatto namespace Fortran::parser { 2264ab3302SCarolineConcatto 238670e499SCaroline Concatto llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const MessageFixedText &t) { 2464ab3302SCarolineConcatto std::size_t n{t.text().size()}; 2564ab3302SCarolineConcatto for (std::size_t j{0}; j < n; ++j) { 2664ab3302SCarolineConcatto o << t.text()[j]; 2764ab3302SCarolineConcatto } 2864ab3302SCarolineConcatto return o; 2964ab3302SCarolineConcatto } 3064ab3302SCarolineConcatto 3164ab3302SCarolineConcatto void MessageFormattedText::Format(const MessageFixedText *text, ...) { 3264ab3302SCarolineConcatto const char *p{text->text().begin()}; 3364ab3302SCarolineConcatto std::string asString; 3464ab3302SCarolineConcatto if (*text->text().end() != '\0') { 3564ab3302SCarolineConcatto // not NUL-terminated 3664ab3302SCarolineConcatto asString = text->text().NULTerminatedToString(); 3764ab3302SCarolineConcatto p = asString.c_str(); 3864ab3302SCarolineConcatto } 3964ab3302SCarolineConcatto va_list ap; 4064ab3302SCarolineConcatto va_start(ap, text); 4135249cb7SIvan Zhechev #ifdef _MSC_VER 4235249cb7SIvan Zhechev // Microsoft has a separate function for "positional arguments", which is 4335249cb7SIvan Zhechev // used in some messages. 4435249cb7SIvan Zhechev int need{_vsprintf_p(nullptr, 0, p, ap)}; 4535249cb7SIvan Zhechev #else 4664ab3302SCarolineConcatto int need{vsnprintf(nullptr, 0, p, ap)}; 4735249cb7SIvan Zhechev #endif 4835249cb7SIvan Zhechev 4964ab3302SCarolineConcatto CHECK(need >= 0); 5064ab3302SCarolineConcatto char *buffer{ 5164ab3302SCarolineConcatto static_cast<char *>(std::malloc(static_cast<std::size_t>(need) + 1))}; 5264ab3302SCarolineConcatto CHECK(buffer); 5364ab3302SCarolineConcatto va_end(ap); 5464ab3302SCarolineConcatto va_start(ap, text); 5535249cb7SIvan Zhechev #ifdef _MSC_VER 5635249cb7SIvan Zhechev // Use positional argument variant of printf. 5735249cb7SIvan Zhechev int need2{_vsprintf_p(buffer, need + 1, p, ap)}; 5835249cb7SIvan Zhechev #else 5964ab3302SCarolineConcatto int need2{vsnprintf(buffer, need + 1, p, ap)}; 6035249cb7SIvan Zhechev #endif 6164ab3302SCarolineConcatto CHECK(need2 == need); 6264ab3302SCarolineConcatto va_end(ap); 6364ab3302SCarolineConcatto string_ = buffer; 6464ab3302SCarolineConcatto std::free(buffer); 6564ab3302SCarolineConcatto conversions_.clear(); 6664ab3302SCarolineConcatto } 6764ab3302SCarolineConcatto 6864ab3302SCarolineConcatto const char *MessageFormattedText::Convert(const std::string &s) { 6964ab3302SCarolineConcatto conversions_.emplace_front(s); 7064ab3302SCarolineConcatto return conversions_.front().c_str(); 7164ab3302SCarolineConcatto } 7264ab3302SCarolineConcatto 73bcba39a5SPeter Klausler const char *MessageFormattedText::Convert(std::string &&s) { 74bcba39a5SPeter Klausler conversions_.emplace_front(std::move(s)); 75bcba39a5SPeter Klausler return conversions_.front().c_str(); 76bcba39a5SPeter Klausler } 77bcba39a5SPeter Klausler 78bcba39a5SPeter Klausler const char *MessageFormattedText::Convert(const std::string_view &s) { 7964ab3302SCarolineConcatto conversions_.emplace_front(s); 8064ab3302SCarolineConcatto return conversions_.front().c_str(); 8164ab3302SCarolineConcatto } 8264ab3302SCarolineConcatto 83bcba39a5SPeter Klausler const char *MessageFormattedText::Convert(std::string_view &&s) { 84bcba39a5SPeter Klausler conversions_.emplace_front(s); 8564ab3302SCarolineConcatto return conversions_.front().c_str(); 8664ab3302SCarolineConcatto } 8764ab3302SCarolineConcatto 8864ab3302SCarolineConcatto const char *MessageFormattedText::Convert(CharBlock x) { 8964ab3302SCarolineConcatto return Convert(x.ToString()); 9064ab3302SCarolineConcatto } 9164ab3302SCarolineConcatto 9264ab3302SCarolineConcatto std::string MessageExpectedText::ToString() const { 93cd03e96fSPeter Klausler return common::visit( 9464ab3302SCarolineConcatto common::visitors{ 9564ab3302SCarolineConcatto [](CharBlock cb) { 9664ab3302SCarolineConcatto return MessageFormattedText("expected '%s'"_err_en_US, cb) 9764ab3302SCarolineConcatto .MoveString(); 9864ab3302SCarolineConcatto }, 9964ab3302SCarolineConcatto [](const SetOfChars &set) { 10064ab3302SCarolineConcatto SetOfChars expect{set}; 10164ab3302SCarolineConcatto if (expect.Has('\n')) { 10264ab3302SCarolineConcatto expect = expect.Difference('\n'); 10364ab3302SCarolineConcatto if (expect.empty()) { 10464ab3302SCarolineConcatto return "expected end of line"_err_en_US.text().ToString(); 10564ab3302SCarolineConcatto } else { 10664ab3302SCarolineConcatto std::string s{expect.ToString()}; 10764ab3302SCarolineConcatto if (s.size() == 1) { 10864ab3302SCarolineConcatto return MessageFormattedText( 10964ab3302SCarolineConcatto "expected end of line or '%s'"_err_en_US, s) 11064ab3302SCarolineConcatto .MoveString(); 11164ab3302SCarolineConcatto } else { 11264ab3302SCarolineConcatto return MessageFormattedText( 11364ab3302SCarolineConcatto "expected end of line or one of '%s'"_err_en_US, s) 11464ab3302SCarolineConcatto .MoveString(); 11564ab3302SCarolineConcatto } 11664ab3302SCarolineConcatto } 11764ab3302SCarolineConcatto } 11864ab3302SCarolineConcatto std::string s{expect.ToString()}; 11964ab3302SCarolineConcatto if (s.size() != 1) { 12064ab3302SCarolineConcatto return MessageFormattedText("expected one of '%s'"_err_en_US, s) 12164ab3302SCarolineConcatto .MoveString(); 12264ab3302SCarolineConcatto } else { 12364ab3302SCarolineConcatto return MessageFormattedText("expected '%s'"_err_en_US, s) 12464ab3302SCarolineConcatto .MoveString(); 12564ab3302SCarolineConcatto } 12664ab3302SCarolineConcatto }, 12764ab3302SCarolineConcatto }, 12864ab3302SCarolineConcatto u_); 12964ab3302SCarolineConcatto } 13064ab3302SCarolineConcatto 13164ab3302SCarolineConcatto bool MessageExpectedText::Merge(const MessageExpectedText &that) { 132cd03e96fSPeter Klausler return common::visit(common::visitors{ 13364ab3302SCarolineConcatto [](SetOfChars &s1, const SetOfChars &s2) { 13464ab3302SCarolineConcatto s1 = s1.Union(s2); 13564ab3302SCarolineConcatto return true; 13664ab3302SCarolineConcatto }, 13764ab3302SCarolineConcatto [](const auto &, const auto &) { return false; }, 13864ab3302SCarolineConcatto }, 13964ab3302SCarolineConcatto u_, that.u_); 14064ab3302SCarolineConcatto } 14164ab3302SCarolineConcatto 14264ab3302SCarolineConcatto bool Message::SortBefore(const Message &that) const { 14364ab3302SCarolineConcatto // Messages from prescanning have ProvenanceRange values for their locations, 14464ab3302SCarolineConcatto // while messages from later phases have CharBlock values, since the 14564ab3302SCarolineConcatto // conversion of cooked source stream locations to provenances is not 14664ab3302SCarolineConcatto // free and needs to be deferred, and many messages created during parsing 14764ab3302SCarolineConcatto // are speculative. Messages with ProvenanceRange locations are ordered 14864ab3302SCarolineConcatto // before others for sorting. 149cd03e96fSPeter Klausler return common::visit( 15064ab3302SCarolineConcatto common::visitors{ 15164ab3302SCarolineConcatto [](CharBlock cb1, CharBlock cb2) { 15264ab3302SCarolineConcatto return cb1.begin() < cb2.begin(); 15364ab3302SCarolineConcatto }, 15464ab3302SCarolineConcatto [](CharBlock, const ProvenanceRange &) { return false; }, 15564ab3302SCarolineConcatto [](const ProvenanceRange &pr1, const ProvenanceRange &pr2) { 15664ab3302SCarolineConcatto return pr1.start() < pr2.start(); 15764ab3302SCarolineConcatto }, 15864ab3302SCarolineConcatto [](const ProvenanceRange &, CharBlock) { return true; }, 15964ab3302SCarolineConcatto }, 16064ab3302SCarolineConcatto location_, that.location_); 16164ab3302SCarolineConcatto } 16264ab3302SCarolineConcatto 163d1344422SPeter Steinfeld bool Message::IsFatal() const { 164d1344422SPeter Steinfeld return severity() == Severity::Error || severity() == Severity::Todo; 165d1344422SPeter Steinfeld } 1662895771fSPeter Klausler 1672895771fSPeter Klausler Severity Message::severity() const { 168cd03e96fSPeter Klausler return common::visit( 16964ab3302SCarolineConcatto common::visitors{ 1702895771fSPeter Klausler [](const MessageExpectedText &) { return Severity::Error; }, 1712895771fSPeter Klausler [](const MessageFixedText &x) { return x.severity(); }, 1722895771fSPeter Klausler [](const MessageFormattedText &x) { return x.severity(); }, 17364ab3302SCarolineConcatto }, 17464ab3302SCarolineConcatto text_); 17564ab3302SCarolineConcatto } 17664ab3302SCarolineConcatto 177ef141aecSPeter Klausler Message &Message::set_severity(Severity severity) { 178cd03e96fSPeter Klausler common::visit( 179ef141aecSPeter Klausler common::visitors{ 180ef141aecSPeter Klausler [](const MessageExpectedText &) {}, 181ef141aecSPeter Klausler [severity](MessageFixedText &x) { x.set_severity(severity); }, 182ef141aecSPeter Klausler [severity](MessageFormattedText &x) { x.set_severity(severity); }, 183ef141aecSPeter Klausler }, 184ef141aecSPeter Klausler text_); 185ef141aecSPeter Klausler return *this; 186ef141aecSPeter Klausler } 187ef141aecSPeter Klausler 188*0f973ac7SPeter Klausler std::optional<common::LanguageFeature> Message::languageFeature() const { 189*0f973ac7SPeter Klausler return languageFeature_; 190*0f973ac7SPeter Klausler } 191*0f973ac7SPeter Klausler 192*0f973ac7SPeter Klausler Message &Message::set_languageFeature(common::LanguageFeature feature) { 193*0f973ac7SPeter Klausler languageFeature_ = feature; 194*0f973ac7SPeter Klausler return *this; 195*0f973ac7SPeter Klausler } 196*0f973ac7SPeter Klausler 197*0f973ac7SPeter Klausler std::optional<common::UsageWarning> Message::usageWarning() const { 198*0f973ac7SPeter Klausler return usageWarning_; 199*0f973ac7SPeter Klausler } 200*0f973ac7SPeter Klausler 201*0f973ac7SPeter Klausler Message &Message::set_usageWarning(common::UsageWarning warning) { 202*0f973ac7SPeter Klausler usageWarning_ = warning; 203*0f973ac7SPeter Klausler return *this; 204*0f973ac7SPeter Klausler } 205*0f973ac7SPeter Klausler 20664ab3302SCarolineConcatto std::string Message::ToString() const { 207cd03e96fSPeter Klausler return common::visit( 20864ab3302SCarolineConcatto common::visitors{ 20964ab3302SCarolineConcatto [](const MessageFixedText &t) { 21064ab3302SCarolineConcatto return t.text().NULTerminatedToString(); 21164ab3302SCarolineConcatto }, 21264ab3302SCarolineConcatto [](const MessageFormattedText &t) { return t.string(); }, 21364ab3302SCarolineConcatto [](const MessageExpectedText &e) { return e.ToString(); }, 21464ab3302SCarolineConcatto }, 21564ab3302SCarolineConcatto text_); 21664ab3302SCarolineConcatto } 21764ab3302SCarolineConcatto 21892a54197Speter klausler void Message::ResolveProvenances(const AllCookedSources &allCooked) { 21964ab3302SCarolineConcatto if (CharBlock * cb{std::get_if<CharBlock>(&location_)}) { 22064ab3302SCarolineConcatto if (std::optional<ProvenanceRange> resolved{ 22192a54197Speter klausler allCooked.GetProvenanceRange(*cb)}) { 22264ab3302SCarolineConcatto location_ = *resolved; 22364ab3302SCarolineConcatto } 22464ab3302SCarolineConcatto } 22564ab3302SCarolineConcatto if (Message * attachment{attachment_.get()}) { 22692a54197Speter klausler attachment->ResolveProvenances(allCooked); 22764ab3302SCarolineConcatto } 22864ab3302SCarolineConcatto } 22964ab3302SCarolineConcatto 23064ab3302SCarolineConcatto std::optional<ProvenanceRange> Message::GetProvenanceRange( 23192a54197Speter klausler const AllCookedSources &allCooked) const { 232cd03e96fSPeter Klausler return common::visit( 23364ab3302SCarolineConcatto common::visitors{ 23492a54197Speter klausler [&](CharBlock cb) { return allCooked.GetProvenanceRange(cb); }, 23564ab3302SCarolineConcatto [](const ProvenanceRange &pr) { return std::make_optional(pr); }, 23664ab3302SCarolineConcatto }, 23764ab3302SCarolineConcatto location_); 23864ab3302SCarolineConcatto } 23964ab3302SCarolineConcatto 240ef141aecSPeter Klausler static std::string Prefix(Severity severity) { 241ef141aecSPeter Klausler switch (severity) { 2422895771fSPeter Klausler case Severity::Error: 243ef141aecSPeter Klausler return "error: "; 2442895771fSPeter Klausler case Severity::Warning: 245ef141aecSPeter Klausler return "warning: "; 2462895771fSPeter Klausler case Severity::Portability: 247ef141aecSPeter Klausler return "portability: "; 248ef141aecSPeter Klausler case Severity::Because: 249ef141aecSPeter Klausler return "because: "; 250ef141aecSPeter Klausler case Severity::Context: 251ef141aecSPeter Klausler return "in the context: "; 252d1344422SPeter Steinfeld case Severity::Todo: 253d1344422SPeter Steinfeld return "error: not yet implemented: "; 2542895771fSPeter Klausler case Severity::None: 2552895771fSPeter Klausler break; 25664ab3302SCarolineConcatto } 257ef141aecSPeter Klausler return ""; 258ef141aecSPeter Klausler } 259ef141aecSPeter Klausler 2608df63a23SPeixin Qiao static llvm::raw_ostream::Colors PrefixColor(Severity severity) { 2618df63a23SPeixin Qiao switch (severity) { 2628df63a23SPeixin Qiao case Severity::Error: 2638df63a23SPeixin Qiao case Severity::Todo: 2648df63a23SPeixin Qiao return llvm::raw_ostream::RED; 2658df63a23SPeixin Qiao case Severity::Warning: 2668df63a23SPeixin Qiao case Severity::Portability: 2678df63a23SPeixin Qiao return llvm::raw_ostream::MAGENTA; 2688df63a23SPeixin Qiao default: 2698df63a23SPeixin Qiao // TODO: Set the color. 2708df63a23SPeixin Qiao break; 2718df63a23SPeixin Qiao } 2728df63a23SPeixin Qiao return llvm::raw_ostream::SAVEDCOLOR; 2738df63a23SPeixin Qiao } 2748df63a23SPeixin Qiao 275ef141aecSPeter Klausler void Message::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked, 276ef141aecSPeter Klausler bool echoSourceLine) const { 277ef141aecSPeter Klausler std::optional<ProvenanceRange> provenanceRange{GetProvenanceRange(allCooked)}; 27892a54197Speter klausler const AllSources &sources{allCooked.allSources()}; 2798df63a23SPeixin Qiao sources.EmitMessage(o, provenanceRange, ToString(), Prefix(severity()), 2808df63a23SPeixin Qiao PrefixColor(severity()), echoSourceLine); 281641ede93Speter klausler bool isContext{attachmentIsContext_}; 28264ab3302SCarolineConcatto for (const Message *attachment{attachment_.get()}; attachment; 28364ab3302SCarolineConcatto attachment = attachment->attachment_.get()) { 2848df63a23SPeixin Qiao Severity severity = isContext ? Severity::Context : attachment->severity(); 285ef141aecSPeter Klausler sources.EmitMessage(o, attachment->GetProvenanceRange(allCooked), 2868df63a23SPeixin Qiao attachment->ToString(), Prefix(severity), PrefixColor(severity), 287ef141aecSPeter Klausler echoSourceLine); 28864ab3302SCarolineConcatto } 28964ab3302SCarolineConcatto } 29064ab3302SCarolineConcatto 2915a9497d6SPeter Steinfeld // Messages are equal if they're for the same location and text, and the user 2925a9497d6SPeter Steinfeld // visible aspects of their attachments are the same 2935a9497d6SPeter Steinfeld bool Message::operator==(const Message &that) const { 294ef141aecSPeter Klausler if (!AtSameLocation(that) || ToString() != that.ToString() || 295ef141aecSPeter Klausler severity() != that.severity() || 296ef141aecSPeter Klausler attachmentIsContext_ != that.attachmentIsContext_) { 2975a9497d6SPeter Steinfeld return false; 2985a9497d6SPeter Steinfeld } 2995a9497d6SPeter Steinfeld const Message *thatAttachment{that.attachment_.get()}; 3005a9497d6SPeter Steinfeld for (const Message *attachment{attachment_.get()}; attachment; 3015a9497d6SPeter Steinfeld attachment = attachment->attachment_.get()) { 302ef141aecSPeter Klausler if (!thatAttachment || !attachment->AtSameLocation(*thatAttachment) || 303ef141aecSPeter Klausler attachment->ToString() != thatAttachment->ToString() || 304ef141aecSPeter Klausler attachment->severity() != thatAttachment->severity()) { 3055a9497d6SPeter Steinfeld return false; 3065a9497d6SPeter Steinfeld } 3075a9497d6SPeter Steinfeld thatAttachment = thatAttachment->attachment_.get(); 3085a9497d6SPeter Steinfeld } 309ef141aecSPeter Klausler return !thatAttachment; 3105a9497d6SPeter Steinfeld } 3115a9497d6SPeter Steinfeld 31264ab3302SCarolineConcatto bool Message::Merge(const Message &that) { 31364ab3302SCarolineConcatto return AtSameLocation(that) && 31464ab3302SCarolineConcatto (!that.attachment_.get() || 31564ab3302SCarolineConcatto attachment_.get() == that.attachment_.get()) && 316cd03e96fSPeter Klausler common::visit( 31764ab3302SCarolineConcatto common::visitors{ 31864ab3302SCarolineConcatto [](MessageExpectedText &e1, const MessageExpectedText &e2) { 31964ab3302SCarolineConcatto return e1.Merge(e2); 32064ab3302SCarolineConcatto }, 32164ab3302SCarolineConcatto [](const auto &, const auto &) { return false; }, 32264ab3302SCarolineConcatto }, 32364ab3302SCarolineConcatto text_, that.text_); 32464ab3302SCarolineConcatto } 32564ab3302SCarolineConcatto 32664ab3302SCarolineConcatto Message &Message::Attach(Message *m) { 32764ab3302SCarolineConcatto if (!attachment_) { 32864ab3302SCarolineConcatto attachment_ = m; 32964ab3302SCarolineConcatto } else { 330641ede93Speter klausler if (attachment_->references() > 1) { 331641ede93Speter klausler // Don't attach to a shared context attachment; copy it first. 332641ede93Speter klausler attachment_ = new Message{*attachment_}; 333641ede93Speter klausler } 33464ab3302SCarolineConcatto attachment_->Attach(m); 33564ab3302SCarolineConcatto } 33664ab3302SCarolineConcatto return *this; 33764ab3302SCarolineConcatto } 33864ab3302SCarolineConcatto 33964ab3302SCarolineConcatto Message &Message::Attach(std::unique_ptr<Message> &&m) { 34064ab3302SCarolineConcatto return Attach(m.release()); 34164ab3302SCarolineConcatto } 34264ab3302SCarolineConcatto 34364ab3302SCarolineConcatto bool Message::AtSameLocation(const Message &that) const { 344cd03e96fSPeter Klausler return common::visit( 34564ab3302SCarolineConcatto common::visitors{ 34664ab3302SCarolineConcatto [](CharBlock cb1, CharBlock cb2) { 34764ab3302SCarolineConcatto return cb1.begin() == cb2.begin(); 34864ab3302SCarolineConcatto }, 34964ab3302SCarolineConcatto [](const ProvenanceRange &pr1, const ProvenanceRange &pr2) { 35064ab3302SCarolineConcatto return pr1.start() == pr2.start(); 35164ab3302SCarolineConcatto }, 35264ab3302SCarolineConcatto [](const auto &, const auto &) { return false; }, 35364ab3302SCarolineConcatto }, 35464ab3302SCarolineConcatto location_, that.location_); 35564ab3302SCarolineConcatto } 35664ab3302SCarolineConcatto 35764ab3302SCarolineConcatto bool Messages::Merge(const Message &msg) { 35864ab3302SCarolineConcatto if (msg.IsMergeable()) { 35964ab3302SCarolineConcatto for (auto &m : messages_) { 36064ab3302SCarolineConcatto if (m.Merge(msg)) { 36164ab3302SCarolineConcatto return true; 36264ab3302SCarolineConcatto } 36364ab3302SCarolineConcatto } 36464ab3302SCarolineConcatto } 36564ab3302SCarolineConcatto return false; 36664ab3302SCarolineConcatto } 36764ab3302SCarolineConcatto 36864ab3302SCarolineConcatto void Messages::Merge(Messages &&that) { 36964ab3302SCarolineConcatto if (messages_.empty()) { 37064ab3302SCarolineConcatto *this = std::move(that); 37164ab3302SCarolineConcatto } else { 37264ab3302SCarolineConcatto while (!that.messages_.empty()) { 37364ab3302SCarolineConcatto if (Merge(that.messages_.front())) { 37464ab3302SCarolineConcatto that.messages_.pop_front(); 37564ab3302SCarolineConcatto } else { 376cc575dd2Speter klausler auto next{that.messages_.begin()}; 377cc575dd2Speter klausler ++next; 378cc575dd2Speter klausler messages_.splice( 379cc575dd2Speter klausler messages_.end(), that.messages_, that.messages_.begin(), next); 38064ab3302SCarolineConcatto } 38164ab3302SCarolineConcatto } 38264ab3302SCarolineConcatto } 38364ab3302SCarolineConcatto } 38464ab3302SCarolineConcatto 38564ab3302SCarolineConcatto void Messages::Copy(const Messages &that) { 38664ab3302SCarolineConcatto for (const Message &m : that.messages_) { 38764ab3302SCarolineConcatto Message copy{m}; 38864ab3302SCarolineConcatto Say(std::move(copy)); 38964ab3302SCarolineConcatto } 39064ab3302SCarolineConcatto } 39164ab3302SCarolineConcatto 39292a54197Speter klausler void Messages::ResolveProvenances(const AllCookedSources &allCooked) { 39364ab3302SCarolineConcatto for (Message &m : messages_) { 39492a54197Speter klausler m.ResolveProvenances(allCooked); 39564ab3302SCarolineConcatto } 39664ab3302SCarolineConcatto } 39764ab3302SCarolineConcatto 39892a54197Speter klausler void Messages::Emit(llvm::raw_ostream &o, const AllCookedSources &allCooked, 3998670e499SCaroline Concatto bool echoSourceLines) const { 40064ab3302SCarolineConcatto std::vector<const Message *> sorted; 40164ab3302SCarolineConcatto for (const auto &msg : messages_) { 40264ab3302SCarolineConcatto sorted.push_back(&msg); 40364ab3302SCarolineConcatto } 40464ab3302SCarolineConcatto std::stable_sort(sorted.begin(), sorted.end(), 40564ab3302SCarolineConcatto [](const Message *x, const Message *y) { return x->SortBefore(*y); }); 4065a9497d6SPeter Steinfeld const Message *lastMsg{nullptr}; 40764ab3302SCarolineConcatto for (const Message *msg : sorted) { 4085a9497d6SPeter Steinfeld if (lastMsg && *msg == *lastMsg) { 4095a9497d6SPeter Steinfeld // Don't emit two identical messages for the same location 4105a9497d6SPeter Steinfeld continue; 4115a9497d6SPeter Steinfeld } 41292a54197Speter klausler msg->Emit(o, allCooked, echoSourceLines); 4135a9497d6SPeter Steinfeld lastMsg = msg; 41464ab3302SCarolineConcatto } 41564ab3302SCarolineConcatto } 41664ab3302SCarolineConcatto 417ef141aecSPeter Klausler void Messages::AttachTo(Message &msg, std::optional<Severity> severity) { 41864ab3302SCarolineConcatto for (Message &m : messages_) { 419ef141aecSPeter Klausler Message m2{std::move(m)}; 420ef141aecSPeter Klausler if (severity) { 421ef141aecSPeter Klausler m2.set_severity(*severity); 422ef141aecSPeter Klausler } 423ef141aecSPeter Klausler msg.Attach(std::move(m2)); 42464ab3302SCarolineConcatto } 42564ab3302SCarolineConcatto messages_.clear(); 42664ab3302SCarolineConcatto } 42764ab3302SCarolineConcatto 42864ab3302SCarolineConcatto bool Messages::AnyFatalError() const { 42964ab3302SCarolineConcatto for (const auto &msg : messages_) { 43064ab3302SCarolineConcatto if (msg.IsFatal()) { 43164ab3302SCarolineConcatto return true; 43264ab3302SCarolineConcatto } 43364ab3302SCarolineConcatto } 43464ab3302SCarolineConcatto return false; 43564ab3302SCarolineConcatto } 4361f879005STim Keith } // namespace Fortran::parser 437