1 //===-- lib/Parser/instrumented-parser.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/Parser/instrumented-parser.h" 10 #include "flang/Parser/message.h" 11 #include "flang/Parser/provenance.h" 12 #include "llvm/Support/raw_ostream.h" 13 #include <map> 14 15 namespace Fortran::parser { 16 17 void ParsingLog::clear() { perPos_.clear(); } 18 19 // In the logs, just use the addresses of the message texts to sort the 20 // map keys. 21 bool operator<(const MessageFixedText &x, const MessageFixedText &y) { 22 return x.text().begin() < y.text().begin(); 23 } 24 25 bool ParsingLog::Fails( 26 const char *at, const MessageFixedText &tag, ParseState &state) { 27 std::size_t offset{reinterpret_cast<std::size_t>(at)}; 28 auto posIter{perPos_.find(offset)}; 29 if (posIter == perPos_.end()) { 30 return false; 31 } 32 auto tagIter{posIter->second.perTag.find(tag)}; 33 if (tagIter == posIter->second.perTag.end()) { 34 return false; 35 } 36 auto &entry{tagIter->second}; 37 if (entry.deferred && !state.deferMessages()) { 38 return false; // don't fail fast, we want to generate messages 39 } 40 ++entry.count; 41 if (!state.deferMessages()) { 42 state.messages().Copy(entry.messages); 43 } 44 return !entry.pass; 45 } 46 47 void ParsingLog::Note(const char *at, const MessageFixedText &tag, bool pass, 48 const ParseState &state) { 49 std::size_t offset{reinterpret_cast<std::size_t>(at)}; 50 auto &entry{perPos_[offset].perTag[tag]}; 51 if (++entry.count == 1) { 52 entry.pass = pass; 53 entry.deferred = state.deferMessages(); 54 if (!entry.deferred) { 55 entry.messages.Copy(state.messages()); 56 } 57 } else { 58 CHECK(entry.pass == pass); 59 if (entry.deferred && !state.deferMessages()) { 60 entry.deferred = false; 61 entry.messages.Copy(state.messages()); 62 } 63 } 64 } 65 66 void ParsingLog::Dump(llvm::raw_ostream &o, const CookedSource &cooked) const { 67 for (const auto &posLog : perPos_) { 68 const char *at{reinterpret_cast<const char *>(posLog.first)}; 69 for (const auto &tagLog : posLog.second.perTag) { 70 Message{at, tagLog.first}.Emit(o, cooked, true); 71 auto &entry{tagLog.second}; 72 o << " " << (entry.pass ? "pass" : "fail") << " " << entry.count << '\n'; 73 entry.messages.Emit(o, cooked); 74 } 75 } 76 } 77 } // namespace Fortran::parser 78