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