未验证 提交 9511dc00 编写于 作者: J Julia Feng 提交者: GitHub

Merge pull request #41371 from y87feng/40967

Introduce explicit downcast refactoring if a variable requires a cast to compile
......@@ -72,5 +72,6 @@ internal static class PredefinedCodeFixProviderNames
public const string UseThrowExpression = nameof(UseThrowExpression);
public const string PreferFrameworkType = nameof(PreferFrameworkType);
public const string MakeStructFieldsWritable = nameof(MakeStructFieldsWritable);
public const string AddExplicitCast = nameof(AddExplicitCast);
}
}
......@@ -643,6 +643,12 @@
<value>Reverse 'for' statement</value>
<comment>{Locked="for"} "for" is a C# keyword and should not be localized.</comment>
</data>
<data name="Add_explicit_cast" xml:space="preserve">
<value>Add explicit cast</value>
</data>
<data name="Convert_type_to_0" xml:space="preserve">
<value>Convert type to '{0}'</value>
</data>
<data name="Convert_to_regular_string" xml:space="preserve">
<value>Convert to regular string</value>
</data>
......
// Licensed to the .NET Foundation under one or more agreements.
// 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;
namespace Microsoft.CodeAnalysis.CSharp.CodeFixes.AddExplicitCast
{
/// <summary>
/// Sort types by inheritance distance from the base type in ascending order, i.e., less specific type
/// has higher priority because it has less probability to make mistakes
/// <para/>
/// For example:
/// class Base { }
/// class Derived1 : Base { }
/// class Derived2 : Derived1 { }
///
/// void Foo(Derived1 d1) { }
/// void Foo(Derived2 d2) { }
///
/// Base b = new Derived1();
/// Foo([||]b);
///
/// operations:
/// 1. Convert type to 'Derived1'
/// 2. Convert type to 'Derived2'
///
/// 'Derived1' is less specific than 'Derived2' compared to 'Base'
/// </summary>
internal sealed class InheritanceDistanceComparer : IComparer<ITypeSymbol>
{
private readonly ITypeSymbol _baseType;
private readonly SemanticModel _semanticModel;
public InheritanceDistanceComparer(SemanticModel semanticModel, ITypeSymbol baseType)
{
_semanticModel = semanticModel;
_baseType = baseType;
}
public int Compare(ITypeSymbol x, ITypeSymbol y)
{
var xDist = GetInheritanceDistance(x);
var yDist = GetInheritanceDistance(y);
return xDist.CompareTo(yDist);
}
/// <summary>
/// Calculate the inheritance distance between _baseType and derivedType.
/// </summary>
private int GetInheritanceDistanceRecursive(ITypeSymbol? derivedType)
{
if (derivedType == null)
return int.MaxValue;
if (derivedType.Equals(_baseType))
return 0;
var distance = GetInheritanceDistanceRecursive(derivedType.BaseType);
if (derivedType.Interfaces.Length != 0)
{
foreach (var interfaceType in derivedType.Interfaces)
{
distance = Math.Min(GetInheritanceDistanceRecursive(interfaceType), distance);
}
}
return distance == int.MaxValue ? distance : distance + 1;
}
/// <summary>
/// Wrapper funtion of [GetInheritanceDistance], also consider the class with explicit conversion operator
/// has the highest priority.
/// </summary>
private int GetInheritanceDistance(ITypeSymbol type)
{
var conversion = _semanticModel.Compilation.ClassifyCommonConversion(_baseType, type);
// If the node has the explicit conversion operator, then it has the shortest distance
// since explicit conversion operator is defined by users and has the highest priority
var distance = conversion.IsUserDefined ? 0 : GetInheritanceDistanceRecursive(type);
return distance;
}
}
}
......@@ -12,6 +12,11 @@
<target state="translated">Přidat await</target>
<note />
</trans-unit>
<trans-unit id="Add_explicit_cast">
<source>Add explicit cast</source>
<target state="new">Add explicit cast</target>
<note />
</trans-unit>
<trans-unit id="Add_missing_usings">
<source>Add missing usings</source>
<target state="translated">Přidat chybějící direktivy using</target>
......@@ -92,6 +97,11 @@
<target state="new">Convert to verbatim string</target>
<note />
</trans-unit>
<trans-unit id="Convert_type_to_0">
<source>Convert type to '{0}'</source>
<target state="new">Convert type to '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Declare_as_nullable">
<source>Declare as nullable</source>
<target state="translated">Deklarovat jako s možnou hodnotou null</target>
......
......@@ -12,6 +12,11 @@
<target state="translated">"await" hinzufügen</target>
<note />
</trans-unit>
<trans-unit id="Add_explicit_cast">
<source>Add explicit cast</source>
<target state="new">Add explicit cast</target>
<note />
</trans-unit>
<trans-unit id="Add_missing_usings">
<source>Add missing usings</source>
<target state="translated">Fehlende using-Anweisungen hinzufügen</target>
......@@ -92,6 +97,11 @@
<target state="new">Convert to verbatim string</target>
<note />
</trans-unit>
<trans-unit id="Convert_type_to_0">
<source>Convert type to '{0}'</source>
<target state="new">Convert type to '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Declare_as_nullable">
<source>Declare as nullable</source>
<target state="translated">Als für NULL-Werte zulässig deklarieren</target>
......
......@@ -12,6 +12,11 @@
<target state="translated">Añadir await</target>
<note />
</trans-unit>
<trans-unit id="Add_explicit_cast">
<source>Add explicit cast</source>
<target state="new">Add explicit cast</target>
<note />
</trans-unit>
<trans-unit id="Add_missing_usings">
<source>Add missing usings</source>
<target state="translated">Añadir valores using que faltan</target>
......@@ -92,6 +97,11 @@
<target state="new">Convert to verbatim string</target>
<note />
</trans-unit>
<trans-unit id="Convert_type_to_0">
<source>Convert type to '{0}'</source>
<target state="new">Convert type to '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Declare_as_nullable">
<source>Declare as nullable</source>
<target state="translated">Declara como que acepta valores NULL</target>
......
......@@ -12,6 +12,11 @@
<target state="translated">Ajouter une expression await</target>
<note />
</trans-unit>
<trans-unit id="Add_explicit_cast">
<source>Add explicit cast</source>
<target state="new">Add explicit cast</target>
<note />
</trans-unit>
<trans-unit id="Add_missing_usings">
<source>Add missing usings</source>
<target state="translated">Ajouter les instructions using manquantes</target>
......@@ -92,6 +97,11 @@
<target state="new">Convert to verbatim string</target>
<note />
</trans-unit>
<trans-unit id="Convert_type_to_0">
<source>Convert type to '{0}'</source>
<target state="new">Convert type to '{0}'</target>
<note />
</trans-unit>
<trans-unit id="Declare_as_nullable">
<source>Declare as nullable</source>
<target state="translated">Déclarer comme nullable</target>
......
......@@ -40,6 +40,7 @@ public static class Features
public const string CodeActionsAddBraces = "CodeActions.AddBraces";
public const string CodeActionsAddConstructorParametersFromMembers = "CodeActions.AddConstructorParametersFromMembers";
public const string CodeActionsAddDocCommentNodes = "CodeActions.AddDocCommentParamNodes";
public const string CodeActionsAddExplicitCast = "CodeActions.AddExplicitCast";
public const string CodeActionsAddFileBanner = "CodeActions.AddFileBanner";
public const string CodeActionsAddImport = "CodeActions.AddImport";
public const string CodeActionsAddMissingReference = "CodeActions.AddMissingReference";
......
......@@ -475,5 +475,7 @@ internal enum FunctionId
LanguageServer_ActivateFailed = 382,
LanguageServer_OnLoadedFailed = 383,
CodeFixes_AddExplicitCast = 384,
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册