Branch data 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 : 164285 : for (const char* c = fmt; *c; ++c)
24 : : {
25 : 157389 : if (*c != '%')
26 : : {
27 : 154936 : ss << *c;
28 : 154936 : continue;
29 : : }
30 : 2453 : c++;
31 : 2453 : 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 : 126 : case '<':
49 : 126 : {
50 : 126 : ss << go_open_quote();
51 : 126 : break;
52 : : }
53 : 126 : case '>':
54 : 126 : {
55 : 126 : ss << go_close_quote();
56 : 126 : break;
57 : : }
58 : 381 : case 'q':
59 : 381 : {
60 : 381 : ss << go_open_quote();
61 : 381 : c++;
62 : 381 : if (*c == 'm')
63 : : {
64 : 0 : ss << mformat_value();
65 : : }
66 : : else
67 : : {
68 : 381 : ss << "%" << *c;
69 : : }
70 : 381 : ss << go_close_quote();
71 : 381 : break;
72 : : }
73 : 1820 : default:
74 : 1820 : {
75 : 1820 : 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 : : "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 : : "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 : }
|