1 //===--- Diagnostics.cpp - Helper class for error diagnostics -----*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "clang/ASTMatchers/Dynamic/Diagnostics.h"
11 
12 namespace clang {
13 namespace ast_matchers {
14 namespace dynamic {
15 
16 Diagnostics::ArgStream &
17 Diagnostics::ArgStream::operator<<(const Twine &Arg) {
18   Out->push_back(Arg.str());
19   return *this;
20 }
21 
22 Diagnostics::ArgStream Diagnostics::pushErrorFrame(const SourceRange &Range,
23                                                    ErrorType Error) {
24   Frames.insert(Frames.begin(), ErrorFrame());
25   ErrorFrame &Last = Frames.front();
26   Last.Range = Range;
27   Last.Type = Error;
28   ArgStream Out = { &Last.Args };
29   return Out;
30 }
31 
32 StringRef ErrorTypeToString(Diagnostics::ErrorType Type) {
33   switch (Type) {
34   case Diagnostics::ET_RegistryNotFound:
35     return "Matcher not found: $0";
36   case Diagnostics::ET_RegistryWrongArgCount:
37     return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
38   case Diagnostics::ET_RegistryWrongArgType:
39     return "Incorrect type on function $0 for arg $1.";
40   case Diagnostics::ET_RegistryNotBindable:
41     return "Matcher does not support binding.";
42 
43   case Diagnostics::ET_ParserStringError:
44     return "Error parsing string token: <$0>";
45   case Diagnostics::ET_ParserMatcherArgFailure:
46     return "Error parsing argument $0 for matcher $1.";
47   case Diagnostics::ET_ParserMatcherFailure:
48     return "Error building matcher $0.";
49   case Diagnostics::ET_ParserNoOpenParen:
50     return "Error parsing matcher. Found token <$0> while looking for '('.";
51   case Diagnostics::ET_ParserNoCloseParen:
52     return "Error parsing matcher. Found end-of-code while looking for ')'.";
53   case Diagnostics::ET_ParserNoComma:
54     return "Error parsing matcher. Found token <$0> while looking for ','.";
55   case Diagnostics::ET_ParserNoCode:
56     return "End of code found while looking for token.";
57   case Diagnostics::ET_ParserNotAMatcher:
58     return "Input value is not a matcher expression.";
59   case Diagnostics::ET_ParserInvalidToken:
60     return "Invalid token <$0> found when looking for a value.";
61   case Diagnostics::ET_ParserMalformedBindExpr:
62     return "Malformed bind() expression.";
63   case Diagnostics::ET_ParserTrailingCode:
64     return "Expected end of code.";
65   case Diagnostics::ET_ParserUnsignedError:
66     return "Error parsing unsigned token: <$0>";
67 
68   case Diagnostics::ET_None:
69     return "<N/A>";
70   }
71   llvm_unreachable("Unknown ErrorType value.");
72 }
73 
74 std::string FormatErrorString(StringRef FormatString,
75                               ArrayRef<std::string> Args) {
76   std::string Out;
77   while (!FormatString.empty()) {
78     std::pair<StringRef, StringRef> Pieces = FormatString.split("$");
79     Out += Pieces.first.str();
80     if (Pieces.second.empty()) break;
81 
82     const char Next = Pieces.second.front();
83     FormatString = Pieces.second.drop_front();
84     if (Next >= '0' && Next <= '9') {
85       const unsigned Index = Next - '0';
86       if (Index < Args.size()) {
87         Out += Args[Index];
88       } else {
89         Out += "<Argument_Not_Provided>";
90       }
91     }
92   }
93   return Out;
94 }
95 
96 std::string Diagnostics::ErrorFrame::ToString() const {
97   StringRef FormatString = ErrorTypeToString(Type);
98   std::string ErrorOut = FormatErrorString(FormatString, Args);
99   if (Range.Start.Line > 0 && Range.Start.Column > 0)
100     return (Twine(Range.Start.Line) + ":" + Twine(Range.Start.Column) + ": " +
101             ErrorOut).str();
102   return ErrorOut;
103 }
104 
105 std::string Diagnostics::ToString() const {
106   if (Frames.empty()) return "";
107   return Frames[Frames.size() - 1].ToString();
108 }
109 
110 std::string Diagnostics::ToStringFull() const {
111   std::string Result;
112   for (size_t i = 0, end = Frames.size(); i != end; ++i) {
113     if (i > 0) Result += "\n";
114     Result += Frames[i].ToString();
115   }
116   return Result;
117 }
118 
119 }  // namespace dynamic
120 }  // namespace ast_matchers
121 }  // namespace clang
122