1 //===--- Diagnostics.h - Helper class for error diagnostics -----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// Diagnostics class to manage error messages. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H 15 #define LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H 16 17 #include "clang/ASTMatchers/Dynamic/VariantValue.h" 18 #include "clang/Basic/LLVM.h" 19 #include "llvm/ADT/ArrayRef.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/ADT/Twine.h" 22 #include "llvm/Support/raw_ostream.h" 23 #include <string> 24 #include <vector> 25 26 namespace clang { 27 namespace ast_matchers { 28 namespace dynamic { 29 30 struct SourceLocation { 31 SourceLocation() : Line(), Column() {} 32 unsigned Line; 33 unsigned Column; 34 }; 35 36 struct SourceRange { 37 SourceLocation Start; 38 SourceLocation End; 39 }; 40 41 /// A VariantValue instance annotated with its parser context. 42 struct ParserValue { 43 ParserValue() : Text(), Range(), Value() {} 44 StringRef Text; 45 SourceRange Range; 46 VariantValue Value; 47 }; 48 49 /// Helper class to manage error messages. 50 class Diagnostics { 51 public: 52 /// Parser context types. 53 enum ContextType { 54 CT_MatcherArg = 0, 55 CT_MatcherConstruct = 1 56 }; 57 58 /// All errors from the system. 59 enum ErrorType { 60 ET_None = 0, 61 62 ET_RegistryMatcherNotFound = 1, 63 ET_RegistryWrongArgCount = 2, 64 ET_RegistryWrongArgType = 3, 65 ET_RegistryNotBindable = 4, 66 ET_RegistryAmbiguousOverload = 5, 67 ET_RegistryValueNotFound = 6, 68 ET_RegistryUnknownEnumWithReplace = 7, 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_ParserNumberError = 109, 80 ET_ParserOverloadedType = 110 81 }; 82 83 /// 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 /// 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 /// About to call the constructor for a matcher. 105 enum ConstructMatcherEnum { ConstructMatcher }; 106 Context(ConstructMatcherEnum, Diagnostics *Error, StringRef MatcherName, 107 SourceRange MatcherRange); 108 /// 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 /// 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 /// Revert all errors that happened within this context. 128 void revertErrors(); 129 130 private: 131 Diagnostics *const Error; 132 unsigned BeginIndex; 133 }; 134 135 /// 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 /// 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 /// 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 /// 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 /// 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 /// 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