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() = default; 32 unsigned Line = 0; 33 unsigned Column = 0; 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 { ParserValueParserValue43 ParserValue() {} 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 ET_RegistryNonNodeMatcher = 8, 70 ET_RegistryMatcherNoWithSupport = 9, 71 72 ET_ParserStringError = 100, 73 ET_ParserNoOpenParen = 101, 74 ET_ParserNoCloseParen = 102, 75 ET_ParserNoComma = 103, 76 ET_ParserNoCode = 104, 77 ET_ParserNotAMatcher = 105, 78 ET_ParserInvalidToken = 106, 79 ET_ParserMalformedBindExpr = 107, 80 ET_ParserTrailingCode = 108, 81 ET_ParserNumberError = 109, 82 ET_ParserOverloadedType = 110, 83 ET_ParserMalformedChainedExpr = 111, 84 ET_ParserFailedToBuildMatcher = 112 85 }; 86 87 /// Helper stream class. 88 class ArgStream { 89 public: ArgStream(std::vector<std::string> * Out)90 ArgStream(std::vector<std::string> *Out) : Out(Out) {} 91 template <class T> ArgStream &operator<<(const T &Arg) { 92 return operator<<(Twine(Arg)); 93 } 94 ArgStream &operator<<(const Twine &Arg); 95 96 private: 97 std::vector<std::string> *Out; 98 }; 99 100 /// Class defining a parser context. 101 /// 102 /// Used by the parser to specify (possibly recursive) contexts where the 103 /// parsing/construction can fail. Any error triggered within a context will 104 /// keep information about the context chain. 105 /// This class should be used as a RAII instance in the stack. 106 struct Context { 107 public: 108 /// About to call the constructor for a matcher. 109 enum ConstructMatcherEnum { ConstructMatcher }; 110 Context(ConstructMatcherEnum, Diagnostics *Error, StringRef MatcherName, 111 SourceRange MatcherRange); 112 /// About to recurse into parsing one argument for a matcher. 113 enum MatcherArgEnum { MatcherArg }; 114 Context(MatcherArgEnum, Diagnostics *Error, StringRef MatcherName, 115 SourceRange MatcherRange, unsigned ArgNumber); 116 ~Context(); 117 118 private: 119 Diagnostics *const Error; 120 }; 121 122 /// Context for overloaded matcher construction. 123 /// 124 /// This context will take care of merging all errors that happen within it 125 /// as "candidate" overloads for the same matcher. 126 struct OverloadContext { 127 public: 128 OverloadContext(Diagnostics* Error); 129 ~OverloadContext(); 130 131 /// Revert all errors that happened within this context. 132 void revertErrors(); 133 134 private: 135 Diagnostics *const Error; 136 unsigned BeginIndex; 137 }; 138 139 /// Add an error to the diagnostics. 140 /// 141 /// All the context information will be kept on the error message. 142 /// \return a helper class to allow the caller to pass the arguments for the 143 /// error message, using the << operator. 144 ArgStream addError(SourceRange Range, ErrorType Error); 145 146 /// Information stored for one frame of the context. 147 struct ContextFrame { 148 ContextType Type; 149 SourceRange Range; 150 std::vector<std::string> Args; 151 }; 152 153 /// Information stored for each error found. 154 struct ErrorContent { 155 std::vector<ContextFrame> ContextStack; 156 struct Message { 157 SourceRange Range; 158 ErrorType Type; 159 std::vector<std::string> Args; 160 }; 161 std::vector<Message> Messages; 162 }; errors()163 ArrayRef<ErrorContent> errors() const { return Errors; } 164 165 /// Returns a simple string representation of each error. 166 /// 167 /// Each error only shows the error message without any context. 168 void printToStream(llvm::raw_ostream &OS) const; 169 std::string toString() const; 170 171 /// Returns the full string representation of each error. 172 /// 173 /// Each error message contains the full context. 174 void printToStreamFull(llvm::raw_ostream &OS) const; 175 std::string toStringFull() const; 176 177 private: 178 /// Helper function used by the constructors of ContextFrame. 179 ArgStream pushContextFrame(ContextType Type, SourceRange Range); 180 181 std::vector<ContextFrame> ContextStack; 182 std::vector<ErrorContent> Errors; 183 }; 184 185 } // namespace dynamic 186 } // namespace ast_matchers 187 } // namespace clang 188 189 #endif // LLVM_CLANG_ASTMATCHERS_DYNAMIC_DIAGNOSTICS_H 190