1ec727ea7Spatrick //===--- Diagnostics.cpp - Helper class for error diagnostics ---*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick
9e5dd7070Spatrick #include "clang/ASTMatchers/Dynamic/Diagnostics.h"
10e5dd7070Spatrick
11e5dd7070Spatrick namespace clang {
12e5dd7070Spatrick namespace ast_matchers {
13e5dd7070Spatrick namespace dynamic {
pushContextFrame(ContextType Type,SourceRange Range)14e5dd7070Spatrick Diagnostics::ArgStream Diagnostics::pushContextFrame(ContextType Type,
15e5dd7070Spatrick SourceRange Range) {
16e5dd7070Spatrick ContextStack.emplace_back();
17e5dd7070Spatrick ContextFrame& data = ContextStack.back();
18e5dd7070Spatrick data.Type = Type;
19e5dd7070Spatrick data.Range = Range;
20e5dd7070Spatrick return ArgStream(&data.Args);
21e5dd7070Spatrick }
22e5dd7070Spatrick
Context(ConstructMatcherEnum,Diagnostics * Error,StringRef MatcherName,SourceRange MatcherRange)23e5dd7070Spatrick Diagnostics::Context::Context(ConstructMatcherEnum, Diagnostics *Error,
24e5dd7070Spatrick StringRef MatcherName,
25e5dd7070Spatrick SourceRange MatcherRange)
26e5dd7070Spatrick : Error(Error) {
27e5dd7070Spatrick Error->pushContextFrame(CT_MatcherConstruct, MatcherRange) << MatcherName;
28e5dd7070Spatrick }
29e5dd7070Spatrick
Context(MatcherArgEnum,Diagnostics * Error,StringRef MatcherName,SourceRange MatcherRange,unsigned ArgNumber)30e5dd7070Spatrick Diagnostics::Context::Context(MatcherArgEnum, Diagnostics *Error,
31e5dd7070Spatrick StringRef MatcherName,
32e5dd7070Spatrick SourceRange MatcherRange,
33e5dd7070Spatrick unsigned ArgNumber)
34e5dd7070Spatrick : Error(Error) {
35e5dd7070Spatrick Error->pushContextFrame(CT_MatcherArg, MatcherRange) << ArgNumber
36e5dd7070Spatrick << MatcherName;
37e5dd7070Spatrick }
38e5dd7070Spatrick
~Context()39e5dd7070Spatrick Diagnostics::Context::~Context() { Error->ContextStack.pop_back(); }
40e5dd7070Spatrick
OverloadContext(Diagnostics * Error)41e5dd7070Spatrick Diagnostics::OverloadContext::OverloadContext(Diagnostics *Error)
42e5dd7070Spatrick : Error(Error), BeginIndex(Error->Errors.size()) {}
43e5dd7070Spatrick
~OverloadContext()44e5dd7070Spatrick Diagnostics::OverloadContext::~OverloadContext() {
45e5dd7070Spatrick // Merge all errors that happened while in this context.
46e5dd7070Spatrick if (BeginIndex < Error->Errors.size()) {
47e5dd7070Spatrick Diagnostics::ErrorContent &Dest = Error->Errors[BeginIndex];
48e5dd7070Spatrick for (size_t i = BeginIndex + 1, e = Error->Errors.size(); i < e; ++i) {
49e5dd7070Spatrick Dest.Messages.push_back(Error->Errors[i].Messages[0]);
50e5dd7070Spatrick }
51e5dd7070Spatrick Error->Errors.resize(BeginIndex + 1);
52e5dd7070Spatrick }
53e5dd7070Spatrick }
54e5dd7070Spatrick
revertErrors()55e5dd7070Spatrick void Diagnostics::OverloadContext::revertErrors() {
56e5dd7070Spatrick // Revert the errors.
57e5dd7070Spatrick Error->Errors.resize(BeginIndex);
58e5dd7070Spatrick }
59e5dd7070Spatrick
operator <<(const Twine & Arg)60e5dd7070Spatrick Diagnostics::ArgStream &Diagnostics::ArgStream::operator<<(const Twine &Arg) {
61e5dd7070Spatrick Out->push_back(Arg.str());
62e5dd7070Spatrick return *this;
63e5dd7070Spatrick }
64e5dd7070Spatrick
addError(SourceRange Range,ErrorType Error)65e5dd7070Spatrick Diagnostics::ArgStream Diagnostics::addError(SourceRange Range,
66e5dd7070Spatrick ErrorType Error) {
67e5dd7070Spatrick Errors.emplace_back();
68e5dd7070Spatrick ErrorContent &Last = Errors.back();
69e5dd7070Spatrick Last.ContextStack = ContextStack;
70e5dd7070Spatrick Last.Messages.emplace_back();
71e5dd7070Spatrick Last.Messages.back().Range = Range;
72e5dd7070Spatrick Last.Messages.back().Type = Error;
73e5dd7070Spatrick return ArgStream(&Last.Messages.back().Args);
74e5dd7070Spatrick }
75e5dd7070Spatrick
contextTypeToFormatString(Diagnostics::ContextType Type)76e5dd7070Spatrick static StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {
77e5dd7070Spatrick switch (Type) {
78e5dd7070Spatrick case Diagnostics::CT_MatcherConstruct:
79e5dd7070Spatrick return "Error building matcher $0.";
80e5dd7070Spatrick case Diagnostics::CT_MatcherArg:
81e5dd7070Spatrick return "Error parsing argument $0 for matcher $1.";
82e5dd7070Spatrick }
83e5dd7070Spatrick llvm_unreachable("Unknown ContextType value.");
84e5dd7070Spatrick }
85e5dd7070Spatrick
errorTypeToFormatString(Diagnostics::ErrorType Type)86e5dd7070Spatrick static StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
87e5dd7070Spatrick switch (Type) {
88e5dd7070Spatrick case Diagnostics::ET_RegistryMatcherNotFound:
89e5dd7070Spatrick return "Matcher not found: $0";
90e5dd7070Spatrick case Diagnostics::ET_RegistryWrongArgCount:
91e5dd7070Spatrick return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
92e5dd7070Spatrick case Diagnostics::ET_RegistryWrongArgType:
93e5dd7070Spatrick return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
94e5dd7070Spatrick case Diagnostics::ET_RegistryNotBindable:
95e5dd7070Spatrick return "Matcher does not support binding.";
96e5dd7070Spatrick case Diagnostics::ET_RegistryAmbiguousOverload:
97e5dd7070Spatrick // TODO: Add type info about the overload error.
98e5dd7070Spatrick return "Ambiguous matcher overload.";
99e5dd7070Spatrick case Diagnostics::ET_RegistryValueNotFound:
100e5dd7070Spatrick return "Value not found: $0";
101ec727ea7Spatrick case Diagnostics::ET_RegistryUnknownEnumWithReplace:
102ec727ea7Spatrick return "Unknown value '$1' for arg $0; did you mean '$2'";
103a9ac8606Spatrick case Diagnostics::ET_RegistryNonNodeMatcher:
104a9ac8606Spatrick return "Matcher not a node matcher: $0";
105a9ac8606Spatrick case Diagnostics::ET_RegistryMatcherNoWithSupport:
106a9ac8606Spatrick return "Matcher does not support with call.";
107e5dd7070Spatrick
108e5dd7070Spatrick case Diagnostics::ET_ParserStringError:
109e5dd7070Spatrick return "Error parsing string token: <$0>";
110e5dd7070Spatrick case Diagnostics::ET_ParserNoOpenParen:
111e5dd7070Spatrick return "Error parsing matcher. Found token <$0> while looking for '('.";
112e5dd7070Spatrick case Diagnostics::ET_ParserNoCloseParen:
113e5dd7070Spatrick return "Error parsing matcher. Found end-of-code while looking for ')'.";
114e5dd7070Spatrick case Diagnostics::ET_ParserNoComma:
115e5dd7070Spatrick return "Error parsing matcher. Found token <$0> while looking for ','.";
116e5dd7070Spatrick case Diagnostics::ET_ParserNoCode:
117e5dd7070Spatrick return "End of code found while looking for token.";
118e5dd7070Spatrick case Diagnostics::ET_ParserNotAMatcher:
119e5dd7070Spatrick return "Input value is not a matcher expression.";
120e5dd7070Spatrick case Diagnostics::ET_ParserInvalidToken:
121e5dd7070Spatrick return "Invalid token <$0> found when looking for a value.";
122e5dd7070Spatrick case Diagnostics::ET_ParserMalformedBindExpr:
123e5dd7070Spatrick return "Malformed bind() expression.";
124e5dd7070Spatrick case Diagnostics::ET_ParserTrailingCode:
125e5dd7070Spatrick return "Expected end of code.";
126e5dd7070Spatrick case Diagnostics::ET_ParserNumberError:
127e5dd7070Spatrick return "Error parsing numeric literal: <$0>";
128e5dd7070Spatrick case Diagnostics::ET_ParserOverloadedType:
129e5dd7070Spatrick return "Input value has unresolved overloaded type: $0";
130a9ac8606Spatrick case Diagnostics::ET_ParserMalformedChainedExpr:
131a9ac8606Spatrick return "Period not followed by valid chained call.";
132a9ac8606Spatrick case Diagnostics::ET_ParserFailedToBuildMatcher:
133a9ac8606Spatrick return "Failed to build matcher: $0.";
134e5dd7070Spatrick
135e5dd7070Spatrick case Diagnostics::ET_None:
136e5dd7070Spatrick return "<N/A>";
137e5dd7070Spatrick }
138e5dd7070Spatrick llvm_unreachable("Unknown ErrorType value.");
139e5dd7070Spatrick }
140e5dd7070Spatrick
formatErrorString(StringRef FormatString,ArrayRef<std::string> Args,llvm::raw_ostream & OS)141e5dd7070Spatrick static void formatErrorString(StringRef FormatString,
142e5dd7070Spatrick ArrayRef<std::string> Args,
143e5dd7070Spatrick llvm::raw_ostream &OS) {
144e5dd7070Spatrick while (!FormatString.empty()) {
145e5dd7070Spatrick std::pair<StringRef, StringRef> Pieces = FormatString.split("$");
146e5dd7070Spatrick OS << Pieces.first.str();
147e5dd7070Spatrick if (Pieces.second.empty()) break;
148e5dd7070Spatrick
149e5dd7070Spatrick const char Next = Pieces.second.front();
150e5dd7070Spatrick FormatString = Pieces.second.drop_front();
151e5dd7070Spatrick if (Next >= '0' && Next <= '9') {
152e5dd7070Spatrick const unsigned Index = Next - '0';
153e5dd7070Spatrick if (Index < Args.size()) {
154e5dd7070Spatrick OS << Args[Index];
155e5dd7070Spatrick } else {
156e5dd7070Spatrick OS << "<Argument_Not_Provided>";
157e5dd7070Spatrick }
158e5dd7070Spatrick }
159e5dd7070Spatrick }
160e5dd7070Spatrick }
161e5dd7070Spatrick
maybeAddLineAndColumn(SourceRange Range,llvm::raw_ostream & OS)162e5dd7070Spatrick static void maybeAddLineAndColumn(SourceRange Range,
163e5dd7070Spatrick llvm::raw_ostream &OS) {
164e5dd7070Spatrick if (Range.Start.Line > 0 && Range.Start.Column > 0) {
165e5dd7070Spatrick OS << Range.Start.Line << ":" << Range.Start.Column << ": ";
166e5dd7070Spatrick }
167e5dd7070Spatrick }
168e5dd7070Spatrick
printContextFrameToStream(const Diagnostics::ContextFrame & Frame,llvm::raw_ostream & OS)169e5dd7070Spatrick static void printContextFrameToStream(const Diagnostics::ContextFrame &Frame,
170e5dd7070Spatrick llvm::raw_ostream &OS) {
171e5dd7070Spatrick maybeAddLineAndColumn(Frame.Range, OS);
172e5dd7070Spatrick formatErrorString(contextTypeToFormatString(Frame.Type), Frame.Args, OS);
173e5dd7070Spatrick }
174e5dd7070Spatrick
175e5dd7070Spatrick static void
printMessageToStream(const Diagnostics::ErrorContent::Message & Message,const Twine Prefix,llvm::raw_ostream & OS)176e5dd7070Spatrick printMessageToStream(const Diagnostics::ErrorContent::Message &Message,
177e5dd7070Spatrick const Twine Prefix, llvm::raw_ostream &OS) {
178e5dd7070Spatrick maybeAddLineAndColumn(Message.Range, OS);
179e5dd7070Spatrick OS << Prefix;
180e5dd7070Spatrick formatErrorString(errorTypeToFormatString(Message.Type), Message.Args, OS);
181e5dd7070Spatrick }
182e5dd7070Spatrick
printErrorContentToStream(const Diagnostics::ErrorContent & Content,llvm::raw_ostream & OS)183e5dd7070Spatrick static void printErrorContentToStream(const Diagnostics::ErrorContent &Content,
184e5dd7070Spatrick llvm::raw_ostream &OS) {
185e5dd7070Spatrick if (Content.Messages.size() == 1) {
186e5dd7070Spatrick printMessageToStream(Content.Messages[0], "", OS);
187e5dd7070Spatrick } else {
188e5dd7070Spatrick for (size_t i = 0, e = Content.Messages.size(); i != e; ++i) {
189e5dd7070Spatrick if (i != 0) OS << "\n";
190e5dd7070Spatrick printMessageToStream(Content.Messages[i],
191e5dd7070Spatrick "Candidate " + Twine(i + 1) + ": ", OS);
192e5dd7070Spatrick }
193e5dd7070Spatrick }
194e5dd7070Spatrick }
195e5dd7070Spatrick
printToStream(llvm::raw_ostream & OS) const196e5dd7070Spatrick void Diagnostics::printToStream(llvm::raw_ostream &OS) const {
197e5dd7070Spatrick for (size_t i = 0, e = Errors.size(); i != e; ++i) {
198e5dd7070Spatrick if (i != 0) OS << "\n";
199e5dd7070Spatrick printErrorContentToStream(Errors[i], OS);
200e5dd7070Spatrick }
201e5dd7070Spatrick }
202e5dd7070Spatrick
toString() const203e5dd7070Spatrick std::string Diagnostics::toString() const {
204e5dd7070Spatrick std::string S;
205e5dd7070Spatrick llvm::raw_string_ostream OS(S);
206e5dd7070Spatrick printToStream(OS);
207*12c85518Srobert return S;
208e5dd7070Spatrick }
209e5dd7070Spatrick
printToStreamFull(llvm::raw_ostream & OS) const210e5dd7070Spatrick void Diagnostics::printToStreamFull(llvm::raw_ostream &OS) const {
211e5dd7070Spatrick for (size_t i = 0, e = Errors.size(); i != e; ++i) {
212e5dd7070Spatrick if (i != 0) OS << "\n";
213e5dd7070Spatrick const ErrorContent &Error = Errors[i];
214e5dd7070Spatrick for (size_t i = 0, e = Error.ContextStack.size(); i != e; ++i) {
215e5dd7070Spatrick printContextFrameToStream(Error.ContextStack[i], OS);
216e5dd7070Spatrick OS << "\n";
217e5dd7070Spatrick }
218e5dd7070Spatrick printErrorContentToStream(Error, OS);
219e5dd7070Spatrick }
220e5dd7070Spatrick }
221e5dd7070Spatrick
toStringFull() const222e5dd7070Spatrick std::string Diagnostics::toStringFull() const {
223e5dd7070Spatrick std::string S;
224e5dd7070Spatrick llvm::raw_string_ostream OS(S);
225e5dd7070Spatrick printToStreamFull(OS);
226*12c85518Srobert return S;
227e5dd7070Spatrick }
228e5dd7070Spatrick
229e5dd7070Spatrick } // namespace dynamic
230e5dd7070Spatrick } // namespace ast_matchers
231e5dd7070Spatrick } // namespace clang
232