Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/EditorFeatures/CSharp/CSharpEditorFeatures.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,9 @@
<Compile Include="SignatureHelp\SignatureHelpUtilities.cs" />
<Compile Include="TextStructureNavigation\TextStructureNavigatorProvider.cs" />
<Compile Include="TodoComment\CSharpTodoCommentIncrementalAnalyzerProvider.cs" />
<Compile Include="UseAutoProperty\UseAutoPropertyAnalyzer.cs" />
<Compile Include="UseAutoProperty\UseAutoPropertyCodeFixProvider.cs" />
<Compile Include="UseAutoProperty\CSharpUseAutoPropertyAnalyzer.cs" />
<Compile Include="UseAutoProperty\CSharpUseAutoPropertyCodeFixProvider.cs" />
<Compile Include="UseAutoProperty\CSharpUseAutoPropertyService.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.CoreUtility, Version=$(VisualStudioReferenceAssemblyVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
namespace Microsoft.CodeAnalysis.Editor.CSharp.UseAutoProperty
{
// https://github.com/dotnet/roslyn/issues/5408
//[Export]
//[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class UseAutoPropertyAnalyzer : AbstractUseAutoPropertyAnalyzer<PropertyDeclarationSyntax, FieldDeclarationSyntax, VariableDeclaratorSyntax, ExpressionSyntax>
[Export]
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class CSharpUseAutoPropertyAnalyzer : AbstractUseAutoPropertyAnalyzer<PropertyDeclarationSyntax, FieldDeclarationSyntax, VariableDeclaratorSyntax, ExpressionSyntax>
{
protected override bool SupportsReadOnlyProperties(Compilation compilation)
{
Expand All @@ -27,61 +27,31 @@ protected override bool SupportsPropertyInitializer(Compilation compilation)
return ((CSharpCompilation)compilation).LanguageVersion >= LanguageVersion.CSharp6;
}

protected override void RegisterIneligibleFieldsAction(CompilationStartAnalysisContext context, ConcurrentBag<IFieldSymbol> ineligibleFields)
{
context.RegisterSyntaxNodeAction(snac => AnalyzeArgument(ineligibleFields, snac), SyntaxKind.Argument);
}

protected override ExpressionSyntax GetFieldInitializer(VariableDeclaratorSyntax variable, CancellationToken cancellationToken)
{
return variable.Initializer?.Value;
}

private void AnalyzeArgument(ConcurrentBag<IFieldSymbol> ineligibleFields, SyntaxNodeAnalysisContext context)
{
// An argument will disqualify a field if that field is used in a ref/out position.
// We can't change such field references to be property references in C#.
var argument = (ArgumentSyntax)context.Node;
if (argument.RefOrOutKeyword.Kind() == SyntaxKind.None)
{
return;
}

var cancellationToken = context.CancellationToken;
var symbolInfo = context.SemanticModel.GetSymbolInfo(argument.Expression, cancellationToken);
AddIneligibleField(symbolInfo.Symbol, ineligibleFields);
foreach (var symbol in symbolInfo.CandidateSymbols)
{
AddIneligibleField(symbol, ineligibleFields);
}
}

private static void AddIneligibleField(ISymbol symbol, ConcurrentBag<IFieldSymbol> ineligibleFields)
{
var field = symbol as IFieldSymbol;
if (field != null)
{
ineligibleFields.Add(field);
}
}

private bool CheckExpressionSyntactically(ExpressionSyntax expression)
private string GetFieldName(ExpressionSyntax expression)
{
if (expression.IsKind(SyntaxKind.SimpleMemberAccessExpression))
{
var memberAccessExpression = (MemberAccessExpressionSyntax)expression;
return memberAccessExpression.Expression.Kind() == SyntaxKind.ThisExpression &&
memberAccessExpression.Name.Kind() == SyntaxKind.IdentifierName;
if (memberAccessExpression.Expression.Kind() == SyntaxKind.ThisExpression &&
memberAccessExpression.Name.Kind() == SyntaxKind.IdentifierName)
{
return ((IdentifierNameSyntax)memberAccessExpression.Name).Identifier.ValueText;
}
}
else if (expression.IsKind(SyntaxKind.IdentifierName))
{
return true;
return ((IdentifierNameSyntax)expression).Identifier.ValueText;
}

return false;
return null;
}

protected override ExpressionSyntax GetGetterExpression(IMethodSymbol getMethod, CancellationToken cancellationToken)
protected override string GetGetterFieldName(IMethodSymbol getMethod, CancellationToken cancellationToken)
{
// Getter has to be of the form:
//
Expand All @@ -95,14 +65,14 @@ protected override ExpressionSyntax GetGetterExpression(IMethodSymbol getMethod,
if (statement.Kind() == SyntaxKind.ReturnStatement)
{
var expr = ((ReturnStatementSyntax)statement).Expression;
return CheckExpressionSyntactically(expr) ? expr : null;
return GetFieldName(expr);
}
}

return null;
}

protected override ExpressionSyntax GetSetterExpression(IMethodSymbol setMethod, SemanticModel semanticModel, CancellationToken cancellationToken)
protected override string GetSetterFieldName(IMethodSymbol setMethod, CancellationToken cancellationToken)
{
// Setter has to be of the form:
//
Expand All @@ -122,7 +92,7 @@ protected override ExpressionSyntax GetSetterExpression(IMethodSymbol setMethod,
if (assignmentExpression.Right.Kind() == SyntaxKind.IdentifierName &&
((IdentifierNameSyntax)assignmentExpression.Right).Identifier.ValueText == "value")
{
return CheckExpressionSyntactically(assignmentExpression.Left) ? assignmentExpression.Left : null;
return GetFieldName(assignmentExpression.Left);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
namespace Microsoft.CodeAnalysis.Editor.CSharp.UseAutoProperty
{
[Shared]
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseAutoPropertyCodeFixProvider))]
internal class UseAutoPropertyCodeFixProvider : AbstractUseAutoPropertyCodeFixProvider<PropertyDeclarationSyntax, FieldDeclarationSyntax, VariableDeclaratorSyntax, ConstructorDeclarationSyntax, ExpressionSyntax>
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(CSharpUseAutoPropertyCodeFixProvider))]
internal class CSharpUseAutoPropertyCodeFixProvider : AbstractUseAutoPropertyCodeFixProvider<PropertyDeclarationSyntax, FieldDeclarationSyntax, VariableDeclaratorSyntax, ConstructorDeclarationSyntax, ExpressionSyntax>
{
protected override SyntaxNode GetNodeToRemove(VariableDeclaratorSyntax declarator)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.UseAutoProperty;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UseAutoProperty
{
[ExportLanguageService(typeof(IUseAutoPropertyService), LanguageNames.CSharp), Shared]
internal class CSharpUseAutoPropertyService : IUseAutoPropertyService
{
public SyntaxToken OnTokenRenamed(SyntaxToken oldToken, SyntaxToken newToken)
{
var parent = oldToken.Parent as ExpressionSyntax;
if (parent != null)
{
if (parent.IsRightSideOfDot())
{
parent = parent.Parent as ExpressionSyntax;
}

if (parent != null &&
parent.Parent.IsKind(SyntaxKind.Argument) &&
((ArgumentSyntax)parent.Parent).RefOrOutKeyword.Kind() != SyntaxKind.None)
{
// We accessed the field in a ref/out location. Add a conflict annotation so the
// usre knows there's a problem here.
return newToken.WithAdditionalAnnotations(ConflictAnnotation.Create(CSharpFeaturesResources.ConflictsDetected));
}
}

return newToken;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class UseAutoPropertyTests : AbstractCSharpDiagnosticProviderBasedUserDia
internal override Tuple<DiagnosticAnalyzer, CodeFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
{
return Tuple.Create<DiagnosticAnalyzer, CodeFixProvider>(
new UseAutoPropertyAnalyzer(), new UseAutoPropertyCodeFixProvider());
new CSharpUseAutoPropertyAnalyzer(), new CSharpUseAutoPropertyCodeFixProvider());
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)]
Expand Down Expand Up @@ -142,22 +142,25 @@ public void TestFieldAndPropertyHaveDifferentStaticInstance()
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)]
public void TestFieldUseInRefArgument1()
{
TestMissing(
@"class Class { [|int i|]; int P { get { return i; } } void M(ref int x) { M(ref i); } }");
Test(
@"class Class { [|int i|]; int P { get { return i; } } void M(ref int x) { M(ref i); } }",
@"class Class { int P { get; set; } void M(ref int x) { M(ref {|Conflict:P|}); } }");
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)]
public void TestFieldUseInRefArgument2()
{
TestMissing(
@"class Class { [|int i|]; int P { get { return i; } } void M(ref int x) { M(ref this.i); } }");
Test(
@"class Class { [|int i|]; int P { get { return i; } } void M(ref int x) { M(ref this.i); } }",
@"class Class { int P { get; set; } void M(ref int x) { M(ref this.{|Conflict:P|}); } }");
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)]
public void TestFieldUseInOutArgument()
{
TestMissing(
@"class Class { [|int i|]; int P { get { return i; } } void M(out x) { M(out i); } }");
Test(
@"class Class { [|int i|]; int P { get { return i; } } void M(out x) { M(out i); } }",
@"class Class { int P { get; set; } void M(out x) { M(out {|Conflict:P|}); } }");
}

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseAutoProperty)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public async Task<IInlineRenameReplacementInfo> GetReplacementsAsync(string repl
{
var conflicts = await ConflictResolver.ResolveConflictsAsync(
_renameLocationSet, _renameLocationSet.Symbol.Name,
_renameInfo.GetFinalSymbolName(replacementText), optionSet, hasConflict: null, cancellationToken: cancellationToken).ConfigureAwait(false);
_renameInfo.GetFinalSymbolName(replacementText), optionSet, callbacks: null, cancellationToken: cancellationToken).ConfigureAwait(false);

return new InlineRenameReplacementInfo(conflicts);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@

Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.CSharp.UseAutoProperty
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UseAutoProperty

Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.UseAutoProperty
Public Class UseAutoPropertyTests
Inherits AbstractCrossLanguageUserDiagnosticTest

Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace, language As String) As Tuple(Of DiagnosticAnalyzer, CodeFixProvider)
If language = LanguageNames.CSharp Then
Return New Tuple(Of DiagnosticAnalyzer, CodeFixProvider)(New CSharp.UseAutoProperty.UseAutoPropertyAnalyzer(), New CSharp.UseAutoProperty.UseAutoPropertyCodeFixProvider())
Return New Tuple(Of DiagnosticAnalyzer, CodeFixProvider)(New CSharpUseAutoPropertyAnalyzer(), New CSharpUseAutoPropertyCodeFixProvider())
ElseIf language = LanguageNames.VisualBasic
Return New Tuple(Of DiagnosticAnalyzer, CodeFixProvider)(New VisualBasic.UseAutoProperty.UseAutoPropertyAnalyzer(), New VisualBasic.UseAutoProperty.UseAutoPropertyCodeFixProvider())
Return New Tuple(Of DiagnosticAnalyzer, CodeFixProvider)(New VisualBasicUseAutoPropertyAnalyzer(), New VisualBasicUseAutoPropertyCodeFixProvider())
Else
Throw New Exception()
End If
Expand Down
2 changes: 1 addition & 1 deletion src/EditorFeatures/Test2/Rename/RenameEngineResult.vb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename
Dim locations = RenameLocations.FindAsync(symbol, workspace.CurrentSolution, optionSet, CancellationToken.None).Result
Dim originalName = symbol.Name.Split("."c).Last()

