-
Notifications
You must be signed in to change notification settings - Fork 10.5k
SwiftSyntax Parser: expose parser diagnostics via C API. #22992
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@swift-ci please smoke test |
swiftparse_range_t range; | ||
/// Represent the text for replacement. | ||
const char* text; | ||
} swiftparse_fixit_t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit better to name this swiftparse_diagnostic_fixit_t
const char* text; | ||
} swiftparse_fixit_t; | ||
|
||
enum swiftparser_diagnostic_severity { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
swiftparser_diagnostic_severity_Note = 3, | ||
}; | ||
|
||
/// This is for the client to provide an opaque pointer that the parser will |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment seems incorrect, swiftparser_diagnostic_t
is provided by the parser, not the client.
|
||
/// This is for the client to provide an opaque pointer that the parser will | ||
/// associate with a diagnostic. | ||
/// This pointer is only valid when received from the argument of a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bit better to re-phrase "this pointer is only valid to access from within the swiftparse_diagnostic_handler_t block
typedef void* swiftparser_diagnostic_t; | ||
|
||
/// Invoked by the parser when a diagnostic is emitted. | ||
typedef void(^swiftparse_diagnostic_handler_t)(const swiftparser_diagnostic_t); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are passing a swiftparser_diagnostic_t
as const
in the block but then the swiftparse_diagnostic_*
functions accept a const
-less swiftparser_diagnostic_t
parameter, which would force to the clients to cast the const
away from the variable before calling the functions. Try changing the definition of the type to typedef const void* swiftparser_diagnostic_t;
instead.
swiftparse_diagnostic_get_fixit_at_index(swiftparser_diagnostic_t diag, | ||
unsigned idx) { | ||
auto allFixits = static_cast<DiagnosticDetail*>(diag)->AllFixits; | ||
assert(allFixits.size() >= idx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
idx
must be less than size()
it will be buffer overflow if it is equal to size()
.
@@ -37,9 +37,26 @@ typedef swiftparse_trivia_piece_t CTriviaPiece; | |||
typedef swiftparse_syntax_kind_t CSyntaxKind; | |||
|
|||
namespace { | |||
|
|||
unsigned getByteOffset(SourceLoc Loc, SourceManager &SM, unsigned BufferID) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick but I much prefer that static
functions have static
in front of them. Otherwise it is not obvious to me that the functions are static unless I check that they are contained in an anonymous namespace, which can be far apart from the function declaration. Same for the function below.
@@ -101,16 +128,6 @@ class CLibParseActions : public SyntaxParseActions { | |||
} | |||
} | |||
|
|||
void makeCRange(CRange &c_range, CharSourceRange range) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't have to remove it, you can have this method delegate to the global static function, e.g.:
void makeCRange(CRange &c_range, CharSourceRange range) {
return makeCRange(c_range, range, SM, BufferID);
}
that way you don't have to update the callers and have to pass the extra parameters at the call sites.
@@ -179,8 +196,68 @@ class CLibParseActions : public SyntaxParseActions { | |||
return {result.length, result.node}; | |||
} | |||
}; | |||
|
|||
swiftparser_diagnostic_severity getSeverity(DiagnosticKind Kind) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add static
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning an enum value is also subject to ABI and API concerns if we decide to add a severity kind in the future/do portability work later. Not sure how much that factors into the current design.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are your concerns ? AFAIK for enums in stable C APIs you only have to make sure to set specific integer values to the enum values and make sure to not change those integers in future versions. If you do add a new enum, bump the API version macro. This is what we have been doing with the libclang C API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that handles the API concerns.
As for ABI, the underlying type of an enumeration is implementation-defined which means there’s a hypothetical world in which the addition of a case (say with a negative tag) causes the compiler to select a new layout and break everybody.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not an issue because:
- This enum will just have a handful of values
- This library is intended to be used with a matching SwiftSyntax (their syntax definitions must match), you can't just mix-and-match them arbitrarily.
Please consider adding an in/out parameter for the length of any C strings this API takes/returns. LLVM’s abstractions that map raw strings have an interesting relationship to NUL bytes, especially internal NUL bytes. |
@CodaFi would it really be a problem? These null-terminated string segments will be used in the SwiftSyntax side to copy to a Swift string and discarded immediately afterwards. |
2fb07d2
to
339d69d
Compare
@akyrtzi all comments are done |
This allows SwiftSyntax to listen to emitted diagnostics during parsing. rdar://48439271
339d69d
to
a86f89d
Compare
@swift-ci please smoke test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job! 👍
This allows SwiftSyntax to listen to emitted diagnostics during
parsing.
rdar://48439271