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