Skip to content

Adjust records behavior around IOperations and analyzer actions.#46308

Merged
AlekseyTs merged 3 commits intodotnet:masterfrom
AlekseyTs:Records_20
Jul 28, 2020
Merged

Adjust records behavior around IOperations and analyzer actions.#46308
AlekseyTs merged 3 commits intodotnet:masterfrom
AlekseyTs:Records_20

Conversation

@AlekseyTs
Copy link
Contributor

No description provided.

@AlekseyTs
Copy link
Contributor Author

@mavasani, @cston, @jcouv, @RikkiGibson, @333fred Please review.

2 similar comments
@AlekseyTs
Copy link
Contributor Author

@mavasani, @cston, @jcouv, @RikkiGibson, @333fred Please review.

@AlekseyTs
Copy link
Contributor Author

@mavasani, @cston, @jcouv, @RikkiGibson, @333fred Please review.

{
context.RegisterSymbolStartAction(Handle1, SymbolKind.Method);
context.RegisterSymbolStartAction(Handle1, SymbolKind.Property);
context.RegisterSymbolStartAction(Handle1, SymbolKind.Parameter);
Copy link
Contributor

@mavasani mavasani Jul 27, 2020

Choose a reason for hiding this comment

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

Can we add a context.RegisterSymbolStartAction(..., SymbolKind.NamedType) with a nested RegisterSymbolEndAction and then verify that all the FireCountX are 0 at the start of the former callback and 1 at the start of latter callback? This should verify correct ordering of callbacks. #Resolved


public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(Handle, SymbolKind.Method);
Copy link
Contributor

@mavasani mavasani Jul 27, 2020

Choose a reason for hiding this comment

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

Should we also add context.RegisterSymbolAction(Handle, SymbolKind.NamedType); to verify callbacks for the record type itself? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we also add context.RegisterSymbolAction(Handle, SymbolKind.NamedType); to verify callbacks for the record type itself?

I can certainly add one, I don't think there is anything interesting about the type itself, the PR is was mostly focused on record members.


In reply to: 461193457 [](ancestors = 461193457)

Debug.Assert(operationBlock.Parent.IsImplicit);
Debug.Assert(operationBlock.Parent.Parent is IConstructorBodyOperation ctorBody &&
ctorBody.Initializer == operationBlock.Parent);

Copy link
Contributor

@mavasani mavasani Jul 27, 2020

Choose a reason for hiding this comment

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

Should we add the below assert?

Suggested change
Debug.Assert(!operationBlock.Parent.Parent.IsImplicit);
``` #Resolved

}
}";
comp = CreateCompilation(sourceB, references: new[] { refA }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe);
comp.VerifyDiagnostics();
Copy link
Contributor

@mavasani mavasani Jul 27, 2020

Choose a reason for hiding this comment

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

Was there a reason to remove this call? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Was there a reason to remove this call?

It was determined redundant in one of the previous PRs due to .VerifyDiagnostics() below.


In reply to: 461201750 [](ancestors = 461201750)

declaredNode, declaredSymbol, executableCodeBlocks, (codeBlocks) => codeBlocks.SelectMany(
cb =>
{
var filter = semanticModel.GetSyntaxNodesToAnalyzeFilter(cb, declaredSymbol);
Copy link
Contributor

@mavasani mavasani Jul 27, 2020

Choose a reason for hiding this comment

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

Is the below existing invocation to this method redundant now?

Func<SyntaxNode, bool> additionalFilterOpt = semanticModel.GetSyntaxNodesToAnalyzeFilter(declaredNode, declaredSymbol);
bool shouldAddNode(SyntaxNode node) => (descendantDeclsToSkipOpt == null || !descendantDeclsToSkipOpt.Contains(node)) && (additionalFilterOpt is null || additionalFilterOpt(node));

#Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is the below existing invocation to this method redundant now?

Func<SyntaxNode, bool> additionalFilterOpt = semanticModel.GetSyntaxNodesToAnalyzeFilter(declaredNode, declaredSymbol);
bool shouldAddNode(SyntaxNode node) => (descendantDeclsToSkipOpt == null || !descendantDeclsToSkipOpt.Contains(node)) && (additionalFilterOpt is null || additionalFilterOpt(node));

No, that place iterates through nodes itself


In reply to: 461205407 [](ancestors = 461205407)

Copy link
Contributor

@mavasani mavasani left a comment

Choose a reason for hiding this comment

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

Overall LGTM. Only relevant open question is if we can remove the existing invocation to GetSyntaxNodesToAnalyzeFilter in the analyzer driver as we are now invoking it directly within the core analyzer executor.

@AlekseyTs
Copy link
Contributor Author

Only relevant open question is if we can remove the existing invocation to GetSyntaxNodesToAnalyzeFilter in the analyzer driver as we are now invoking it directly within the core analyzer executor.

Responded on that thread.


In reply to: 456180326 [](ancestors = 456180326)

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 2)

@jcouv jcouv self-assigned this Jul 27, 2020
@AlekseyTs
Copy link
Contributor Author

@cston, @RikkiGibson, @333fred Please review, need a second sign-off.

@AlekseyTs
Copy link
Contributor Author

@cston, @RikkiGibson, @333fred Please review, need a second sign-off.

model = (accessor.Body != null || accessor.ExpressionBody != null) ? GetOrAddModel(node) : null;
break;

case RecordDeclarationSyntax { ParameterList: { }, PrimaryConstructorBaseType: { } } recordDeclaration when TryGetSynthesizedRecordConstructor(recordDeclaration) is SynthesizedRecordConstructor ctor:
Copy link
Contributor

@cston cston Jul 28, 2020

Choose a reason for hiding this comment

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

ctor [](start = 210, length = 4)

Consider omitting the variable name so it's clear we're not expecting to use the value. #Pending

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Consider omitting the variable name so it's clear we're not expecting to use the value.

Sometimes it is useful during debugging


In reply to: 461794242 [](ancestors = 461794242)

return node == baseType.ArgumentList;
}

return true;
Copy link
Contributor

@cston cston Jul 28, 2020

Choose a reason for hiding this comment

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

return true [](start = 39, length = 11)

Is this correct given the comment above ("Accept only nodes ...")? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this correct given the comment above ("Accept only nodes ...")?

I think yes, this filter is called in the process of descending down the tree. If it returns false for parent node, it is never called for a child node.


In reply to: 461820251 [](ancestors = 461820251)

var recordDeclarations = tree.GetRoot().DescendantNodes().OfType<RecordDeclarationSyntax>().Skip(1).ToArray();

Assert.Equal("C", recordDeclarations[0].Identifier.ValueText);
Assert.Null(model.GetOperation(recordDeclarations[0]));
Copy link
Contributor

@cston cston Jul 28, 2020

Choose a reason for hiding this comment

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

model.GetOperation(recordDeclarations[0]) [](start = 24, length = 41)

Why does GetOperation() return null? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why does GetOperation() return null?

There is no user code for this primary constructor, no code blocks to fire analyzers on, we never create a member semantic model for a primary constructor like that, etc. Technically, we could produce an "empty" IConstructorBodyOperation node, but then we would have to do something with analyzers to make sure an action for this node would fire. Unfortunately, analyzer driver is able to do that only when there is a "real" node for an initializer or a body (see GetOperationsToAnalyze in AnalyzerDriver.cs), we have neither of them here. I decided to not deal with this complexity right now, when we don't really have a real scenario to enable.


In reply to: 461876729 [](ancestors = 461876729)

@AlekseyTs AlekseyTs merged commit 5d1ba27 into dotnet:master Jul 28, 2020
@ghost ghost added this to the Next milestone Jul 28, 2020
Copy link
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

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

Sorry for the late review. This LGTM

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