brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.8 KiB · fe92aa7 Raw
733 lines · cpp
1//===-- lib/Parser/provenance.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/Parser/provenance.h"10#include "flang/Common/idioms.h"11#include "llvm/Support/raw_ostream.h"12#include <algorithm>13#include <set>14#include <utility>15 16namespace Fortran::parser {17 18ProvenanceRangeToOffsetMappings::ProvenanceRangeToOffsetMappings() {}19ProvenanceRangeToOffsetMappings::~ProvenanceRangeToOffsetMappings() {}20 21void ProvenanceRangeToOffsetMappings::Put(22    ProvenanceRange range, std::size_t offset) {23  auto fromTo{map_.equal_range(range)};24  for (auto iter{fromTo.first}; iter != fromTo.second; ++iter) {25    if (range == iter->first) {26      iter->second = std::min(offset, iter->second);27      return;28    }29  }30  if (fromTo.second != map_.end()) {31    map_.emplace_hint(fromTo.second, range, offset);32  } else {33    map_.emplace(range, offset);34  }35}36 37std::optional<std::size_t> ProvenanceRangeToOffsetMappings::Map(38    ProvenanceRange range) const {39  auto fromTo{map_.equal_range(range)};40  std::optional<std::size_t> result;41  for (auto iter{fromTo.first}; iter != fromTo.second; ++iter) {42    ProvenanceRange that{iter->first};43    if (that.Contains(range)) {44      std::size_t offset{iter->second + that.MemberOffset(range.start())};45      if (!result || offset < *result) {46        result = offset;47      }48    }49  }50  return result;51}52 53bool ProvenanceRangeToOffsetMappings::WhollyPrecedes::operator()(54    ProvenanceRange before, ProvenanceRange after) const {55  return before.start() + before.size() <= after.start();56}57 58void OffsetToProvenanceMappings::clear() { provenanceMap_.clear(); }59 60void OffsetToProvenanceMappings::swap(OffsetToProvenanceMappings &that) {61  provenanceMap_.swap(that.provenanceMap_);62}63 64void OffsetToProvenanceMappings::shrink_to_fit() {65  provenanceMap_.shrink_to_fit();66}67 68std::size_t OffsetToProvenanceMappings::SizeInBytes() const {69  if (provenanceMap_.empty()) {70    return 0;71  } else {72    const ContiguousProvenanceMapping &last{provenanceMap_.back()};73    return last.start + last.range.size();74  }75}76 77void OffsetToProvenanceMappings::Put(ProvenanceRange range) {78  if (provenanceMap_.empty()) {79    provenanceMap_.push_back({0, range});80  } else {81    ContiguousProvenanceMapping &last{provenanceMap_.back()};82    if (!last.range.AnnexIfPredecessor(range)) {83      provenanceMap_.push_back({last.start + last.range.size(), range});84    }85  }86}87 88void OffsetToProvenanceMappings::Put(const OffsetToProvenanceMappings &that) {89  for (const auto &map : that.provenanceMap_) {90    Put(map.range);91  }92}93 94ProvenanceRange OffsetToProvenanceMappings::Map(std::size_t at) const {95  if (provenanceMap_.empty()) {96    CHECK(at == 0);97    return {};98  }99  std::size_t low{0}, count{provenanceMap_.size()};100  while (count > 1) {101    std::size_t mid{low + (count >> 1)};102    if (provenanceMap_[mid].start > at) {103      count = mid - low;104    } else {105      count -= mid - low;106      low = mid;107    }108  }109  std::size_t offset{at - provenanceMap_[low].start};110  return provenanceMap_[low].range.Suffix(offset);111}112 113void OffsetToProvenanceMappings::RemoveLastBytes(std::size_t bytes) {114  for (; bytes > 0; provenanceMap_.pop_back()) {115    CHECK(!provenanceMap_.empty());116    ContiguousProvenanceMapping &last{provenanceMap_.back()};117    std::size_t chunk{last.range.size()};118    if (bytes < chunk) {119      last.range = last.range.Prefix(chunk - bytes);120      break;121    }122    bytes -= chunk;123  }124}125 126ProvenanceRangeToOffsetMappings OffsetToProvenanceMappings::Invert(127    const AllSources &allSources) const {128  ProvenanceRangeToOffsetMappings result;129  for (const auto &contig : provenanceMap_) {130    ProvenanceRange range{contig.range};131    while (!range.empty()) {132      ProvenanceRange source{allSources.IntersectionWithSourceFiles(range)};133      if (source.empty()) {134        break;135      }136      result.Put(137          source, contig.start + contig.range.MemberOffset(source.start()));138      Provenance after{source.NextAfter()};139      if (range.Contains(after)) {140        range = range.Suffix(range.MemberOffset(after));141      } else {142        break;143      }144    }145  }146  return result;147}148 149AllSources::AllSources() : range_{1, 1} {150  // Start the origin_ array with a dummy entry that has a forced provenance,151  // so that provenance offset 0 remains reserved as an uninitialized152  // value.153  origin_.emplace_back(range_, std::string{'?'});154}155 156AllSources::~AllSources() {}157 158const char &AllSources::operator[](Provenance at) const {159  const Origin &origin{MapToOrigin(at)};160  return origin[origin.covers.MemberOffset(at)];161}162 163void AllSources::ClearSearchPath() { searchPath_.clear(); }164 165void AllSources::AppendSearchPathDirectory(std::string directory) {166  // gfortran and ifort append to current path, PGI prepends167  searchPath_.push_back(directory);168}169 170const SourceFile *AllSources::OpenPath(171    std::string path, llvm::raw_ostream &error) {172  std::unique_ptr<SourceFile> source{std::make_unique<SourceFile>(encoding_)};173  if (source->Open(path, error)) {174    return ownedSourceFiles_.emplace_back(std::move(source)).get();175  } else {176    return nullptr;177  }178}179 180const SourceFile *AllSources::Open(std::string path, llvm::raw_ostream &error,181    std::optional<std::string> &&prependPath) {182  std::unique_ptr<SourceFile> source{std::make_unique<SourceFile>(encoding_)};183  if (prependPath) {184    // Set to "." for the initial source file; set to the directory name185    // of the including file for #include "quoted-file" directives &186    // INCLUDE statements.187    searchPath_.emplace_front(std::move(*prependPath));188  }189  std::optional<std::string> found{LocateSourceFile(path, searchPath_)};190  if (prependPath) {191    searchPath_.pop_front();192  }193  if (found) {194    return OpenPath(*found, error);195  } else {196    error << "Source file '" << path << "' was not found";197    return nullptr;198  }199}200 201const SourceFile *AllSources::ReadStandardInput(llvm::raw_ostream &error) {202  std::unique_ptr<SourceFile> source{std::make_unique<SourceFile>(encoding_)};203  if (source->ReadStandardInput(error)) {204    return ownedSourceFiles_.emplace_back(std::move(source)).get();205  }206  return nullptr;207}208 209ProvenanceRange AllSources::AddIncludedFile(210    const SourceFile &source, ProvenanceRange from, bool isModule) {211  ProvenanceRange covers{range_.NextAfter(), source.bytes()};212  CHECK(range_.AnnexIfPredecessor(covers));213  CHECK(origin_.back().covers.ImmediatelyPrecedes(covers));214  origin_.emplace_back(covers, source, from, isModule);215  return covers;216}217 218ProvenanceRange AllSources::AddMacroCall(219    ProvenanceRange def, ProvenanceRange use, const std::string &expansion) {220  ProvenanceRange covers{range_.NextAfter(), expansion.size()};221  CHECK(range_.AnnexIfPredecessor(covers));222  CHECK(origin_.back().covers.ImmediatelyPrecedes(covers));223  origin_.emplace_back(covers, def, use, expansion);224  return covers;225}226 227ProvenanceRange AllSources::AddCompilerInsertion(std::string text) {228  ProvenanceRange covers{range_.NextAfter(), text.size()};229  CHECK(range_.AnnexIfPredecessor(covers));230  CHECK(origin_.back().covers.ImmediatelyPrecedes(covers));231  origin_.emplace_back(covers, text);232  return covers;233}234 235static void EmitPrefix(llvm::raw_ostream &o, llvm::raw_ostream::Colors color,236    const std::string &prefix, bool showColors) {237  if (prefix.empty()) {238    return;239  }240  if (showColors) {241    o.changeColor(color, true);242  }243  o << prefix;244  if (showColors) {245    o.resetColor();246  }247}248 249std::optional<ProvenanceRange> AllSources::GetInclusionInfo(250    const std::optional<ProvenanceRange> &range) const {251  if (!range || !IsValid(range->start()))252    return std::nullopt;253  const Origin &origin{MapToOrigin(range->start())};254 255  return common::visit(256      common::visitors{257          [&](const Inclusion &inc) -> std::optional<ProvenanceRange> {258            if (IsValid(origin.replaces) &&259                range_.Contains(origin.replaces.start()))260              return origin.replaces;261            return std::nullopt;262          },263          [&](const auto &) -> std::optional<ProvenanceRange> {264            return std::nullopt;265          },266      },267      origin.u);268}269 270void AllSources::EmitMessage(llvm::raw_ostream &o,271    const std::optional<ProvenanceRange> &range, const std::string &message,272    const std::string &prefix, llvm::raw_ostream::Colors color,273    bool echoSourceLine) const {274  if (!range) {275    EmitPrefix(o, color, prefix, this->getShowColors());276    o << message << '\n';277    return;278  }279  CHECK(IsValid(*range));280  const Origin &origin{MapToOrigin(range->start())};281  common::visit(282      common::visitors{283          [&](const Inclusion &inc) {284            std::size_t offset{origin.covers.MemberOffset(range->start())};285            SourcePosition pos{inc.source.GetSourcePosition(offset)};286            o << pos.path << ':' << pos.line << ':' << pos.column << ": ";287            EmitPrefix(o, color, prefix, this->getShowColors());288            o << message << '\n';289            if (echoSourceLine) {290              const char *text{inc.source.content().data() +291                  inc.source.GetLineStartOffset(pos.trueLineNumber)};292              o << "  ";293              for (const char *p{text}; *p != '\n'; ++p) {294                o << *p;295              }296              o << "\n  ";297              for (int j{1}; j < pos.column; ++j) {298                char ch{text[j - 1]};299                o << (ch == '\t' ? '\t' : ' ');300              }301              o << '^';302              if (range->size() > 1) {303                auto last{range->start() + range->size() - 1};304                if (&MapToOrigin(last) == &origin) {305                  auto endOffset{origin.covers.MemberOffset(last)};306                  auto endPos{inc.source.GetSourcePosition(endOffset)};307                  if (pos.line == endPos.line) {308                    for (int j{pos.column}; j < endPos.column; ++j) {309                      o << '^';310                    }311                  }312                }313              }314              o << '\n';315            }316            if (IsValid(origin.replaces)) {317              EmitMessage(o, origin.replaces,318                  inc.isModule ? "used here"s : "included here"s, prefix, color,319                  echoSourceLine);320            }321          },322          [&](const Macro &mac) {323            EmitMessage(324                o, origin.replaces, message, prefix, color, echoSourceLine);325            EmitMessage(o, mac.definition, "in a macro defined here", ""s,326                color, echoSourceLine);327            if (echoSourceLine) {328              o << "that expanded to:\n  " << mac.expansion << "\n  ";329              for (std::size_t j{0};330                   origin.covers.OffsetMember(j) < range->start(); ++j) {331                o << (mac.expansion[j] == '\t' ? '\t' : ' ');332              }333              o << "^\n";334            }335          },336          [&](const CompilerInsertion &) {337            EmitPrefix(o, color, prefix, this->getShowColors());338            o << message << '\n';339          },340      },341      origin.u);342}343 344const SourceFile *AllSources::GetSourceFile(345    Provenance at, std::size_t *offset, bool topLevel) const {346  const Origin &origin{MapToOrigin(at)};347  return common::visit(common::visitors{348                           [&](const Inclusion &inc) {349                             if (topLevel && !origin.replaces.empty()) {350                               return GetSourceFile(351                                   origin.replaces.start(), offset, topLevel);352                             } else {353                               if (offset) {354                                 *offset = origin.covers.MemberOffset(at);355                               }356                               return &inc.source;357                             }358                           },359                           [&](const Macro &) {360                             return GetSourceFile(361                                 origin.replaces.start(), offset);362                           },363                           [offset](const CompilerInsertion &) {364                             if (offset) {365                               *offset = 0;366                             }367                             return static_cast<const SourceFile *>(nullptr);368                           },369                       },370      origin.u);371}372 373const char *AllSources::GetSource(ProvenanceRange range) const {374  Provenance start{range.start()};375  const Origin &origin{MapToOrigin(start)};376  return origin.covers.Contains(range)377      ? &origin[origin.covers.MemberOffset(start)]378      : nullptr;379}380 381std::optional<SourcePosition> AllSources::GetSourcePosition(382    Provenance prov) const {383  const Origin &origin{MapToOrigin(prov)};384  return common::visit(385      common::visitors{386          [&](const Inclusion &inc) -> std::optional<SourcePosition> {387            std::size_t offset{origin.covers.MemberOffset(prov)};388            return inc.source.GetSourcePosition(offset);389          },390          [&](const Macro &) {391            return GetSourcePosition(origin.replaces.start());392          },393          [](const CompilerInsertion &) -> std::optional<SourcePosition> {394            return std::nullopt;395          },396      },397      origin.u);398}399 400std::optional<ProvenanceRange> AllSources::GetFirstFileProvenance() const {401  for (const auto &origin : origin_) {402    if (std::holds_alternative<Inclusion>(origin.u)) {403      return origin.covers;404    }405  }406  return std::nullopt;407}408 409std::string AllSources::GetPath(Provenance at, bool topLevel) const {410  std::size_t offset{0};411  const SourceFile *source{GetSourceFile(at, &offset, topLevel)};412  return source ? *source->GetSourcePosition(offset).path : ""s;413}414 415int AllSources::GetLineNumber(Provenance at) const {416  std::size_t offset{0};417  const SourceFile *source{GetSourceFile(at, &offset)};418  return source ? source->GetSourcePosition(offset).line : 0;419}420 421Provenance AllSources::CompilerInsertionProvenance(char ch) {422  auto iter{compilerInsertionProvenance_.find(ch)};423  if (iter != compilerInsertionProvenance_.end()) {424    return iter->second;425  }426  ProvenanceRange newCharRange{AddCompilerInsertion(std::string{ch})};427  Provenance newCharProvenance{newCharRange.start()};428  compilerInsertionProvenance_.insert(std::make_pair(ch, newCharProvenance));429  return newCharProvenance;430}431 432ProvenanceRange AllSources::IntersectionWithSourceFiles(433    ProvenanceRange range) const {434  if (range.empty()) {435    return {};436  } else {437    const Origin &origin{MapToOrigin(range.start())};438    if (std::holds_alternative<Inclusion>(origin.u)) {439      return range.Intersection(origin.covers);440    } else {441      auto skip{442          origin.covers.size() - origin.covers.MemberOffset(range.start())};443      return IntersectionWithSourceFiles(range.Suffix(skip));444    }445  }446}447 448AllSources::Origin::Origin(ProvenanceRange r, const SourceFile &source)449    : u{Inclusion{source}}, covers{r} {}450AllSources::Origin::Origin(ProvenanceRange r, const SourceFile &included,451    ProvenanceRange from, bool isModule)452    : u{Inclusion{included, isModule}}, covers{r}, replaces{from} {}453AllSources::Origin::Origin(ProvenanceRange r, ProvenanceRange def,454    ProvenanceRange use, const std::string &expansion)455    : u{Macro{def, expansion}}, covers{r}, replaces{use} {}456AllSources::Origin::Origin(ProvenanceRange r, const std::string &text)457    : u{CompilerInsertion{text}}, covers{r} {}458 459const char &AllSources::Origin::operator[](std::size_t n) const {460  return common::visit(461      common::visitors{462          [n](const Inclusion &inc) -> const char & {463            return inc.source.content()[n];464          },465          [n](const Macro &mac) -> const char & { return mac.expansion[n]; },466          [n](const CompilerInsertion &ins) -> const char & {467            return ins.text[n];468          },469      },470      u);471}472 473const AllSources::Origin &AllSources::MapToOrigin(Provenance at) const {474  CHECK(range_.Contains(at));475  std::size_t low{0}, count{origin_.size()};476  while (count > 1) {477    std::size_t mid{low + (count >> 1)};478    if (at < origin_[mid].covers.start()) {479      count = mid - low;480    } else {481      count -= mid - low;482      low = mid;483    }484  }485  CHECK(origin_[low].covers.Contains(at));486  return origin_[low];487}488 489Provenance AllSources::GetReplacedProvenance(Provenance provenance) const {490  const Origin &origin{MapToOrigin(provenance)};491  if (std::holds_alternative<Macro>(origin.u)) {492    return origin.replaces.start();493  }494  return provenance;495}496 497std::optional<ProvenanceRange> CookedSource::GetProvenanceRange(498    CharBlock cookedRange) const {499  if (!AsCharBlock().Contains(cookedRange)) {500    return std::nullopt;501  }502  ProvenanceRange first{provenanceMap_.Map(cookedRange.begin() - &data_[0])};503  if (cookedRange.size() <= first.size()) { // always true when empty504    return first.Prefix(cookedRange.size());505  }506  ProvenanceRange last{provenanceMap_.Map(cookedRange.end() - 1 - &data_[0])};507  if (first.start() <= last.start()) {508    return {ProvenanceRange{first.start(), last.start() - first.start() + 1}};509  } else {510    // cookedRange may start (resp. end) in a macro expansion while it does not511    // end (resp. start) in this macro expansion. Attempt to build a range512    // over the replaced source.513    Provenance firstStart{allSources_.GetReplacedProvenance(first.start())};514    Provenance lastStart{allSources_.GetReplacedProvenance(last.start())};515    if (firstStart <= lastStart) {516      return {ProvenanceRange{firstStart, lastStart - firstStart + 1}};517    } else {518      return std::nullopt;519    }520  }521}522 523std::optional<CharBlock> CookedSource::GetCharBlock(524    ProvenanceRange range) const {525  CHECK(!invertedMap_.empty() &&526      "CompileProvenanceRangeToOffsetMappings not called");527  if (auto to{invertedMap_.Map(range)}) {528    return CharBlock{data_.c_str() + *to, range.size()};529  } else {530    return std::nullopt;531  }532}533 534std::size_t CookedSource::BufferedBytes() const { return buffer_.bytes(); }535 536void CookedSource::Marshal(AllCookedSources &allCookedSources) {537  CHECK(provenanceMap_.SizeInBytes() == buffer_.bytes());538  provenanceMap_.Put(allCookedSources.allSources().AddCompilerInsertion(539      "(after end of source)"));540  data_ = buffer_.Marshal();541  buffer_.clear();542  for (std::size_t ffStart : possibleFixedFormContinuations_) {543    if (ffStart > 0 && ffStart + 1 < data_.size() &&544        data_[ffStart - 1] == '\n' && data_[ffStart] == ' ') {545      // This fixed form include line is the first source line in an546      // #include file (or after an empty one).  Connect it with the previous547      // source line by deleting its terminal newline.548      data_[ffStart - 1] = ' ';549    }550  }551  possibleFixedFormContinuations_.clear();552  allCookedSources.Register(*this);553}554 555void CookedSource::CompileProvenanceRangeToOffsetMappings(556    AllSources &allSources) {557  if (invertedMap_.empty()) {558    invertedMap_ = provenanceMap_.Invert(allSources);559  }560}561 562static void DumpRange(llvm::raw_ostream &o, const ProvenanceRange &r) {563  o << "[" << r.start().offset() << ".." << r.Last().offset() << "] ("564    << r.size() << " bytes)";565}566 567llvm::raw_ostream &ProvenanceRangeToOffsetMappings::Dump(568    llvm::raw_ostream &o) const {569  for (const auto &m : map_) {570    o << "provenances ";571    DumpRange(o, m.first);572    o << " -> offsets [" << m.second << ".." << (m.second + m.first.size() - 1)573      << "]\n";574  }575  return o;576}577 578llvm::raw_ostream &OffsetToProvenanceMappings::Dump(579    llvm::raw_ostream &o) const {580  for (const ContiguousProvenanceMapping &m : provenanceMap_) {581    std::size_t n{m.range.size()};582    o << "offsets [" << m.start << ".." << (m.start + n - 1)583      << "] -> provenances ";584    DumpRange(o, m.range);585    o << '\n';586  }587  return o;588}589 590llvm::raw_ostream &AllSources::Dump(llvm::raw_ostream &o) const {591  o << "AllSources range_ ";592  DumpRange(o, range_);593  o << '\n';594  std::set<const SourceFile *> sources;595  for (const Origin &m : origin_) {596    o << "   ";597    DumpRange(o, m.covers);598    o << " -> ";599    common::visit(common::visitors{600                      [&](const Inclusion &inc) {601                        if (inc.isModule) {602                          o << "module ";603                        }604                        o << "file " << inc.source.path();605                        sources.emplace(&inc.source);606                      },607                      [&](const Macro &mac) { o << "macro " << mac.expansion; },608                      [&](const CompilerInsertion &ins) {609                        o << "compiler '" << ins.text << '\'';610                        if (ins.text.length() == 1) {611                          int ch = ins.text[0];612                          o << "(0x";613                          o.write_hex(ch & 0xff) << ")";614                        }615                      },616                  },617        m.u);618    if (IsValid(m.replaces)) {619      o << " replaces ";620      DumpRange(o, m.replaces);621    }622    o << '\n';623  }624  for (const SourceFile *sf : sources) {625    sf->Dump(o);626  }627  return o;628}629 630llvm::raw_ostream &CookedSource::Dump(llvm::raw_ostream &o) const {631  o << "CookedSource::provenanceMap_:\n";632  provenanceMap_.Dump(o);633  o << "CookedSource::invertedMap_:\n";634  invertedMap_.Dump(o);635  return o;636}637 638AllCookedSources::AllCookedSources(AllSources &s) : allSources_{s} {}639AllCookedSources::~AllCookedSources() {}640 641CookedSource &AllCookedSources::NewCookedSource() {642  return cooked_.emplace_back(allSources_);643}644 645const CookedSource *AllCookedSources::Find(CharBlock x) const {646  auto pair{index_.equal_range(x)};647  for (auto iter{pair.first}; iter != pair.second; ++iter) {648    if (iter->second.AsCharBlock().Contains(x)) {649      return &iter->second;650    }651  }652  return nullptr;653}654 655std::optional<ProvenanceRange> AllCookedSources::GetProvenanceRange(656    CharBlock cb) const {657  if (const CookedSource * c{Find(cb)}) {658    return c->GetProvenanceRange(cb);659  } else {660    return std::nullopt;661  }662}663 664std::optional<CharBlock> AllCookedSources::GetCharBlockFromLineAndColumns(665    int line, int startColumn, int endColumn) const {666  // 2nd column is exclusive, meaning it is target column + 1.667  CHECK(line > 0 && startColumn > 0 && endColumn > 0);668  CHECK(startColumn < endColumn);669  auto provenanceStart{allSources_.GetFirstFileProvenance().value().start()};670  if (auto sourceFile{allSources_.GetSourceFile(provenanceStart)}) {671    CHECK(line <= static_cast<int>(sourceFile->lines()));672    return GetCharBlock(ProvenanceRange(sourceFile->GetLineStartOffset(line) +673            provenanceStart.offset() + startColumn - 1,674        endColumn - startColumn));675  }676  return std::nullopt;677}678 679std::optional<std::pair<SourcePosition, SourcePosition>>680AllCookedSources::GetSourcePositionRange(CharBlock cookedRange) const {681  if (auto range{GetProvenanceRange(cookedRange)}) {682    if (auto firstOffset{allSources_.GetSourcePosition(range->start())}) {683      if (auto secondOffset{684              allSources_.GetSourcePosition(range->start() + range->size())}) {685        return std::pair{*firstOffset, *secondOffset};686      }687    }688  }689  return std::nullopt;690}691 692std::optional<CharBlock> AllCookedSources::GetCharBlock(693    ProvenanceRange range) const {694  for (const auto &c : cooked_) {695    if (auto result{c.GetCharBlock(range)}) {696      return result;697    }698  }699  return std::nullopt;700}701 702void AllCookedSources::Dump(llvm::raw_ostream &o) const {703  o << "AllSources:\n";704  allSources_.Dump(o);705  for (const auto &c : cooked_) {706    c.Dump(o);707  }708}709 710bool AllCookedSources::Precedes(CharBlock x, CharBlock y) const {711  if (const CookedSource * xSource{Find(x)}) {712    if (xSource->AsCharBlock().Contains(y)) {713      return x.begin() < y.begin();714    } else if (const CookedSource * ySource{Find(y)}) {715      return xSource->number() < ySource->number();716    } else {717      return true; // by fiat, all cooked source < anything outside718    }719  } else if (Find(y)) {720    return false;721  } else {722    // Both names are compiler-created (SaveTempName).723    return x < y;724  }725}726 727void AllCookedSources::Register(CookedSource &cooked) {728  index_.emplace(cooked.AsCharBlock(), cooked);729  cooked.set_number(static_cast<int>(index_.size()));730}731 732} // namespace Fortran::parser733