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