xref: /llvm-project/flang/lib/Parser/message.cpp (revision 0f973ac783aa100cfbce1cd2c6e8a3a8f648fae7)
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