public override Task ProvideArgumentAsync(ArgumentContext context) { if (context.PreviousValue is not null) { // This argument provider does not attempt to replace arguments already in code. return(Task.CompletedTask); } var symbols = context.SemanticModel.LookupSymbols( context.Position, name: context.Parameter.Name ); foreach (var symbol in symbols) { // Currently we check for an exact type match before using a variable from context. As we hone the // default argument provider heuristics, we may alter the definition of "in scope" as well as the type // and name check(s) that occur. if ( SymbolEqualityComparer.Default.Equals( context.Parameter.Type, symbol.GetSymbolType() ) ) { context.DefaultValue = context.Parameter.Name; return(Task.CompletedTask); } } return(Task.CompletedTask); }
public override async Task ProvideArgumentAsync(ArgumentContext context) { if (context.PreviousValue is not null) { // This argument provider does not attempt to replace arguments already in code. return; } var requireExactType = context.Parameter.Type.IsSpecialType() || context.Parameter.RefKind != RefKind.None; var symbols = context.SemanticModel.LookupSymbols(context.Position); // First try to find a local variable ISymbol? bestSymbol = null; string? bestSymbolName = null; CommonConversion bestConversion = default; foreach (var symbol in symbols) { ISymbol candidate; if (symbol.IsKind(SymbolKind.Parameter, out IParameterSymbol? parameter)) { candidate = parameter; } else if (symbol.IsKind(SymbolKind.Local, out ILocalSymbol? local)) { candidate = local; } else { continue; } CheckCandidate(candidate); } if (bestSymbol is not null) { context.DefaultValue = bestSymbolName; return; } // Next try fields and properties of the current type foreach (var symbol in symbols) { ISymbol candidate; if (symbol.IsKind(SymbolKind.Field, out IFieldSymbol? field)) { candidate = field; } else if (symbol.IsKind(SymbolKind.Property, out IPropertySymbol? property)) { candidate = property; } else { continue; } // Require a name match for primitive types if (candidate.GetSymbolType().IsSpecialType() && !string.Equals(candidate.Name, context.Parameter.Name, StringComparison.OrdinalIgnoreCase)) { continue; } CheckCandidate(candidate); } if (bestSymbol is not null) { context.DefaultValue = bestSymbolName; return; } // Finally, if the invocation occurs in an instance context, check the current type ('this' or 'Me') var tree = context.SemanticModel.SyntaxTree; var targetToken = await tree.GetTouchingTokenAsync(context.Position, context.CancellationToken).ConfigureAwait(false); if (IsInstanceContext(tree, targetToken, context.SemanticModel, context.CancellationToken)) { var enclosingSymbol = context.SemanticModel.GetEnclosingSymbol(targetToken.SpanStart, context.CancellationToken); while (enclosingSymbol is IMethodSymbol { MethodKind: MethodKind.LocalFunction or MethodKind.AnonymousFunction } method) { // It is allowed to reference the instance (`this`) within a local function or anonymous function, // as long as the containing method allows it enclosingSymbol = enclosingSymbol.ContainingSymbol; } if (enclosingSymbol is IMethodSymbol { ContainingType: { } containingType })