diff --git a/src/Analyzers/CSharp/CodeFixes/RemoveConfusingSuppression/CSharpRemoveConfusingSuppressionCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/RemoveConfusingSuppression/CSharpRemoveConfusingSuppressionCodeFixProvider.cs index 4ce53f02a69bfc073a36b7cd69650bb7d48968c1..1950842ac6f04453480ba56e74275b49436d5fcd 100644 --- a/src/Analyzers/CSharp/CodeFixes/RemoveConfusingSuppression/CSharpRemoveConfusingSuppressionCodeFixProvider.cs +++ b/src/Analyzers/CSharp/CodeFixes/RemoveConfusingSuppression/CSharpRemoveConfusingSuppressionCodeFixProvider.cs @@ -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(); diff --git a/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs index ac29ad754025d7efad0807623f10fea6ff30d6b7..4c072cae8e523f014b9421174dea831c0aa189b4 100644 --- a/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/ReverseForStatement/CSharpReverseForStatementCodeRefactoringProvider.cs @@ -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; diff --git a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs index c4ca6849d578d4e71c374ff210badf8350270656..b51e9c36fa0e59231f317362e52d3ce8f53be8a0 100644 --- a/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs +++ b/src/Features/Core/Portable/InitializeParameter/AbstractInitializeMemberFromParameterCodeRefactoringProviderMemberCreation.cs @@ -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); diff --git a/src/Features/Core/Portable/MakeClassAbstract/AbstractMakeClassAbstractCodeFixProvider.cs b/src/Features/Core/Portable/MakeClassAbstract/AbstractMakeClassAbstractCodeFixProvider.cs index 352789dded19dbb3ed70eca0bb137312d7cad12c..8d375b359183ebea135a8cd51246e6f83225fe65 100644 --- a/src/Features/Core/Portable/MakeClassAbstract/AbstractMakeClassAbstractCodeFixProvider.cs +++ b/src/Features/Core/Portable/MakeClassAbstract/AbstractMakeClassAbstractCodeFixProvider.cs @@ -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 : 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; diff --git a/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs b/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs index f6076fb028e25910a144fc8994c2599984254d85..db5793781fdca236d81a0c969a2f5a9414378ac7 100644 --- a/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs +++ b/src/Features/Core/Portable/ReplaceMethodWithProperty/AbstractReplaceMethodWithPropertyService.cs @@ -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 where TMethodDeclarationSyntax : SyntaxNode { #pragma warning disable CA1822 // Mark members as static - implements interface method for sub-types. - public async Task GetMethodDeclarationAsync(CodeRefactoringContext context) + public async Task GetMethodDeclarationAsync(CodeRefactoringContext context) #pragma warning restore CA1822 // Mark members as static => await context.TryGetRelevantNodeAsync().ConfigureAwait(false); - protected static string GetWarning(GetAndSetMethods getAndSetMethods) + protected static string? GetWarning(GetAndSetMethods getAndSetMethods) { if (OverridesMetadataSymbol(getAndSetMethods.GetMethod) || OverridesMetadataSymbol(getAndSetMethods.SetMethod)) diff --git a/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs b/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs index d9e9b4358749aa6b60118274232f8ae68bb25a33..0f9cd46d884bf8123b81be0d4853907fd1819443 100644 --- a/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ReplaceMethodWithProperty/ReplaceMethodWithPropertyCodeRefactoringProvider.cs @@ -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 UpdateReferencesAsync(Solution updatedSoluti IEnumerable 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(); + var service = originalDocument.GetRequiredLanguageService(); ReplaceGetReferences(propertyName, nameChanged, getReferences, root, editor, service, cancellationToken); ReplaceSetReferences(propertyName, nameChanged, setReferences, root, editor, service, cancellationToken); @@ -247,6 +249,11 @@ private static async Task 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 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 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(); + var service = updatedDocument.GetRequiredLanguageService(); - 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 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 UpdateReferencesAsync(Solution updatedSoluti return result.ToImmutable(); } - private static TSymbol GetSymbolInCurrentCompilation(Compilation compilation, TSymbol originalDefinition, CancellationToken cancellationToken) + private static TSymbol? GetSymbolInCurrentCompilation(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 GetMethodDeclarationAsync(IMethodSymbol method, CancellationToken cancellationToken) + private static async Task GetMethodDeclarationAsync(IMethodSymbol? method, CancellationToken cancellationToken) { if (method == null) { @@ -454,7 +466,7 @@ private static async Task GetMethodDeclarationAsync(IMethodSymbol me } #pragma warning disable IDE0060 // Remove unused parameter - Method not completely implemented. - private static string GetDefinitionIssues(IEnumerable getMethodReferences) + private static string? GetDefinitionIssues(IEnumerable getMethodReferences) #pragma warning restore IDE0060 // Remove unused parameter { // TODO: add things to be concerned about here. For example: diff --git a/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs b/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs index dcbcb365c8eb7a0e2540527b30007740987394aa..1691b2ca6b148457e16145c84ce84c6e2174452b 100644 --- a/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs +++ b/src/Features/Core/Portable/ReplacePropertyWithMethods/AbstractReplacePropertyWithMethodsService.cs @@ -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( diff --git a/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs b/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs index 0445e4be1b179c3d249ed9e89d45bf6aa800b260..fd6af2eff1ce5e0aebfc010504954fdcb4bfcaa3 100644 --- a/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ReplacePropertyWithMethods/ReplacePropertyWithMethodsCodeRefactoringProvider.cs @@ -349,7 +349,7 @@ private static bool HasAnyMatchingSetMethods(IPropertySymbol property, string na var service = updatedDocument.GetRequiredLanguageService(); - var root = await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + var root = await updatedDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var editor = new SyntaxEditor(root, updatedSolution.Workspace); diff --git a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs index 9521e13e93670de0abd9eefee51f6e4a838374de..b9b32a1ebe53fb916acdef451e9c8dacbbad1cf6 100644 --- a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs +++ b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs @@ -202,7 +202,7 @@ private async Task 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); diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs b/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs index 82f9ca5512e8451caf2e3190056bcc8056f51c24..8b5041a90a8a32f43ea9d3b7e7d582024bc8341f 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs @@ -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 _changes; private bool _allowEditsOnLazilyCreatedTrackedNewNodes; - private HashSet _lazyTrackedNewNodesOpt; + private HashSet? _lazyTrackedNewNodesOpt; /// /// Creates a new instance. @@ -40,7 +44,8 @@ internal SyntaxEditor(SyntaxNode root, SyntaxGenerator generator) _changes = new List(); } - private SyntaxNode ApplyTrackingToNewNode(SyntaxNode node) + [return: NotNullIfNotNull("node")] + private SyntaxNode? ApplyTrackingToNewNode(SyntaxNode? node) { if (node == null) { @@ -60,7 +65,8 @@ private IEnumerable ApplyTrackingToNewNodes(IEnumerable { 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 _modifier; + private readonly Func _modifier; private readonly SyntaxEditor _editor; public ReplaceChange( SyntaxNode node, - Func modifier, + Func 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); } }