Dim result = ConflictResolver.ResolveConflictsAsync(locations, originalName, renameTo, optionSet, hasConflict:=Nothing, cancellationToken:=CancellationToken.None).Result
Dim result = ConflictResolver.ResolveConflictsAsync(locations, originalName, renameTo, optionSet, callbacks:=Nothing, cancellationToken:=CancellationToken.None).Result

engineResult = New RenameEngineResult(workspace, result, renameTo)
engineResult.AssertUnlabeledSpansRenamedAndHaveNoConflicts()
Expand Down
4 changes: 2 additions & 2 deletions src/EditorFeatures/VisualBasic/BasicEditorFeatures.vbproj
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@
<Compile Include="SignatureHelp\SignatureHelpUtilities.vb" />
<Compile Include="TextStructureNavigation\TextStructureNavigatorProvider.vb" />
<Compile Include="TodoComment\BasicTodoCommentIncrementalAnalyzerProvider.vb" />
<Compile Include="UseAutoProperty\UseAutoPropertyAnalyzer.vb" />
<Compile Include="UseAutoProperty\UseAutoPropertyCodeFixProvider.vb" />
<Compile Include="UseAutoProperty\VisualBasicUseAutoPropertyAnalyzer.vb" />
<Compile Include="UseAutoProperty\VisualBasicUseAutoPropertyCodeFixProvider.vb" />
<Compile Include="UseAutoProperty\Utilities.vb" />
<Compile Include="Utilities\LineAdjustmentFormattingRule.vb" />
<Compile Include="Utilities\CommandHandlers\AbstractImplementAbstractClassOrInterfaceCommandHandler.vb" />
Expand Down
Loading