16fae38ecSIlya Biryukov //===--- Annotations.cpp - Annotated source code for unit tests --*- C++-*-===//
26fae38ecSIlya Biryukov //
36fae38ecSIlya Biryukov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46fae38ecSIlya Biryukov // See https://llvm.org/LICENSE.txt for license information.
56fae38ecSIlya Biryukov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66fae38ecSIlya Biryukov //
76fae38ecSIlya Biryukov //===----------------------------------------------------------------------===//
86fae38ecSIlya Biryukov
96fae38ecSIlya Biryukov #include "llvm/Testing/Support/Annotations.h"
106fae38ecSIlya Biryukov
116fae38ecSIlya Biryukov #include "llvm/ADT/StringExtras.h"
126fae38ecSIlya Biryukov #include "llvm/Support/FormatVariadic.h"
136fae38ecSIlya Biryukov #include "llvm/Support/raw_ostream.h"
146fae38ecSIlya Biryukov
156fae38ecSIlya Biryukov using namespace llvm;
166fae38ecSIlya Biryukov
176fae38ecSIlya Biryukov // Crash if the assertion fails, printing the message and testcase.
186fae38ecSIlya Biryukov // More elegant error handling isn't needed for unit tests.
require(bool Assertion,const char * Msg,llvm::StringRef Code)196fae38ecSIlya Biryukov static void require(bool Assertion, const char *Msg, llvm::StringRef Code) {
206fae38ecSIlya Biryukov if (!Assertion) {
216fae38ecSIlya Biryukov llvm::errs() << "Annotated testcase: " << Msg << "\n" << Code << "\n";
226fae38ecSIlya Biryukov llvm_unreachable("Annotated testcase assertion failed!");
236fae38ecSIlya Biryukov }
246fae38ecSIlya Biryukov }
256fae38ecSIlya Biryukov
Annotations(llvm::StringRef Text)266fae38ecSIlya Biryukov Annotations::Annotations(llvm::StringRef Text) {
276fae38ecSIlya Biryukov auto Require = [Text](bool Assertion, const char *Msg) {
286fae38ecSIlya Biryukov require(Assertion, Msg, Text);
296fae38ecSIlya Biryukov };
306fae38ecSIlya Biryukov llvm::Optional<llvm::StringRef> Name;
316fae38ecSIlya Biryukov llvm::SmallVector<std::pair<llvm::StringRef, size_t>, 8> OpenRanges;
326fae38ecSIlya Biryukov
336fae38ecSIlya Biryukov Code.reserve(Text.size());
346fae38ecSIlya Biryukov while (!Text.empty()) {
356fae38ecSIlya Biryukov if (Text.consume_front("^")) {
36*129b531cSKazu Hirata Points[Name.value_or("")].push_back(Code.size());
376fae38ecSIlya Biryukov Name = llvm::None;
386fae38ecSIlya Biryukov continue;
396fae38ecSIlya Biryukov }
406fae38ecSIlya Biryukov if (Text.consume_front("[[")) {
41*129b531cSKazu Hirata OpenRanges.emplace_back(Name.value_or(""), Code.size());
426fae38ecSIlya Biryukov Name = llvm::None;
436fae38ecSIlya Biryukov continue;
446fae38ecSIlya Biryukov }
456fae38ecSIlya Biryukov Require(!Name, "$name should be followed by ^ or [[");
466fae38ecSIlya Biryukov if (Text.consume_front("]]")) {
476fae38ecSIlya Biryukov Require(!OpenRanges.empty(), "unmatched ]]");
486fae38ecSIlya Biryukov Range R;
496fae38ecSIlya Biryukov R.Begin = OpenRanges.back().second;
506fae38ecSIlya Biryukov R.End = Code.size();
516fae38ecSIlya Biryukov Ranges[OpenRanges.back().first].push_back(R);
526fae38ecSIlya Biryukov OpenRanges.pop_back();
536fae38ecSIlya Biryukov continue;
546fae38ecSIlya Biryukov }
556fae38ecSIlya Biryukov if (Text.consume_front("$")) {
56dd8fb212SSam McCall Name =
57dd8fb212SSam McCall Text.take_while([](char C) { return llvm::isAlnum(C) || C == '_'; });
586fae38ecSIlya Biryukov Text = Text.drop_front(Name->size());
596fae38ecSIlya Biryukov continue;
606fae38ecSIlya Biryukov }
616fae38ecSIlya Biryukov Code.push_back(Text.front());
626fae38ecSIlya Biryukov Text = Text.drop_front();
636fae38ecSIlya Biryukov }
646fae38ecSIlya Biryukov Require(!Name, "unterminated $name");
656fae38ecSIlya Biryukov Require(OpenRanges.empty(), "unmatched [[");
666fae38ecSIlya Biryukov }
676fae38ecSIlya Biryukov
point(llvm::StringRef Name) const686fae38ecSIlya Biryukov size_t Annotations::point(llvm::StringRef Name) const {
696fae38ecSIlya Biryukov auto I = Points.find(Name);
706fae38ecSIlya Biryukov require(I != Points.end() && I->getValue().size() == 1,
716fae38ecSIlya Biryukov "expected exactly one point", Code);
726fae38ecSIlya Biryukov return I->getValue()[0];
736fae38ecSIlya Biryukov }
746fae38ecSIlya Biryukov
points(llvm::StringRef Name) const756fae38ecSIlya Biryukov std::vector<size_t> Annotations::points(llvm::StringRef Name) const {
765a2febb3SNathan James auto I = Points.find(Name);
775a2febb3SNathan James if (I == Points.end())
785a2febb3SNathan James return {};
795a2febb3SNathan James return {I->getValue().begin(), I->getValue().end()};
806fae38ecSIlya Biryukov }
816fae38ecSIlya Biryukov
range(llvm::StringRef Name) const826fae38ecSIlya Biryukov Annotations::Range Annotations::range(llvm::StringRef Name) const {
836fae38ecSIlya Biryukov auto I = Ranges.find(Name);
846fae38ecSIlya Biryukov require(I != Ranges.end() && I->getValue().size() == 1,
856fae38ecSIlya Biryukov "expected exactly one range", Code);
866fae38ecSIlya Biryukov return I->getValue()[0];
876fae38ecSIlya Biryukov }
886fae38ecSIlya Biryukov
896fae38ecSIlya Biryukov std::vector<Annotations::Range>
ranges(llvm::StringRef Name) const906fae38ecSIlya Biryukov Annotations::ranges(llvm::StringRef Name) const {
915a2febb3SNathan James auto I = Ranges.find(Name);
925a2febb3SNathan James if (I == Ranges.end())
935a2febb3SNathan James return {};
945a2febb3SNathan James return {I->getValue().begin(), I->getValue().end()};
956fae38ecSIlya Biryukov }
966fae38ecSIlya Biryukov
operator <<(llvm::raw_ostream & O,const llvm::Annotations::Range & R)976fae38ecSIlya Biryukov llvm::raw_ostream &llvm::operator<<(llvm::raw_ostream &O,
986fae38ecSIlya Biryukov const llvm::Annotations::Range &R) {
996fae38ecSIlya Biryukov return O << llvm::formatv("[{0}, {1})", R.Begin, R.End);
1006fae38ecSIlya Biryukov }
101