private static SyntaxNode Unwrap(ISyntaxFactsService syntaxFacts, SyntaxNode node) { var invocation = node as TInvocationExpression; if (invocation != null) { return(syntaxFacts.GetExpressionOfInvocationExpression(invocation)); } var memberAccess = node as TMemberAccessExpression; if (memberAccess != null) { return(syntaxFacts.GetExpressionOfMemberAccessExpression(memberAccess)); } var conditionalAccess = node as TConditionalAccessExpression; if (conditionalAccess != null) { return(syntaxFacts.GetExpressionOfConditionalAccessExpression(conditionalAccess)); } var elementAccess = node as TElementAccessExpression; if (elementAccess != null) { return(syntaxFacts.GetExpressionOfElementAccessExpression(elementAccess)); } return(null); }
protected override bool IsViableExtensionMethod(IMethodSymbol method, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken) { var leftExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(expression) ?? syntaxFacts.GetExpressionOfConditionalMemberAccessExpression(expression); if (leftExpression == null) { return(false); } var semanticInfo = semanticModel.GetTypeInfo(leftExpression, cancellationToken); var leftExpressionType = semanticInfo.Type; return(leftExpressionType != null && method.ReduceExtensionMethod(leftExpressionType) != null); }
protected override bool IsViableExtensionMethod(IMethodSymbol method, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken) { var leftExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(expression); if (leftExpression == null) { if (expression.IsKind(SyntaxKind.CollectionInitializerExpression)) { leftExpression = expression.GetAncestor <ObjectCreationExpressionSyntax>(); } else { return(false); } } var semanticInfo = semanticModel.GetTypeInfo(leftExpression, cancellationToken); var leftExpressionType = semanticInfo.Type; return(IsViableExtensionMethod(method, leftExpressionType)); }
private static SyntaxNode Unwrap(ISyntaxFactsService syntaxFacts, SyntaxNode node) { if (node is TInvocationExpression invocation) { return(syntaxFacts.GetExpressionOfInvocationExpression(invocation)); } if (node is TMemberAccessExpression memberAccess) { return(syntaxFacts.GetExpressionOfMemberAccessExpression(memberAccess)); } if (node is TConditionalAccessExpression conditionalAccess) { return(syntaxFacts.GetExpressionOfConditionalAccessExpression(conditionalAccess)); } if (node is TElementAccessExpression elementAccess) { return(syntaxFacts.GetExpressionOfElementAccessExpression(elementAccess)); } return(null); }
internal List <Match <TAssignmentStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax> > Analyze() { if (_syntaxFacts.GetObjectCreationInitializer(_objectCreationExpression) != null) { // Don't bother if this already has an initializer. return(null); } _containingStatement = _objectCreationExpression.FirstAncestorOrSelf <TStatementSyntax>(); if (_containingStatement == null) { return(null); } if (!TryInitializeVariableDeclarationCase() && !TryInitializeAssignmentCase()) { return(null); } var containingBlock = _containingStatement.Parent; var foundStatement = false; List <Match <TAssignmentStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax> > matches = null; HashSet <string> seenNames = null; foreach (var child in containingBlock.ChildNodesAndTokens()) { if (!foundStatement) { if (child == _containingStatement) { foundStatement = true; } continue; } if (child.IsToken) { break; } var statement = child.AsNode() as TAssignmentStatementSyntax; if (statement == null) { break; } if (!_syntaxFacts.IsSimpleAssignmentStatement(statement)) { break; } SyntaxNode left, right; _syntaxFacts.GetPartsOfAssignmentStatement(statement, out left, out right); var rightExpression = right as TExpressionSyntax; var leftMemberAccess = left as TMemberAccessExpressionSyntax; if (!_syntaxFacts.IsSimpleMemberAccessExpression(leftMemberAccess)) { break; } var expression = (TExpressionSyntax)_syntaxFacts.GetExpressionOfMemberAccessExpression(leftMemberAccess); if (!ValuePatternMatches(expression)) { break; } // found a match! seenNames = seenNames ?? new HashSet <string>(); matches = matches ?? new List <Match <TAssignmentStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax> >(); // If we see an assignment to the same property/field, we can't convert it // to an initializer. var name = _syntaxFacts.GetNameOfMemberAccessExpression(leftMemberAccess); var identifier = _syntaxFacts.GetIdentifierOfSimpleName(name); if (!seenNames.Add(identifier.ValueText)) { break; } matches.Add(new Match <TAssignmentStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax>( statement, leftMemberAccess, rightExpression)); } return(matches); }
internal ImmutableArray <Match <TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax> >?Analyze() { if (_syntaxFacts.GetObjectCreationInitializer(_objectCreationExpression) != null) { // Don't bother if this already has an initializer. return(null); } _containingStatement = _objectCreationExpression.FirstAncestorOrSelf <TStatementSyntax>(); if (_containingStatement == null) { return(null); } if (!TryInitializeVariableDeclarationCase() && !TryInitializeAssignmentCase()) { return(null); } var containingBlock = _containingStatement.Parent; var foundStatement = false; var matches = ArrayBuilder <Match <TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax> > .GetInstance(); HashSet <string> seenNames = null; foreach (var child in containingBlock.ChildNodesAndTokens()) { if (!foundStatement) { if (child == _containingStatement) { foundStatement = true; continue; } continue; } if (child.IsToken) { break; } var statement = child.AsNode() as TAssignmentStatementSyntax; if (statement == null) { break; } if (!_syntaxFacts.IsSimpleAssignmentStatement(statement)) { break; } _syntaxFacts.GetPartsOfAssignmentStatement( statement, out var left, out var right); var rightExpression = right as TExpressionSyntax; var leftMemberAccess = left as TMemberAccessExpressionSyntax; if (!_syntaxFacts.IsSimpleMemberAccessExpression(leftMemberAccess)) { break; } var expression = (TExpressionSyntax)_syntaxFacts.GetExpressionOfMemberAccessExpression(leftMemberAccess); if (!ValuePatternMatches(expression)) { break; } // Don't offer this fix if the value we're initializing is itself referenced // on the RHS of the assignment. For example: // // var v = new X(); // v.Prop = v.Prop.WithSomething(); // // Or with // // v = new X(); // v.Prop = v.Prop.WithSomething(); // // In the first case, 'v' is being initialized, and so will not be available // in the object initializer we create. // // In the second case we'd change semantics because we'd access the old value // before the new value got written. if (ExpressionContainsValuePattern(rightExpression)) { break; } // If we have code like "x.v = .Length.ToString()" // then we don't want to change this into: // // var x = new Whatever() With { .v = .Length.ToString() } // // The problem here is that .Length will change it's meaning to now refer to the // object that we're creating in our object-creation expression. if (ImplicitMemberAccessWouldBeAffected(rightExpression)) { break; } // found a match! seenNames = seenNames ?? new HashSet <string>(); // If we see an assignment to the same property/field, we can't convert it // to an initializer. var name = _syntaxFacts.GetNameOfMemberAccessExpression(leftMemberAccess); var identifier = _syntaxFacts.GetIdentifierOfSimpleName(name); if (!seenNames.Add(identifier.ValueText)) { break; } matches.Add(new Match <TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax>( statement, leftMemberAccess, rightExpression)); } return(matches.ToImmutableAndFree()); }
private static void RemoveAwaitFromCallerIfPresent( SyntaxEditor editor, ISyntaxFactsService syntaxFacts, SyntaxNode root, ReferenceLocation referenceLocation, CancellationToken cancellationToken) { if (referenceLocation.IsImplicit) { return; } var location = referenceLocation.Location; var token = location.FindToken(cancellationToken); var nameNode = token.Parent; if (nameNode == null) { return; } // Look for the following forms: // await M(...) // await <expr>.M(...) // await M(...).ConfigureAwait(...) // await <expr>.M(...).ConfigureAwait(...) var expressionNode = nameNode; if (syntaxFacts.IsNameOfMemberAccessExpression(nameNode)) { expressionNode = nameNode.Parent; } if (!syntaxFacts.IsExpressionOfInvocationExpression(expressionNode)) { return; } // We now either have M(...) or <expr>.M(...) var invocationExpression = expressionNode.Parent; Debug.Assert(syntaxFacts.IsInvocationExpression(invocationExpression)); if (syntaxFacts.IsExpressionOfAwaitExpression(invocationExpression)) { // Handle the case where we're directly awaited. var awaitExpression = invocationExpression.Parent; editor.ReplaceNode(awaitExpression, (currentAwaitExpression, generator) => syntaxFacts.GetExpressionOfAwaitExpression(currentAwaitExpression) .WithTriviaFrom(currentAwaitExpression)); } else if (syntaxFacts.IsExpressionOfMemberAccessExpression(invocationExpression)) { // Check for the .ConfigureAwait case. var parentMemberAccessExpression = invocationExpression.Parent; var parentMemberAccessExpressionNameNode = syntaxFacts.GetNameOfMemberAccessExpression( parentMemberAccessExpression); var parentMemberAccessExpressionName = syntaxFacts.GetIdentifierOfSimpleName(parentMemberAccessExpressionNameNode).ValueText; if (parentMemberAccessExpressionName == nameof(Task.ConfigureAwait)) { var parentExpression = parentMemberAccessExpression.Parent; if (syntaxFacts.IsExpressionOfAwaitExpression(parentExpression)) { var awaitExpression = parentExpression.Parent; editor.ReplaceNode(awaitExpression, (currentAwaitExpression, generator) => { var currentConfigureAwaitInvocation = syntaxFacts.GetExpressionOfAwaitExpression(currentAwaitExpression); var currentMemberAccess = syntaxFacts.GetExpressionOfInvocationExpression(currentConfigureAwaitInvocation); var currentInvocationExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(currentMemberAccess); return(currentInvocationExpression.WithTriviaFrom(currentAwaitExpression)); }); } } } }
protected override bool IsViableExtensionMethod(IMethodSymbol method, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken) { var leftExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(expression) ?? syntaxFacts.GetExpressionOfConditionalMemberAccessExpression(expression); if (leftExpression == null) { if (expression.IsKind(SyntaxKind.CollectionInitializerExpression)) { leftExpression = expression.GetAncestor<ObjectCreationExpressionSyntax>(); } else { return false; } } var semanticInfo = semanticModel.GetTypeInfo(leftExpression, cancellationToken); var leftExpressionType = semanticInfo.Type; return leftExpressionType != null && method.ReduceExtensionMethod(leftExpressionType) != null; }
private void RemoveAwaitFromCallerIfPresent( SyntaxEditor editor, ISyntaxFactsService syntaxFacts, SyntaxNode root, ReferenceLocation referenceLocation, CancellationToken cancellationToken) { if (referenceLocation.IsImplicit) { return; } var location = referenceLocation.Location; var token = location.FindToken(cancellationToken); var nameNode = token.Parent; if (nameNode == null) { return; } // Look for the following forms: // await M(...) // await <expr>.M(...) // await M(...).ConfigureAwait(...) // await <expr>.M(...).ConfigureAwait(...) var expressionNode = nameNode; if (syntaxFacts.IsNameOfMemberAccessExpression(nameNode)) { expressionNode = nameNode.Parent; } if (!syntaxFacts.IsExpressionOfInvocationExpression(expressionNode)) { return; } // We now either have M(...) or <expr>.M(...) var invocationExpression = expressionNode.Parent; Debug.Assert(syntaxFacts.IsInvocationExpression(invocationExpression)); if (syntaxFacts.IsExpressionOfAwaitExpression(invocationExpression)) { // Handle the case where we're directly awaited. var awaitExpression = invocationExpression.Parent; editor.ReplaceNode(awaitExpression, (currentAwaitExpression, generator) => syntaxFacts.GetExpressionOfAwaitExpression(currentAwaitExpression) .WithTriviaFrom(currentAwaitExpression)); } else if (syntaxFacts.IsExpressionOfMemberAccessExpression(invocationExpression)) { // Check for the .ConfigureAwait case. var parentMemberAccessExpression = invocationExpression.Parent; var parentMemberAccessExpressionNameNode = syntaxFacts.GetNameOfMemberAccessExpression( parentMemberAccessExpression); var parentMemberAccessExpressionName = syntaxFacts.GetIdentifierOfSimpleName(parentMemberAccessExpressionNameNode).ValueText; if (parentMemberAccessExpressionName == nameof(Task.ConfigureAwait)) { var parentExpression = parentMemberAccessExpression.Parent; if (syntaxFacts.IsExpressionOfAwaitExpression(parentExpression)) { var awaitExpression = parentExpression.Parent; editor.ReplaceNode(awaitExpression, (currentAwaitExpression, generator) => { var currentConfigureAwaitInvocation = syntaxFacts.GetExpressionOfAwaitExpression(currentAwaitExpression); var currentMemberAccess = syntaxFacts.GetExpressionOfInvocationExpression(currentConfigureAwaitInvocation); var currentInvocationExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(currentMemberAccess); return currentInvocationExpression.WithTriviaFrom(currentAwaitExpression); }); } } } }
protected override bool IsViableExtensionMethod(IMethodSymbol method, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken) { var leftExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(expression) ?? syntaxFacts.GetExpressionOfConditionalMemberAccessExpression(expression); if (leftExpression == null) { return false; } var semanticInfo = semanticModel.GetTypeInfo(leftExpression, cancellationToken); var leftExpressionType = semanticInfo.Type; return leftExpressionType != null && method.ReduceExtensionMethod(leftExpressionType) != null; }