yql_issue.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. #pragma once
  2. #include <util/system/types.h>
  3. #include <util/generic/hash.h>
  4. #include <util/generic/maybe.h>
  5. #include <util/generic/vector.h>
  6. #include <util/generic/string.h>
  7. #include <util/generic/strbuf.h>
  8. #include <util/generic/ptr.h>
  9. #include <util/stream/output.h>
  10. #include <util/stream/str.h>
  11. #include <util/digest/numeric.h>
  12. #include <google/protobuf/message.h>
  13. #include "yql_issue_id.h"
  14. namespace NYql {
  15. void SanitizeNonAscii(TString& s);
  16. ///////////////////////////////////////////////////////////////////////////////
  17. // TPosition
  18. ///////////////////////////////////////////////////////////////////////////////
  19. struct TPosition {
  20. ui32 Column = 0U;
  21. ui32 Row = 0U;
  22. TString File;
  23. TPosition() = default;
  24. TPosition(ui32 column, ui32 row, const TString& file = {})
  25. : Column(column)
  26. , Row(row)
  27. , File(file)
  28. {
  29. SanitizeNonAscii(File);
  30. }
  31. explicit operator bool() const {
  32. return HasValue();
  33. }
  34. inline bool HasValue() const {
  35. return Row | Column;
  36. }
  37. inline bool operator==(const TPosition& other) const {
  38. return Column == other.Column && Row == other.Row && File == other.File;
  39. }
  40. inline bool operator<(const TPosition& other) const {
  41. return std::tie(Row, Column, File) < std::tie(other.Row, other.Column, other.File);
  42. }
  43. };
  44. class TTextWalker {
  45. public:
  46. TTextWalker(TPosition& position, bool utf8Aware)
  47. : Position(position)
  48. , Utf8Aware(utf8Aware)
  49. , HaveCr(false)
  50. , LfCount(0)
  51. {
  52. }
  53. static inline bool IsUtf8Intermediate(char c) {
  54. return (c & 0xC0) == 0x80;
  55. }
  56. template<typename T>
  57. TTextWalker& Advance(const T& buf) {
  58. for (char c : buf) {
  59. Advance(c);
  60. }
  61. return *this;
  62. }
  63. TTextWalker& Advance(char c);
  64. private:
  65. TPosition& Position;
  66. const bool Utf8Aware;
  67. bool HaveCr;
  68. ui32 LfCount;
  69. };
  70. struct TRange {
  71. TPosition Position;
  72. TPosition EndPosition;
  73. TRange() = default;
  74. TRange(TPosition position)
  75. : Position(position)
  76. , EndPosition(position)
  77. {
  78. }
  79. TRange(TPosition position, TPosition endPosition)
  80. : Position(position)
  81. , EndPosition(endPosition)
  82. {
  83. }
  84. inline bool IsRange() const {
  85. return !(Position == EndPosition);
  86. }
  87. };
  88. ///////////////////////////////////////////////////////////////////////////////
  89. // TIssue
  90. ///////////////////////////////////////////////////////////////////////////////
  91. class TIssue;
  92. using TIssuePtr = TIntrusivePtr<TIssue>;
  93. class TIssue: public TThrRefBase {
  94. TVector<TIntrusivePtr<TIssue>> Children_;
  95. TString Message;
  96. public:
  97. TPosition Position;
  98. TPosition EndPosition;
  99. TIssueCode IssueCode = 0U;
  100. ESeverity Severity = TSeverityIds::S_ERROR;
  101. TIssue() = default;
  102. template <typename T>
  103. explicit TIssue(const T& message)
  104. : Message(message)
  105. , Position(TPosition())
  106. , EndPosition(TPosition())
  107. {
  108. SanitizeNonAscii(Message);
  109. }
  110. template <typename T>
  111. TIssue(TPosition position, const T& message)
  112. : Message(message)
  113. , Position(position)
  114. , EndPosition(position)
  115. {
  116. SanitizeNonAscii(Message);
  117. }
  118. inline TRange Range() const {
  119. return{ Position, EndPosition };
  120. }
  121. template <typename T>
  122. TIssue(TPosition position, TPosition endPosition, const T& message)
  123. : Message(message)
  124. , Position(position)
  125. , EndPosition(endPosition)
  126. {
  127. SanitizeNonAscii(Message);
  128. }
  129. inline bool operator==(const TIssue& other) const {
  130. return Position == other.Position && Message == other.Message
  131. && IssueCode == other.IssueCode;
  132. }
  133. ui64 Hash() const noexcept {
  134. return CombineHashes(
  135. CombineHashes(
  136. (size_t)CombineHashes(IntHash(Position.Row), IntHash(Position.Column)),
  137. ComputeHash(Position.File)
  138. ),
  139. (size_t)CombineHashes((size_t)IntHash(static_cast<int>(IssueCode)), ComputeHash(Message)));
  140. }
  141. TIssue& SetCode(TIssueCode id, ESeverity severity) {
  142. IssueCode = id;
  143. Severity = severity;
  144. return *this;
  145. }
  146. TIssue& SetMessage(const TString& msg) {
  147. Message = msg;
  148. SanitizeNonAscii(Message);
  149. return *this;
  150. }
  151. ESeverity GetSeverity() const {
  152. return Severity;
  153. }
  154. TIssueCode GetCode() const {
  155. return IssueCode;
  156. }
  157. const TString& GetMessage() const {
  158. return Message;
  159. }
  160. TIssue& AddSubIssue(TIntrusivePtr<TIssue> issue) {
  161. Severity = (ESeverity)Min((ui32)issue->GetSeverity(), (ui32)Severity);
  162. Children_.push_back(issue);
  163. return *this;
  164. }
  165. const TVector<TIntrusivePtr<TIssue>>& GetSubIssues() const {
  166. return Children_;
  167. }
  168. void PrintTo(IOutputStream& out, bool oneLine = false) const;
  169. TString ToString(bool oneLine = false) const {
  170. TStringStream out;
  171. PrintTo(out, oneLine);
  172. return out.Str();
  173. }
  174. // Unsafe method. Doesn't call SanitizeNonAscii(Message)
  175. TString* MutableMessage() {
  176. return &Message;
  177. }
  178. TIssue& CopyWithoutSubIssues(const TIssue& src) {
  179. Message = src.Message;
  180. IssueCode = src.IssueCode;
  181. Severity = src.Severity;
  182. Position = src.Position;
  183. EndPosition = src.EndPosition;
  184. return *this;
  185. }
  186. };
  187. void WalkThroughIssues(const TIssue& topIssue, bool leafOnly, std::function<void(const TIssue&, ui16 level)> fn, std::function<void(const TIssue&, ui16 level)> afterChildrenFn = {});
  188. ///////////////////////////////////////////////////////////////////////////////
  189. // TIssues
  190. ///////////////////////////////////////////////////////////////////////////////
  191. class TIssues {
  192. public:
  193. TIssues() = default;
  194. inline TIssues(const TVector<TIssue>& issues)
  195. : Issues_(issues)
  196. {
  197. }
  198. inline TIssues(const std::initializer_list<TIssue>& issues)
  199. : TIssues(TVector<TIssue>(issues))
  200. {
  201. }
  202. inline TIssues(const TIssues& rhs)
  203. : Issues_(rhs.Issues_)
  204. {
  205. }
  206. inline TIssues& operator=(const TIssues& rhs) {
  207. Issues_ = rhs.Issues_;
  208. return *this;
  209. }
  210. inline TIssues(TIssues&& rhs) : Issues_(std::move(rhs.Issues_))
  211. {
  212. }
  213. inline TIssues& operator=(TIssues&& rhs) {
  214. Issues_ = std::move(rhs.Issues_);
  215. return *this;
  216. }
  217. template <typename ... Args> void AddIssue(Args&& ... args) {
  218. Issues_.emplace_back(std::forward<Args>(args)...);
  219. }
  220. inline void AddIssues(const TIssues& errors) {
  221. Issues_.insert(Issues_.end(),
  222. errors.Issues_.begin(), errors.Issues_.end());
  223. }
  224. inline void AddIssues(const TPosition& pos, const TIssues& errors) {
  225. Issues_.reserve(Issues_.size() + errors.Size());
  226. for (const auto& e: errors) {
  227. TIssue& issue = Issues_.emplace_back();
  228. *issue.MutableMessage() = e.GetMessage(); // No need to sanitize message, it has already been sanitized.
  229. issue.Position = pos;
  230. issue.SetCode(e.IssueCode, e.Severity);
  231. }
  232. }
  233. inline const TIssue* begin() const {
  234. return Issues_.begin();
  235. }
  236. inline const TIssue* end() const {
  237. return Issues_.end();
  238. }
  239. inline TIssue& back() {
  240. return Issues_.back();
  241. }
  242. inline const TIssue& back() const {
  243. return Issues_.back();
  244. }
  245. inline bool Empty() const {
  246. return Issues_.empty();
  247. }
  248. explicit operator bool() const noexcept {
  249. return !Issues_.empty();
  250. }
  251. inline size_t Size() const {
  252. return Issues_.size();
  253. }
  254. void PrintTo(IOutputStream& out, bool oneLine = false) const;
  255. void PrintWithProgramTo(
  256. IOutputStream& out,
  257. const TString& programFilename,
  258. const TString& programText) const;
  259. inline TString ToString(bool oneLine = false) const {
  260. TStringStream out;
  261. PrintTo(out, oneLine);
  262. return out.Str();
  263. }
  264. TString ToOneLineString() const {
  265. return ToString(true);
  266. }
  267. inline void Clear() {
  268. Issues_.clear();
  269. }
  270. void Reserve(size_t capacity) {
  271. Issues_.reserve(capacity);
  272. }
  273. private:
  274. TVector<TIssue> Issues_;
  275. };
  276. class TErrorException : public yexception {
  277. const TIssueCode Code_;
  278. public:
  279. explicit TErrorException(TIssueCode code)
  280. : Code_(code)
  281. {}
  282. TIssueCode GetCode() const {
  283. return Code_;
  284. }
  285. };
  286. TIssue ExceptionToIssue(const std::exception& e, const TPosition& pos = TPosition());
  287. TMaybe<TPosition> TryParseTerminationMessage(TStringBuf& message);
  288. } // namespace NYql
  289. template <>
  290. void Out<NYql::TPosition>(IOutputStream& out, const NYql::TPosition& pos);
  291. template <>
  292. void Out<NYql::TRange>(IOutputStream& out, const NYql::TRange& pos);
  293. template <>
  294. void Out<NYql::TIssue>(IOutputStream& out, const NYql::TIssue& error);
  295. template <>
  296. struct THash<NYql::TIssue> {
  297. inline size_t operator()(const NYql::TIssue& err) const {
  298. return err.Hash();
  299. }
  300. };