Skip to content

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

Merged
merged 1 commit into from
Mar 2, 2019

Conversation

nkcsgexi
Copy link
Contributor

This allows SwiftSyntax to listen to emitted diagnostics during
parsing.

rdar://48439271

@nkcsgexi
Copy link
Contributor Author

@swift-ci please smoke test

@nkcsgexi nkcsgexi requested a review from akyrtzi February 28, 2019 19:33
swiftparse_range_t range;
/// Represent the text for replacement.
const char* text;
} swiftparse_fixit_t;
Copy link
Contributor

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 {
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

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) {
Copy link
Contributor

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) {
Copy link
Contributor

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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add static.

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

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.

@CodaFi
Copy link
Contributor

CodaFi commented Mar 1, 2019

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.

@nkcsgexi
Copy link
Contributor Author

nkcsgexi commented Mar 1, 2019

@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.

@nkcsgexi nkcsgexi force-pushed the diagnostics-c-api branch from 2fb07d2 to 339d69d Compare March 1, 2019 21:22
@nkcsgexi
Copy link
Contributor Author

nkcsgexi commented Mar 1, 2019

@akyrtzi all comments are done

This allows SwiftSyntax to listen to emitted diagnostics during
parsing.

rdar://48439271
@nkcsgexi nkcsgexi force-pushed the diagnostics-c-api branch from 339d69d to a86f89d Compare March 1, 2019 23:22
@nkcsgexi
Copy link
Contributor Author

nkcsgexi commented Mar 2, 2019

@swift-ci please smoke test

Copy link
Contributor

@akyrtzi akyrtzi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job! 👍

@nkcsgexi nkcsgexi merged commit 740b476 into swiftlang:master Mar 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants