1 //===--- Annotations.cpp - Annotated source code for unit tests --*- C++-*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Testing/Support/Annotations.h"
11 #include "llvm/ADT/StringExtras.h"
12 #include "llvm/Support/FormatVariadic.h"
13 #include "llvm/Support/raw_ostream.h"
17 // Crash if the assertion fails, printing the message and testcase.
18 // More elegant error handling isn't needed for unit tests.
19 static void require(bool Assertion
, const char *Msg
, llvm::StringRef Code
) {
21 llvm::errs() << "Annotated testcase: " << Msg
<< "\n" << Code
<< "\n";
22 llvm_unreachable("Annotated testcase assertion failed!");
26 Annotations::Annotations(llvm::StringRef Text
) {
27 auto Require
= [Text
](bool Assertion
, const char *Msg
) {
28 require(Assertion
, Msg
, Text
);
30 llvm::Optional
<llvm::StringRef
> Name
;
31 llvm::SmallVector
<std::pair
<llvm::StringRef
, size_t>, 8> OpenRanges
;
33 Code
.reserve(Text
.size());
34 while (!Text
.empty()) {
35 if (Text
.consume_front("^")) {
36 Points
[Name
.getValueOr("")].push_back(Code
.size());
40 if (Text
.consume_front("[[")) {
41 OpenRanges
.emplace_back(Name
.getValueOr(""), Code
.size());
45 Require(!Name
, "$name should be followed by ^ or [[");
46 if (Text
.consume_front("]]")) {
47 Require(!OpenRanges
.empty(), "unmatched ]]");
49 R
.Begin
= OpenRanges
.back().second
;
51 Ranges
[OpenRanges
.back().first
].push_back(R
);
52 OpenRanges
.pop_back();
55 if (Text
.consume_front("$")) {
56 Name
= Text
.take_while(llvm::isAlnum
);
57 Text
= Text
.drop_front(Name
->size());
60 Code
.push_back(Text
.front());
61 Text
= Text
.drop_front();
63 Require(!Name
, "unterminated $name");
64 Require(OpenRanges
.empty(), "unmatched [[");
67 size_t Annotations::point(llvm::StringRef Name
) const {
68 auto I
= Points
.find(Name
);
69 require(I
!= Points
.end() && I
->getValue().size() == 1,
70 "expected exactly one point", Code
);
71 return I
->getValue()[0];
74 std::vector
<size_t> Annotations::points(llvm::StringRef Name
) const {
75 auto P
= Points
.lookup(Name
);
76 return {P
.begin(), P
.end()};
79 Annotations::Range
Annotations::range(llvm::StringRef Name
) const {
80 auto I
= Ranges
.find(Name
);
81 require(I
!= Ranges
.end() && I
->getValue().size() == 1,
82 "expected exactly one range", Code
);
83 return I
->getValue()[0];
86 std::vector
<Annotations::Range
>
87 Annotations::ranges(llvm::StringRef Name
) const {
88 auto R
= Ranges
.lookup(Name
);
89 return {R
.begin(), R
.end()};
92 llvm::raw_ostream
&llvm::operator<<(llvm::raw_ostream
&O
,
93 const llvm::Annotations::Range
&R
) {
94 return O
<< llvm::formatv("[{0}, {1})", R
.Begin
, R
.End
);