Line data Source code
1 : // go-diagnostics.cc -- Go error/warning diagnostics utilities.
2 :
3 : // Copyright 2016 The Go Authors. All rights reserved.
4 : // Use of this source code is governed by a BSD-style
5 : // license that can be found in the LICENSE file.
6 :
7 : #include "go-diagnostics.h"
8 :
9 : static std::string
10 0 : mformat_value()
11 : {
12 0 : return std::string(xstrerror(errno));
13 : }
14 :
15 : // Rewrite a format string to expand any extensions not
16 : // supported by sprintf(). See comments in go-diagnostics.h
17 : // for list of supported format specifiers.
18 :
19 : static std::string
20 6896 : expand_format(const char* fmt)
21 : {
22 6896 : std::stringstream ss;
23 164275 : for (const char* c = fmt; *c; ++c)
24 : {
25 157379 : if (*c != '%')
26 : {
27 154936 : ss << *c;
28 154936 : continue;
29 : }
30 2443 : c++;
31 2443 : switch (*c)
32 : {
33 0 : case '\0':
34 0 : {
35 : // malformed format string
36 0 : go_unreachable();
37 : }
38 0 : case '%':
39 0 : {
40 0 : ss << "%";
41 0 : break;
42 : }
43 0 : case 'm':
44 0 : {
45 0 : ss << mformat_value();
46 0 : break;
47 : }
48 121 : case '<':
49 121 : {
50 121 : ss << go_open_quote();
51 121 : break;
52 : }
53 121 : case '>':
54 121 : {
55 121 : ss << go_close_quote();
56 121 : break;
57 : }
58 386 : case 'q':
59 386 : {
60 386 : ss << go_open_quote();
61 386 : c++;
62 386 : if (*c == 'm')
63 : {
64 0 : ss << mformat_value();
65 : }
66 : else
67 : {
68 386 : ss << "%" << *c;
69 : }
70 386 : ss << go_close_quote();
71 386 : break;
72 : }
73 1815 : default:
74 1815 : {
75 1815 : ss << "%" << *c;
76 : }
77 : }
78 : }
79 6896 : return ss.str();
80 6896 : }
81 :
82 : // Expand message format specifiers, using a combination of
83 : // expand_format above to handle extensions (ex: %m, %q) and vasprintf()
84 : // to handle regular printf-style formatting. A pragma is being used here to
85 : // suppress this warning:
86 : //
87 : // warning: function ‘std::__cxx11::string expand_message(const char*, __va_list_tag*)’ might be a candidate for ‘gnu_printf’ format attribute [-Wsuggest-attribute=format]
88 : //
89 : // What appears to be happening here is that the checker is deciding that
90 : // because of the call to vasprintf() (which has attribute gnu_printf), the
91 : // calling function must need to have attribute gnu_printf as well, even
92 : // though there is already an attribute declaration for it.
93 :
94 : static std::string
95 : expand_message(const char* fmt, va_list ap) GO_ATTRIBUTE_GCC_DIAG(1,0);
96 :
97 : #pragma GCC diagnostic push
98 : #pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
99 :
100 : static std::string
101 6896 : expand_message(const char* fmt, va_list ap)
102 : {
103 6896 : char* mbuf = 0;
104 6896 : std::string expanded_fmt = expand_format(fmt);
105 6896 : int nwr = vasprintf(&mbuf, expanded_fmt.c_str(), ap);
106 6896 : if (nwr == -1)
107 : {
108 : // memory allocation failed
109 0 : go_be_error_at(Linemap::unknown_location(),
110 0 : "memory allocation failed in vasprintf");
111 0 : go_assert(0);
112 : }
113 6896 : std::string rval = std::string(mbuf);
114 6896 : free(mbuf);
115 6896 : return rval;
116 6896 : }
117 :
118 : #pragma GCC diagnostic pop
119 :
120 : static const char* cached_open_quote = NULL;
121 : static const char* cached_close_quote = NULL;
122 :
123 : const char*
124 525 : go_open_quote()
125 : {
126 525 : if (cached_open_quote == NULL)
127 187 : go_be_get_quotechars(&cached_open_quote, &cached_close_quote);
128 525 : return cached_open_quote;
129 : }
130 :
131 : const char*
132 525 : go_close_quote()
133 : {
134 525 : if (cached_close_quote == NULL)
135 4 : go_be_get_quotechars(&cached_open_quote, &cached_close_quote);
136 525 : return cached_close_quote;
137 : }
138 :
139 : void
140 6789 : go_error_at(const Location location, const char* fmt, ...)
141 : {
142 6789 : va_list ap;
143 :
144 6789 : va_start(ap, fmt);
145 6789 : go_be_error_at(location, expand_message(fmt, ap));
146 6789 : va_end(ap);
147 6789 : }
148 :
149 : void
150 17 : go_warning_at(const Location location, int opt, const char* fmt, ...)
151 : {
152 17 : va_list ap;
153 :
154 17 : va_start(ap, fmt);
155 17 : go_be_warning_at(location, opt, expand_message(fmt, ap));
156 17 : va_end(ap);
157 17 : }
158 :
159 : void
160 0 : go_fatal_error(const Location location, const char* fmt, ...)
161 : {
162 0 : va_list ap;
163 :
164 0 : va_start(ap, fmt);
165 0 : go_be_fatal_error(location, expand_message(fmt, ap));
166 0 : va_end(ap);
167 0 : }
168 :
169 : void
170 90 : go_inform(const Location location, const char* fmt, ...)
171 : {
172 90 : va_list ap;
173 :
174 90 : va_start(ap, fmt);
175 90 : go_be_inform(location, expand_message(fmt, ap));
176 90 : va_end(ap);
177 90 : }
178 :
179 : // go_debug uses normal printf formatting, not GCC diagnostic formatting.
180 :
181 : void
182 9 : go_debug(const Location location, const char* fmt, ...)
183 : {
184 9 : va_list ap;
185 :
186 9 : va_start(ap, fmt);
187 9 : char* mbuf = NULL;
188 9 : int nwr = vasprintf(&mbuf, fmt, ap);
189 9 : va_end(ap);
190 9 : if (nwr == -1)
191 : {
192 0 : go_be_error_at(Linemap::unknown_location(),
193 0 : "memory allocation failed in vasprintf");
194 0 : go_assert(0);
195 : }
196 9 : std::string rval = std::string(mbuf);
197 9 : free(mbuf);
198 9 : go_be_inform(location, rval);
199 9 : }
|