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 { 32 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 { 44 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: 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 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 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(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 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