Skip to content

Parsing for Parameter Nullchecking#35826

Merged
fayrose merged 52 commits intodotnet:features/param-nullcheckingfrom
fayrose:param-nullchecking
May 30, 2019
Merged

Parsing for Parameter Nullchecking#35826
fayrose merged 52 commits intodotnet:features/param-nullcheckingfrom
fayrose:param-nullchecking

Conversation

@fayrose
Copy link
Copy Markdown
Contributor

@fayrose fayrose commented May 20, 2019

Contains parsing for general case, lambda case and lambda case with multiple parameters, as well as initial test cases.

Relates to #36024 (test plan)

@fayrose fayrose requested a review from a team as a code owner May 20, 2019 20:58
@YairHalberstadt
Copy link
Copy Markdown
Contributor

In commit b567a0d you made a large number of white space changes that appear to be unintended.

Would you be able to revert that commit?

This reverts commit 5c7612b.
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

Do we have a tracking bug to update the "add null check" IDE feature to use this if the language version is high enough?

We should also have a feature that looks for null-param checking code and offers to convert to this form.

public void TestAnonymousDelegateNullChecking()
{
UsingTree(@"
delegate void Del(int x!);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this should likely be an error right? you shouldnt' be allowed to place these on delegate-decls or interface/abstract methods right?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note: if these are not allowed, i would put the check for this not in hte parser.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Will create interface/abstract tests and take a look at delegates

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note: just to make sure we're on hte same page, even if this is not allowed by the language, the checks should not be in the parser. That will make parsing of these guys even more context sensitive, which adds complexity and makes incremental parsing harder/more-dangerous. So we should allow parsing of these, but then give a nice error later on (i.e. when making the actual parameter symbols) if these are not allowed for teh current sort of construct.

Another case: extern methods.

Copy link
Copy Markdown
Member

@RikkiGibson RikkiGibson May 28, 2019

Choose a reason for hiding this comment

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

if you are already writing tests for abstract methods and interface methods then please go ahead, but I would approve the PR without them as I know you'll get to them when you do the semantic side of this feature.

When PRing to feature branches please feel free to handle suggestions for additions with // PROTOTYPE comments, as long as the implementation is correct for the scenarios you've tested so far.

Copy link
Copy Markdown
Member

@RikkiGibson RikkiGibson left a comment

Choose a reason for hiding this comment

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

Looks good. All I see remaining is:

  • Mark PROTOTYPE or fix diagnostics produced in TestNullCheckedSingleParamNoSpaces
  • Mark PROTOTYPE the places where TryEatToken could be used, to update after master gets merged into the feature branch

/// <summary>
/// Looks up a localized string similar to The attribute [EnumeratorCancellation] cannot be used on multiple parameters.
/// </summary>
internal static string ERR_MultipleEnumeratorCancellationAttributes {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Feels odd that this diff is in here. Maybe merging in latest master and rebuilding will clean it up.

else
{
var name = this.ParseIdentifierToken();
var exclamation = this.CurrentToken.Kind == SyntaxKind.ExclamationToken ? this.EatToken(SyntaxKind.ExclamationToken) : null;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Perhaps a prototype comment for this and similar checks which can be resolved after you merge master into the feature branch.

@RikkiGibson
Copy link
Copy Markdown
Member

Might be good to squash when you merge due to the number of commits.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

Overall, things look good. But i would attempt to unify the pattern you use for handling incorrect tokens. Note: i do not mean you need to extract a common method to handle them, simply that the codepaths should look and feel similar, since they're effectively doing the same thing.

@333fred
Copy link
Copy Markdown
Member

333fred commented May 29, 2019

LGTM (commit 48). The comment I left about leading trivia can be addressed via prototype for now if you determine I was correct.

[Fact]
public void TestOptParamMethodDeclarationWithNullValidationNoSpaces()
{
UsingStatement(@"void M(string name!=null) { }", expectedErrors: new DiagnosticDescription[]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

!= [](start = 47, length = 2)

We should also add more tests around trivia before/after this node so we make sure that we're preserving. Can be added in a follow up PR to not hold this initial one up.

arrow = AddTrailingSkippedSyntax(arrow, gt);
AddLeadingSkippedSyntax(arrow, notEq.GetLeadingTrivia());
exclamation = AddLeadingSkippedSyntax(arrow, SyntaxFactory.MissingToken(SyntaxKind.ExclamationToken));
exclamation = SyntaxFactory.MissingToken(SyntaxKind.ExclamationToken);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👍 Hopefully, all the construction/shuffling of the raw information is clear here for you :) I try to keep a mental model of all the nodes and what's going on with them, which helps make certain things stand out as looking "wrong". i.e. we had the 'arrow' nodes appearing in two places. on the 'arrow' local itself, but also as leading skipped syntax for the exclamation. This violated the strict invariants of the tree.

Thanks!

N(SyntaxKind.Parameter);
{
N(SyntaxKind.IdentifierToken, "x");
N(SyntaxKind.ExclamationToken);
Copy link
Copy Markdown
Contributor

@CyrusNajmabadi CyrusNajmabadi May 30, 2019

Choose a reason for hiding this comment

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

do our parsing tests actually validate that tree invariants are preserved? we should do that so that we catch cases where we are either missing data in the tree, or we have duplicated data.

Note: such a change can come in a later PR.

However, it is very important as literally every layer above is written with the assumption that the compiler is absolutely guaranteeing these tree invariants. So we have to be careful to abide by them, otherwise the whole system above will fall over :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I believe there is a string equality assert that ensures the tree is correct (bc I kept running into that failing for a bit), but not 100% sure what you're referring to.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That's likely what i'm referring to. Note: if that assert fails, we def should never be checking in (to master). To me, that specific assert is a hard blocker as it means we're not abiding by a core invariant that everything else needs in order to function properly.

Thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

To be clear: merging into feature branch: totally ok. Merging into master with it possible to hit that assert (either inside our outside of tests): Def not ok. Thanks! :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah all tests would fail if that assert is hit; currently all passing :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Or at least the no-space test would fail.

@fayrose fayrose merged commit 3816bf8 into dotnet:features/param-nullchecking May 30, 2019
@fayrose fayrose deleted the param-nullchecking branch May 30, 2019 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants