clang API Documentation
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