未验证 提交 7c6cbead 编写于 作者: A Allison Chou 提交者: GitHub

Replace property with method: Add more support for null catching (#46144)

上级 7628d776
......@@ -68,7 +68,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
bool negate, CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var editor = new SyntaxEditor(root, document.Project.Solution.Workspace);
var generator = editor.Generator;
var generatorInternal = document.GetRequiredLanguageService<SyntaxGeneratorInternal>();
......
......@@ -264,7 +264,7 @@ private static bool IsVariableReference(VariableDeclaratorSyntax variable, Expre
var condition = (BinaryExpressionSyntax)forStatement.Condition!;
var after = forStatement.Incrementors[0];
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var editor = new SyntaxEditor(root, document.Project.Solution.Workspace);
var generator = editor.Generator;
......
......@@ -420,7 +420,7 @@ private static string GenerateUniqueName(IParameterSymbol parameter, ImmutableAr
CancellationToken cancellationToken)
{
var workspace = document.Project.Solution.Workspace;
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var editor = new SyntaxEditor(root, workspace);
var generator = editor.Generator;
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
......
......@@ -6,6 +6,7 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
......@@ -18,7 +19,7 @@ namespace Microsoft.CodeAnalysis.MakeClassAbstract
internal abstract class AbstractMakeClassAbstractCodeFixProvider<TClassDeclarationSyntax> : SyntaxEditorBasedCodeFixProvider
where TClassDeclarationSyntax : SyntaxNode
{
protected abstract bool IsValidRefactoringContext(SyntaxNode? node, out TClassDeclarationSyntax? classDeclaration);
protected abstract bool IsValidRefactoringContext(SyntaxNode? node, [NotNullWhen(true)] out TClassDeclarationSyntax? classDeclaration);
internal sealed override CodeFixCategory CodeFixCategory => CodeFixCategory.Compile;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeRefactorings;
......@@ -12,11 +14,11 @@ namespace Microsoft.CodeAnalysis.ReplaceMethodWithProperty
internal abstract class AbstractReplaceMethodWithPropertyService<TMethodDeclarationSyntax> where TMethodDeclarationSyntax : SyntaxNode
{
#pragma warning disable CA1822 // Mark members as static - implements interface method for sub-types.
public async Task<SyntaxNode> GetMethodDeclarationAsync(CodeRefactoringContext context)
public async Task<SyntaxNode?> GetMethodDeclarationAsync(CodeRefactoringContext context)
#pragma warning restore CA1822 // Mark members as static
=> await context.TryGetRelevantNodeAsync<TMethodDeclarationSyntax>().ConfigureAwait(false);
protected static string GetWarning(GetAndSetMethods getAndSetMethods)
protected static string? GetWarning(GetAndSetMethods getAndSetMethods)
{
if (OverridesMetadataSymbol(getAndSetMethods.GetMethod) ||
OverridesMetadataSymbol(getAndSetMethods.SetMethod))
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
......@@ -54,9 +56,9 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte
var generator = SyntaxGenerator.GetGenerator(document);
var methodName = generator.GetName(methodDeclaration);
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration) as IMethodSymbol;
if (!IsValidGetMethod(methodSymbol))
var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
if (!(semanticModel.GetDeclaredSymbol(methodDeclaration) is IMethodSymbol methodSymbol) ||
!IsValidGetMethod(methodSymbol))
{
return;
}
......@@ -161,7 +163,7 @@ private static bool IsValidSetMethod(IMethodSymbol setMethod)
string propertyName,
bool nameChanged,
IMethodSymbol getMethod,
IMethodSymbol setMethod,
IMethodSymbol? setMethod,
CancellationToken cancellationToken)
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
......@@ -219,10 +221,10 @@ private static async Task<Solution> UpdateReferencesAsync(Solution updatedSoluti
IEnumerable<ReferenceLocation> setReferences,
CancellationToken cancellationToken)
{
var root = await originalDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var root = await originalDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var editor = new SyntaxEditor(root, originalDocument.Project.Solution.Workspace);
var service = originalDocument.GetLanguageService<IReplaceMethodWithPropertyService>();
var service = originalDocument.GetRequiredLanguageService<IReplaceMethodWithPropertyService>();
ReplaceGetReferences(propertyName, nameChanged, getReferences, root, editor, service, cancellationToken);
ReplaceSetReferences(propertyName, nameChanged, setReferences, root, editor, service, cancellationToken);
......@@ -247,6 +249,11 @@ private static async Task<Solution> UpdateReferencesAsync(Solution updatedSoluti
var location = referenceLocation.Location;
var nameToken = root.FindToken(location.SourceSpan.Start);
if (nameToken.Parent == null)
{
Debug.Fail($"Parent node of {nameToken} is null.");
continue;
}
if (referenceLocation.IsImplicit)
{
......@@ -277,6 +284,11 @@ private static async Task<Solution> UpdateReferencesAsync(Solution updatedSoluti
var location = referenceLocation.Location;
var nameToken = root.FindToken(location.SourceSpan.Start);
if (nameToken.Parent == null)
{
Debug.Fail($"Parent node of {nameToken} is null.");
continue;
}
if (referenceLocation.IsImplicit)
{
......@@ -330,19 +342,19 @@ private static async Task<Solution> UpdateReferencesAsync(Solution updatedSoluti
bool updateSetMethod,
CancellationToken cancellationToken)
{
var updatedDocument = updatedSolution.GetDocument(documentId);
var compilation = await updatedDocument.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var updatedDocument = updatedSolution.GetRequiredDocument(documentId);
var compilation = await updatedDocument.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
// We've already gone and updated all references. So now re-resolve all the definitions
// in the current compilation to find their updated location.
var getSetPairs = await GetGetSetPairsAsync(
updatedSolution, compilation, documentId, originalGetDefinitions, updateSetMethod, cancellationToken).ConfigureAwait(false);
var service = updatedDocument.GetLanguageService<IReplaceMethodWithPropertyService>();
var service = updatedDocument.GetRequiredLanguageService<IReplaceMethodWithPropertyService>();
var semanticModel = await updatedDocument.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var syntaxTree = await updatedDocument.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var root = await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var semanticModel = await updatedDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var syntaxTree = await updatedDocument.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var root = await updatedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var editor = new SyntaxEditor(root, updatedSolution.Workspace);
......@@ -391,7 +403,7 @@ private static async Task<Solution> UpdateReferencesAsync(Solution updatedSoluti
cancellationToken.ThrowIfCancellationRequested();
var getMethod = GetSymbolInCurrentCompilation(compilation, originalDefinition, cancellationToken);
if (IsValidGetMethod(getMethod))
if (getMethod != null && IsValidGetMethod(getMethod))
{
var setMethod = updateSetMethod ? FindSetMethod(getMethod) : null;
var getMethodDeclaration = await GetMethodDeclarationAsync(getMethod, cancellationToken).ConfigureAwait(false);
......@@ -407,13 +419,13 @@ private static async Task<Solution> UpdateReferencesAsync(Solution updatedSoluti
return result.ToImmutable();
}
private static TSymbol GetSymbolInCurrentCompilation<TSymbol>(Compilation compilation, TSymbol originalDefinition, CancellationToken cancellationToken)
private static TSymbol? GetSymbolInCurrentCompilation<TSymbol>(Compilation compilation, TSymbol originalDefinition, CancellationToken cancellationToken)
where TSymbol : class, ISymbol
{
return originalDefinition.GetSymbolKey(cancellationToken).Resolve(compilation, cancellationToken: cancellationToken).GetAnySymbol() as TSymbol;
}
private static async Task<SyntaxNode> GetMethodDeclarationAsync(IMethodSymbol method, CancellationToken cancellationToken)
private static async Task<SyntaxNode?> GetMethodDeclarationAsync(IMethodSymbol? method, CancellationToken cancellationToken)
{
if (method == null)
{
......@@ -454,7 +466,7 @@ private static async Task<SyntaxNode> GetMethodDeclarationAsync(IMethodSymbol me
}
#pragma warning disable IDE0060 // Remove unused parameter - Method not completely implemented.
private static string GetDefinitionIssues(IEnumerable<ReferencedSymbol> getMethodReferences)
private static string? GetDefinitionIssues(IEnumerable<ReferencedSymbol> getMethodReferences)
#pragma warning restore IDE0060 // Remove unused parameter
{
// TODO: add things to be concerned about here. For example:
......
......@@ -5,7 +5,6 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
......@@ -120,6 +119,8 @@ protected static SyntaxNode GetFieldReference(SyntaxGenerator generator, IFieldS
{
_expression = (TExpressionSyntax)_expression.Parent!;
}
Contract.ThrowIfNull(_expression.Parent, $"Parent of {_expression} is null.");
}
// To avoid allocating lambdas each time we hit a reference, we instead
......@@ -258,7 +259,8 @@ public void Do()
_identifierName.WithoutTrivia(),
readExpression);
_editor.ReplaceNode(declarator, newDeclarator);
// We know declarator isn't null due to the earlier call to IsInferredAnonymousObjectMemberDeclarator
_editor.ReplaceNode(declarator!, newDeclarator);
}
else if (_syntaxFacts.IsRightSideOfQualifiedName(_identifierName))
{
......@@ -286,6 +288,8 @@ private void ReplaceRead(bool keepTrivia, string? conflictMessage)
bool keepTrivia,
string? conflictMessage)
{
Contract.ThrowIfNull(_expression.Parent, $"Parent of {_expression} is null.");
// Call this overload so we can see this node after already replacing any
// references in the writing side of it.
_editor.ReplaceNode(
......
......@@ -349,7 +349,7 @@ private static bool HasAnyMatchingSetMethods(IPropertySymbol property, string na
var service = updatedDocument.GetRequiredLanguageService<IReplacePropertyWithMethodsService>();
var root = await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var root = await updatedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var editor = new SyntaxEditor(root, updatedSolution.Workspace);
......
......@@ -202,7 +202,7 @@ private async Task<Solution> ProcessResultAsync(CodeFixContext context, Diagnost
if (fieldDocument == propertyDocument)
{
// Same file. Have to do this in a slightly complicated fashion.
var declaratorTreeRoot = await fieldDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var declaratorTreeRoot = await fieldDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var editor = new SyntaxEditor(declaratorTreeRoot, fieldDocument.Project.Solution.Workspace);
editor.ReplaceNode(property, updatedProperty);
......
......@@ -2,9 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editing
{
......@@ -16,7 +20,7 @@ public class SyntaxEditor
private readonly SyntaxGenerator _generator;
private readonly List<Change> _changes;
private bool _allowEditsOnLazilyCreatedTrackedNewNodes;
private HashSet<SyntaxNode> _lazyTrackedNewNodesOpt;
private HashSet<SyntaxNode>? _lazyTrackedNewNodesOpt;
/// <summary>
/// Creates a new <see cref="SyntaxEditor"/> instance.
......@@ -40,7 +44,8 @@ internal SyntaxEditor(SyntaxNode root, SyntaxGenerator generator)
_changes = new List<Change>();
}
private SyntaxNode ApplyTrackingToNewNode(SyntaxNode node)
[return: NotNullIfNotNull("node")]
private SyntaxNode? ApplyTrackingToNewNode(SyntaxNode? node)
{
if (node == null)
{
......@@ -60,7 +65,8 @@ private IEnumerable<SyntaxNode> ApplyTrackingToNewNodes(IEnumerable<SyntaxNode>
{
foreach (var node in nodes)
{
yield return ApplyTrackingToNewNode(node);
var result = ApplyTrackingToNewNode(node);
yield return result;
}
}
......@@ -295,15 +301,16 @@ public override SyntaxNode Apply(SyntaxNode root, SyntaxGenerator generator)
private class ReplaceChange : Change
{
private readonly Func<SyntaxNode, SyntaxGenerator, SyntaxNode> _modifier;
private readonly Func<SyntaxNode, SyntaxGenerator, SyntaxNode?> _modifier;
private readonly SyntaxEditor _editor;
public ReplaceChange(
SyntaxNode node,
Func<SyntaxNode, SyntaxGenerator, SyntaxNode> modifier,
Func<SyntaxNode, SyntaxGenerator, SyntaxNode?> modifier,
SyntaxEditor editor)
: base(node)
{
Contract.ThrowIfNull(node, "Passed in node is null.");
_modifier = modifier;
_editor = editor;
}
......@@ -313,6 +320,8 @@ public override SyntaxNode Apply(SyntaxNode root, SyntaxGenerator generator)
var current = root.GetCurrentNode(this.Node);
var newNode = _modifier(current, generator);
newNode = _editor.ApplyTrackingToNewNode(newNode);
Contract.ThrowIfNull(current, $"GetCurrentNode returned null with the following node: {this.Node}");
return generator.ReplaceNode(root, current, newNode);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册