提交 51485e66 编写于 作者: C CyrusNajmabadi

Don't offer to use an object/collection initializer if it would break code...

Don't offer to use an object/collection initializer if it would break code that crosses pp-directives.
上级 92c529d1
......@@ -769,5 +769,60 @@ void Foo()
}
}");
}
[WorkItem(17953, "https://github.com/dotnet/roslyn/issues/17953")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseObjectInitializer)]
public async Task TestMissingAcrossPreprocessorDirective()
{
await TestMissingInRegularAndScriptAsync(
@"
using System.Collections.Generic;
public class Foo
{
public void M()
{
var items = new [||]List<object>();
#if true
items.Add(1);
#endif
}
}");
}
[WorkItem(17953, "https://github.com/dotnet/roslyn/issues/17953")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseObjectInitializer)]
public async Task TestAvailableInsidePreprocessorDirective()
{
await TestInRegularAndScript1Async(
@"
using System.Collections.Generic;
public class Foo
{
public void M()
{
#if true
var items = new [||]List<object>();
items.Add(1);
#endif
}
}",
@"
using System.Collections.Generic;
public class Foo
{
public void M()
{
#if true
var items = new List<object>
{
1
};
#endif
}
}", ignoreTrivia: false);
}
}
}
\ No newline at end of file
......@@ -481,5 +481,60 @@ void Foo()
}
}");
}
[WorkItem(17953, "https://github.com/dotnet/roslyn/issues/17953")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseObjectInitializer)]
public async Task TestMissingAcrossPreprocessorDirective()
{
await TestMissingInRegularAndScriptAsync(
@"
public class Foo
{
public void M()
{
var foo = [||]new Foo();
#if true
foo.Value = "";
#endif
}
public string Value { get; set; }
}");
}
[WorkItem(17953, "https://github.com/dotnet/roslyn/issues/17953")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseObjectInitializer)]
public async Task TestAvailableInsidePreprocessorDirective()
{
await TestInRegularAndScript1Async(
@"
public class Foo
{
public void M()
{
#if true
var foo = [||]new Foo();
foo.Value = "";
#endif
}
public string Value { get; set; }
}",
@"
public class Foo
{
public void M()
{
#if true
var foo = new Foo
{
Value = "";
};
#endif
}
public string Value { get; set; }
}", ignoreTrivia: false);
}
}
}
\ No newline at end of file
......@@ -98,6 +98,14 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context, INamedTypeSymbol ien
return;
}
var containingStatement = objectCreationExpression.FirstAncestorOrSelf<TStatementSyntax>();
var nodes = ImmutableArray.Create<SyntaxNode>(containingStatement).AddRange(matches.Value);
var syntaxFacts = GetSyntaxFactsService();
if (syntaxFacts.ContainsInterleavedDirective(nodes, cancellationToken))
{
return;
}
var locations = ImmutableArray.Create(objectCreationExpression.GetLocation());
var severity = option.Notification.Value;
......
// 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 Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.LanguageServices;
......@@ -78,6 +79,13 @@ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
return;
}
var containingStatement = objectCreationExpression.FirstAncestorOrSelf<TStatementSyntax>();
var nodes = ImmutableArray.Create<SyntaxNode>(containingStatement).AddRange(result.Value.Select(m => m.Statement));
if (syntaxFacts.ContainsInterleavedDirective(nodes, cancellationToken))
{
return;
}
var locations = ImmutableArray.Create(objectCreationExpression.GetLocation());
var severity = option.Notification.Value;
......
......@@ -311,9 +311,7 @@ public static bool IsAnyLambda(this SyntaxNode node)
}
public static bool IsAnyLambdaOrAnonymousMethod(this SyntaxNode node)
{
return node.IsAnyLambda() || node.IsKind(SyntaxKind.AnonymousMethodExpression);
}
=> node.IsAnyLambda() || node.IsKind(SyntaxKind.AnonymousMethodExpression);
/// <summary>
/// Returns true if the passed in node contains an interleaved pp directive.
......@@ -352,28 +350,12 @@ public static bool IsAnyLambdaOrAnonymousMethod(this SyntaxNode node)
/// constructs (like #if/#endif or #region/#endregion), but the grouping construct isn't
/// entirely contained within the span of the node.
/// </summary>
public static bool ContainsInterleavedDirective(
this SyntaxNode syntaxNode,
CancellationToken cancellationToken)
{
// Check if this node contains a start, middle or end pp construct whose matching construct is
// not contained within this node. If so, this node must be pinned and cannot move.
var span = syntaxNode.Span;
foreach (var token in syntaxNode.DescendantTokens())
{
if (ContainsInterleavedDirective(span, token, cancellationToken))
{
return true;
}
}
return false;
}
public static bool ContainsInterleavedDirective(this SyntaxNode syntaxNode, CancellationToken cancellationToken)
=> CSharpSyntaxFactsService.Instance.ContainsInterleavedDirective(syntaxNode, cancellationToken);
private static bool ContainsInterleavedDirective(
public static bool ContainsInterleavedDirective(
this SyntaxToken token,
TextSpan textSpan,
SyntaxToken token,
CancellationToken cancellationToken)
{
return
......
......@@ -1989,5 +1989,8 @@ public bool IsBetweenTypeMembers(SourceText sourceText, SyntaxNode root, int pos
public ImmutableArray<SyntaxNode> GetSelectedMembers(SyntaxNode root, TextSpan textSpan)
=> ImmutableArray<SyntaxNode>.CastUp(root.GetMembersInSpan(textSpan));
protected override bool ContainsInterleavedDirective(TextSpan span, SyntaxToken token, CancellationToken cancellationToken)
=> token.ContainsInterleavedDirective(span, cancellationToken);
}
}
\ No newline at end of file
using System;
// 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.LanguageServices
......@@ -206,5 +210,45 @@ public ImmutableArray<SyntaxTrivia> GetFileBanner(SyntaxNode root)
return ImmutableArray.CreateRange(leadingTrivia.Take(index));
}
public bool ContainsInterleavedDirective(
ImmutableArray<SyntaxNode> nodes, CancellationToken cancellationToken)
{
if (nodes.Length > 0)
{
var span = TextSpan.FromBounds(nodes.First().Span.Start, nodes.Last().Span.End);
foreach (var node in nodes)
{
cancellationToken.ThrowIfCancellationRequested();
if (ContainsInterleavedDirective(span, node, cancellationToken))
{
return true;
}
}
}
return false;
}
public bool ContainsInterleavedDirective(SyntaxNode node, CancellationToken cancellationToken)
=> ContainsInterleavedDirective(node.Span, node, cancellationToken);
private bool ContainsInterleavedDirective(
TextSpan span, SyntaxNode node, CancellationToken cancellationToken)
{
foreach (var token in node.DescendantTokens())
{
if (ContainsInterleavedDirective(span, token, cancellationToken))
{
return true;
}
}
return false;
}
protected abstract bool ContainsInterleavedDirective(TextSpan span, SyntaxToken token, CancellationToken cancellationToken);
}
}
\ No newline at end of file
......@@ -281,6 +281,9 @@ internal interface ISyntaxFactsService : ILanguageService
SyntaxNode GetNextExecutableStatement(SyntaxNode statement);
ImmutableArray<SyntaxTrivia> GetFileBanner(SyntaxNode root);
bool ContainsInterleavedDirective(SyntaxNode node, CancellationToken cancellationToken);
bool ContainsInterleavedDirective(ImmutableArray<SyntaxNode> nodes, CancellationToken cancellationToken);
}
[Flags]
......
......@@ -340,20 +340,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions
''' </summary>
<Extension()>
Public Function ContainsInterleavedDirective(node As SyntaxNode, cancellationToken As CancellationToken) As Boolean
' Check if this node contains a start or end pp construct whose
' matching construct is not contained within this node. If so,
' this node must be pinned and cannot move.
'
' Also, keep track of those spans so that if we see #else/#elif we
' can tell if they belong to a pp span that is entirely within the
' node.
Dim span = node.Span
Return node.DescendantTokens().Any(Function(token) ContainsInterleavedDirective(span, token, cancellationToken))
Return VisualBasicSyntaxFactsService.Instance.ContainsInterleavedDirective(node, cancellationToken)
End Function
Private Function ContainsInterleavedDirective(
textSpan As TextSpan,
<Extension>
Public Function ContainsInterleavedDirective(
token As SyntaxToken,
textSpan As TextSpan,
cancellationToken As CancellationToken) As Boolean
Return ContainsInterleavedDirective(textSpan, token.LeadingTrivia, cancellationToken) OrElse
......
......@@ -1755,5 +1755,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Private Function ISyntaxFactsService_GetFileBanner(root As SyntaxNode) As ImmutableArray(Of SyntaxTrivia) Implements ISyntaxFactsService.GetFileBanner
Return GetFileBanner(root)
End Function
Protected Overrides Function ContainsInterleavedDirective(span As TextSpan, token As SyntaxToken, cancellationToken As CancellationToken) As Boolean
Return token.ContainsInterleavedDirective(span, cancellationToken)
End Function
Private Function ISyntaxFactsService_ContainsInterleavedDirective(node As SyntaxNode, cancellationToken As CancellationToken) As Boolean Implements ISyntaxFactsService.ContainsInterleavedDirective
Return ContainsInterleavedDirective(node, cancellationToken)
End Function
Private Function ISyntaxFactsService_ContainsInterleavedDirective1(nodes As ImmutableArray(Of SyntaxNode), cancellationToken As CancellationToken) As Boolean Implements ISyntaxFactsService.ContainsInterleavedDirective
Return ContainsInterleavedDirective(nodes, cancellationToken)
End Function
End Class
End Namespace
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册