clang API Documentation

Diagnostics.cpp
Go to the documentation of this file.
00001 //===--- Diagnostics.cpp - Helper class for error diagnostics -----*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "clang/ASTMatchers/Dynamic/Diagnostics.h"
00011 
00012 namespace clang {
00013 namespace ast_matchers {
00014 namespace dynamic {
00015 
00016 Diagnostics::ArgStream Diagnostics::pushContextFrame(ContextType Type,
00017                                                      SourceRange Range) {
00018   ContextStack.push_back(ContextFrame());
00019   ContextFrame& data = ContextStack.back();
00020   data.Type = Type;
00021   data.Range = Range;
00022   return ArgStream(&data.Args);
00023 }
00024 
00025 Diagnostics::Context::Context(ConstructMatcherEnum, Diagnostics *Error,
00026                               StringRef MatcherName,
00027                               const SourceRange &MatcherRange)
00028     : Error(Error) {
00029   Error->pushContextFrame(CT_MatcherConstruct, MatcherRange) << MatcherName;
00030 }
00031 
00032 Diagnostics::Context::Context(MatcherArgEnum, Diagnostics *Error,
00033                               StringRef MatcherName,
00034                               const SourceRange &MatcherRange,
00035                               unsigned ArgNumber)
00036     : Error(Error) {
00037   Error->pushContextFrame(CT_MatcherArg, MatcherRange) << ArgNumber
00038                                                        << MatcherName;
00039 }
00040 
00041 Diagnostics::Context::~Context() { Error->ContextStack.pop_back(); }
00042 
00043 Diagnostics::OverloadContext::OverloadContext(Diagnostics *Error)
00044     : Error(Error), BeginIndex(Error->Errors.size()) {}
00045 
00046 Diagnostics::OverloadContext::~OverloadContext() {
00047   // Merge all errors that happened while in this context.
00048   if (BeginIndex < Error->Errors.size()) {
00049     Diagnostics::ErrorContent &Dest = Error->Errors[BeginIndex];
00050     for (size_t i = BeginIndex + 1, e = Error->Errors.size(); i < e; ++i) {
00051       Dest.Messages.push_back(Error->Errors[i].Messages[0]);
00052     }
00053     Error->Errors.resize(BeginIndex + 1);
00054   }
00055 }
00056 
00057 void Diagnostics::OverloadContext::revertErrors() {
00058   // Revert the errors.
00059   Error->Errors.resize(BeginIndex);
00060 }
00061 
00062 Diagnostics::ArgStream &Diagnostics::ArgStream::operator<<(const Twine &Arg) {
00063   Out->push_back(Arg.str());
00064   return *this;
00065 }
00066 
00067 Diagnostics::ArgStream Diagnostics::addError(const SourceRange &Range,
00068                                              ErrorType Error) {
00069   Errors.push_back(ErrorContent());
00070   ErrorContent &Last = Errors.back();
00071   Last.ContextStack = ContextStack;
00072   Last.Messages.push_back(ErrorContent::Message());
00073   Last.Messages.back().Range = Range;
00074   Last.Messages.back().Type = Error;
00075   return ArgStream(&Last.Messages.back().Args);
00076 }
00077 
00078 StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {
00079   switch (Type) {
00080     case Diagnostics::CT_MatcherConstruct:
00081       return "Error building matcher $0.";
00082     case Diagnostics::CT_MatcherArg:
00083       return "Error parsing argument $0 for matcher $1.";
00084   }
00085   llvm_unreachable("Unknown ContextType value.");
00086 }
00087 
00088 StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
00089   switch (Type) {
00090   case Diagnostics::ET_RegistryMatcherNotFound:
00091     return "Matcher not found: $0";
00092   case Diagnostics::ET_RegistryWrongArgCount:
00093     return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
00094   case Diagnostics::ET_RegistryWrongArgType:
00095     return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
00096   case Diagnostics::ET_RegistryNotBindable:
00097     return "Matcher does not support binding.";
00098   case Diagnostics::ET_RegistryAmbiguousOverload:
00099     // TODO: Add type info about the overload error.
00100     return "Ambiguous matcher overload.";
00101   case Diagnostics::ET_RegistryValueNotFound:
00102     return "Value not found: $0";
00103 
00104   case Diagnostics::ET_ParserStringError:
00105     return "Error parsing string token: <$0>";
00106   case Diagnostics::ET_ParserNoOpenParen:
00107     return "Error parsing matcher. Found token <$0> while looking for '('.";
00108   case Diagnostics::ET_ParserNoCloseParen:
00109     return "Error parsing matcher. Found end-of-code while looking for ')'.";
00110   case Diagnostics::ET_ParserNoComma:
00111     return "Error parsing matcher. Found token <$0> while looking for ','.";
00112   case Diagnostics::ET_ParserNoCode:
00113     return "End of code found while looking for token.";
00114   case Diagnostics::ET_ParserNotAMatcher:
00115     return "Input value is not a matcher expression.";
00116   case Diagnostics::ET_ParserInvalidToken:
00117     return "Invalid token <$0> found when looking for a value.";
00118   case Diagnostics::ET_ParserMalformedBindExpr:
00119     return "Malformed bind() expression.";
00120   case Diagnostics::ET_ParserTrailingCode:
00121     return "Expected end of code.";
00122   case Diagnostics::ET_ParserUnsignedError:
00123     return "Error parsing unsigned token: <$0>";
00124   case Diagnostics::ET_ParserOverloadedType:
00125     return "Input value has unresolved overloaded type: $0";
00126 
00127   case Diagnostics::ET_None:
00128     return "<N/A>";
00129   }
00130   llvm_unreachable("Unknown ErrorType value.");
00131 }
00132 
00133 void formatErrorString(StringRef FormatString, ArrayRef<std::string> Args,
00134                        llvm::raw_ostream &OS) {
00135   while (!FormatString.empty()) {
00136     std::pair<StringRef, StringRef> Pieces = FormatString.split("$");
00137     OS << Pieces.first.str();
00138     if (Pieces.second.empty()) break;
00139 
00140     const char Next = Pieces.second.front();
00141     FormatString = Pieces.second.drop_front();
00142     if (Next >= '0' && Next <= '9') {
00143       const unsigned Index = Next - '0';
00144       if (Index < Args.size()) {
00145         OS << Args[Index];
00146       } else {
00147         OS << "<Argument_Not_Provided>";
00148       }
00149     }
00150   }
00151 }
00152 
00153 static void maybeAddLineAndColumn(const SourceRange &Range,
00154                                   llvm::raw_ostream &OS) {
00155   if (Range.Start.Line > 0 && Range.Start.Column > 0) {
00156     OS << Range.Start.Line << ":" << Range.Start.Column << ": ";
00157   }
00158 }
00159 
00160 static void printContextFrameToStream(const Diagnostics::ContextFrame &Frame,
00161                                       llvm::raw_ostream &OS) {
00162   maybeAddLineAndColumn(Frame.Range, OS);
00163   formatErrorString(contextTypeToFormatString(Frame.Type), Frame.Args, OS);
00164 }
00165 
00166 static void
00167 printMessageToStream(const Diagnostics::ErrorContent::Message &Message,
00168                      const Twine Prefix, llvm::raw_ostream &OS) {
00169   maybeAddLineAndColumn(Message.Range, OS);
00170   OS << Prefix;
00171   formatErrorString(errorTypeToFormatString(Message.Type), Message.Args, OS);
00172 }
00173 
00174 static void printErrorContentToStream(const Diagnostics::ErrorContent &Content,
00175                                       llvm::raw_ostream &OS) {
00176   if (Content.Messages.size() == 1) {
00177     printMessageToStream(Content.Messages[0], "", OS);
00178   } else {
00179     for (size_t i = 0, e = Content.Messages.size(); i != e; ++i) {
00180       if (i != 0) OS << "\n";
00181       printMessageToStream(Content.Messages[i],
00182                            "Candidate " + Twine(i + 1) + ": ", OS);
00183     }
00184   }
00185 }
00186 
00187 void Diagnostics::printToStream(llvm::raw_ostream &OS) const {
00188   for (size_t i = 0, e = Errors.size(); i != e; ++i) {
00189     if (i != 0) OS << "\n";
00190     printErrorContentToStream(Errors[i], OS);
00191   }
00192 }
00193 
00194 std::string Diagnostics::toString() const {
00195   std::string S;
00196   llvm::raw_string_ostream OS(S);
00197   printToStream(OS);
00198   return OS.str();
00199 }
00200 
00201 void Diagnostics::printToStreamFull(llvm::raw_ostream &OS) const {
00202   for (size_t i = 0, e = Errors.size(); i != e; ++i) {
00203     if (i != 0) OS << "\n";
00204     const ErrorContent &Error = Errors[i];
00205     for (size_t i = 0, e = Error.ContextStack.size(); i != e; ++i) {
00206       printContextFrameToStream(Error.ContextStack[i], OS);
00207       OS << "\n";
00208     }
00209     printErrorContentToStream(Error, OS);
00210   }
00211 }
00212 
00213 std::string Diagnostics::toStringFull() const {
00214   std::string S;
00215   llvm::raw_string_ostream OS(S);
00216   printToStreamFull(OS);
00217   return OS.str();
00218 }
00219 
00220 }  // namespace dynamic
00221 }  // namespace ast_matchers
00222 }  // namespace clang