提交 8de57141 编写于 作者: C CyrusNajmabadi

Merge remote-tracking branch 'upstream/master' into suggestionScrollBar

......@@ -979,6 +979,76 @@ void M()
void Baz(out string s) { }
void Bar(Action a) { }
}");
}
[WorkItem(15408, "https://github.com/dotnet/roslyn/issues/15408")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInlineDeclaration)]
public async Task TestDataFlow1()
{
await TestMissingAsync(
@"
using System;
class C
{
void Foo(string x)
{
object [|s|] = null;
if (x != null || TryBaz(out s))
{
Console.WriteLine(s);
}
}
private bool TryBaz(out object s)
{
throw new NotImplementedException();
}
}");
}
[WorkItem(15408, "https://github.com/dotnet/roslyn/issues/15408")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInlineDeclaration)]
public async Task TestDataFlow2()
{
await TestAsync(
@"
using System;
class C
{
void Foo(string x)
{
object [|s|] = null;
if (x != null && TryBaz(out s))
{
Console.WriteLine(s);
}
}
private bool TryBaz(out object s)
{
throw new NotImplementedException();
}
}",
@"
using System;
class C
{
void Foo(string x)
{
if (x != null && TryBaz(out object s))
{
Console.WriteLine(s);
}
}
private bool TryBaz(out object s)
{
throw new NotImplementedException();
}
}");
}
}
......
......@@ -454,5 +454,20 @@ void M()
}",
compareTokens: false);
}
[WorkItem(15459, "https://github.com/dotnet/roslyn/issues/15459")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseObjectInitializer)]
public async Task TestMissingInNonTopLevelObjectInitializer()
{
await TestMissingAsync(
@"class C {
int a;
C Add(int x) {
var c = Add([||]new int());
c.a = 1;
return c;
}
}");
}
}
}
\ No newline at end of file
// 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.Immutable;
using System.Linq;
using System.Threading;
......@@ -8,6 +7,7 @@
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CSharp.InlineDeclaration
{
......@@ -26,6 +26,8 @@ namespace Microsoft.CodeAnalysis.CSharp.InlineDeclaration
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class CSharpInlineDeclarationDiagnosticAnalyzer : AbstractCodeStyleDiagnosticAnalyzer
{
private const string CS0165 = nameof(CS0165); // Use of unassigned local variable 's'
public CSharpInlineDeclarationDiagnosticAnalyzer()
: base(IDEDiagnosticIds.InlineDeclarationDiagnosticId,
new LocalizableResourceString(nameof(FeaturesResources.Inline_variable_declaration), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
......@@ -186,6 +188,15 @@ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
return;
}
// See if inlining this variable would make it so that some variables were no
// longer definitely assigned.
if (WouldCauseDefiniteAssignmentErrors(
semanticModel, localDeclarator, enclosingBlockOfLocalStatement,
outSymbol, cancellationToken))
{
return;
}
// Collect some useful nodes for the fix provider to use so it doesn't have to
// find them again.
var allLocations = ImmutableArray.Create(
......@@ -206,6 +217,79 @@ private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context)
additionalLocations: allLocations));
}
private bool WouldCauseDefiniteAssignmentErrors(
SemanticModel semanticModel, VariableDeclaratorSyntax localDeclarator,
BlockSyntax enclosingBlock, ISymbol outSymbol, CancellationToken cancellationToken)
{
// See if we have something like:
//
// int i = 0;
// if (Foo() || Bar(out i))
// {
// Console.WriteLine(i);
// }
//
// In this case, inlining the 'i' would cause it to longer be definitely
// assigned in the WriteLine invocation.
if (localDeclarator.Initializer == null)
{
// Don't need to examine this unless the variable has an initializer.
return false;
}
// Find all the current read-references to the local.
var query = from t in enclosingBlock.DescendantTokens()
where t.Kind() == SyntaxKind.IdentifierToken
where t.ValueText == outSymbol.Name
let id = t.Parent as IdentifierNameSyntax
where id != null
where !id.IsOnlyWrittenTo()
let symbol = semanticModel.GetSymbolInfo(id).GetAnySymbol()
where outSymbol.Equals(symbol)
select id;
var references = query.ToImmutableArray<SyntaxNode>();
var root = semanticModel.SyntaxTree.GetCompilationUnitRoot(cancellationToken);
// Ensure we can track the references and the local variable as we make edits
// to the tree.
var rootWithTrackedNodes = root.TrackNodes(references.Concat(localDeclarator).Concat(enclosingBlock));
// Now, take the local variable and remove it's initializer. Then go to all
// the locations where we read from it. If they're definitely assigned, then
// that means the out-var did it's work and assigned the variable across all
// paths. If it's not definitely assigned, then we can't inline this variable.
var currentLocalDeclarator = rootWithTrackedNodes.GetCurrentNode(localDeclarator);
var rootWithoutInitializer = rootWithTrackedNodes.ReplaceNode(
currentLocalDeclarator,
currentLocalDeclarator.WithInitializer(null));
// Fork the compilation so we can do this analysis.
var newCompilation = semanticModel.Compilation.ReplaceSyntaxTree(
root.SyntaxTree, rootWithoutInitializer.SyntaxTree);
var newSemanticModel = newCompilation.GetSemanticModel(rootWithoutInitializer.SyntaxTree);
// NOTE: there is no current compiler API to determine if a variable is definitely
// assigned or not. So, for now, we just get diagnostics for this block and see if
// we get any definite assigment errors where we have a reference to the symbol. If
// so, then we don't offer the fix.
var currentBlock = rootWithoutInitializer.GetCurrentNode(enclosingBlock);
var diagnostics = newSemanticModel.GetDiagnostics(currentBlock.Span, cancellationToken);
var diagnosticSpans = diagnostics.Where(d => d.Id == CS0165)
.Select(d => d.Location.SourceSpan)
.Distinct();
var newReferenceSpans = rootWithoutInitializer.GetCurrentNodes<SyntaxNode>(references)
.Select(n => n.Span)
.Distinct();
return diagnosticSpans.Intersect(newReferenceSpans).Any();
}
private SyntaxNode GetOutArgumentScope(SyntaxNode argumentExpression)
{
for (var current = argumentExpression; current != null; current = current.Parent)
......
......@@ -238,7 +238,7 @@ private bool TryInitializeVariableDeclarationCase()
return false;
}
var containingDeclarator = _objectCreationExpression.FirstAncestorOrSelf<TVariableDeclaratorSyntax>();
var containingDeclarator = _objectCreationExpression.Parent.Parent as TVariableDeclaratorSyntax;
if (containingDeclarator == null)
{
return false;
......
......@@ -248,7 +248,7 @@ private bool TryInitializeVariableDeclarationCase()
return false;
}
var containingDeclarator = _objectCreationExpression.FirstAncestorOrSelf<TVariableDeclaratorSyntax>();
var containingDeclarator = _objectCreationExpression.Parent.Parent as TVariableDeclaratorSyntax;
if (containingDeclarator == null)
{
return false;
......
......@@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration
internal class CSharpFlagsEnumGenerator : AbstractFlagsEnumGenerator
{
internal static readonly CSharpFlagsEnumGenerator Instance = new CSharpFlagsEnumGenerator();
private static readonly SyntaxGenerator s_generatorInstance = new CSharpSyntaxGenerator();
private static readonly SyntaxGenerator s_generatorInstance = CSharpSyntaxGenerator.Instance;
private CSharpFlagsEnumGenerator()
{
......@@ -41,8 +41,7 @@ private CSharpFlagsEnumGenerator()
return expression;
}
var factory = new CSharpSyntaxGenerator();
return factory.CastExpression(enumType, expression);
return CSharpSyntaxGenerator.Instance.CastExpression(enumType, expression);
}
protected override SyntaxGenerator GetSyntaxGenerator()
......
......@@ -21,6 +21,8 @@ internal class CSharpSyntaxGenerator : SyntaxGenerator
{
internal override SyntaxTrivia CarriageReturnLineFeed => SyntaxFactory.CarriageReturnLineFeed;
public static readonly SyntaxGenerator Instance = new CSharpSyntaxGenerator();
#region Declarations
public override SyntaxNode CompilationUnit(IEnumerable<SyntaxNode> declarations)
{
......
......@@ -29,6 +29,13 @@ public SyntaxEditor(SyntaxNode root, Workspace workspace)
_changes = new List<Change>();
}
internal SyntaxEditor(SyntaxNode root, SyntaxGenerator generator)
{
OriginalRoot = root ?? throw new ArgumentNullException(nameof(root));
_generator = generator;
_changes = new List<Change>();
}
/// <summary>
/// The <see cref="SyntaxNode"/> that was specified when the <see cref="SyntaxEditor"/> was constructed.
/// </summary>
......@@ -280,4 +287,4 @@ public override SyntaxNode Apply(SyntaxNode root, SyntaxGenerator generator)
}
}
}
}
}
\ No newline at end of file
......@@ -106,4 +106,4 @@ public static void AddBaseType(this SyntaxEditor editor, SyntaxNode declaration,
editor.ReplaceNode(declaration, (d, g) => g.AddBaseType(d, baseType));
}
}
}
}
\ No newline at end of file
......@@ -74,7 +74,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
End Function
Private Shared Function GenerateStringConstantExpression(name As String) As MemberAccessExpressionSyntax
Dim factory = New VisualBasicSyntaxGenerator()
Dim result = GenerateMemberAccessExpression("Microsoft", "VisualBasic", "Constants", name)
Return result.WithAdditionalAnnotations(Simplifier.Annotation)
......
......@@ -142,7 +142,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
End Function
Private Function GenerateChrWExpression(c As Char) As InvocationExpressionSyntax
Dim factory = New VisualBasicSyntaxGenerator()
Dim access = GenerateMemberAccessExpression("Microsoft", "VisualBasic", "Strings", "ChrW")
Dim value = AscW(c)
......
......@@ -17,7 +17,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Inherits AbstractFlagsEnumGenerator
Public Shared ReadOnly Instance As VisualBasicFlagsEnumGenerator = New VisualBasicFlagsEnumGenerator
Private Shared ReadOnly s_syntaxGeneratorInstance As SyntaxGenerator = New VisualBasicSyntaxGenerator
Private Shared ReadOnly s_syntaxGeneratorInstance As SyntaxGenerator = VisualBasicSyntaxGenerator.Instance
Private Sub New()
End Sub
......@@ -32,8 +32,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Return expression
End If
Dim factory = New VisualBasicSyntaxGenerator()
Return factory.ConvertExpression(enumType, expression)
Return VisualBasicSyntaxGenerator.Instance.ConvertExpression(enumType, expression)
End Function
Protected Overrides Function GetSyntaxGenerator() As SyntaxGenerator
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册