protected ImmutableArray <TMatch>?AnalyzeWorker() { if (_syntaxFacts.GetObjectCreationInitializer(_objectCreationExpression) != null) { // Don't bother if this already has an initializer. return(null); } if (!ShouldAnalyze()) { return(null); } _containingStatement = _objectCreationExpression.FirstAncestorOrSelf <TStatementSyntax>(); if (_containingStatement == null) { return(null); } if (!TryInitializeVariableDeclarationCase() && !TryInitializeAssignmentCase()) { return(null); } var matches = ArrayBuilder <TMatch> .GetInstance(); AddMatches(matches); return(matches.ToImmutableAndFree()); }
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()); }