blob: b0abdc7cf810145d9de555409a9e1cd68f1dfce6 [file] [log] [blame]
Manuel Klimek24db0f02013-05-14 09:13:00 +00001//===--- Diagnostics.cpp - 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#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
11
12namespace clang {
13namespace ast_matchers {
14namespace dynamic {
15
Samuel Benzaquena37bb8c2013-07-18 19:47:59 +000016Diagnostics::ArgStream Diagnostics::pushContextFrame(ContextType Type,
17 SourceRange Range) {
18 ContextStack.push_back(ContextFrame());
19 ContextFrame& data = ContextStack.back();
20 data.Type = Type;
21 data.Range = Range;
22 return ArgStream(&data.Args);
23}
24
25Diagnostics::Context::Context(ConstructMatcherEnum, Diagnostics *Error,
26 StringRef MatcherName,
27 const SourceRange &MatcherRange)
28 : Error(Error) {
29 Error->pushContextFrame(CT_MatcherConstruct, MatcherRange) << MatcherName;
30}
31
32Diagnostics::Context::Context(MatcherArgEnum, Diagnostics *Error,
33 StringRef MatcherName,
34 const SourceRange &MatcherRange,
35 unsigned ArgNumber)
36 : Error(Error) {
37 Error->pushContextFrame(CT_MatcherArg, MatcherRange) << ArgNumber
38 << MatcherName;
39}
40
41Diagnostics::Context::~Context() { Error->ContextStack.pop_back(); }
42
Samuel Benzaquene0b2c8e2013-07-22 16:13:57 +000043Diagnostics::OverloadContext::OverloadContext(Diagnostics *Error)
44 : Error(Error), BeginIndex(Error->Errors.size()) {}
45
46Diagnostics::OverloadContext::~OverloadContext() {
47 // Merge all errors that happened while in this context.
48 if (BeginIndex < Error->Errors.size()) {
49 Diagnostics::ErrorContent &Dest = Error->Errors[BeginIndex];
50 for (size_t i = BeginIndex + 1, e = Error->Errors.size(); i < e; ++i) {
51 Dest.Messages.push_back(Error->Errors[i].Messages[0]);
52 }
53 Error->Errors.resize(BeginIndex + 1);
54 }
55}
56
57void Diagnostics::OverloadContext::revertErrors() {
58 // Revert the errors.
59 Error->Errors.resize(BeginIndex);
60}
61
Samuel Benzaquena37bb8c2013-07-18 19:47:59 +000062Diagnostics::ArgStream &Diagnostics::ArgStream::operator<<(const Twine &Arg) {
Manuel Klimek24db0f02013-05-14 09:13:00 +000063 Out->push_back(Arg.str());
64 return *this;
65}
66
Samuel Benzaquena37bb8c2013-07-18 19:47:59 +000067Diagnostics::ArgStream Diagnostics::addError(const SourceRange &Range,
68 ErrorType Error) {
69 Errors.push_back(ErrorContent());
70 ErrorContent &Last = Errors.back();
71 Last.ContextStack = ContextStack;
Samuel Benzaquene0b2c8e2013-07-22 16:13:57 +000072 Last.Messages.push_back(ErrorContent::Message());
73 Last.Messages.back().Range = Range;
74 Last.Messages.back().Type = Error;
75 return ArgStream(&Last.Messages.back().Args);
Samuel Benzaquena37bb8c2013-07-18 19:47:59 +000076}
77
Samuel Benzaquenb8372482013-07-19 20:02:35 +000078StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {
Samuel Benzaquena37bb8c2013-07-18 19:47:59 +000079 switch (Type) {
80 case Diagnostics::CT_MatcherConstruct:
81 return "Error building matcher $0.";
82 case Diagnostics::CT_MatcherArg:
83 return "Error parsing argument $0 for matcher $1.";
84 }
85 llvm_unreachable("Unknown ContextType value.");
Manuel Klimek24db0f02013-05-14 09:13:00 +000086}
87
Samuel Benzaquenb8372482013-07-19 20:02:35 +000088StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
Manuel Klimek24db0f02013-05-14 09:13:00 +000089 switch (Type) {
Samuel Benzaquenf434c4f2014-04-14 13:51:21 +000090 case Diagnostics::ET_RegistryMatcherNotFound:
Manuel Klimek24db0f02013-05-14 09:13:00 +000091 return "Matcher not found: $0";
92 case Diagnostics::ET_RegistryWrongArgCount:
93 return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
94 case Diagnostics::ET_RegistryWrongArgType:
Samuel Benzaquen81ef9292013-06-20 14:28:32 +000095 return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
Samuel Benzaquen31edb512013-06-03 19:31:08 +000096 case Diagnostics::ET_RegistryNotBindable:
97 return "Matcher does not support binding.";
Samuel Benzaquene0b2c8e2013-07-22 16:13:57 +000098 case Diagnostics::ET_RegistryAmbiguousOverload:
99 // TODO: Add type info about the overload error.
100 return "Ambiguous matcher overload.";
Samuel Benzaquenf434c4f2014-04-14 13:51:21 +0000101 case Diagnostics::ET_RegistryValueNotFound:
102 return "Value not found: $0";
Manuel Klimek24db0f02013-05-14 09:13:00 +0000103
104 case Diagnostics::ET_ParserStringError:
105 return "Error parsing string token: <$0>";
Manuel Klimek24db0f02013-05-14 09:13:00 +0000106 case Diagnostics::ET_ParserNoOpenParen:
107 return "Error parsing matcher. Found token <$0> while looking for '('.";
108 case Diagnostics::ET_ParserNoCloseParen:
109 return "Error parsing matcher. Found end-of-code while looking for ')'.";
110 case Diagnostics::ET_ParserNoComma:
111 return "Error parsing matcher. Found token <$0> while looking for ','.";
112 case Diagnostics::ET_ParserNoCode:
113 return "End of code found while looking for token.";
114 case Diagnostics::ET_ParserNotAMatcher:
115 return "Input value is not a matcher expression.";
116 case Diagnostics::ET_ParserInvalidToken:
117 return "Invalid token <$0> found when looking for a value.";
Samuel Benzaquen31edb512013-06-03 19:31:08 +0000118 case Diagnostics::ET_ParserMalformedBindExpr:
119 return "Malformed bind() expression.";
120 case Diagnostics::ET_ParserTrailingCode:
121 return "Expected end of code.";
Samuel Benzaquenc31b3522013-06-04 15:46:22 +0000122 case Diagnostics::ET_ParserUnsignedError:
123 return "Error parsing unsigned token: <$0>";
Samuel Benzaquenc6f2c9b2013-06-21 15:51:31 +0000124 case Diagnostics::ET_ParserOverloadedType:
125 return "Input value has unresolved overloaded type: $0";
Manuel Klimek24db0f02013-05-14 09:13:00 +0000126
127 case Diagnostics::ET_None:
128 return "<N/A>";
129 }
130 llvm_unreachable("Unknown ErrorType value.");
131}
132
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000133void formatErrorString(StringRef FormatString, ArrayRef<std::string> Args,
134 llvm::raw_ostream &OS) {
Manuel Klimek24db0f02013-05-14 09:13:00 +0000135 while (!FormatString.empty()) {
136 std::pair<StringRef, StringRef> Pieces = FormatString.split("$");
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000137 OS << Pieces.first.str();
Manuel Klimek24db0f02013-05-14 09:13:00 +0000138 if (Pieces.second.empty()) break;
139
140 const char Next = Pieces.second.front();
141 FormatString = Pieces.second.drop_front();
142 if (Next >= '0' && Next <= '9') {
143 const unsigned Index = Next - '0';
144 if (Index < Args.size()) {
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000145 OS << Args[Index];
Manuel Klimek24db0f02013-05-14 09:13:00 +0000146 } else {
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000147 OS << "<Argument_Not_Provided>";
Manuel Klimek24db0f02013-05-14 09:13:00 +0000148 }
149 }
150 }
Manuel Klimek24db0f02013-05-14 09:13:00 +0000151}
152
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000153static void maybeAddLineAndColumn(const SourceRange &Range,
154 llvm::raw_ostream &OS) {
155 if (Range.Start.Line > 0 && Range.Start.Column > 0) {
156 OS << Range.Start.Line << ":" << Range.Start.Column << ": ";
Samuel Benzaquena37bb8c2013-07-18 19:47:59 +0000157 }
Manuel Klimek24db0f02013-05-14 09:13:00 +0000158}
159
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000160static void printContextFrameToStream(const Diagnostics::ContextFrame &Frame,
161 llvm::raw_ostream &OS) {
162 maybeAddLineAndColumn(Frame.Range, OS);
163 formatErrorString(contextTypeToFormatString(Frame.Type), Frame.Args, OS);
164}
165
Samuel Benzaquene0b2c8e2013-07-22 16:13:57 +0000166static void
167printMessageToStream(const Diagnostics::ErrorContent::Message &Message,
168 const Twine Prefix, llvm::raw_ostream &OS) {
169 maybeAddLineAndColumn(Message.Range, OS);
170 OS << Prefix;
171 formatErrorString(errorTypeToFormatString(Message.Type), Message.Args, OS);
172}
173
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000174static void printErrorContentToStream(const Diagnostics::ErrorContent &Content,
175 llvm::raw_ostream &OS) {
Samuel Benzaquene0b2c8e2013-07-22 16:13:57 +0000176 if (Content.Messages.size() == 1) {
177 printMessageToStream(Content.Messages[0], "", OS);
178 } else {
179 for (size_t i = 0, e = Content.Messages.size(); i != e; ++i) {
180 if (i != 0) OS << "\n";
181 printMessageToStream(Content.Messages[i],
182 "Candidate " + Twine(i + 1) + ": ", OS);
183 }
184 }
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000185}
186
187void Diagnostics::printToStream(llvm::raw_ostream &OS) const {
Samuel Benzaquena37bb8c2013-07-18 19:47:59 +0000188 for (size_t i = 0, e = Errors.size(); i != e; ++i) {
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000189 if (i != 0) OS << "\n";
190 printErrorContentToStream(Errors[i], OS);
191 }
192}
193
194std::string Diagnostics::toString() const {
195 std::string S;
196 llvm::raw_string_ostream OS(S);
197 printToStream(OS);
198 return OS.str();
199}
200
201void Diagnostics::printToStreamFull(llvm::raw_ostream &OS) const {
202 for (size_t i = 0, e = Errors.size(); i != e; ++i) {
203 if (i != 0) OS << "\n";
Samuel Benzaquena37bb8c2013-07-18 19:47:59 +0000204 const ErrorContent &Error = Errors[i];
205 for (size_t i = 0, e = Error.ContextStack.size(); i != e; ++i) {
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000206 printContextFrameToStream(Error.ContextStack[i], OS);
207 OS << "\n";
Samuel Benzaquena37bb8c2013-07-18 19:47:59 +0000208 }
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000209 printErrorContentToStream(Error, OS);
Manuel Klimek24db0f02013-05-14 09:13:00 +0000210 }
Samuel Benzaquenb8372482013-07-19 20:02:35 +0000211}
212
213std::string Diagnostics::toStringFull() const {
214 std::string S;
215 llvm::raw_string_ostream OS(S);
216 printToStreamFull(OS);
217 return OS.str();
Manuel Klimek24db0f02013-05-14 09:13:00 +0000218}
219
220} // namespace dynamic
221} // namespace ast_matchers
222} // namespace clang