Diagnostics.cpp 7.6 KB

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