aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm16/include/llvm/Testing/Annotations/Annotations.h
blob: 476cd7878c25bbe8251540c1b1491aeac0c5fb9f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#pragma once

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

//===--- Annotations.h - Annotated source code for tests ---------*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TESTING_SUPPORT_ANNOTATIONS_H
#define LLVM_TESTING_SUPPORT_ANNOTATIONS_H

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include <tuple>
#include <vector>

namespace llvm {

class raw_ostream;

/// Annotations lets you mark points and ranges inside source code, for tests:
///
///    Annotations Example(R"cpp(
///       int complete() { x.pri^ }         // ^ indicates a point
///       void err() { [["hello" == 42]]; } // [[this is a range]]
///       $definition^class Foo{};          // points can be named: "definition"
///       $(foo)^class Foo{};               // ...or have a payload: "foo"
///       $definition(foo)^class Foo{};     // ...or both
///       $fail(runtime)[[assert(false)]]   // ranges can have names/payloads too
///    )cpp");
///
///    StringRef Code = Example.code();             // annotations stripped.
///    std::vector<size_t> PP = Example.points();   // all unnamed points
///    size_t P = Example.point();                  // there must be exactly one
///    llvm::Range R = Example.range("fail");       // find named ranges
///
/// Points/ranges are coordinated into `code()` which is stripped of
/// annotations.
///
/// Names consist of only alphanumeric characters or '_'.
/// Payloads can contain any character expect '(' and ')'.
///
/// Ranges may be nested (and points can be inside ranges), but there's no way
/// to define general overlapping ranges.
///
/// FIXME: the choice of the marking syntax makes it impossible to represent
///        some of the C++ and Objective C constructs (including common ones
///        like C++ attributes). We can fix this by:
///          1. introducing an escaping mechanism for the special characters,
///          2. making characters for marking points and ranges configurable,
///          3. changing the syntax to something less commonly used,
///          4. ...
class Annotations {
public:
  /// Two offsets pointing to a continuous substring. End is not included, i.e.
  /// represents a half-open range.
  struct Range {
    size_t Begin = 0;
    size_t End = 0;

    friend bool operator==(const Range &L, const Range &R) {
      return std::tie(L.Begin, L.End) == std::tie(R.Begin, R.End);
    }
    friend bool operator!=(const Range &L, const Range &R) { return !(L == R); }
  };

  /// Parses the annotations from Text. Crashes if it's malformed.
  Annotations(llvm::StringRef Text);

  /// The input text with all annotations stripped.
  /// All points and ranges are relative to this stripped text.
  llvm::StringRef code() const { return Code; }

  /// Returns the position of the point marked by ^ (or $name^) in the text.
  /// Crashes if there isn't exactly one.
  size_t point(llvm::StringRef Name = "") const;
  /// Returns the position of the point with \p Name and its payload (if any).
  std::pair<size_t, llvm::StringRef>
  pointWithPayload(llvm::StringRef Name = "") const;
  /// Returns the position of all points marked by ^ (or $name^) in the text.
  /// Order matches the order within the text.
  std::vector<size_t> points(llvm::StringRef Name = "") const;
  /// Returns the positions and payloads (if any) of all points named \p Name
  std::vector<std::pair<size_t, llvm::StringRef>>
  pointsWithPayload(llvm::StringRef Name = "") const;
  /// Returns the mapping of all names of points marked in the text to their
  /// position. Unnamed points are mapped to the empty string. The positions are
  /// sorted.
  /// FIXME Remove this and expose `All` directly (currently used out-of-tree)
  llvm::StringMap<llvm::SmallVector<size_t, 1>> all_points() const;

  /// Returns the location of the range marked by [[ ]] (or $name[[ ]]).
  /// Crashes if there isn't exactly one.
  Range range(llvm::StringRef Name = "") const;
  /// Returns the location and payload of the range marked by [[ ]]
  /// (or $name(payload)[[ ]]). Crashes if there isn't exactly one.
  std::pair<Range, llvm::StringRef>
  rangeWithPayload(llvm::StringRef Name = "") const;
  /// Returns the location of all ranges marked by [[ ]] (or $name[[ ]]).
  /// They are ordered by start position within the text.
  std::vector<Range> ranges(llvm::StringRef Name = "") const;
  /// Returns the location of all ranges marked by [[ ]]
  /// (or $name(payload)[[ ]]).
  /// They are ordered by start position within the text.
  std::vector<std::pair<Range, llvm::StringRef>>
  rangesWithPayload(llvm::StringRef Name = "") const;
  /// Returns the mapping of all names of ranges marked in the text to their
  /// location. Unnamed ranges are mapped to the empty string. The ranges are
  /// sorted by their start position.
  llvm::StringMap<llvm::SmallVector<Range, 1>> all_ranges() const;

private:
  std::string Code;
  /// Either a Point (Only Start) or a Range (Start and End)
  struct Annotation {
    size_t Begin;
    size_t End = -1;
    bool isPoint() const { return End == size_t(-1); }
    llvm::StringRef Name;
    llvm::StringRef Payload;
  };
  std::vector<Annotation> All;
  // Values are the indices into All
  llvm::StringMap<llvm::SmallVector<size_t, 1>> Points;
  llvm::StringMap<llvm::SmallVector<size_t, 1>> Ranges;
};

llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
                              const llvm::Annotations::Range &R);

} // namespace llvm

#endif

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif