Path: blob/main/contrib/llvm-project/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp
35292 views
//===--- Diagnostics.cpp - Helper class for error diagnostics ---*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/ASTMatchers/Dynamic/Diagnostics.h"910namespace clang {11namespace ast_matchers {12namespace dynamic {13Diagnostics::ArgStream Diagnostics::pushContextFrame(ContextType Type,14SourceRange Range) {15ContextStack.emplace_back();16ContextFrame& data = ContextStack.back();17data.Type = Type;18data.Range = Range;19return ArgStream(&data.Args);20}2122Diagnostics::Context::Context(ConstructMatcherEnum, Diagnostics *Error,23StringRef MatcherName,24SourceRange MatcherRange)25: Error(Error) {26Error->pushContextFrame(CT_MatcherConstruct, MatcherRange) << MatcherName;27}2829Diagnostics::Context::Context(MatcherArgEnum, Diagnostics *Error,30StringRef MatcherName,31SourceRange MatcherRange,32unsigned ArgNumber)33: Error(Error) {34Error->pushContextFrame(CT_MatcherArg, MatcherRange) << ArgNumber35<< MatcherName;36}3738Diagnostics::Context::~Context() { Error->ContextStack.pop_back(); }3940Diagnostics::OverloadContext::OverloadContext(Diagnostics *Error)41: Error(Error), BeginIndex(Error->Errors.size()) {}4243Diagnostics::OverloadContext::~OverloadContext() {44// Merge all errors that happened while in this context.45if (BeginIndex < Error->Errors.size()) {46Diagnostics::ErrorContent &Dest = Error->Errors[BeginIndex];47for (size_t i = BeginIndex + 1, e = Error->Errors.size(); i < e; ++i) {48Dest.Messages.push_back(Error->Errors[i].Messages[0]);49}50Error->Errors.resize(BeginIndex + 1);51}52}5354void Diagnostics::OverloadContext::revertErrors() {55// Revert the errors.56Error->Errors.resize(BeginIndex);57}5859Diagnostics::ArgStream &Diagnostics::ArgStream::operator<<(const Twine &Arg) {60Out->push_back(Arg.str());61return *this;62}6364Diagnostics::ArgStream Diagnostics::addError(SourceRange Range,65ErrorType Error) {66Errors.emplace_back();67ErrorContent &Last = Errors.back();68Last.ContextStack = ContextStack;69Last.Messages.emplace_back();70Last.Messages.back().Range = Range;71Last.Messages.back().Type = Error;72return ArgStream(&Last.Messages.back().Args);73}7475static StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {76switch (Type) {77case Diagnostics::CT_MatcherConstruct:78return "Error building matcher $0.";79case Diagnostics::CT_MatcherArg:80return "Error parsing argument $0 for matcher $1.";81}82llvm_unreachable("Unknown ContextType value.");83}8485static StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {86switch (Type) {87case Diagnostics::ET_RegistryMatcherNotFound:88return "Matcher not found: $0";89case Diagnostics::ET_RegistryWrongArgCount:90return "Incorrect argument count. (Expected = $0) != (Actual = $1)";91case Diagnostics::ET_RegistryWrongArgType:92return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";93case Diagnostics::ET_RegistryNotBindable:94return "Matcher does not support binding.";95case Diagnostics::ET_RegistryAmbiguousOverload:96// TODO: Add type info about the overload error.97return "Ambiguous matcher overload.";98case Diagnostics::ET_RegistryValueNotFound:99return "Value not found: $0";100case Diagnostics::ET_RegistryUnknownEnumWithReplace:101return "Unknown value '$1' for arg $0; did you mean '$2'";102case Diagnostics::ET_RegistryNonNodeMatcher:103return "Matcher not a node matcher: $0";104case Diagnostics::ET_RegistryMatcherNoWithSupport:105return "Matcher does not support with call.";106107case Diagnostics::ET_ParserStringError:108return "Error parsing string token: <$0>";109case Diagnostics::ET_ParserNoOpenParen:110return "Error parsing matcher. Found token <$0> while looking for '('.";111case Diagnostics::ET_ParserNoCloseParen:112return "Error parsing matcher. Found end-of-code while looking for ')'.";113case Diagnostics::ET_ParserNoComma:114return "Error parsing matcher. Found token <$0> while looking for ','.";115case Diagnostics::ET_ParserNoCode:116return "End of code found while looking for token.";117case Diagnostics::ET_ParserNotAMatcher:118return "Input value is not a matcher expression.";119case Diagnostics::ET_ParserInvalidToken:120return "Invalid token <$0> found when looking for a value.";121case Diagnostics::ET_ParserMalformedBindExpr:122return "Malformed bind() expression.";123case Diagnostics::ET_ParserTrailingCode:124return "Expected end of code.";125case Diagnostics::ET_ParserNumberError:126return "Error parsing numeric literal: <$0>";127case Diagnostics::ET_ParserOverloadedType:128return "Input value has unresolved overloaded type: $0";129case Diagnostics::ET_ParserMalformedChainedExpr:130return "Period not followed by valid chained call.";131case Diagnostics::ET_ParserFailedToBuildMatcher:132return "Failed to build matcher: $0.";133134case Diagnostics::ET_None:135return "<N/A>";136}137llvm_unreachable("Unknown ErrorType value.");138}139140static void formatErrorString(StringRef FormatString,141ArrayRef<std::string> Args,142llvm::raw_ostream &OS) {143while (!FormatString.empty()) {144std::pair<StringRef, StringRef> Pieces = FormatString.split("$");145OS << Pieces.first.str();146if (Pieces.second.empty()) break;147148const char Next = Pieces.second.front();149FormatString = Pieces.second.drop_front();150if (Next >= '0' && Next <= '9') {151const unsigned Index = Next - '0';152if (Index < Args.size()) {153OS << Args[Index];154} else {155OS << "<Argument_Not_Provided>";156}157}158}159}160161static void maybeAddLineAndColumn(SourceRange Range,162llvm::raw_ostream &OS) {163if (Range.Start.Line > 0 && Range.Start.Column > 0) {164OS << Range.Start.Line << ":" << Range.Start.Column << ": ";165}166}167168static void printContextFrameToStream(const Diagnostics::ContextFrame &Frame,169llvm::raw_ostream &OS) {170maybeAddLineAndColumn(Frame.Range, OS);171formatErrorString(contextTypeToFormatString(Frame.Type), Frame.Args, OS);172}173174static void175printMessageToStream(const Diagnostics::ErrorContent::Message &Message,176const Twine Prefix, llvm::raw_ostream &OS) {177maybeAddLineAndColumn(Message.Range, OS);178OS << Prefix;179formatErrorString(errorTypeToFormatString(Message.Type), Message.Args, OS);180}181182static void printErrorContentToStream(const Diagnostics::ErrorContent &Content,183llvm::raw_ostream &OS) {184if (Content.Messages.size() == 1) {185printMessageToStream(Content.Messages[0], "", OS);186} else {187for (size_t i = 0, e = Content.Messages.size(); i != e; ++i) {188if (i != 0) OS << "\n";189printMessageToStream(Content.Messages[i],190"Candidate " + Twine(i + 1) + ": ", OS);191}192}193}194195void Diagnostics::printToStream(llvm::raw_ostream &OS) const {196for (size_t i = 0, e = Errors.size(); i != e; ++i) {197if (i != 0) OS << "\n";198printErrorContentToStream(Errors[i], OS);199}200}201202std::string Diagnostics::toString() const {203std::string S;204llvm::raw_string_ostream OS(S);205printToStream(OS);206return S;207}208209void Diagnostics::printToStreamFull(llvm::raw_ostream &OS) const {210for (size_t i = 0, e = Errors.size(); i != e; ++i) {211if (i != 0) OS << "\n";212const ErrorContent &Error = Errors[i];213for (size_t i = 0, e = Error.ContextStack.size(); i != e; ++i) {214printContextFrameToStream(Error.ContextStack[i], OS);215OS << "\n";216}217printErrorContentToStream(Error, OS);218}219}220221std::string Diagnostics::toStringFull() const {222std::string S;223llvm::raw_string_ostream OS(S);224printToStreamFull(OS);225return S;226}227228} // namespace dynamic229} // namespace ast_matchers230} // namespace clang231232233