提交 b7806c3a 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #18270 from CyrusNajmabadi/collectionInit2

Don't update collection initializer statement that references collection being created
......@@ -722,7 +722,7 @@ static void M()
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseCollectionInitializer)]
[WorkItem(17823, "https://github.com/dotnet/roslyn/issues/17823")]
public async Task TestWhenReferencedInInitializer()
public async Task TestWhenReferencedInInitializer_LocalVar()
{
await TestInRegularAndScript1Async(
@"
......@@ -753,6 +753,97 @@ static void M()
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseCollectionInitializer)]
[WorkItem(17823, "https://github.com/dotnet/roslyn/issues/17823")]
public async Task TestWhenReferencedInInitializer_LocalVar2()
{
await TestMissingInRegularAndScriptAsync(
@"
using System.Collections.Generic;
using System.Linq;
class C
{
void M()
{
var t = [||]new List<int>(new int[] { 1, 2, 3 });
t.Add(t.Min() - 1);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseCollectionInitializer)]
[WorkItem(18260, "https://github.com/dotnet/roslyn/issues/18260")]
public async Task TestWhenReferencedInInitializer_Assignment()
{
await TestInRegularAndScript1Async(
@"
using System.Collections.Generic;
class C
{
static void M()
{
List<object> items = null;
items = new [||]List<object>();
items[0] = 1;
items[1] = items[0];
}
}",
@"
using System.Collections.Generic;
class C
{
static void M()
{
List<object> items = null;
items = new [||]List<object>
{
[0] = 1
};
items[1] = items[0];
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseCollectionInitializer)]
[WorkItem(18260, "https://github.com/dotnet/roslyn/issues/18260")]
public async Task TestWhenReferencedInInitializer_Assignment2()
{
await TestMissingInRegularAndScriptAsync(
@"using System.Collections.Generic;
using System.Linq;
class C
{
void M()
{
List<int> t = null;
t = [||]new List<int>(new int[] { 1, 2, 3 });
t.Add(t.Min() - 1);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseCollectionInitializer)]
[WorkItem(18260, "https://github.com/dotnet/roslyn/issues/18260")]
public async Task TestFieldReference()
{
await TestMissingInRegularAndScriptAsync(
@"using System.Collections.Generic;
class C
{
private List<int> myField;
void M()
{
myField = [||]new List<int>();
myField.Add(this.myField.Count);
}
}");
}
[WorkItem(17853, "https://github.com/dotnet/roslyn/issues/17853")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseCollectionInitializer)]
public async Task TestMissingForDynamic()
......
......@@ -172,6 +172,7 @@
<Compile Include="TodoComments\IRemoteTodoCommentService.cs" />
<Compile Include="TodoComments\ITodoCommentService.cs" />
<Compile Include="UpgradeProject\AbstractUpgradeProjectCodeFixProvider.cs" />
<Compile Include="UseCollectionInitializer\AbstractObjectCreationExpressionAnalyzer.cs" />
<Compile Include="UseCollectionInitializer\AbstractUseCollectionInitializerCodeFixProvider.cs" />
<Compile Include="UseCollectionInitializer\AbstractUseCollectionInitializerDiagnosticAnalyzer.cs" />
<Compile Include="UseCoalesceExpression\AbstractUseCoalesceExpressionForNullableDiagnosticAnalyzer.cs" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.UseCollectionInitializer
{
internal abstract class AbstractObjectCreationExpressionAnalyzer<
TExpressionSyntax,
TStatementSyntax,
TObjectCreationExpressionSyntax,
TVariableDeclaratorSyntax,
TMatch>
where TExpressionSyntax : SyntaxNode
where TStatementSyntax : SyntaxNode
where TObjectCreationExpressionSyntax : TExpressionSyntax
where TVariableDeclaratorSyntax : SyntaxNode
{
protected SemanticModel _semanticModel;
protected ISyntaxFactsService _syntaxFacts;
protected TObjectCreationExpressionSyntax _objectCreationExpression;
protected CancellationToken _cancellationToken;
protected TStatementSyntax _containingStatement;
private SyntaxNodeOrToken _valuePattern;
private ISymbol _initializedSymbol;
protected AbstractObjectCreationExpressionAnalyzer()
{
}
public void Initialize(
SemanticModel semanticModel,
ISyntaxFactsService syntaxFacts,
TObjectCreationExpressionSyntax objectCreationExpression,
CancellationToken cancellationToken)
{
_semanticModel = semanticModel;
_syntaxFacts = syntaxFacts;
_objectCreationExpression = objectCreationExpression;
_cancellationToken = cancellationToken;
}
protected void Clear()
{
_semanticModel = null;
_syntaxFacts = null;
_objectCreationExpression = null;
_cancellationToken = default(CancellationToken);
_containingStatement = null;
_valuePattern = default(SyntaxNodeOrToken);
_initializedSymbol = null;
}
protected abstract void AddMatches(ArrayBuilder<TMatch> matches);
protected ImmutableArray<TMatch>? AnalyzeWorker()
{
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 matches = ArrayBuilder<TMatch>.GetInstance();
AddMatches(matches);
return matches.ToImmutableAndFree();
}
private bool TryInitializeVariableDeclarationCase()
{
if (!_syntaxFacts.IsLocalDeclarationStatement(_containingStatement))
{
return false;
}
var containingDeclarator = _objectCreationExpression.Parent.Parent as TVariableDeclaratorSyntax;
if (containingDeclarator == null)
{
return false;
}
_initializedSymbol = _semanticModel.GetDeclaredSymbol(containingDeclarator, _cancellationToken);
if (_initializedSymbol is ILocalSymbol local &&
local.Type is IDynamicTypeSymbol)
{
// Not supported if we're creating a dynamic local. The object we're instantiating
// may not have the members that we're trying to access on the dynamic object.
return false;
}
if (!_syntaxFacts.IsDeclaratorOfLocalDeclarationStatement(containingDeclarator, _containingStatement))
{
return false;
}
_valuePattern = _syntaxFacts.GetIdentifierOfVariableDeclarator(containingDeclarator);
return true;
}
private bool TryInitializeAssignmentCase()
{
if (!_syntaxFacts.IsSimpleAssignmentStatement(_containingStatement))
{
return false;
}
_syntaxFacts.GetPartsOfAssignmentStatement(_containingStatement,
out var left, out var right);
if (right != _objectCreationExpression)
{
return false;
}
var typeInfo = _semanticModel.GetTypeInfo(left, _cancellationToken);
if (typeInfo.Type is IDynamicTypeSymbol || typeInfo.ConvertedType is IDynamicTypeSymbol)
{
// Not supported if we're initializing something dynamic. The object we're instantiating
// may not have the members that we're trying to access on the dynamic object.
return false;
}
_valuePattern = left;
_initializedSymbol = _semanticModel.GetSymbolInfo(left, _cancellationToken).GetAnySymbol();
return true;
}
protected bool ValuePatternMatches(TExpressionSyntax expression)
{
if (_valuePattern.IsToken)
{
return _syntaxFacts.IsIdentifierName(expression) &&
_syntaxFacts.AreEquivalent(
_valuePattern.AsToken(),
_syntaxFacts.GetIdentifierOfSimpleName(expression));
}
else
{
return _syntaxFacts.AreEquivalent(
_valuePattern.AsNode(), expression);
}
}
protected bool ExpressionContainsValuePatternOrReferencesInitializedSymbol(SyntaxNode expression)
{
foreach (var subExpression in expression.DescendantNodesAndSelf().OfType<TExpressionSyntax>())
{
if (!_syntaxFacts.IsNameOfMemberAccessExpression(subExpression))
{
if (ValuePatternMatches(subExpression))
{
return true;
}
}
if (_initializedSymbol != null &&
_initializedSymbol.Equals(
_semanticModel.GetSymbolInfo(subExpression, _cancellationToken).GetAnySymbol()))
{
return true;
}
}
return false;
}
}
}
\ No newline at end of file
......@@ -51,7 +51,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
}
protected override async Task FixAllAsync(
Document document, ImmutableArray<Diagnostic> diagnostics,
Document document, ImmutableArray<Diagnostic> diagnostics,
SyntaxEditor editor, CancellationToken cancellationToken)
{
// Fix-All for this feature is somewhat complicated. As Collection-Initializers
......@@ -85,9 +85,9 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
var originalObjectCreation = originalObjectCreationNodes.Pop();
var objectCreation = currentRoot.GetCurrentNodes(originalObjectCreation).Single();
var analyzer = new ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclaratorSyntax>(
var matches = ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclaratorSyntax>.Analyze(
semanticModel, syntaxFacts, objectCreation, cancellationToken);
var matches = analyzer.Analyze();
if (matches == null || matches.Value.Length == 0)
{
continue;
......
......@@ -91,9 +91,9 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol ien
return;
}
var analyzer = new ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclaratorSyntax>(
var matches = ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclaratorSyntax>.Analyze(
semanticModel, GetSyntaxFactsService(), objectCreationExpression, cancellationToken);
var matches = analyzer.Analyze();
if (matches == null || matches.Value.Length == 0)
{
return;
......
......@@ -2,21 +2,25 @@
using System.Collections;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.UseCollectionInitializer
{
internal struct ObjectCreationExpressionAnalyzer<
internal class ObjectCreationExpressionAnalyzer<
TExpressionSyntax,
TStatementSyntax,
TObjectCreationExpressionSyntax,
TMemberAccessExpressionSyntax,
TInvocationExpressionSyntax,
TExpressionStatementSyntax,
TVariableDeclaratorSyntax>
TVariableDeclaratorSyntax> : AbstractObjectCreationExpressionAnalyzer<
TExpressionSyntax,
TStatementSyntax,
TObjectCreationExpressionSyntax,
TVariableDeclaratorSyntax,
TExpressionStatementSyntax>
where TExpressionSyntax : SyntaxNode
where TStatementSyntax : SyntaxNode
where TObjectCreationExpressionSyntax : TExpressionSyntax
......@@ -25,53 +29,34 @@ internal struct ObjectCreationExpressionAnalyzer<
where TExpressionStatementSyntax : TStatementSyntax
where TVariableDeclaratorSyntax : SyntaxNode
{
private readonly SemanticModel _semanticModel;
private readonly ISyntaxFactsService _syntaxFacts;
private readonly TObjectCreationExpressionSyntax _objectCreationExpression;
private readonly CancellationToken _cancellationToken;
private static readonly ObjectPool<ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclaratorSyntax>> s_pool
= new ObjectPool<ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclaratorSyntax>>(
() => new ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TInvocationExpressionSyntax, TExpressionStatementSyntax, TVariableDeclaratorSyntax>());
private TStatementSyntax _containingStatement;
private SyntaxNodeOrToken _valuePattern;
private ISymbol _variableSymbol;
private ObjectCreationExpressionAnalyzer()
{
}
public ObjectCreationExpressionAnalyzer(
public static ImmutableArray<TExpressionStatementSyntax>? Analyze(
SemanticModel semanticModel,
ISyntaxFactsService syntaxFacts,
TObjectCreationExpressionSyntax objectCreationExpression,
CancellationToken cancellationToken) : this()
{
_semanticModel = semanticModel;
_syntaxFacts = syntaxFacts;
_objectCreationExpression = objectCreationExpression;
_cancellationToken = cancellationToken;
}
internal ImmutableArray<TExpressionStatementSyntax>? Analyze()
CancellationToken cancellationToken)
{
if (_syntaxFacts.GetObjectCreationInitializer(_objectCreationExpression) != null)
{
// Don't bother if this already has an initializer.
return null;
}
_containingStatement = _objectCreationExpression.FirstAncestorOrSelf<TStatementSyntax>();
if (_containingStatement == null)
var analyzer = s_pool.Allocate();
analyzer.Initialize(semanticModel, syntaxFacts, objectCreationExpression, cancellationToken);
try
{
return null;
return analyzer.AnalyzeWorker();
}
if (!TryInitializeVariableDeclarationCase() &&
!TryInitializeAssignmentCase())
finally
{
return null;
analyzer.Clear();
s_pool.Free(analyzer);
}
var matches = ArrayBuilder<TExpressionStatementSyntax>.GetInstance();
AddMatches(matches);
return matches.ToImmutableAndFree();
}
private void AddMatches(ArrayBuilder<TExpressionStatementSyntax> matches)
protected override void AddMatches(ArrayBuilder<TExpressionStatementSyntax> matches)
{
var containingBlock = _containingStatement.Parent;
var foundStatement = false;
......@@ -159,16 +144,9 @@ private void AddMatches(ArrayBuilder<TExpressionStatementSyntax> matches)
// If we're initializing a variable, then we can't reference that variable on the right
// side of the initialization. Rewriting this into a collection initializer would lead
// to a definite-assignment error.
if (_variableSymbol != null)
if (ExpressionContainsValuePatternOrReferencesInitializedSymbol(right))
{
foreach (var child in right.DescendantNodesAndSelf().OfType<TExpressionSyntax>())
{
if (ValuePatternMatches(child) &&
_variableSymbol.Equals(_semanticModel.GetSymbolInfo(child, _cancellationToken).GetAnySymbol()))
{
return false;
}
}
return false;
}
instance = _syntaxFacts.GetExpressionOfElementAccessExpression(left);
......@@ -198,6 +176,12 @@ private void AddMatches(ArrayBuilder<TExpressionStatementSyntax> matches)
{
return false;
}
var argumentExpression = _syntaxFacts.GetExpressionOfArgument(argument);
if (ExpressionContainsValuePatternOrReferencesInitializedSymbol(argumentExpression))
{
return false;
}
}
var memberAccess = _syntaxFacts.GetExpressionOfInvocationExpression(invocationExpression) as TMemberAccessExpressionSyntax;
......@@ -222,79 +206,5 @@ private void AddMatches(ArrayBuilder<TExpressionStatementSyntax> matches)
instance = localInstance;
return true;
}
private bool ValuePatternMatches(TExpressionSyntax expression)
{
if (_valuePattern.IsToken)
{
return _syntaxFacts.IsIdentifierName(expression) &&
_syntaxFacts.AreEquivalent(
_valuePattern.AsToken(),
_syntaxFacts.GetIdentifierOfSimpleName(expression));
}
else
{
return _syntaxFacts.AreEquivalent(
_valuePattern.AsNode(), expression);
}
}
private bool TryInitializeAssignmentCase()
{
if (!_syntaxFacts.IsSimpleAssignmentStatement(_containingStatement))
{
return false;
}
_syntaxFacts.GetPartsOfAssignmentStatement(_containingStatement,
out var left, out var right);
if (right != _objectCreationExpression)
{
return false;
}
var typeInfo = _semanticModel.GetTypeInfo(left, _cancellationToken);
if (typeInfo.Type is IDynamicTypeSymbol || typeInfo.ConvertedType is IDynamicTypeSymbol)
{
// Not supported if we're initializing something dynamic. The object we're instantiating
// may not have the members that we're trying to access on the dynamic object.
return false;
}
_valuePattern = left;
return true;
}
private bool TryInitializeVariableDeclarationCase()
{
if (!_syntaxFacts.IsLocalDeclarationStatement(_containingStatement))
{
return false;
}
var containingDeclarator = _objectCreationExpression.Parent.Parent as TVariableDeclaratorSyntax;
if (containingDeclarator == null)
{
return false;
}
var symbol = _semanticModel.GetDeclaredSymbol(containingDeclarator, _cancellationToken);
if (symbol is ILocalSymbol local &&
local.Type is IDynamicTypeSymbol)
{
// Not supported if we're creating a dynamic local. The object we're instantiating
// may not have the members that we're trying to access on the dynamic object.
return false;
}
if (!_syntaxFacts.IsDeclaratorOfLocalDeclarationStatement(containingDeclarator, _containingStatement))
{
return false;
}
_valuePattern = _syntaxFacts.GetIdentifierOfVariableDeclarator(containingDeclarator);
_variableSymbol = _semanticModel.GetDeclaredSymbol(containingDeclarator);
return true;
}
}
}
\ No newline at end of file
......@@ -84,9 +84,8 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
var originalObjectCreation = originalObjectCreationNodes.Pop();
var objectCreation = currentRoot.GetCurrentNodes(originalObjectCreation).Single();
var analyzer = new ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax>(
var matches = ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax>.Analyze(
semanticModel, syntaxFacts, objectCreation, cancellationToken);
var matches = analyzer.Analyze();
if (matches == null || matches.Value.Length == 0)
{
......
......@@ -70,17 +70,16 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
}
var syntaxFacts = GetSyntaxFactsService();
var analyzer = new ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax>(
var matches = ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax>.Analyze(
context.SemanticModel, syntaxFacts, objectCreationExpression, context.CancellationToken);
var result = analyzer.Analyze();
if (result == null || result.Value.Length == 0)
if (matches == null || matches.Value.Length == 0)
{
return;
}
var containingStatement = objectCreationExpression.FirstAncestorOrSelf<TStatementSyntax>();
var nodes = ImmutableArray.Create<SyntaxNode>(containingStatement).AddRange(result.Value.Select(m => m.Statement));
var nodes = ImmutableArray.Create<SyntaxNode>(containingStatement).AddRange(matches.Value.Select(m => m.Statement));
if (syntaxFacts.ContainsInterleavedDirective(nodes, cancellationToken))
{
return;
......@@ -94,7 +93,7 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
objectCreationExpression.GetLocation(),
additionalLocations: locations));
FadeOutCode(context, optionSet, result.Value, locations);
FadeOutCode(context, optionSet, matches.Value, locations);
}
private void FadeOutCode(
......
......@@ -2,19 +2,22 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.UseCollectionInitializer;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.UseObjectInitializer
{
internal struct ObjectCreationExpressionAnalyzer<
internal class ObjectCreationExpressionAnalyzer<
TExpressionSyntax,
TStatementSyntax,
TObjectCreationExpressionSyntax,
TMemberAccessExpressionSyntax,
TAssignmentStatementSyntax,
TVariableDeclaratorSyntax>
TVariableDeclaratorSyntax> : AbstractObjectCreationExpressionAnalyzer<
TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TVariableDeclaratorSyntax,
Match<TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax>>
where TExpressionSyntax : SyntaxNode
where TStatementSyntax : SyntaxNode
where TObjectCreationExpressionSyntax : TExpressionSyntax
......@@ -22,50 +25,38 @@ internal struct ObjectCreationExpressionAnalyzer<
where TAssignmentStatementSyntax : TStatementSyntax
where TVariableDeclaratorSyntax : SyntaxNode
{
private readonly ISyntaxFactsService _syntaxFacts;
private readonly TObjectCreationExpressionSyntax _objectCreationExpression;
private static readonly ObjectPool<ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax>> s_pool
= new ObjectPool<ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax>>(
() => new ObjectCreationExpressionAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax>());
private TStatementSyntax _containingStatement;
private SyntaxNodeOrToken _valuePattern;
private readonly SemanticModel _semanticModel;
private readonly CancellationToken _cancellationToken;
private ObjectCreationExpressionAnalyzer()
{
}
public ObjectCreationExpressionAnalyzer(
public static ImmutableArray<Match<TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax>>? Analyze(
SemanticModel semanticModel,
ISyntaxFactsService syntaxFacts,
TObjectCreationExpressionSyntax objectCreationExpression,
CancellationToken cancellationToken) : this()
{
_semanticModel = semanticModel;
_syntaxFacts = syntaxFacts;
_objectCreationExpression = objectCreationExpression;
_cancellationToken = cancellationToken;
}
internal ImmutableArray<Match<TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax>>? Analyze()
CancellationToken cancellationToken)
{
if (_syntaxFacts.GetObjectCreationInitializer(_objectCreationExpression) != null)
var analyzer = s_pool.Allocate();
analyzer.Initialize(semanticModel, syntaxFacts, objectCreationExpression, cancellationToken);
try
{
// Don't bother if this already has an initializer.
return null;
return analyzer.AnalyzeWorker();
}
_containingStatement = _objectCreationExpression.FirstAncestorOrSelf<TStatementSyntax>();
if (_containingStatement == null)
finally
{
return null;
}
if (!TryInitializeVariableDeclarationCase() &&
!TryInitializeAssignmentCase())
{
return null;
analyzer.Clear();
s_pool.Free(analyzer);
}
}
protected override void AddMatches(ArrayBuilder<Match<TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax>> matches)
{
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())
......@@ -130,7 +121,7 @@ internal struct ObjectCreationExpressionAnalyzer<
//
// In the second case we'd change semantics because we'd access the old value
// before the new value got written.
if (ExpressionContainsValuePattern(rightExpression))
if (ExpressionContainsValuePatternOrReferencesInitializedSymbol(rightExpression))
{
break;
}
......@@ -162,8 +153,6 @@ internal struct ObjectCreationExpressionAnalyzer<
matches.Add(new Match<TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax>(
statement, leftMemberAccess, rightExpression));
}
return matches.ToImmutableAndFree();
}
private bool ImplicitMemberAccessWouldBeAffected(SyntaxNode node)
......@@ -197,95 +186,6 @@ private bool ImplicitMemberAccessWouldBeAffected(SyntaxNode node)
return false;
}
private bool ExpressionContainsValuePattern(TExpressionSyntax expression)
{
foreach (var subExpression in expression.DescendantNodesAndSelf().OfType<TExpressionSyntax>())
{
if (!_syntaxFacts.IsNameOfMemberAccessExpression(subExpression))
{
if (ValuePatternMatches(subExpression))
{
return true;
}
}
}
return false;
}
private bool ValuePatternMatches(TExpressionSyntax expression)
{
if (_valuePattern.IsToken)
{
return _syntaxFacts.IsIdentifierName(expression) &&
_syntaxFacts.AreEquivalent(
_valuePattern.AsToken(),
_syntaxFacts.GetIdentifierOfSimpleName(expression));
}
else
{
return _syntaxFacts.AreEquivalent(
_valuePattern.AsNode(), expression);
}
}
private bool TryInitializeAssignmentCase()
{
if (!_syntaxFacts.IsSimpleAssignmentStatement(_containingStatement))
{
return false;
}
_syntaxFacts.GetPartsOfAssignmentStatement(
_containingStatement, out var left, out var right);
if (right != _objectCreationExpression)
{
return false;
}
var typeInfo = _semanticModel.GetTypeInfo(left, _cancellationToken);
if (typeInfo.Type is IDynamicTypeSymbol || typeInfo.ConvertedType is IDynamicTypeSymbol)
{
// Not supported if we're initializing something dynamic. The object we're instantiating
// may not have the members that we're trying to access on the dynamic object.
return false;
}
_valuePattern = left;
return true;
}
private bool TryInitializeVariableDeclarationCase()
{
if (!_syntaxFacts.IsLocalDeclarationStatement(_containingStatement))
{
return false;
}
var containingDeclarator = _objectCreationExpression.Parent.Parent as TVariableDeclaratorSyntax;
if (containingDeclarator == null)
{
return false;
}
var symbol = _semanticModel.GetDeclaredSymbol(containingDeclarator, _cancellationToken);
if (symbol is ILocalSymbol local &&
local.Type is IDynamicTypeSymbol)
{
// Not supported if we're creating a dynamic local. The object we're instantiating
// may not have the members that we're trying to access on the dynamic object.
return false;
}
if (!_syntaxFacts.IsDeclaratorOfLocalDeclarationStatement(containingDeclarator, _containingStatement))
{
return false;
}
_valuePattern = _syntaxFacts.GetIdentifierOfVariableDeclarator(containingDeclarator);
return true;
}
}
internal struct Match<
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册