From 00cf9ee8b6294025c58dcd86ea8fbb8c5ccad0c8 Mon Sep 17 00:00:00 2001 From: Manish Vasani Date: Fri, 13 Mar 2020 14:30:24 -0700 Subject: [PATCH] Oops forgot to checkin the files that were removed when moving couple of language services to shared layer --- ...harpMoveDeclarationNearReferenceService.cs | 68 ----- ...scardDeclarationsWithAssignmentsService.cs | 247 ----------------- ...veDeclarationNearReferenceService.State.cs | 193 ------------- ...ractMoveDeclarationNearReferenceService.cs | 258 ------------------ .../IMoveDeclarationNearReferenceService.cs | 26 -- ...scardDeclarationsWithAssignmentsService.cs | 32 --- ...asicMoveDeclarationNearReferenceService.vb | 52 ---- 7 files changed, 876 deletions(-) delete mode 100644 src/Features/CSharp/Portable/MoveDeclarationNearReference/CSharpMoveDeclarationNearReferenceService.cs delete mode 100644 src/Features/CSharp/Portable/ReplaceDiscardDeclarationsWithAssignments/CSharpReplaceDiscardDeclarationsWithAssignmentsService.cs delete mode 100644 src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.State.cs delete mode 100644 src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.cs delete mode 100644 src/Features/Core/Portable/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.cs delete mode 100644 src/Features/Core/Portable/ReplaceDiscardDeclarationsWithAssignments/IReplaceDiscardDeclarationsWithAssignmentsService.cs delete mode 100644 src/Features/VisualBasic/Portable/MoveDeclarationNearReference/VisualBasicMoveDeclarationNearReferenceService.vb diff --git a/src/Features/CSharp/Portable/MoveDeclarationNearReference/CSharpMoveDeclarationNearReferenceService.cs b/src/Features/CSharp/Portable/MoveDeclarationNearReference/CSharpMoveDeclarationNearReferenceService.cs deleted file mode 100644 index e0549978881..00000000000 --- a/src/Features/CSharp/Portable/MoveDeclarationNearReference/CSharpMoveDeclarationNearReferenceService.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Composition; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.MoveDeclarationNearReference; - -namespace Microsoft.CodeAnalysis.CSharp.MoveDeclarationNearReference -{ - [ExportLanguageService(typeof(IMoveDeclarationNearReferenceService), LanguageNames.CSharp), Shared] - internal partial class CSharpMoveDeclarationNearReferenceService : - AbstractMoveDeclarationNearReferenceService< - CSharpMoveDeclarationNearReferenceService, - StatementSyntax, - LocalDeclarationStatementSyntax, - VariableDeclaratorSyntax> - { - [ImportingConstructor] - public CSharpMoveDeclarationNearReferenceService() - { - } - - protected override bool IsMeaningfulBlock(SyntaxNode node) - { - return node is AnonymousFunctionExpressionSyntax || - node is LocalFunctionStatementSyntax || - node is CommonForEachStatementSyntax || - node is ForStatementSyntax || - node is WhileStatementSyntax || - node is DoStatementSyntax || - node is CheckedStatementSyntax; - } - - protected override SyntaxNode GetVariableDeclaratorSymbolNode(VariableDeclaratorSyntax variableDeclarator) - => variableDeclarator; - - protected override bool IsValidVariableDeclarator(VariableDeclaratorSyntax variableDeclarator) - => true; - - protected override SyntaxToken GetIdentifierOfVariableDeclarator(VariableDeclaratorSyntax variableDeclarator) - => variableDeclarator.Identifier; - - protected override async Task TypesAreCompatibleAsync( - Document document, ILocalSymbol localSymbol, - LocalDeclarationStatementSyntax declarationStatement, - SyntaxNode right, CancellationToken cancellationToken) - { - var type = declarationStatement.Declaration.Type; - if (type.IsVar) - { - // Type inference. Only merge if types match. - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - var rightType = semanticModel.GetTypeInfo(right, cancellationToken); - return Equals(localSymbol.Type, rightType.Type); - } - - return true; - } - - protected override bool CanMoveToBlock(ILocalSymbol localSymbol, SyntaxNode currentBlock, SyntaxNode destinationBlock) - => localSymbol.CanSafelyMoveLocalToBlock(currentBlock, destinationBlock); - } -} diff --git a/src/Features/CSharp/Portable/ReplaceDiscardDeclarationsWithAssignments/CSharpReplaceDiscardDeclarationsWithAssignmentsService.cs b/src/Features/CSharp/Portable/ReplaceDiscardDeclarationsWithAssignments/CSharpReplaceDiscardDeclarationsWithAssignmentsService.cs deleted file mode 100644 index e4ac85dff47..00000000000 --- a/src/Features/CSharp/Portable/ReplaceDiscardDeclarationsWithAssignments/CSharpReplaceDiscardDeclarationsWithAssignmentsService.cs +++ /dev/null @@ -1,247 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Composition; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp.CodeGeneration; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.CSharp.Utilities; -using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.RemoveUnusedParametersAndValues; -using Microsoft.CodeAnalysis.ReplaceDiscardDeclarationsWithAssignments; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.CSharp.ReplaceDiscardDeclarationsWithAssignments -{ - [ExportLanguageService(typeof(IReplaceDiscardDeclarationsWithAssignmentsService), LanguageNames.CSharp), Shared] - internal sealed class CSharpReplaceDiscardDeclarationsWithAssignmentsService : IReplaceDiscardDeclarationsWithAssignmentsService - { - [ImportingConstructor] - public CSharpReplaceDiscardDeclarationsWithAssignmentsService() - { - } - - public Task ReplaceAsync(SyntaxNode memberDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken) - { - var editor = new SyntaxEditor(memberDeclaration, CSharpSyntaxGenerator.Instance); - foreach (var child in memberDeclaration.DescendantNodes()) - { - switch (child) - { - case LocalDeclarationStatementSyntax localDeclarationStatement: - if (localDeclarationStatement.Declaration.Variables.Any(IsDiscardDeclaration)) - { - RemoveDiscardHelper.ProcessDeclarationStatement(localDeclarationStatement, editor); - } - - break; - - case CatchDeclarationSyntax catchDeclaration: - if (IsDiscardDeclaration(catchDeclaration)) - { - // "catch (Exception _)" => "catch (Exception)" - editor.ReplaceNode(catchDeclaration, catchDeclaration.WithIdentifier(default)); - } - - break; - - case DeclarationExpressionSyntax declarationExpression: - if (declarationExpression.Designation is DiscardDesignationSyntax discardSyntax) - { - // "M(out var _)" => "M(out _)" - // "M(out int _)" => "M(out _)" - - var discardToken = SyntaxFactory.Identifier( - leading: declarationExpression.GetLeadingTrivia(), - contextualKind: SyntaxKind.UnderscoreToken, - text: discardSyntax.UnderscoreToken.Text, - valueText: discardSyntax.UnderscoreToken.ValueText, - trailing: declarationExpression.GetTrailingTrivia()); - var replacementNode = SyntaxFactory.IdentifierName(discardToken); - - // Removing explicit type is possible only if there are no overloads of the method with same parameter. - // For example, if method "M" had overloads with signature "void M(int x)" and "void M(char x)", - // then the replacement "M(out int _)" => "M(out _)" will cause overload resolution error. - // Bail out if replacement changes semantics. - var speculationAnalyzer = new SpeculationAnalyzer(declarationExpression, - replacementNode, semanticModel, cancellationToken); - if (!speculationAnalyzer.ReplacementChangesSemantics()) - { - editor.ReplaceNode(declarationExpression, replacementNode); - } - } - - break; - - case DeclarationPatternSyntax declarationPattern: - if (declarationPattern.Designation is DiscardDesignationSyntax discardDesignationSyntax && - declarationPattern.Parent is IsPatternExpressionSyntax isPatternExpression) - { - // "x is int _" => "x is int" - var replacementNode = SyntaxFactory.BinaryExpression( - kind: SyntaxKind.IsExpression, - left: isPatternExpression.Expression, - operatorToken: isPatternExpression.IsKeyword, - right: declarationPattern.Type.WithTrailingTrivia(declarationPattern.GetTrailingTrivia())); - editor.ReplaceNode(isPatternExpression, replacementNode); - } - - break; - } - } - - return Task.FromResult(editor.GetChangedRoot()); - } - - private static bool IsDiscardDeclaration(VariableDeclaratorSyntax variable) - => variable.Identifier.Text == AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.DiscardVariableName; - private static bool IsDiscardDeclaration(CatchDeclarationSyntax catchDeclaration) - => catchDeclaration.Identifier.Text == AbstractRemoveUnusedParametersAndValuesDiagnosticAnalyzer.DiscardVariableName; - - private sealed class RemoveDiscardHelper : IDisposable - { - private readonly LocalDeclarationStatementSyntax _localDeclarationStatement; - private readonly SyntaxEditor _editor; - private readonly ArrayBuilder _statementsBuilder; - private SeparatedSyntaxList _currentNonDiscardVariables; - - private RemoveDiscardHelper(LocalDeclarationStatementSyntax localDeclarationStatement, SyntaxEditor editor) - { - _localDeclarationStatement = localDeclarationStatement; - _editor = editor; - - _statementsBuilder = ArrayBuilder.GetInstance(); - _currentNonDiscardVariables = new SeparatedSyntaxList(); - } - - public static void ProcessDeclarationStatement( - LocalDeclarationStatementSyntax localDeclarationStatement, - SyntaxEditor editor) - { - using var helper = new RemoveDiscardHelper(localDeclarationStatement, editor); - helper.ProcessDeclarationStatement(); - } - - public void Dispose() => _statementsBuilder.Free(); - - private void ProcessDeclarationStatement() - { - // We will replace all discard variable declarations in this method with discard assignments, - // For example, - // 1. "int _ = M();" is replaced with "_ = M();" - // 2. "int x = 1, _ = M(), y = 2;" is replaced with following statements: - // int x = 1; - // _ = M(); - // int y = 2; - // This is done to prevent compiler errors where the existing method has a discard - // variable declaration at a line following the one we added a discard assignment in our fix. - - // Process all the declared variables in the given local declaration statement, - // tracking the currently encountered non-discard variables. - foreach (var variable in _localDeclarationStatement.Declaration.Variables) - { - if (!IsDiscardDeclaration(variable)) - { - // Add to the list of currently encountered non-discard variables - _currentNonDiscardVariables = _currentNonDiscardVariables.Add(variable); - } - else - { - // Process currently encountered non-discard variables to generate - // a local declaration statement with these variables. - GenerateDeclarationStatementForCurrentNonDiscardVariables(); - - // Process the discard variable declaration to replace it - // with an assignment to discard. - GenerateAssignmentForDiscardVariable(variable); - } - } - - // Process all the remaining variable declarators to generate - // a local declaration statement with these variables. - GenerateDeclarationStatementForCurrentNonDiscardVariables(); - - // Now replace the original local declaration statement with - // the replacement statement list tracked in _statementsBuilder. - - if (_statementsBuilder.Count == 0) - { - // Nothing to replace. - return; - } - - // Move the leading trivia from original local declaration statement - // to the first statement of the replacement statement list. - var leadingTrivia = _localDeclarationStatement.Declaration.Type.GetLeadingTrivia() - .Concat(_localDeclarationStatement.Declaration.Type.GetTrailingTrivia()); - _statementsBuilder[0] = _statementsBuilder[0].WithLeadingTrivia(leadingTrivia); - - // Move the trailing trivia from original local declaration statement - // to the last statement of the replacement statement list. - var last = _statementsBuilder.Count - 1; - var trailingTrivia = _localDeclarationStatement.SemicolonToken.GetAllTrivia(); - _statementsBuilder[last] = _statementsBuilder[last].WithTrailingTrivia(trailingTrivia); - - // Replace the original local declaration statement with new statement list - // from _statementsBuilder. - if (_localDeclarationStatement.Parent is BlockSyntax || _localDeclarationStatement.Parent is SwitchSectionSyntax) - { - if (_statementsBuilder.Count > 1) - { - _editor.InsertAfter(_localDeclarationStatement, _statementsBuilder.Skip(1)); - } - - _editor.ReplaceNode(_localDeclarationStatement, _statementsBuilder[0]); - } - else - { - _editor.ReplaceNode(_localDeclarationStatement, SyntaxFactory.Block(_statementsBuilder)); - } - } - - private void GenerateDeclarationStatementForCurrentNonDiscardVariables() - { - // Generate a variable declaration with all the currently tracked non-discard declarators. - // For example, for a declaration "int x = 1, y = 2, _ = M(), z = 3;", we generate two variable declarations: - // 1. "int x = 1, y = 2;" and - // 2. "int z = 3;", - // which are split by a single assignment statement "_ = M();" - if (_currentNonDiscardVariables.Count > 0) - { - var statement = SyntaxFactory.LocalDeclarationStatement( - SyntaxFactory.VariableDeclaration(_localDeclarationStatement.Declaration.Type, _currentNonDiscardVariables)) - .WithAdditionalAnnotations(Formatter.Annotation); - _statementsBuilder.Add(statement); - _currentNonDiscardVariables = new SeparatedSyntaxList(); - } - } - - private void GenerateAssignmentForDiscardVariable(VariableDeclaratorSyntax variable) - { - Debug.Assert(IsDiscardDeclaration(variable)); - - // Convert a discard declaration with initializer of the form "int _ = M();" into - // a discard assignment "_ = M();" - if (variable.Initializer != null) - { - _statementsBuilder.Add( - SyntaxFactory.ExpressionStatement( - SyntaxFactory.AssignmentExpression( - kind: SyntaxKind.SimpleAssignmentExpression, - left: SyntaxFactory.IdentifierName(variable.Identifier), - operatorToken: variable.Initializer.EqualsToken, - right: variable.Initializer.Value)) - .WithAdditionalAnnotations(Formatter.Annotation)); - } - } - } - } -} diff --git a/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.State.cs b/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.State.cs deleted file mode 100644 index 59f7d8ca063..00000000000 --- a/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.State.cs +++ /dev/null @@ -1,193 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.LanguageServices; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Text; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.MoveDeclarationNearReference -{ - internal partial class AbstractMoveDeclarationNearReferenceService< - TService, - TStatementSyntax, - TLocalDeclarationStatementSyntax, - TVariableDeclaratorSyntax> - { - private class State - { - public TLocalDeclarationStatementSyntax DeclarationStatement { get; private set; } - public TVariableDeclaratorSyntax VariableDeclarator { get; private set; } - public ILocalSymbol LocalSymbol { get; private set; } - public SyntaxNode OutermostBlock { get; private set; } - public SyntaxNode InnermostBlock { get; private set; } - public SyntaxList OutermostBlockStatements { get; private set; } - public SyntaxList InnermostBlockStatements { get; private set; } - public TStatementSyntax FirstStatementAffectedInInnermostBlock { get; private set; } - public int IndexOfDeclarationStatementInInnermostBlock { get; private set; } - public int IndexOfFirstStatementAffectedInInnermostBlock { get; private set; } - - internal static async Task GenerateAsync( - TService service, - Document document, - TLocalDeclarationStatementSyntax statement, - CancellationToken cancellationToken) - { - var state = new State(); - if (!await state.TryInitializeAsync(service, document, statement, cancellationToken).ConfigureAwait(false)) - { - return null; - } - - return state; - } - - private async Task TryInitializeAsync( - TService service, - Document document, - TLocalDeclarationStatementSyntax node, - CancellationToken cancellationToken) - { - var syntaxFacts = document.GetLanguageService(); - - DeclarationStatement = node; - - var variables = syntaxFacts.GetVariablesOfLocalDeclarationStatement(DeclarationStatement); - if (variables.Count != 1) - { - return false; - } - - VariableDeclarator = (TVariableDeclaratorSyntax)variables[0]; - if (!service.IsValidVariableDeclarator(VariableDeclarator)) - { - return false; - } - - OutermostBlock = DeclarationStatement.Parent; - if (!syntaxFacts.IsExecutableBlock(OutermostBlock)) - { - return false; - } - - var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - LocalSymbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol( - service.GetVariableDeclaratorSymbolNode(VariableDeclarator), cancellationToken); - if (LocalSymbol == null) - { - // This can happen in broken code, for example: "{ object x; object }" - return false; - } - - var findReferencesResult = await SymbolFinder.FindReferencesAsync(LocalSymbol, document.Project.Solution, cancellationToken).ConfigureAwait(false); - var findReferencesList = findReferencesResult.ToList(); - if (findReferencesList.Count != 1) - { - return false; - } - - var references = findReferencesList[0].Locations.ToList(); - if (references.Count == 0) - { - return false; - } - - var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var referencingStatements = - (from r in references - let token = syntaxRoot.FindToken(r.Location.SourceSpan.Start) - let statement = token.GetAncestor() - where statement != null - select statement).ToSet(); - - if (referencingStatements.Count == 0) - { - return false; - } - - InnermostBlock = syntaxFacts.FindInnermostCommonExecutableBlock(referencingStatements); - if (InnermostBlock == null) - { - return false; - } - - InnermostBlockStatements = syntaxFacts.GetExecutableBlockStatements(InnermostBlock); - OutermostBlockStatements = syntaxFacts.GetExecutableBlockStatements(OutermostBlock); - - var allAffectedStatements = new HashSet(referencingStatements.SelectMany( - expr => expr.GetAncestorsOrThis())); - FirstStatementAffectedInInnermostBlock = InnermostBlockStatements.FirstOrDefault(allAffectedStatements.Contains); - - if (FirstStatementAffectedInInnermostBlock == null) - { - return false; - } - - if (FirstStatementAffectedInInnermostBlock == DeclarationStatement) - { - return false; - } - - IndexOfDeclarationStatementInInnermostBlock = InnermostBlockStatements.IndexOf(DeclarationStatement); - IndexOfFirstStatementAffectedInInnermostBlock = InnermostBlockStatements.IndexOf(FirstStatementAffectedInInnermostBlock); - if (IndexOfDeclarationStatementInInnermostBlock >= 0 && - IndexOfDeclarationStatementInInnermostBlock < IndexOfFirstStatementAffectedInInnermostBlock) - { - // Don't want to move a decl with initializer past other decls in order to move it to the first - // affected statement. If we do we can end up in the following situation: -#if false - int x = 0; - int y = 0; - Console.WriteLine(x + y); -#endif - // Each of these declarations will want to 'move' down to the WriteLine - // statement and we don't want to keep offering the refactoring. Note: this - // solution is overly aggressive. Technically if 'y' weren't referenced in - // Console.Writeline, then it might be a good idea to move the 'x'. But this - // gives good enough behavior most of the time. - - // Note that if the variable declaration has no initializer, then we still want to offer - // the move as the closest reference will be an assignment to the variable - // and we should be able to merge the declaration and assignment into a single - // statement. - // So, we also check if the variable declaration has an initializer below. - - if (syntaxFacts.GetInitializerOfVariableDeclarator(VariableDeclarator) != null && - InDeclarationStatementGroup(IndexOfDeclarationStatementInInnermostBlock, IndexOfFirstStatementAffectedInInnermostBlock)) - { - return false; - } - } - - var previousToken = FirstStatementAffectedInInnermostBlock.GetFirstToken().GetPreviousToken(); - var affectedSpan = TextSpan.FromBounds(previousToken.SpanStart, FirstStatementAffectedInInnermostBlock.Span.End); - if (semanticModel.SyntaxTree.OverlapsHiddenPosition(affectedSpan, cancellationToken)) - { - return false; - } - - return true; - } - - private bool InDeclarationStatementGroup( - int originalIndexInBlock, int firstStatementIndexAffectedInBlock) - { - for (var i = originalIndexInBlock; i < firstStatementIndexAffectedInBlock; i++) - { - if (!(InnermostBlockStatements[i] is TLocalDeclarationStatementSyntax)) - { - return false; - } - } - - return true; - } - } - } -} diff --git a/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.cs b/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.cs deleted file mode 100644 index f7b8079f8b5..00000000000 --- a/src/Features/Core/Portable/MoveDeclarationNearReference/AbstractMoveDeclarationNearReferenceService.cs +++ /dev/null @@ -1,258 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.LanguageServices; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Simplification; - -namespace Microsoft.CodeAnalysis.MoveDeclarationNearReference -{ - internal abstract partial class AbstractMoveDeclarationNearReferenceService< - TService, - TStatementSyntax, - TLocalDeclarationStatementSyntax, - TVariableDeclaratorSyntax> : IMoveDeclarationNearReferenceService - where TService : AbstractMoveDeclarationNearReferenceService - where TStatementSyntax : SyntaxNode - where TLocalDeclarationStatementSyntax : TStatementSyntax - where TVariableDeclaratorSyntax : SyntaxNode - { - protected abstract bool IsMeaningfulBlock(SyntaxNode node); - protected abstract bool CanMoveToBlock(ILocalSymbol localSymbol, SyntaxNode currentBlock, SyntaxNode destinationBlock); - protected abstract SyntaxNode GetVariableDeclaratorSymbolNode(TVariableDeclaratorSyntax variableDeclarator); - protected abstract bool IsValidVariableDeclarator(TVariableDeclaratorSyntax variableDeclarator); - protected abstract SyntaxToken GetIdentifierOfVariableDeclarator(TVariableDeclaratorSyntax variableDeclarator); - protected abstract Task TypesAreCompatibleAsync(Document document, ILocalSymbol localSymbol, TLocalDeclarationStatementSyntax declarationStatement, SyntaxNode right, CancellationToken cancellationToken); - - public async Task CanMoveDeclarationNearReferenceAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) - { - var state = await ComputeStateAsync(document, node, cancellationToken).ConfigureAwait(false); - return state != null; - } - - private async Task ComputeStateAsync(Document document, SyntaxNode node, CancellationToken cancellationToken) - { - if (!(node is TLocalDeclarationStatementSyntax statement)) - { - return null; - } - - var state = await State.GenerateAsync((TService)this, document, statement, cancellationToken).ConfigureAwait(false); - if (state == null) - { - return null; - } - - if (state.IndexOfDeclarationStatementInInnermostBlock >= 0 && - state.IndexOfDeclarationStatementInInnermostBlock == state.IndexOfFirstStatementAffectedInInnermostBlock - 1 && - !await CanMergeDeclarationAndAssignmentAsync(document, state, cancellationToken).ConfigureAwait(false)) - { - // Declaration statement is already closest to the first reference - // and they both cannot be merged into a single statement, so bail out. - return null; - } - - if (!CanMoveToBlock(state.LocalSymbol, state.OutermostBlock, state.InnermostBlock)) - { - return null; - } - - return state; - } - - public async Task MoveDeclarationNearReferenceAsync( - Document document, SyntaxNode localDeclarationStatement, CancellationToken cancellationToken) - { - var state = await ComputeStateAsync(document, localDeclarationStatement, cancellationToken).ConfigureAwait(false); - if (state == null) - { - return document; - } - - var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); - var editor = new SyntaxEditor(root, document.Project.Solution.Workspace); - - var crossesMeaningfulBlock = CrossesMeaningfulBlock(state); - var warningAnnotation = crossesMeaningfulBlock - ? WarningAnnotation.Create(FeaturesResources.Warning_colon_Declaration_changes_scope_and_may_change_meaning) - : null; - - var canMergeDeclarationAndAssignment = await CanMergeDeclarationAndAssignmentAsync(document, state, cancellationToken).ConfigureAwait(false); - if (canMergeDeclarationAndAssignment) - { - editor.RemoveNode(state.DeclarationStatement); - MergeDeclarationAndAssignment( - document, state, editor, warningAnnotation); - } - else - { - var statementIndex = state.OutermostBlockStatements.IndexOf(state.DeclarationStatement); - if (statementIndex + 1 < state.OutermostBlockStatements.Count && - state.OutermostBlockStatements[statementIndex + 1] == state.FirstStatementAffectedInInnermostBlock) - { - // Already at the correct location. - return document; - } - - editor.RemoveNode(state.DeclarationStatement); - await MoveDeclarationToFirstReferenceAsync( - document, state, editor, warningAnnotation, cancellationToken).ConfigureAwait(false); - } - - var newRoot = editor.GetChangedRoot(); - return document.WithSyntaxRoot(newRoot); - } - - private static async Task MoveDeclarationToFirstReferenceAsync(Document document, State state, SyntaxEditor editor, SyntaxAnnotation warningAnnotation, CancellationToken cancellationToken) - { - // If we're not merging with an existing declaration, make the declaration semantically - // explicit to improve the chances that it won't break code. - var explicitDeclarationStatement = await Simplifier.ExpandAsync( - state.DeclarationStatement, document, cancellationToken: cancellationToken).ConfigureAwait(false); - - // place the declaration above the first statement that references it. - var declarationStatement = warningAnnotation == null - ? explicitDeclarationStatement - : explicitDeclarationStatement.WithAdditionalAnnotations(warningAnnotation); - declarationStatement = declarationStatement.WithAdditionalAnnotations(Formatter.Annotation); - - var syntaxFacts = document.GetLanguageService(); - - var newNextStatement = state.FirstStatementAffectedInInnermostBlock; - declarationStatement = declarationStatement.WithPrependedLeadingTrivia( - syntaxFacts.GetLeadingBlankLines(newNextStatement)); - - editor.InsertBefore( - state.FirstStatementAffectedInInnermostBlock, - declarationStatement); - - editor.ReplaceNode( - newNextStatement, - newNextStatement.WithAdditionalAnnotations(Formatter.Annotation).WithLeadingTrivia( - syntaxFacts.GetTriviaAfterLeadingBlankLines(newNextStatement))); - - // Move leading whitespace from the declaration statement to the next statement. - var statementIndex = state.OutermostBlockStatements.IndexOf(state.DeclarationStatement); - if (statementIndex + 1 < state.OutermostBlockStatements.Count) - { - var originalNextStatement = state.OutermostBlockStatements[statementIndex + 1]; - editor.ReplaceNode( - originalNextStatement, - (current, generator) => current.WithAdditionalAnnotations(Formatter.Annotation).WithPrependedLeadingTrivia( - syntaxFacts.GetLeadingBlankLines(state.DeclarationStatement))); - } - } - - private void MergeDeclarationAndAssignment( - Document document, State state, SyntaxEditor editor, SyntaxAnnotation warningAnnotation) - { - // Replace the first reference with a new declaration. - var declarationStatement = CreateMergedDeclarationStatement(document, state); - declarationStatement = warningAnnotation == null - ? declarationStatement - : declarationStatement.WithAdditionalAnnotations(warningAnnotation); - - var syntaxFacts = document.GetLanguageService(); - declarationStatement = declarationStatement.WithLeadingTrivia( - GetMergedTrivia(syntaxFacts, state.DeclarationStatement, state.FirstStatementAffectedInInnermostBlock)); - - editor.ReplaceNode( - state.FirstStatementAffectedInInnermostBlock, - declarationStatement.WithAdditionalAnnotations(Formatter.Annotation)); - } - - private ImmutableArray GetMergedTrivia( - ISyntaxFactsService syntaxFacts, TStatementSyntax statement1, TStatementSyntax statement2) - { - return syntaxFacts.GetLeadingBlankLines(statement2).Concat( - syntaxFacts.GetTriviaAfterLeadingBlankLines(statement1)).Concat( - syntaxFacts.GetTriviaAfterLeadingBlankLines(statement2)); - } - - private bool CrossesMeaningfulBlock(State state) - { - var blocks = state.InnermostBlock.GetAncestorsOrThis(); - foreach (var block in blocks) - { - if (block == state.OutermostBlock) - { - break; - } - - if (IsMeaningfulBlock(block)) - { - return true; - } - } - - return false; - } - - private async Task CanMergeDeclarationAndAssignmentAsync( - Document document, - State state, - CancellationToken cancellationToken) - { - var syntaxFacts = document.GetLanguageService(); - - var initializer = syntaxFacts.GetInitializerOfVariableDeclarator(state.VariableDeclarator); - if (initializer == null || - syntaxFacts.IsLiteralExpression(syntaxFacts.GetValueOfEqualsValueClause(initializer))) - { - var firstStatement = state.FirstStatementAffectedInInnermostBlock; - if (syntaxFacts.IsSimpleAssignmentStatement(firstStatement)) - { - syntaxFacts.GetPartsOfAssignmentStatement(firstStatement, out var left, out var right); - if (syntaxFacts.IsIdentifierName(left)) - { - var localSymbol = state.LocalSymbol; - var name = syntaxFacts.GetIdentifierOfSimpleName(left).ValueText; - if (syntaxFacts.StringComparer.Equals(name, localSymbol.Name)) - { - return await TypesAreCompatibleAsync( - document, localSymbol, state.DeclarationStatement, right, cancellationToken).ConfigureAwait(false); - } - } - } - } - - return false; - } - - private TLocalDeclarationStatementSyntax CreateMergedDeclarationStatement( - Document document, State state) - { - var generator = SyntaxGenerator.GetGenerator(document); - - var syntaxFacts = document.GetLanguageService(); - syntaxFacts.GetPartsOfAssignmentStatement( - state.FirstStatementAffectedInInnermostBlock, - out var left, out var operatorToken, out var right); - - return state.DeclarationStatement.ReplaceNode( - state.VariableDeclarator, - generator.WithInitializer( - state.VariableDeclarator.WithoutTrailingTrivia(), - generator.EqualsValueClause(operatorToken, right)) - .WithTrailingTrivia(state.VariableDeclarator.GetTrailingTrivia())); - } - - private class MyCodeAction : CodeAction.DocumentChangeAction - { - public MyCodeAction(Func> createChangedDocument) - : base(FeaturesResources.Move_declaration_near_reference, createChangedDocument) - { - } - - internal override CodeActionPriority Priority => CodeActionPriority.Low; - } - } -} diff --git a/src/Features/Core/Portable/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.cs b/src/Features/Core/Portable/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.cs deleted file mode 100644 index 07df6f6a45d..00000000000 --- a/src/Features/Core/Portable/MoveDeclarationNearReference/IMoveDeclarationNearReferenceService.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; - -namespace Microsoft.CodeAnalysis.MoveDeclarationNearReference -{ - internal interface IMoveDeclarationNearReferenceService : ILanguageService - { - /// - /// Returns true if is local declaration statement - /// that can be moved forward to be closer to its first reference. - /// - Task CanMoveDeclarationNearReferenceAsync(Document document, SyntaxNode localDeclarationStatement, CancellationToken cancellationToken); - - /// - /// Moves closer to its first reference. Only - /// applicable if returned - /// true. If not, then the original document will be returned unchanged. - /// - Task MoveDeclarationNearReferenceAsync(Document document, SyntaxNode localDeclarationStatement, CancellationToken cancellationToken); - } -} diff --git a/src/Features/Core/Portable/ReplaceDiscardDeclarationsWithAssignments/IReplaceDiscardDeclarationsWithAssignmentsService.cs b/src/Features/Core/Portable/ReplaceDiscardDeclarationsWithAssignments/IReplaceDiscardDeclarationsWithAssignmentsService.cs deleted file mode 100644 index bbc52c28e68..00000000000 --- a/src/Features/Core/Portable/ReplaceDiscardDeclarationsWithAssignments/IReplaceDiscardDeclarationsWithAssignmentsService.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; - -namespace Microsoft.CodeAnalysis.ReplaceDiscardDeclarationsWithAssignments -{ - internal interface IReplaceDiscardDeclarationsWithAssignmentsService : ILanguageService - { - /// - /// Returns an updated with all the - /// local declarations named '_' replaced with simple assignments to discard. - /// For example, - /// 1. int _ = M(); is replaced with _ = M(); - /// 2. int x = 1, _ = M(), y = 2; is replaced with following statements: - /// - /// int x = 1; - /// _ = M(); - /// int y = 2; - /// - /// This is normally done in context of a code transformation that generates new discard assignment(s), - /// such as _ = M();, and wants to prevent compiler errors where the containing method already - /// has a discard variable declaration, say var _ = M2(); at some line after the one - /// where the code transformation wants to generate new discard assignment(s), which would be a compiler error. - /// This method replaces such discard variable declarations with discard assignments. - /// - Task ReplaceAsync(SyntaxNode memberDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken); - } -} diff --git a/src/Features/VisualBasic/Portable/MoveDeclarationNearReference/VisualBasicMoveDeclarationNearReferenceService.vb b/src/Features/VisualBasic/Portable/MoveDeclarationNearReference/VisualBasicMoveDeclarationNearReferenceService.vb deleted file mode 100644 index d881a8e0d3f..00000000000 --- a/src/Features/VisualBasic/Portable/MoveDeclarationNearReference/VisualBasicMoveDeclarationNearReferenceService.vb +++ /dev/null @@ -1,52 +0,0 @@ -' Licensed to the .NET Foundation under one or more agreements. -' The .NET Foundation licenses this file to you under the MIT license. -' See the LICENSE file in the project root for more information. - -Imports System.Composition -Imports System.Threading -Imports Microsoft.CodeAnalysis.Host.Mef -Imports Microsoft.CodeAnalysis.MoveDeclarationNearReference -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - -Namespace Microsoft.CodeAnalysis.VisualBasic.MoveDeclarationNearReference - - Friend Class VisualBasicMoveDeclarationNearReferenceService - Inherits AbstractMoveDeclarationNearReferenceService(Of - VisualBasicMoveDeclarationNearReferenceService, - StatementSyntax, - LocalDeclarationStatementSyntax, - VariableDeclaratorSyntax) - - - Public Sub New() - End Sub - - Protected Overrides Function IsMeaningfulBlock(node As SyntaxNode) As Boolean - Return TypeOf node Is LambdaExpressionSyntax OrElse - TypeOf node Is ForOrForEachBlockSyntax OrElse - TypeOf node Is WhileStatementSyntax OrElse - TypeOf node Is DoStatementSyntax OrElse - TypeOf node Is LoopStatementSyntax - End Function - - Protected Overrides Function GetVariableDeclaratorSymbolNode(variableDeclarator As VariableDeclaratorSyntax) As SyntaxNode - Return variableDeclarator.Names(0) - End Function - - Protected Overrides Function IsValidVariableDeclarator(variableDeclarator As VariableDeclaratorSyntax) As Boolean - Return variableDeclarator.Names.Count = 1 - End Function - - Protected Overrides Function GetIdentifierOfVariableDeclarator(variableDeclarator As VariableDeclaratorSyntax) As SyntaxToken - Return variableDeclarator.Names(0).Identifier - End Function - - Protected Overrides Function TypesAreCompatibleAsync(document As Document, localSymbol As ILocalSymbol, declarationStatement As LocalDeclarationStatementSyntax, right As SyntaxNode, cancellationToken As CancellationToken) As Task(Of Boolean) - Return SpecializedTasks.True - End Function - - Protected Overrides Function CanMoveToBlock(localSymbol As ILocalSymbol, currentBlock As SyntaxNode, destinationBlock As SyntaxNode) As Boolean - Return True - End Function - End Class -End Namespace -- GitLab