In a C# incremental generator I am authoring, beginning from an ArgumentSyntax, I am trying to inspect the inline initializer for a readonly field referenced as a method argument. Understanding that value inspection is impossible, I thought that I could traverse the syntax tree to find the definition of the field, and if it had an inline initializer, then I could at least use that value (with the understanding that the field could be overwritten in a constructor).
var argumentOperation = (IArgumentOperation)context.SemanticModel.GetOperation(argumentSyntax, cancellationToken)!;
switch (argumentOperation.Parameter?.Name)
{
case "argumentToInspect":
break;
default:
return;
}
if (argumentOperation.Value is not IFieldReferenceOperation fieldReferenceOperation ||
!fieldReferenceOperation.Field.IsReadOnly)
{
return;
}
var fieldSyntaxNode = fieldReferenceOperation.Field.DeclaringSyntaxReferences[0].GetSyntax(cancellationToken);
Debug.WriteLine($"fieldSyntaxNode kind: {fieldSyntaxNode.Kind()}"); // VariableDeclarator
Debug.WriteLine($"parent kind: {fieldSyntaxNode.Parent.Kind()}"); // VariableDeclaration
Debug.WriteLine($"grandparent kind: {fieldSyntaxNode.Parent.Parent.Kind()}"); // FieldDeclaration
var nodeOperation = context.SemanticModel.GetOperation(fieldSyntaxNode, cancellationToken); // null
var parentOperation = context.SemanticModel.GetOperation(fieldSyntaxNode.Parent, cancellationToken); // null
var grandparentOperation = context.SemanticModel.GetOperation(fieldSyntaxNode.Parent.Parent, cancellationToken); // null
The field in question is declared such as:
private static readonly MyClass instance = new();
Which is then referenced as:
MyMethod(instance);
Given that I am able to find the FieldDeclarationSyntax (fieldSyntaxNode.Parent.Parent), I'm not sure why I'm unable to find any relevant IOperations (e.g., IVariableDeclaratorOperation, IVariableDeclarationOperation, or IFieldInitializerOperation). The field declaration and field reference passed as an argument (to MyMethod) are in the same file, so my understanding is that the same semantic model (context.SemanticModel) should be able to produce the relevant operations, but I am only getting null from GetOperation on the field declaration.
Am I approaching this the wrong way? Given that I can find the syntax of the field declaration, I could try to manually parse the text for the information that I need, but I don't understand why I can't use the IOperation API to inspect the field initializer.
While I am still unclear as to which nodes might generate either
IVariableDeclaratorOperationorIVariableDeclarationOperation, I was able to discover theIFieldInitializerOperation(which is ultimately the one I was actually looking for).In the case of an inline field initializer,
GetOperationwill yield theIFieldInitializerOperationfor theEqualsValueClauseSyntaxnode, which is a descendant node of theFieldDeclarationSyntax.Tangentially related to what I originally asked, I can discover an initializing assignment in the constructor by finding an
AssignmentExpressionSyntaxwithKindofSimpleAssignmentExpressionwhich has aConstructorDeclarationSyntaxancestor node. From this node I can receive anISimpleAssignmentOperationwith aTargetofIFieldReferenceOperation.Given the
Valueof theIFieldInitializationOperationand/orISimpleAssignmentOperation, I am able to use this information to more powerfully (and correctly) parse the initialization ofreadonlyfields.