@@ -37,9 +37,27 @@ typedef swiftparse_trivia_piece_t CTriviaPiece;
3737typedef swiftparse_syntax_kind_t CSyntaxKind;
3838
3939namespace {
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+
4057class SynParser {
4158 swiftparse_node_handler_t NodeHandler = nullptr ;
4259 swiftparse_node_lookup_t NodeLookup = nullptr ;
60+ swiftparse_diagnostic_handler_t DiagHandler = nullptr ;
4361
4462public:
4563 swiftparse_node_handler_t getNodeHandler () const {
@@ -50,6 +68,10 @@ class SynParser {
5068 return NodeLookup;
5169 }
5270
71+ swiftparse_diagnostic_handler_t getDiagnosticHandler () const {
72+ return DiagHandler;
73+ }
74+
5375 void setNodeHandler (swiftparse_node_handler_t hdl) {
5476 auto prevBlk = NodeHandler;
5577 NodeHandler = Block_copy (hdl);
@@ -62,9 +84,16 @@ class SynParser {
6284 Block_release (prevBlk);
6385 }
6486
87+ void setDiagnosticHandler (swiftparse_diagnostic_handler_t hdl) {
88+ auto prevBlk = DiagHandler;
89+ DiagHandler = Block_copy (hdl);
90+ Block_release (prevBlk);
91+ }
92+
6593 ~SynParser () {
6694 setNodeHandler (nullptr );
6795 setNodeLookup (nullptr );
96+ setDiagnosticHandler (nullptr );
6897 }
6998
7099 swiftparse_client_node_t parse (const char *source);
@@ -102,13 +131,7 @@ class CLibParseActions : public SyntaxParseActions {
102131 }
103132
104133 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);
112135 }
113136
114137 void makeCRawToken (CRawSyntaxNode &node,
@@ -179,8 +202,71 @@ class CLibParseActions : public SyntaxParseActions {
179202 return {result.length , result.node };
180203 }
181204};
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+ }
182217}
183218
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+
184270swiftparse_client_node_t SynParser::parse (const char *source) {
185271 SourceManager SM;
186272 unsigned bufID = SM.addNewSourceBuffer (
@@ -193,12 +279,19 @@ swiftparse_client_node_t SynParser::parse(const char *source) {
193279
194280 auto parseActions =
195281 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,
197285 " syntax_parse_module" , std::move (parseActions),
198286 /* 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+ }
199292 return PU.parse ();
200293}
201-
294+ }
202295// ===--- C API ------------------------------------------------------------===//
203296
204297swiftparse_parser_t
@@ -235,3 +328,45 @@ swiftparse_parse_string(swiftparse_parser_t c_parser, const char *source) {
235328const char * swiftparse_syntax_structure_versioning_identifier (void ) {
236329 return getSyntaxStructureVersioningIdentifier ();
237330}
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