Annotations.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===--- Annotations.h - Annotated source code for tests ---------*- C++-*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_TESTING_SUPPORT_ANNOTATIONS_H
  14. #define LLVM_TESTING_SUPPORT_ANNOTATIONS_H
  15. #include "llvm/ADT/SmallVector.h"
  16. #include "llvm/ADT/StringMap.h"
  17. #include "llvm/ADT/StringRef.h"
  18. #include <tuple>
  19. #include <vector>
  20. namespace llvm {
  21. class raw_ostream;
  22. /// Annotations lets you mark points and ranges inside source code, for tests:
  23. ///
  24. /// Annotations Example(R"cpp(
  25. /// int complete() { x.pri^ } // ^ indicates a point
  26. /// void err() { [["hello" == 42]]; } // [[this is a range]]
  27. /// $definition^class Foo{}; // points can be named: "definition"
  28. /// $(foo)^class Foo{}; // ...or have a payload: "foo"
  29. /// $definition(foo)^class Foo{}; // ...or both
  30. /// $fail(runtime)[[assert(false)]] // ranges can have names/payloads too
  31. /// )cpp");
  32. ///
  33. /// StringRef Code = Example.code(); // annotations stripped.
  34. /// std::vector<size_t> PP = Example.points(); // all unnamed points
  35. /// size_t P = Example.point(); // there must be exactly one
  36. /// llvm::Range R = Example.range("fail"); // find named ranges
  37. ///
  38. /// Points/ranges are coordinated into `code()` which is stripped of
  39. /// annotations.
  40. ///
  41. /// Names consist of only alphanumeric characters or '_'.
  42. /// Payloads can contain any character expect '(' and ')'.
  43. ///
  44. /// Ranges may be nested (and points can be inside ranges), but there's no way
  45. /// to define general overlapping ranges.
  46. ///
  47. /// FIXME: the choice of the marking syntax makes it impossible to represent
  48. /// some of the C++ and Objective C constructs (including common ones
  49. /// like C++ attributes). We can fix this by:
  50. /// 1. introducing an escaping mechanism for the special characters,
  51. /// 2. making characters for marking points and ranges configurable,
  52. /// 3. changing the syntax to something less commonly used,
  53. /// 4. ...
  54. class Annotations {
  55. public:
  56. /// Two offsets pointing to a continuous substring. End is not included, i.e.
  57. /// represents a half-open range.
  58. struct Range {
  59. size_t Begin = 0;
  60. size_t End = 0;
  61. friend bool operator==(const Range &L, const Range &R) {
  62. return std::tie(L.Begin, L.End) == std::tie(R.Begin, R.End);
  63. }
  64. friend bool operator!=(const Range &L, const Range &R) { return !(L == R); }
  65. };
  66. /// Parses the annotations from Text. Crashes if it's malformed.
  67. Annotations(llvm::StringRef Text);
  68. /// The input text with all annotations stripped.
  69. /// All points and ranges are relative to this stripped text.
  70. llvm::StringRef code() const { return Code; }
  71. /// Returns the position of the point marked by ^ (or $name^) in the text.
  72. /// Crashes if there isn't exactly one.
  73. size_t point(llvm::StringRef Name = "") const;
  74. /// Returns the position of the point with \p Name and its payload (if any).
  75. std::pair<size_t, llvm::StringRef>
  76. pointWithPayload(llvm::StringRef Name = "") const;
  77. /// Returns the position of all points marked by ^ (or $name^) in the text.
  78. /// Order matches the order within the text.
  79. std::vector<size_t> points(llvm::StringRef Name = "") const;
  80. /// Returns the positions and payloads (if any) of all points named \p Name
  81. std::vector<std::pair<size_t, llvm::StringRef>>
  82. pointsWithPayload(llvm::StringRef Name = "") const;
  83. /// Returns the mapping of all names of points marked in the text to their
  84. /// position. Unnamed points are mapped to the empty string. The positions are
  85. /// sorted.
  86. /// FIXME Remove this and expose `All` directly (currently used out-of-tree)
  87. llvm::StringMap<llvm::SmallVector<size_t, 1>> all_points() const;
  88. /// Returns the location of the range marked by [[ ]] (or $name[[ ]]).
  89. /// Crashes if there isn't exactly one.
  90. Range range(llvm::StringRef Name = "") const;
  91. /// Returns the location and payload of the range marked by [[ ]]
  92. /// (or $name(payload)[[ ]]). Crashes if there isn't exactly one.
  93. std::pair<Range, llvm::StringRef>
  94. rangeWithPayload(llvm::StringRef Name = "") const;
  95. /// Returns the location of all ranges marked by [[ ]] (or $name[[ ]]).
  96. /// They are ordered by start position within the text.
  97. std::vector<Range> ranges(llvm::StringRef Name = "") const;
  98. /// Returns the location of all ranges marked by [[ ]]
  99. /// (or $name(payload)[[ ]]).
  100. /// They are ordered by start position within the text.
  101. std::vector<std::pair<Range, llvm::StringRef>>
  102. rangesWithPayload(llvm::StringRef Name = "") const;
  103. /// Returns the mapping of all names of ranges marked in the text to their
  104. /// location. Unnamed ranges are mapped to the empty string. The ranges are
  105. /// sorted by their start position.
  106. llvm::StringMap<llvm::SmallVector<Range, 1>> all_ranges() const;
  107. private:
  108. std::string Code;
  109. /// Either a Point (Only Start) or a Range (Start and End)
  110. struct Annotation {
  111. size_t Begin;
  112. size_t End = -1;
  113. bool isPoint() const { return End == size_t(-1); }
  114. llvm::StringRef Name;
  115. llvm::StringRef Payload;
  116. };
  117. std::vector<Annotation> All;
  118. // Values are the indices into All
  119. llvm::StringMap<llvm::SmallVector<size_t, 1>> Points;
  120. llvm::StringMap<llvm::SmallVector<size_t, 1>> Ranges;
  121. };
  122. llvm::raw_ostream &operator<<(llvm::raw_ostream &O,
  123. const llvm::Annotations::Range &R);
  124. } // namespace llvm
  125. #endif
  126. #ifdef __GNUC__
  127. #pragma GCC diagnostic pop
  128. #endif