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