1//===--- Diagnostics.h - Helper class for error diagnostics -----*- C++ -*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// Diagnostics class to manage error messages.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H
15#define LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H
16
17#include "clang/ASTMatchers/Dynamic/VariantValue.h"
18#include "clang/Basic/LLVM.h"
19#include "llvm/ADT/ArrayRef.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/ADT/Twine.h"
22#include "llvm/Support/raw_ostream.h"
23#include <string>
24#include <vector>
25
26namespace clang {
27namespace ast_matchers {
28namespace dynamic {
29
30struct SourceLocation {
31  SourceLocation() : Line(), Column() {}
32  unsigned Line;
33  unsigned Column;
34};
35
36struct SourceRange {
37  SourceLocation Start;
38  SourceLocation End;
39};
40
41/// A VariantValue instance annotated with its parser context.
42struct ParserValue {
43  ParserValue() : Text(), Range(), Value() {}
44  StringRef Text;
45  SourceRange Range;
46  VariantValue Value;
47};
48
49/// Helper class to manage error messages.
50class Diagnostics {
51public:
52  /// Parser context types.
53  enum ContextType {
54    CT_MatcherArg = 0,
55    CT_MatcherConstruct = 1
56  };
57
58  /// All errors from the system.
59  enum ErrorType {
60    ET_None = 0,
61
62    ET_RegistryMatcherNotFound = 1,
63    ET_RegistryWrongArgCount = 2,
64    ET_RegistryWrongArgType = 3,
65    ET_RegistryNotBindable = 4,
66    ET_RegistryAmbiguousOverload = 5,
67    ET_RegistryValueNotFound = 6,
68
69    ET_ParserStringError = 100,
70    ET_ParserNoOpenParen = 101,
71    ET_ParserNoCloseParen = 102,
72    ET_ParserNoComma = 103,
73    ET_ParserNoCode = 104,
74    ET_ParserNotAMatcher = 105,
75    ET_ParserInvalidToken = 106,
76    ET_ParserMalformedBindExpr = 107,
77    ET_ParserTrailingCode = 108,
78    ET_ParserNumberError = 109,
79    ET_ParserOverloadedType = 110
80  };
81
82  /// Helper stream class.
83  class ArgStream {
84  public:
85    ArgStream(std::vector<std::string> *Out) : Out(Out) {}
86    template <class T> ArgStream &operator<<(const T &Arg) {
87      return operator<<(Twine(Arg));
88    }
89    ArgStream &operator<<(const Twine &Arg);
90
91  private:
92    std::vector<std::string> *Out;
93  };
94
95  /// Class defining a parser context.
96  ///
97  /// Used by the parser to specify (possibly recursive) contexts where the
98  /// parsing/construction can fail. Any error triggered within a context will
99  /// keep information about the context chain.
100  /// This class should be used as a RAII instance in the stack.
101  struct Context {
102  public:
103    /// About to call the constructor for a matcher.
104    enum ConstructMatcherEnum { ConstructMatcher };
105    Context(ConstructMatcherEnum, Diagnostics *Error, StringRef MatcherName,
106            SourceRange MatcherRange);
107    /// About to recurse into parsing one argument for a matcher.
108    enum MatcherArgEnum { MatcherArg };
109    Context(MatcherArgEnum, Diagnostics *Error, StringRef MatcherName,
110            SourceRange MatcherRange, unsigned ArgNumber);
111    ~Context();
112
113  private:
114    Diagnostics *const Error;
115  };
116
117  /// Context for overloaded matcher construction.
118  ///
119  /// This context will take care of merging all errors that happen within it
120  /// as "candidate" overloads for the same matcher.
121  struct OverloadContext {
122  public:
123   OverloadContext(Diagnostics* Error);
124   ~OverloadContext();
125
126   /// Revert all errors that happened within this context.
127   void revertErrors();
128
129  private:
130    Diagnostics *const Error;
131    unsigned BeginIndex;
132  };
133
134  /// Add an error to the diagnostics.
135  ///
136  /// All the context information will be kept on the error message.
137  /// \return a helper class to allow the caller to pass the arguments for the
138  /// error message, using the << operator.
139  ArgStream addError(SourceRange Range, ErrorType Error);
140
141  /// Information stored for one frame of the context.
142  struct ContextFrame {
143    ContextType Type;
144    SourceRange Range;
145    std::vector<std::string> Args;
146  };
147
148  /// Information stored for each error found.
149  struct ErrorContent {
150    std::vector<ContextFrame> ContextStack;
151    struct Message {
152      SourceRange Range;
153      ErrorType Type;
154      std::vector<std::string> Args;
155    };
156    std::vector<Message> Messages;
157  };
158  ArrayRef<ErrorContent> errors() const { return Errors; }
159
160  /// Returns a simple string representation of each error.
161  ///
162  /// Each error only shows the error message without any context.
163  void printToStream(llvm::raw_ostream &OS) const;
164  std::string toString() const;
165
166  /// Returns the full string representation of each error.
167  ///
168  /// Each error message contains the full context.
169  void printToStreamFull(llvm::raw_ostream &OS) const;
170  std::string toStringFull() const;
171
172private:
173  /// Helper function used by the constructors of ContextFrame.
174  ArgStream pushContextFrame(ContextType Type, SourceRange Range);
175
176  std::vector<ContextFrame> ContextStack;
177  std::vector<ErrorContent> Errors;
178};
179
180}  // namespace dynamic
181}  // namespace ast_matchers
182}  // namespace clang
183
184#endif  // LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
185