@@ -37,9 +37,27 @@ typedef swiftparse_trivia_piece_t CTriviaPiece;
37
37
typedef swiftparse_syntax_kind_t CSyntaxKind;
38
38
39
39
namespace {
40
+
41
+ static unsigned getByteOffset (SourceLoc Loc, SourceManager &SM,
42
+ unsigned BufferID) {
43
+ return Loc.isValid () ? SM.getLocOffsetInBuffer (Loc, BufferID) : 0 ;
44
+ }
45
+
46
+ static void initCRange (CRange &c_range, CharSourceRange range, SourceManager &SM,
47
+ unsigned BufferID) {
48
+ if (range.isValid ()) {
49
+ c_range.offset = getByteOffset (range.getStart (), SM, BufferID);
50
+ c_range.length = range.getByteLength ();
51
+ } else {
52
+ c_range.offset = 0 ;
53
+ c_range.length = 0 ;
54
+ }
55
+ }
56
+
40
57
class SynParser {
41
58
swiftparse_node_handler_t NodeHandler = nullptr ;
42
59
swiftparse_node_lookup_t NodeLookup = nullptr ;
60
+ swiftparse_diagnostic_handler_t DiagHandler = nullptr ;
43
61
44
62
public:
45
63
swiftparse_node_handler_t getNodeHandler () const {
@@ -50,6 +68,10 @@ class SynParser {
50
68
return NodeLookup;
51
69
}
52
70
71
+ swiftparse_diagnostic_handler_t getDiagnosticHandler () const {
72
+ return DiagHandler;
73
+ }
74
+
53
75
void setNodeHandler (swiftparse_node_handler_t hdl) {
54
76
auto prevBlk = NodeHandler;
55
77
NodeHandler = Block_copy (hdl);
@@ -62,9 +84,16 @@ class SynParser {
62
84
Block_release (prevBlk);
63
85
}
64
86
87
+ void setDiagnosticHandler (swiftparse_diagnostic_handler_t hdl) {
88
+ auto prevBlk = DiagHandler;
89
+ DiagHandler = Block_copy (hdl);
90
+ Block_release (prevBlk);
91
+ }
92
+
65
93
~SynParser () {
66
94
setNodeHandler (nullptr );
67
95
setNodeLookup (nullptr );
96
+ setDiagnosticHandler (nullptr );
68
97
}
69
98
70
99
swiftparse_client_node_t parse (const char *source);
@@ -102,13 +131,7 @@ class CLibParseActions : public SyntaxParseActions {
102
131
}
103
132
104
133
void makeCRange (CRange &c_range, CharSourceRange range) {
105
- if (range.isValid ()) {
106
- c_range.offset = SM.getLocOffsetInBuffer (range.getStart (), BufferID);
107
- c_range.length = range.getByteLength ();
108
- } else {
109
- c_range.offset = 0 ;
110
- c_range.length = 0 ;
111
- }
134
+ return initCRange (c_range, range, SM, BufferID);
112
135
}
113
136
114
137
void makeCRawToken (CRawSyntaxNode &node,
@@ -179,8 +202,71 @@ class CLibParseActions : public SyntaxParseActions {
179
202
return {result.length , result.node };
180
203
}
181
204
};
205
+
206
+ static swiftparser_diagnostic_severity_t getSeverity (DiagnosticKind Kind) {
207
+ switch (Kind) {
208
+ case swift::DiagnosticKind::Error:
209
+ return SWIFTPARSER_DIAGNOSTIC_SEVERITY_ERROR;
210
+ case swift::DiagnosticKind::Warning:
211
+ return SWIFTPARSER_DIAGNOSTIC_SEVERITY_WARNING;
212
+ case swift::DiagnosticKind::Note:
213
+ return SWIFTPARSER_DIAGNOSTIC_SEVERITY_NOTE;
214
+ default :
215
+ llvm_unreachable (" unrecognized diagnostic kind." );
216
+ }
182
217
}
183
218
219
+ struct DiagnosticDetail {
220
+ const char * Message;
221
+ unsigned Offset;
222
+ std::vector<CRange> CRanges;
223
+ swiftparser_diagnostic_severity_t Severity;
224
+ std::vector<swiftparse_diagnostic_fixit_t > AllFixits;
225
+ };
226
+
227
+ struct SynParserDiagConsumer : public DiagnosticConsumer {
228
+ SynParser &Parser;
229
+ const unsigned BufferID;
230
+ SynParserDiagConsumer (SynParser &Parser, unsigned BufferID):
231
+ Parser (Parser), BufferID(BufferID) {}
232
+ void handleDiagnostic (SourceManager &SM, SourceLoc Loc,
233
+ DiagnosticKind Kind,
234
+ StringRef FormatString,
235
+ ArrayRef<DiagnosticArgument> FormatArgs,
236
+ const DiagnosticInfo &Info) override {
237
+ assert (Kind != DiagnosticKind::Remark && " Shouldn't see this in parser." );
238
+ // The buffer where all char* will point into.
239
+ llvm::SmallString<256 > Buffer;
240
+ auto getCurrentText = [&]() -> const char * {
241
+ return Buffer.data () + Buffer.size ();
242
+ };
243
+ DiagnosticDetail Result;
244
+ Result.Severity = getSeverity (Kind);
245
+ Result.Offset = getByteOffset (Loc, SM, BufferID);
246
+
247
+ // Terminate each printed text with 0 so the client-side can use char* directly.
248
+ char NullTerm = ' \0 ' ;
249
+ {
250
+ // Print the error message to buffer and record it.
251
+ llvm::raw_svector_ostream OS (Buffer);
252
+ Result.Message = getCurrentText ();
253
+ DiagnosticEngine::formatDiagnosticText (OS, FormatString, FormatArgs);
254
+ OS << NullTerm;
255
+ }
256
+ for (auto R: Info.Ranges ) {
257
+ Result.CRanges .emplace_back ();
258
+ initCRange (Result.CRanges .back (), R, SM, BufferID);
259
+ }
260
+ for (auto Fixit: Info.FixIts ) {
261
+ Result.AllFixits .push_back ({CRange (), getCurrentText ()});
262
+ initCRange (Result.AllFixits .back ().range , Fixit.getRange (), SM, BufferID);
263
+ llvm::raw_svector_ostream OS (Buffer);
264
+ OS << Fixit.getText () << NullTerm;
265
+ }
266
+ Parser.getDiagnosticHandler ()(static_cast <void *>(&Result));
267
+ }
268
+ };
269
+
184
270
swiftparse_client_node_t SynParser::parse (const char *source) {
185
271
SourceManager SM;
186
272
unsigned bufID = SM.addNewSourceBuffer (
@@ -193,12 +279,19 @@ swiftparse_client_node_t SynParser::parse(const char *source) {
193
279
194
280
auto parseActions =
195
281
std::make_shared<CLibParseActions>(*this , SM, bufID);
196
- ParserUnit PU (SM, SourceFileKind::Library, bufID, langOpts,
282
+ // We have to use SourceFileKind::Main to avoid diagnostics like
283
+ // illegal_top_level_expr
284
+ ParserUnit PU (SM, SourceFileKind::Main, bufID, langOpts,
197
285
" syntax_parse_module" , std::move (parseActions),
198
286
/* SyntaxCache=*/ nullptr );
287
+ std::unique_ptr<SynParserDiagConsumer> pConsumer;
288
+ if (DiagHandler) {
289
+ pConsumer = llvm::make_unique<SynParserDiagConsumer>(*this , bufID);
290
+ PU.getDiagnosticEngine ().addConsumer (*pConsumer);
291
+ }
199
292
return PU.parse ();
200
293
}
201
-
294
+ }
202
295
// ===--- C API ------------------------------------------------------------===//
203
296
204
297
swiftparse_parser_t
@@ -235,3 +328,45 @@ swiftparse_parse_string(swiftparse_parser_t c_parser, const char *source) {
235
328
const char * swiftparse_syntax_structure_versioning_identifier (void ) {
236
329
return getSyntaxStructureVersioningIdentifier ();
237
330
}
331
+
332
+ // ===--------------------- C API for diagnostics -------------------------====//
333
+
334
+ void
335
+ swiftparse_parser_set_diagnostic_handler (swiftparse_parser_t c_parser,
336
+ swiftparse_diagnostic_handler_t hdl) {
337
+ SynParser *parser = static_cast <SynParser*>(c_parser);
338
+ parser->setDiagnosticHandler (hdl);
339
+ }
340
+
341
+ const char * swiftparse_diagnostic_get_message (swiftparser_diagnostic_t diag) {
342
+ return static_cast <const DiagnosticDetail*>(diag)->Message ;
343
+ }
344
+
345
+ unsigned swiftparse_diagnostic_get_fixit_count (swiftparser_diagnostic_t diag) {
346
+ return static_cast <const DiagnosticDetail*>(diag)->AllFixits .size ();
347
+ }
348
+
349
+ swiftparse_diagnostic_fixit_t
350
+ swiftparse_diagnostic_get_fixit (swiftparser_diagnostic_t diag, unsigned idx) {
351
+ auto allFixits = static_cast <const DiagnosticDetail*>(diag)->AllFixits ;
352
+ assert (idx < allFixits.size ());
353
+ return allFixits[idx];
354
+ }
355
+
356
+ unsigned swiftparse_diagnostic_get_range_count (swiftparser_diagnostic_t diag) {
357
+ return static_cast <const DiagnosticDetail*>(diag)->CRanges .size ();
358
+ }
359
+
360
+ swiftparse_range_t
361
+ swiftparse_diagnostic_get_range (swiftparser_diagnostic_t diag, unsigned idx) {
362
+ return static_cast <const DiagnosticDetail*>(diag)->CRanges [idx];
363
+ }
364
+
365
+ swiftparser_diagnostic_severity_t
366
+ swiftparse_diagnostic_get_severity (swiftparser_diagnostic_t diag) {
367
+ return static_cast <const DiagnosticDetail*>(diag)->Severity ;
368
+ }
369
+
370
+ unsigned swiftparse_diagnostic_get_source_loc (swiftparser_diagnostic_t diag) {
371
+ return static_cast <const DiagnosticDetail*>(diag)->Offset ;
372
+ }
0 commit comments