xref: /llvm-project/mlir/lib/Query/Matcher/Diagnostics.cpp (revision 58b44c8102afb0e76d1cb70d4a5d089f70d2f657)
1 //===- Diagnostic.cpp -----------------------------------------------------===//
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 #include "Diagnostics.h"
10 #include "mlir/Query/Matcher/ErrorBuilder.h"
11 
12 namespace mlir::query::matcher::internal {
13 
14 Diagnostics::ArgStream &
operator <<(const llvm::Twine & arg)15 Diagnostics::ArgStream::operator<<(const llvm::Twine &arg) {
16   out->push_back(arg.str());
17   return *this;
18 }
19 
addError(SourceRange range,ErrorType error)20 Diagnostics::ArgStream Diagnostics::addError(SourceRange range,
21                                              ErrorType error) {
22   errorValues.emplace_back();
23   ErrorContent &last = errorValues.back();
24   last.contextStack = contextStack;
25   last.messages.emplace_back();
26   last.messages.back().range = range;
27   last.messages.back().type = error;
28   return ArgStream(&last.messages.back().args);
29 }
30 
errorTypeToFormatString(ErrorType type)31 static llvm::StringRef errorTypeToFormatString(ErrorType type) {
32   switch (type) {
33   case ErrorType::RegistryMatcherNotFound:
34     return "Matcher not found: $0";
35   case ErrorType::RegistryWrongArgCount:
36     return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
37   case ErrorType::RegistryWrongArgType:
38     return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
39   case ErrorType::RegistryValueNotFound:
40     return "Value not found: $0";
41   case ErrorType::RegistryNotBindable:
42     return "Matcher does not support binding.";
43 
44   case ErrorType::ParserStringError:
45     return "Error parsing string token: <$0>";
46   case ErrorType::ParserNoOpenParen:
47     return "Error parsing matcher. Found token <$0> while looking for '('.";
48   case ErrorType::ParserNoCloseParen:
49     return "Error parsing matcher. Found end-of-code while looking for ')'.";
50   case ErrorType::ParserNoComma:
51     return "Error parsing matcher. Found token <$0> while looking for ','.";
52   case ErrorType::ParserNoCode:
53     return "End of code found while looking for token.";
54   case ErrorType::ParserNotAMatcher:
55     return "Input value is not a matcher expression.";
56   case ErrorType::ParserInvalidToken:
57     return "Invalid token <$0> found when looking for a value.";
58   case ErrorType::ParserTrailingCode:
59     return "Unexpected end of code.";
60   case ErrorType::ParserOverloadedType:
61     return "Input value has unresolved overloaded type: $0";
62   case ErrorType::ParserMalformedChainedExpr:
63     return "Period not followed by valid chained call.";
64   case ErrorType::ParserChainedExprInvalidArg:
65     return "Missing/Invalid argument for the chained call.";
66   case ErrorType::ParserChainedExprNoCloseParen:
67     return "Missing ')' for the chained call.";
68   case ErrorType::ParserChainedExprNoOpenParen:
69     return "Missing '(' for the chained call.";
70   case ErrorType::ParserFailedToBuildMatcher:
71     return "Failed to build matcher: $0.";
72 
73   case ErrorType::None:
74     return "<N/A>";
75   }
76   llvm_unreachable("Unknown ErrorType value.");
77 }
78 
formatErrorString(llvm::StringRef formatString,llvm::ArrayRef<std::string> args,llvm::raw_ostream & os)79 static void formatErrorString(llvm::StringRef formatString,
80                               llvm::ArrayRef<std::string> args,
81                               llvm::raw_ostream &os) {
82   while (!formatString.empty()) {
83     std::pair<llvm::StringRef, llvm::StringRef> pieces =
84         formatString.split("$");
85     os << pieces.first.str();
86     if (pieces.second.empty())
87       break;
88 
89     const char next = pieces.second.front();
90     formatString = pieces.second.drop_front();
91     if (next >= '0' && next <= '9') {
92       const unsigned index = next - '0';
93       if (index < args.size()) {
94         os << args[index];
95       } else {
96         os << "<Argument_Not_Provided>";
97       }
98     }
99   }
100 }
101 
maybeAddLineAndColumn(SourceRange range,llvm::raw_ostream & os)102 static void maybeAddLineAndColumn(SourceRange range, llvm::raw_ostream &os) {
103   if (range.start.line > 0 && range.start.column > 0) {
104     os << range.start.line << ":" << range.start.column << ": ";
105   }
106 }
107 
printMessage(const Diagnostics::ErrorContent::Message & message,const llvm::Twine prefix,llvm::raw_ostream & os) const108 void Diagnostics::printMessage(
109     const Diagnostics::ErrorContent::Message &message, const llvm::Twine prefix,
110     llvm::raw_ostream &os) const {
111   maybeAddLineAndColumn(message.range, os);
112   os << prefix;
113   formatErrorString(errorTypeToFormatString(message.type), message.args, os);
114 }
115 
printErrorContent(const Diagnostics::ErrorContent & content,llvm::raw_ostream & os) const116 void Diagnostics::printErrorContent(const Diagnostics::ErrorContent &content,
117                                     llvm::raw_ostream &os) const {
118   if (content.messages.size() == 1) {
119     printMessage(content.messages[0], "", os);
120   } else {
121     for (size_t i = 0, e = content.messages.size(); i != e; ++i) {
122       if (i != 0)
123         os << "\n";
124       printMessage(content.messages[i],
125                    "Candidate " + llvm::Twine(i + 1) + ": ", os);
126     }
127   }
128 }
129 
print(llvm::raw_ostream & os) const130 void Diagnostics::print(llvm::raw_ostream &os) const {
131   for (const ErrorContent &error : errorValues) {
132     if (&error != &errorValues.front())
133       os << "\n";
134     printErrorContent(error, os);
135   }
136 }
137 
138 } // namespace mlir::query::matcher::internal
139