1259701Sdim//===--- Diagnostics.h - Helper class for error diagnostics -----*- C++ -*-===//
2259701Sdim//
3259701Sdim//                     The LLVM Compiler Infrastructure
4259701Sdim//
5259701Sdim// This file is distributed under the University of Illinois Open Source
6259701Sdim// License. See LICENSE.TXT for details.
7259701Sdim//
8259701Sdim//===----------------------------------------------------------------------===//
9259701Sdim///
10259701Sdim/// \file
11259701Sdim/// \brief Diagnostics class to manage error messages.
12259701Sdim///
13259701Sdim//===----------------------------------------------------------------------===//
14259701Sdim
15259701Sdim#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
16259701Sdim#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
17259701Sdim
18259701Sdim#include <string>
19259701Sdim#include <vector>
20259701Sdim
21259701Sdim#include "clang/ASTMatchers/Dynamic/VariantValue.h"
22259701Sdim#include "clang/Basic/LLVM.h"
23259701Sdim#include "llvm/ADT/ArrayRef.h"
24259701Sdim#include "llvm/ADT/StringRef.h"
25259701Sdim#include "llvm/ADT/Twine.h"
26259701Sdim#include "llvm/Support/raw_ostream.h"
27259701Sdim
28259701Sdimnamespace clang {
29259701Sdimnamespace ast_matchers {
30259701Sdimnamespace dynamic {
31259701Sdim
32259701Sdimstruct SourceLocation {
33259701Sdim  SourceLocation() : Line(), Column() {}
34259701Sdim  unsigned Line;
35259701Sdim  unsigned Column;
36259701Sdim};
37259701Sdim
38259701Sdimstruct SourceRange {
39259701Sdim  SourceLocation Start;
40259701Sdim  SourceLocation End;
41259701Sdim};
42259701Sdim
43259701Sdim/// \brief A VariantValue instance annotated with its parser context.
44259701Sdimstruct ParserValue {
45259701Sdim  ParserValue() : Text(), Range(), Value() {}
46259701Sdim  StringRef Text;
47259701Sdim  SourceRange Range;
48259701Sdim  VariantValue Value;
49259701Sdim};
50259701Sdim
51259701Sdim/// \brief Helper class to manage error messages.
52259701Sdimclass Diagnostics {
53259701Sdimpublic:
54259701Sdim  /// \brief Parser context types.
55259701Sdim  enum ContextType {
56259701Sdim    CT_MatcherArg = 0,
57259701Sdim    CT_MatcherConstruct = 1
58259701Sdim  };
59259701Sdim
60259701Sdim  /// \brief All errors from the system.
61259701Sdim  enum ErrorType {
62259701Sdim    ET_None = 0,
63259701Sdim
64259701Sdim    ET_RegistryNotFound = 1,
65259701Sdim    ET_RegistryWrongArgCount = 2,
66259701Sdim    ET_RegistryWrongArgType = 3,
67259701Sdim    ET_RegistryNotBindable = 4,
68259701Sdim    ET_RegistryAmbiguousOverload = 5,
69259701Sdim
70259701Sdim    ET_ParserStringError = 100,
71259701Sdim    ET_ParserNoOpenParen = 101,
72259701Sdim    ET_ParserNoCloseParen = 102,
73259701Sdim    ET_ParserNoComma = 103,
74259701Sdim    ET_ParserNoCode = 104,
75259701Sdim    ET_ParserNotAMatcher = 105,
76259701Sdim    ET_ParserInvalidToken = 106,
77259701Sdim    ET_ParserMalformedBindExpr = 107,
78259701Sdim    ET_ParserTrailingCode = 108,
79259701Sdim    ET_ParserUnsignedError = 109,
80259701Sdim    ET_ParserOverloadedType = 110
81259701Sdim  };
82259701Sdim
83259701Sdim  /// \brief Helper stream class.
84259701Sdim  class ArgStream {
85259701Sdim  public:
86259701Sdim    ArgStream(std::vector<std::string> *Out) : Out(Out) {}
87259701Sdim    template <class T> ArgStream &operator<<(const T &Arg) {
88259701Sdim      return operator<<(Twine(Arg));
89259701Sdim    }
90259701Sdim    ArgStream &operator<<(const Twine &Arg);
91259701Sdim
92259701Sdim  private:
93259701Sdim    std::vector<std::string> *Out;
94259701Sdim  };
95259701Sdim
96259701Sdim  /// \brief Class defining a parser context.
97259701Sdim  ///
98259701Sdim  /// Used by the parser to specify (possibly recursive) contexts where the
99259701Sdim  /// parsing/construction can fail. Any error triggered within a context will
100259701Sdim  /// keep information about the context chain.
101259701Sdim  /// This class should be used as a RAII instance in the stack.
102259701Sdim  struct Context {
103259701Sdim  public:
104259701Sdim    /// \brief About to call the constructor for a matcher.
105259701Sdim    enum ConstructMatcherEnum { ConstructMatcher };
106259701Sdim    Context(ConstructMatcherEnum, Diagnostics *Error, StringRef MatcherName,
107259701Sdim            const SourceRange &MatcherRange);
108259701Sdim    /// \brief About to recurse into parsing one argument for a matcher.
109259701Sdim    enum MatcherArgEnum { MatcherArg };
110259701Sdim    Context(MatcherArgEnum, Diagnostics *Error, StringRef MatcherName,
111259701Sdim            const SourceRange &MatcherRange, unsigned ArgNumber);
112259701Sdim    ~Context();
113259701Sdim
114259701Sdim  private:
115259701Sdim    Diagnostics *const Error;
116259701Sdim  };
117259701Sdim
118259701Sdim  /// \brief Context for overloaded matcher construction.
119259701Sdim  ///
120259701Sdim  /// This context will take care of merging all errors that happen within it
121259701Sdim  /// as "candidate" overloads for the same matcher.
122259701Sdim  struct OverloadContext {
123259701Sdim  public:
124259701Sdim   OverloadContext(Diagnostics* Error);
125259701Sdim   ~OverloadContext();
126259701Sdim
127259701Sdim   /// \brief Revert all errors that happened within this context.
128259701Sdim   void revertErrors();
129259701Sdim
130259701Sdim  private:
131259701Sdim    Diagnostics *const Error;
132259701Sdim    unsigned BeginIndex;
133259701Sdim  };
134259701Sdim
135259701Sdim  /// \brief Add an error to the diagnostics.
136259701Sdim  ///
137259701Sdim  /// All the context information will be kept on the error message.
138259701Sdim  /// \return a helper class to allow the caller to pass the arguments for the
139259701Sdim  /// error message, using the << operator.
140259701Sdim  ArgStream addError(const SourceRange &Range, ErrorType Error);
141259701Sdim
142259701Sdim  /// \brief Information stored for one frame of the context.
143259701Sdim  struct ContextFrame {
144259701Sdim    ContextType Type;
145259701Sdim    SourceRange Range;
146259701Sdim    std::vector<std::string> Args;
147259701Sdim  };
148259701Sdim
149259701Sdim  /// \brief Information stored for each error found.
150259701Sdim  struct ErrorContent {
151259701Sdim    std::vector<ContextFrame> ContextStack;
152259701Sdim    struct Message {
153259701Sdim      SourceRange Range;
154259701Sdim      ErrorType Type;
155259701Sdim      std::vector<std::string> Args;
156259701Sdim    };
157259701Sdim    std::vector<Message> Messages;
158259701Sdim  };
159259701Sdim  ArrayRef<ErrorContent> errors() const { return Errors; }
160259701Sdim
161259701Sdim  /// \brief Returns a simple string representation of each error.
162259701Sdim  ///
163259701Sdim  /// Each error only shows the error message without any context.
164259701Sdim  void printToStream(llvm::raw_ostream &OS) const;
165259701Sdim  std::string toString() const;
166259701Sdim
167259701Sdim  /// \brief Returns the full string representation of each error.
168259701Sdim  ///
169259701Sdim  /// Each error message contains the full context.
170259701Sdim  void printToStreamFull(llvm::raw_ostream &OS) const;
171259701Sdim  std::string toStringFull() const;
172259701Sdim
173259701Sdimprivate:
174259701Sdim  /// \brief Helper function used by the constructors of ContextFrame.
175259701Sdim  ArgStream pushContextFrame(ContextType Type, SourceRange Range);
176259701Sdim
177259701Sdim  std::vector<ContextFrame> ContextStack;
178259701Sdim  std::vector<ErrorContent> Errors;
179259701Sdim};
180259701Sdim
181259701Sdim}  // namespace dynamic
182259701Sdim}  // namespace ast_matchers
183259701Sdim}  // namespace clang
184259701Sdim
185259701Sdim#endif  // LLVM_CLANG_AST_MATCHERS_DYNAMIC_DIAGNOSTICS_H
186