Diagnostics.cpp revision 288943
1259701Sdim//===--- Diagnostics.cpp - Helper class for error diagnostics -----*- C++ -*-===//
2259701Sdim//
3259701Sdim//                     The LLVM Compiler Infrastructure
4259701Sdim//
5259701Sdim// This file is distributed under the University of Illinois Open Source
6259701Sdim// License. See LICENSE.TXT for details.
7259701Sdim//
8259701Sdim//===----------------------------------------------------------------------===//
9259701Sdim
10259701Sdim#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
11259701Sdim
12259701Sdimnamespace clang {
13259701Sdimnamespace ast_matchers {
14259701Sdimnamespace dynamic {
15259701SdimDiagnostics::ArgStream Diagnostics::pushContextFrame(ContextType Type,
16259701Sdim                                                     SourceRange Range) {
17288943Sdim  ContextStack.emplace_back();
18259701Sdim  ContextFrame& data = ContextStack.back();
19259701Sdim  data.Type = Type;
20259701Sdim  data.Range = Range;
21259701Sdim  return ArgStream(&data.Args);
22259701Sdim}
23259701Sdim
24259701SdimDiagnostics::Context::Context(ConstructMatcherEnum, Diagnostics *Error,
25259701Sdim                              StringRef MatcherName,
26259701Sdim                              const SourceRange &MatcherRange)
27259701Sdim    : Error(Error) {
28259701Sdim  Error->pushContextFrame(CT_MatcherConstruct, MatcherRange) << MatcherName;
29259701Sdim}
30259701Sdim
31259701SdimDiagnostics::Context::Context(MatcherArgEnum, Diagnostics *Error,
32259701Sdim                              StringRef MatcherName,
33259701Sdim                              const SourceRange &MatcherRange,
34259701Sdim                              unsigned ArgNumber)
35259701Sdim    : Error(Error) {
36259701Sdim  Error->pushContextFrame(CT_MatcherArg, MatcherRange) << ArgNumber
37259701Sdim                                                       << MatcherName;
38259701Sdim}
39259701Sdim
40259701SdimDiagnostics::Context::~Context() { Error->ContextStack.pop_back(); }
41259701Sdim
42259701SdimDiagnostics::OverloadContext::OverloadContext(Diagnostics *Error)
43259701Sdim    : Error(Error), BeginIndex(Error->Errors.size()) {}
44259701Sdim
45259701SdimDiagnostics::OverloadContext::~OverloadContext() {
46259701Sdim  // Merge all errors that happened while in this context.
47259701Sdim  if (BeginIndex < Error->Errors.size()) {
48259701Sdim    Diagnostics::ErrorContent &Dest = Error->Errors[BeginIndex];
49259701Sdim    for (size_t i = BeginIndex + 1, e = Error->Errors.size(); i < e; ++i) {
50259701Sdim      Dest.Messages.push_back(Error->Errors[i].Messages[0]);
51259701Sdim    }
52259701Sdim    Error->Errors.resize(BeginIndex + 1);
53259701Sdim  }
54259701Sdim}
55259701Sdim
56259701Sdimvoid Diagnostics::OverloadContext::revertErrors() {
57259701Sdim  // Revert the errors.
58259701Sdim  Error->Errors.resize(BeginIndex);
59259701Sdim}
60259701Sdim
61259701SdimDiagnostics::ArgStream &Diagnostics::ArgStream::operator<<(const Twine &Arg) {
62259701Sdim  Out->push_back(Arg.str());
63259701Sdim  return *this;
64259701Sdim}
65259701Sdim
66259701SdimDiagnostics::ArgStream Diagnostics::addError(const SourceRange &Range,
67259701Sdim                                             ErrorType Error) {
68288943Sdim  Errors.emplace_back();
69259701Sdim  ErrorContent &Last = Errors.back();
70259701Sdim  Last.ContextStack = ContextStack;
71288943Sdim  Last.Messages.emplace_back();
72259701Sdim  Last.Messages.back().Range = Range;
73259701Sdim  Last.Messages.back().Type = Error;
74259701Sdim  return ArgStream(&Last.Messages.back().Args);
75259701Sdim}
76259701Sdim
77288943Sdimstatic StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {
78259701Sdim  switch (Type) {
79259701Sdim    case Diagnostics::CT_MatcherConstruct:
80259701Sdim      return "Error building matcher $0.";
81259701Sdim    case Diagnostics::CT_MatcherArg:
82259701Sdim      return "Error parsing argument $0 for matcher $1.";
83259701Sdim  }
84259701Sdim  llvm_unreachable("Unknown ContextType value.");
85259701Sdim}
86259701Sdim
87288943Sdimstatic StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
88259701Sdim  switch (Type) {
89276479Sdim  case Diagnostics::ET_RegistryMatcherNotFound:
90259701Sdim    return "Matcher not found: $0";
91259701Sdim  case Diagnostics::ET_RegistryWrongArgCount:
92259701Sdim    return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
93259701Sdim  case Diagnostics::ET_RegistryWrongArgType:
94259701Sdim    return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
95259701Sdim  case Diagnostics::ET_RegistryNotBindable:
96259701Sdim    return "Matcher does not support binding.";
97259701Sdim  case Diagnostics::ET_RegistryAmbiguousOverload:
98259701Sdim    // TODO: Add type info about the overload error.
99259701Sdim    return "Ambiguous matcher overload.";
100276479Sdim  case Diagnostics::ET_RegistryValueNotFound:
101276479Sdim    return "Value not found: $0";
102259701Sdim
103259701Sdim  case Diagnostics::ET_ParserStringError:
104259701Sdim    return "Error parsing string token: <$0>";
105259701Sdim  case Diagnostics::ET_ParserNoOpenParen:
106259701Sdim    return "Error parsing matcher. Found token <$0> while looking for '('.";
107259701Sdim  case Diagnostics::ET_ParserNoCloseParen:
108259701Sdim    return "Error parsing matcher. Found end-of-code while looking for ')'.";
109259701Sdim  case Diagnostics::ET_ParserNoComma:
110259701Sdim    return "Error parsing matcher. Found token <$0> while looking for ','.";
111259701Sdim  case Diagnostics::ET_ParserNoCode:
112259701Sdim    return "End of code found while looking for token.";
113259701Sdim  case Diagnostics::ET_ParserNotAMatcher:
114259701Sdim    return "Input value is not a matcher expression.";
115259701Sdim  case Diagnostics::ET_ParserInvalidToken:
116259701Sdim    return "Invalid token <$0> found when looking for a value.";
117259701Sdim  case Diagnostics::ET_ParserMalformedBindExpr:
118259701Sdim    return "Malformed bind() expression.";
119259701Sdim  case Diagnostics::ET_ParserTrailingCode:
120259701Sdim    return "Expected end of code.";
121259701Sdim  case Diagnostics::ET_ParserUnsignedError:
122259701Sdim    return "Error parsing unsigned token: <$0>";
123259701Sdim  case Diagnostics::ET_ParserOverloadedType:
124259701Sdim    return "Input value has unresolved overloaded type: $0";
125259701Sdim
126259701Sdim  case Diagnostics::ET_None:
127259701Sdim    return "<N/A>";
128259701Sdim  }
129259701Sdim  llvm_unreachable("Unknown ErrorType value.");
130259701Sdim}
131259701Sdim
132288943Sdimstatic void formatErrorString(StringRef FormatString,
133288943Sdim                              ArrayRef<std::string> Args,
134288943Sdim                              llvm::raw_ostream &OS) {
135259701Sdim  while (!FormatString.empty()) {
136259701Sdim    std::pair<StringRef, StringRef> Pieces = FormatString.split("$");
137259701Sdim    OS << Pieces.first.str();
138259701Sdim    if (Pieces.second.empty()) break;
139259701Sdim
140259701Sdim    const char Next = Pieces.second.front();
141259701Sdim    FormatString = Pieces.second.drop_front();
142259701Sdim    if (Next >= '0' && Next <= '9') {
143259701Sdim      const unsigned Index = Next - '0';
144259701Sdim      if (Index < Args.size()) {
145259701Sdim        OS << Args[Index];
146259701Sdim      } else {
147259701Sdim        OS << "<Argument_Not_Provided>";
148259701Sdim      }
149259701Sdim    }
150259701Sdim  }
151259701Sdim}
152259701Sdim
153259701Sdimstatic void maybeAddLineAndColumn(const SourceRange &Range,
154259701Sdim                                  llvm::raw_ostream &OS) {
155259701Sdim  if (Range.Start.Line > 0 && Range.Start.Column > 0) {
156259701Sdim    OS << Range.Start.Line << ":" << Range.Start.Column << ": ";
157259701Sdim  }
158259701Sdim}
159259701Sdim
160259701Sdimstatic void printContextFrameToStream(const Diagnostics::ContextFrame &Frame,
161259701Sdim                                      llvm::raw_ostream &OS) {
162259701Sdim  maybeAddLineAndColumn(Frame.Range, OS);
163259701Sdim  formatErrorString(contextTypeToFormatString(Frame.Type), Frame.Args, OS);
164259701Sdim}
165259701Sdim
166259701Sdimstatic void
167259701SdimprintMessageToStream(const Diagnostics::ErrorContent::Message &Message,
168259701Sdim                     const Twine Prefix, llvm::raw_ostream &OS) {
169259701Sdim  maybeAddLineAndColumn(Message.Range, OS);
170259701Sdim  OS << Prefix;
171259701Sdim  formatErrorString(errorTypeToFormatString(Message.Type), Message.Args, OS);
172259701Sdim}
173259701Sdim
174259701Sdimstatic void printErrorContentToStream(const Diagnostics::ErrorContent &Content,
175259701Sdim                                      llvm::raw_ostream &OS) {
176259701Sdim  if (Content.Messages.size() == 1) {
177259701Sdim    printMessageToStream(Content.Messages[0], "", OS);
178259701Sdim  } else {
179259701Sdim    for (size_t i = 0, e = Content.Messages.size(); i != e; ++i) {
180259701Sdim      if (i != 0) OS << "\n";
181259701Sdim      printMessageToStream(Content.Messages[i],
182259701Sdim                           "Candidate " + Twine(i + 1) + ": ", OS);
183259701Sdim    }
184259701Sdim  }
185259701Sdim}
186259701Sdim
187259701Sdimvoid Diagnostics::printToStream(llvm::raw_ostream &OS) const {
188259701Sdim  for (size_t i = 0, e = Errors.size(); i != e; ++i) {
189259701Sdim    if (i != 0) OS << "\n";
190259701Sdim    printErrorContentToStream(Errors[i], OS);
191259701Sdim  }
192259701Sdim}
193259701Sdim
194259701Sdimstd::string Diagnostics::toString() const {
195259701Sdim  std::string S;
196259701Sdim  llvm::raw_string_ostream OS(S);
197259701Sdim  printToStream(OS);
198259701Sdim  return OS.str();
199259701Sdim}
200259701Sdim
201259701Sdimvoid Diagnostics::printToStreamFull(llvm::raw_ostream &OS) const {
202259701Sdim  for (size_t i = 0, e = Errors.size(); i != e; ++i) {
203259701Sdim    if (i != 0) OS << "\n";
204259701Sdim    const ErrorContent &Error = Errors[i];
205259701Sdim    for (size_t i = 0, e = Error.ContextStack.size(); i != e; ++i) {
206259701Sdim      printContextFrameToStream(Error.ContextStack[i], OS);
207259701Sdim      OS << "\n";
208259701Sdim    }
209259701Sdim    printErrorContentToStream(Error, OS);
210259701Sdim  }
211259701Sdim}
212259701Sdim
213259701Sdimstd::string Diagnostics::toStringFull() const {
214259701Sdim  std::string S;
215259701Sdim  llvm::raw_string_ostream OS(S);
216259701Sdim  printToStreamFull(OS);
217259701Sdim  return OS.str();
218259701Sdim}
219259701Sdim
220259701Sdim}  // namespace dynamic
221259701Sdim}  // namespace ast_matchers
222259701Sdim}  // namespace clang
223