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