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_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H
16 #define LLVM_CLANG_ASTMATCHERS_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 
27 namespace clang {
28 namespace ast_matchers {
29 namespace dynamic {
30 
31 struct SourceLocation {
SourceLocationSourceLocation32   SourceLocation() : Line(), Column() {}
33   unsigned Line;
34   unsigned Column;
35 };
36 
37 struct SourceRange {
38   SourceLocation Start;
39   SourceLocation End;
40 };
41 
42 /// \brief A VariantValue instance annotated with its parser context.
43 struct ParserValue {
ParserValueParserValue44   ParserValue() : Text(), Range(), Value() {}
45   StringRef Text;
46   SourceRange Range;
47   VariantValue Value;
48 };
49 
50 /// \brief Helper class to manage error messages.
51 class Diagnostics {
52 public:
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:
ArgStream(std::vector<std::string> * Out)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   };
errors()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 
173 private:
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