brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.1 KiB · 41ab0ed Raw
232 lines · cpp
1//===--- Diagnostics.cpp - Helper class for error diagnostics ---*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/ASTMatchers/Dynamic/Diagnostics.h"10 11namespace clang {12namespace ast_matchers {13namespace dynamic {14Diagnostics::ArgStream Diagnostics::pushContextFrame(ContextType Type,15                                                     SourceRange Range) {16  ContextStack.emplace_back();17  ContextFrame& data = ContextStack.back();18  data.Type = Type;19  data.Range = Range;20  return ArgStream(&data.Args);21}22 23Diagnostics::Context::Context(ConstructMatcherEnum, Diagnostics *Error,24                              StringRef MatcherName,25                              SourceRange MatcherRange)26    : Error(Error) {27  Error->pushContextFrame(CT_MatcherConstruct, MatcherRange) << MatcherName;28}29 30Diagnostics::Context::Context(MatcherArgEnum, Diagnostics *Error,31                              StringRef MatcherName,32                              SourceRange MatcherRange,33                              unsigned ArgNumber)34    : Error(Error) {35  Error->pushContextFrame(CT_MatcherArg, MatcherRange) << ArgNumber36                                                       << MatcherName;37}38 39Diagnostics::Context::~Context() { Error->ContextStack.pop_back(); }40 41Diagnostics::OverloadContext::OverloadContext(Diagnostics *Error)42    : Error(Error), BeginIndex(Error->Errors.size()) {}43 44Diagnostics::OverloadContext::~OverloadContext() {45  // Merge all errors that happened while in this context.46  if (BeginIndex < Error->Errors.size()) {47    Diagnostics::ErrorContent &Dest = Error->Errors[BeginIndex];48    for (size_t i = BeginIndex + 1, e = Error->Errors.size(); i < e; ++i) {49      Dest.Messages.push_back(Error->Errors[i].Messages[0]);50    }51    Error->Errors.resize(BeginIndex + 1);52  }53}54 55void Diagnostics::OverloadContext::revertErrors() {56  // Revert the errors.57  Error->Errors.resize(BeginIndex);58}59 60Diagnostics::ArgStream &Diagnostics::ArgStream::operator<<(const Twine &Arg) {61  Out->push_back(Arg.str());62  return *this;63}64 65Diagnostics::ArgStream Diagnostics::addError(SourceRange Range,66                                             ErrorType Error) {67  Errors.emplace_back();68  ErrorContent &Last = Errors.back();69  Last.ContextStack = ContextStack;70  Last.Messages.emplace_back();71  Last.Messages.back().Range = Range;72  Last.Messages.back().Type = Error;73  return ArgStream(&Last.Messages.back().Args);74}75 76static StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {77  switch (Type) {78    case Diagnostics::CT_MatcherConstruct:79      return "Error building matcher $0.";80    case Diagnostics::CT_MatcherArg:81      return "Error parsing argument $0 for matcher $1.";82  }83  llvm_unreachable("Unknown ContextType value.");84}85 86static StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {87  switch (Type) {88  case Diagnostics::ET_RegistryMatcherNotFound:89    return "Matcher not found: $0";90  case Diagnostics::ET_RegistryWrongArgCount:91    return "Incorrect argument count. (Expected = $0) != (Actual = $1)";92  case Diagnostics::ET_RegistryWrongArgType:93    return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";94  case Diagnostics::ET_RegistryNotBindable:95    return "Matcher does not support binding.";96  case Diagnostics::ET_RegistryAmbiguousOverload:97    // TODO: Add type info about the overload error.98    return "Ambiguous matcher overload.";99  case Diagnostics::ET_RegistryValueNotFound:100    return "Value not found: $0";101  case Diagnostics::ET_RegistryUnknownEnumWithReplace:102    return "Unknown value '$1' for arg $0; did you mean '$2'";103  case Diagnostics::ET_RegistryNonNodeMatcher:104    return "Matcher not a node matcher: $0";105  case Diagnostics::ET_RegistryMatcherNoWithSupport:106    return "Matcher does not support with call.";107 108  case Diagnostics::ET_ParserStringError:109    return "Error parsing string token: <$0>";110  case Diagnostics::ET_ParserNoOpenParen:111    return "Error parsing matcher. Found token <$0> while looking for '('.";112  case Diagnostics::ET_ParserNoCloseParen:113    return "Error parsing matcher. Found end-of-code while looking for ')'.";114  case Diagnostics::ET_ParserNoComma:115    return "Error parsing matcher. Found token <$0> while looking for ','.";116  case Diagnostics::ET_ParserNoCode:117    return "End of code found while looking for token.";118  case Diagnostics::ET_ParserNotAMatcher:119    return "Input value is not a matcher expression.";120  case Diagnostics::ET_ParserInvalidToken:121    return "Invalid token <$0> found when looking for a value.";122  case Diagnostics::ET_ParserMalformedBindExpr:123    return "Malformed bind() expression.";124  case Diagnostics::ET_ParserTrailingCode:125    return "Expected end of code.";126  case Diagnostics::ET_ParserNumberError:127    return "Error parsing numeric literal: <$0>";128  case Diagnostics::ET_ParserOverloadedType:129    return "Input value has unresolved overloaded type: $0";130  case Diagnostics::ET_ParserMalformedChainedExpr:131    return "Period not followed by valid chained call.";132  case Diagnostics::ET_ParserFailedToBuildMatcher:133    return "Failed to build matcher: $0.";134 135  case Diagnostics::ET_None:136    return "<N/A>";137  }138  llvm_unreachable("Unknown ErrorType value.");139}140 141static void formatErrorString(StringRef FormatString,142                              ArrayRef<std::string> Args,143                              llvm::raw_ostream &OS) {144  while (!FormatString.empty()) {145    std::pair<StringRef, StringRef> Pieces = FormatString.split("$");146    OS << Pieces.first.str();147    if (Pieces.second.empty()) break;148 149    const char Next = Pieces.second.front();150    FormatString = Pieces.second.drop_front();151    if (Next >= '0' && Next <= '9') {152      const unsigned Index = Next - '0';153      if (Index < Args.size()) {154        OS << Args[Index];155      } else {156        OS << "<Argument_Not_Provided>";157      }158    }159  }160}161 162static void maybeAddLineAndColumn(SourceRange Range,163                                  llvm::raw_ostream &OS) {164  if (Range.Start.Line > 0 && Range.Start.Column > 0) {165    OS << Range.Start.Line << ":" << Range.Start.Column << ": ";166  }167}168 169static void printContextFrameToStream(const Diagnostics::ContextFrame &Frame,170                                      llvm::raw_ostream &OS) {171  maybeAddLineAndColumn(Frame.Range, OS);172  formatErrorString(contextTypeToFormatString(Frame.Type), Frame.Args, OS);173}174 175static void176printMessageToStream(const Diagnostics::ErrorContent::Message &Message,177                     const Twine Prefix, llvm::raw_ostream &OS) {178  maybeAddLineAndColumn(Message.Range, OS);179  OS << Prefix;180  formatErrorString(errorTypeToFormatString(Message.Type), Message.Args, OS);181}182 183static void printErrorContentToStream(const Diagnostics::ErrorContent &Content,184                                      llvm::raw_ostream &OS) {185  if (Content.Messages.size() == 1) {186    printMessageToStream(Content.Messages[0], "", OS);187  } else {188    for (size_t i = 0, e = Content.Messages.size(); i != e; ++i) {189      if (i != 0) OS << "\n";190      printMessageToStream(Content.Messages[i],191                           "Candidate " + Twine(i + 1) + ": ", OS);192    }193  }194}195 196void Diagnostics::printToStream(llvm::raw_ostream &OS) const {197  for (size_t i = 0, e = Errors.size(); i != e; ++i) {198    if (i != 0) OS << "\n";199    printErrorContentToStream(Errors[i], OS);200  }201}202 203std::string Diagnostics::toString() const {204  std::string S;205  llvm::raw_string_ostream OS(S);206  printToStream(OS);207  return S;208}209 210void Diagnostics::printToStreamFull(llvm::raw_ostream &OS) const {211  for (size_t i = 0, e = Errors.size(); i != e; ++i) {212    if (i != 0) OS << "\n";213    const ErrorContent &Error = Errors[i];214    for (size_t i = 0, e = Error.ContextStack.size(); i != e; ++i) {215      printContextFrameToStream(Error.ContextStack[i], OS);216      OS << "\n";217    }218    printErrorContentToStream(Error, OS);219  }220}221 222std::string Diagnostics::toStringFull() const {223  std::string S;224  llvm::raw_string_ostream OS(S);225  printToStreamFull(OS);226  return S;227}228 229}  // namespace dynamic230}  // namespace ast_matchers231}  // namespace clang232