提交 13caed70 编写于 作者: C Cyrus Najmabadi

Add feature to update existing GetHashCode implementations to use System.GetHashCode

上级 e45806ce
...@@ -113,6 +113,8 @@ internal static class IDEDiagnosticIds ...@@ -113,6 +113,8 @@ internal static class IDEDiagnosticIds
public const string UseRecommendedDisposePatternDiagnosticId = "IDE0068"; public const string UseRecommendedDisposePatternDiagnosticId = "IDE0068";
public const string DisposableFieldsShouldBeDisposedDiagnosticId = "IDE0069"; public const string DisposableFieldsShouldBeDisposedDiagnosticId = "IDE0069";
public const string UseSystemHashCode = "IDE0070";
// Analyzer error Ids // Analyzer error Ids
public const string AnalyzerChangedId = "IDE1001"; public const string AnalyzerChangedId = "IDE1001";
public const string AnalyzerDependencyConflictId = "IDE1002"; public const string AnalyzerDependencyConflictId = "IDE1002";
......
...@@ -4617,6 +4617,15 @@ internal class FeaturesResources { ...@@ -4617,6 +4617,15 @@ internal class FeaturesResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Use &apos;System.HashCode&apos;.
/// </summary>
internal static string Use_System_HashCode {
get {
return ResourceManager.GetString("Use_System_HashCode", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Use &apos;throw&apos; expression. /// Looks up a localized string similar to Use &apos;throw&apos; expression.
/// </summary> /// </summary>
...@@ -4636,7 +4645,7 @@ internal class FeaturesResources { ...@@ -4636,7 +4645,7 @@ internal class FeaturesResources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a &apos;using&apos; statement or a &apos;using&apos; declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the &apos;finally&apos; region, say &apos;x?.Dispose()&apos;. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object [rest of string was truncated]&quot;;. /// Looks up a localized string similar to Use recommended dispose pattern to ensure that locally scoped disposable objects are disposed on all paths. If possible, wrap the creation within a &apos;using&apos; statement or a &apos;using&apos; declaration. Otherwise, use a try-finally pattern, with a dedicated local variable declared before the try region and an unconditional Dispose invocation on non-null value in the &apos;finally&apos; region, say &apos;x?.Dispose()&apos;. If the object is explicitly disposed within the try region or the dispose ownership is transferred to another object [rest of string was truncated]&quot;;.
/// </summary> /// </summary>
internal static string UseRecommendedDisposePatternDescription { internal static string UseRecommendedDisposePatternDescription {
get { get {
......
...@@ -1711,4 +1711,7 @@ This version used in: {2}</value> ...@@ -1711,4 +1711,7 @@ This version used in: {2}</value>
<data name="Add_null_checks_for_all_parameters" xml:space="preserve"> <data name="Add_null_checks_for_all_parameters" xml:space="preserve">
<value>Add null checks for all parameters</value> <value>Add null checks for all parameters</value>
</data> </data>
<data name="Use_System_HashCode" xml:space="preserve">
<value>Use 'System.HashCode'</value>
</data>
</root> </root>
\ No newline at end of file
...@@ -119,17 +119,15 @@ public async Task<Document> FormatDocumentAsync(Document document, CancellationT ...@@ -119,17 +119,15 @@ public async Task<Document> FormatDocumentAsync(Document document, CancellationT
{ {
var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var factory = document.GetLanguageService<SyntaxGenerator>(); var factory = document.GetLanguageService<SyntaxGenerator>();
return CreateGetHashCodeMethod( return CreateGetHashCodeMethod(factory, compilation, namedType, members);
factory, compilation, namedType, members, cancellationToken);
} }
private IMethodSymbol CreateGetHashCodeMethod( private IMethodSymbol CreateGetHashCodeMethod(
SyntaxGenerator factory, Compilation compilation, SyntaxGenerator factory, Compilation compilation,
INamedTypeSymbol namedType, ImmutableArray<ISymbol> members, INamedTypeSymbol namedType, ImmutableArray<ISymbol> members)
CancellationToken cancellationToken)
{ {
var statements = CreateGetHashCodeStatements( var statements = CreateGetHashCodeStatements(
factory, compilation, namedType, members, cancellationToken); factory, compilation, namedType, members);
return CodeGenerationSymbolFactory.CreateMethodSymbol( return CodeGenerationSymbolFactory.CreateMethodSymbol(
attributes: default, attributes: default,
...@@ -146,15 +144,13 @@ public async Task<Document> FormatDocumentAsync(Document document, CancellationT ...@@ -146,15 +144,13 @@ public async Task<Document> FormatDocumentAsync(Document document, CancellationT
private ImmutableArray<SyntaxNode> CreateGetHashCodeStatements( private ImmutableArray<SyntaxNode> CreateGetHashCodeStatements(
SyntaxGenerator factory, Compilation compilation, SyntaxGenerator factory, Compilation compilation,
INamedTypeSymbol namedType, ImmutableArray<ISymbol> members, INamedTypeSymbol namedType, ImmutableArray<ISymbol> members)
CancellationToken cancellationToken)
{ {
// If we have access to System.HashCode, then just use that. // If we have access to System.HashCode, then just use that.
var hashCodeType = compilation.GetTypeByMetadataName("System.HashCode"); var hashCodeType = compilation.GetTypeByMetadataName("System.HashCode");
var components = factory.GetGetHashCodeComponents( var components = factory.GetGetHashCodeComponents(
compilation, namedType, members, compilation, namedType, members, justMemberReference: true);
justMemberReference: true, cancellationToken);
if (components.Length > 0 && hashCodeType != null) if (components.Length > 0 && hashCodeType != null)
{ {
...@@ -164,7 +160,7 @@ public async Task<Document> FormatDocumentAsync(Document document, CancellationT ...@@ -164,7 +160,7 @@ public async Task<Document> FormatDocumentAsync(Document document, CancellationT
// Otherwise, try to just spit out a reasonable hash code for these members. // Otherwise, try to just spit out a reasonable hash code for these members.
var statements = factory.CreateGetHashCodeMethodStatements( var statements = factory.CreateGetHashCodeMethodStatements(
compilation, namedType, members, useInt64: false, cancellationToken); compilation, namedType, members, useInt64: false);
// Unfortunately, our 'reasonable' hash code may overflow in checked contexts. // Unfortunately, our 'reasonable' hash code may overflow in checked contexts.
// C# can handle this by adding 'checked{}' around the code, VB has to jump // C# can handle this by adding 'checked{}' around the code, VB has to jump
...@@ -198,7 +194,7 @@ public async Task<Document> FormatDocumentAsync(Document document, CancellationT ...@@ -198,7 +194,7 @@ public async Task<Document> FormatDocumentAsync(Document document, CancellationT
// //
// This does mean all hashcodes will be positive. But it will avoid the overflow problem. // This does mean all hashcodes will be positive. But it will avoid the overflow problem.
return factory.CreateGetHashCodeMethodStatements( return factory.CreateGetHashCodeMethodStatements(
compilation, namedType, members, useInt64: true, cancellationToken); compilation, namedType, members, useInt64: true);
} }
private ImmutableArray<SyntaxNode> CreateGetHashCodeStatementsUsingSystemHashCode( private ImmutableArray<SyntaxNode> CreateGetHashCodeStatementsUsingSystemHashCode(
......
...@@ -273,12 +273,8 @@ private bool IsStringCheck(IOperation condition, IParameterSymbol parameter) ...@@ -273,12 +273,8 @@ private bool IsStringCheck(IOperation condition, IParameterSymbol parameter)
} }
private bool IsNullCheck(IOperation operand1, IOperation operand2, IParameterSymbol parameter) private bool IsNullCheck(IOperation operand1, IOperation operand2, IParameterSymbol parameter)
=> IsNullLiteral(UnwrapImplicitConversion(operand1)) && IsParameterReference(operand2, parameter); => UnwrapImplicitConversion(operand1).IsNullLiteral() && IsParameterReference(operand2, parameter);
private bool IsNullLiteral(IOperation operand)
=> operand is ILiteralOperation literal &&
literal.ConstantValue.HasValue &&
literal.ConstantValue.Value == null;
private async Task<Document> AddNullCheckAsync( private async Task<Document> AddNullCheckAsync(
Document document, Document document,
......
// 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 Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.UseSystemHashCode
{
internal struct Analyzer
{
private readonly IMethodSymbol _getHashCodeMethod;
private readonly IMethodSymbol _objectGetHashCodeMethod;
private readonly INamedTypeSymbol _containingType;
private readonly INamedTypeSymbol _equalityComparerTypeOpt;
public Analyzer(IMethodSymbol getHashCodeMethod, IMethodSymbol objectGetHashCode, INamedTypeSymbol equalityComparerTypeOpt)
{
_getHashCodeMethod = getHashCodeMethod;
_containingType = _getHashCodeMethod.ContainingType.OriginalDefinition;
_objectGetHashCodeMethod = objectGetHashCode;
_equalityComparerTypeOpt = equalityComparerTypeOpt;
}
public ImmutableArray<ISymbol> GetHashedMembers(IBlockOperation blockOperation)
{
// Unwind through nested blocks.
while (blockOperation.Operations.Length == 1 &&
blockOperation.Operations[0] is IBlockOperation childBlock)
{
blockOperation = childBlock;
}
// Needs to be of the form:
//
// // accumulator
// var hashCode = <initializer>
//
// // 1-N member hashes mixed into the accumulator.
// hashCode = (hashCode op constant) op member_hash
//
// // return of the value.
// return hashCode;
var statements = blockOperation.Operations;
if (statements.Length == 0)
{
return default;
}
var firstStatement = statements.First();
var lastStatement = statements.Last();
if (!(firstStatement is IVariableDeclarationGroupOperation varDeclStatement) ||
!(lastStatement is IReturnOperation returnStatement))
{
return default;
}
var variables = varDeclStatement.GetDeclaredVariables();
if (variables.Length != 1)
{
return default;
}
if (varDeclStatement.Declarations.Length != 1)
{
return default;
}
var declaration = varDeclStatement.Declarations[0];
if (declaration.Declarators.Length != 1)
{
return default;
}
var declarator = declaration.Declarators[0];
if (declarator.Initializer == null ||
declarator.Initializer.Value == null)
{
return default;
}
var accumulatorVariable = declarator.Symbol;
if (!(IsLocalReference(returnStatement.ReturnedValue, accumulatorVariable)))
{
return default;
}
var initializerValue = declarator.Initializer.Value;
var hashedSymbols = ArrayBuilder<ISymbol>.GetInstance();
if (!IsLiteralNumber(initializerValue) &&
!TryGetHashedSymbol(accumulatorVariable, hashedSymbols, initializerValue))
{
return default;
}
for (var i = 1; i < statements.Length - 1; i++)
{
var statement = statements[i];
if (!(statement is IExpressionStatementOperation expressionStatement) ||
!(expressionStatement.Operation is ISimpleAssignmentOperation simpleAssignment) ||
!IsLocalReference(simpleAssignment.Target, accumulatorVariable) ||
!TryGetHashedSymbol(accumulatorVariable, hashedSymbols, simpleAssignment.Value))
{
return default;
}
}
return hashedSymbols.ToImmutableAndFree();
}
private bool TryGetHashedSymbol(
ILocalSymbol accumulatorVariable, ArrayBuilder<ISymbol> hashedSymbols, IOperation value)
{
value = Unwrap(value);
if (value is IInvocationOperation invocation)
{
var targetMethod = invocation.TargetMethod;
if (OverridesSystemObject(_objectGetHashCodeMethod, targetMethod))
{
// (hashCode * -1521134295 + a.GetHashCode()).GetHashCode()
// recurse on the value we're calling GetHashCode on.
return TryGetHashedSymbol(accumulatorVariable, hashedSymbols, invocation.Instance);
}
if (targetMethod.Name == nameof(GetHashCode) &&
Equals(_equalityComparerTypeOpt, targetMethod.ContainingType.OriginalDefinition) &&
invocation.Arguments.Length == 1)
{
// EqualityComparer<T>.Default.GetHashCode(i)
return TryGetHashedSymbol(accumulatorVariable, hashedSymbols, invocation.Arguments[0].Value);
}
}
// (hashCode op1 constant) op1 hashed_value
if (value is IBinaryOperation topBinary)
{
return topBinary.LeftOperand is IBinaryOperation leftBinary &&
IsLocalReference(leftBinary.LeftOperand, accumulatorVariable) &&
IsLiteralNumber(leftBinary.RightOperand) &&
TryGetHashedSymbol(accumulatorVariable, hashedSymbols, topBinary.RightOperand);
}
if (value is IInstanceReferenceOperation instanceReference)
{
// reference to this/base.
return instanceReference.ReferenceKind == InstanceReferenceKind.ContainingTypeInstance;
}
if (value is IConditionalOperation conditional &&
conditional.Condition is IBinaryOperation binary)
{
if (binary.RightOperand.IsNullLiteral() &&
TryGetFieldOrProperty(binary.LeftOperand, out _))
{
if (binary.OperatorKind == BinaryOperatorKind.Equals)
{
// (StringProperty == null ? 0 : StringProperty.GetHashCode())
return TryGetHashedSymbol(accumulatorVariable, hashedSymbols, conditional.WhenFalse);
}
else if (binary.OperatorKind == BinaryOperatorKind.NotEquals)
{
// (StringProperty != null ? StringProperty.GetHashCode() : 0)
return TryGetHashedSymbol(accumulatorVariable, hashedSymbols, conditional.WhenTrue);
}
}
}
if (TryGetFieldOrProperty(value, out var fieldOrProp) &&
Equals(fieldOrProp.ContainingType.OriginalDefinition, _containingType))
{
return Add(hashedSymbols, fieldOrProp);
}
return false;
}
private static bool TryGetFieldOrProperty(IOperation operation, out ISymbol symbol)
{
if (operation is IFieldReferenceOperation fieldReference)
{
symbol = fieldReference.Member;
return true;
}
if (operation is IPropertyReferenceOperation propertyReference)
{
symbol = propertyReference.Member;
return true;
}
symbol = null;
return false;
}
private bool Add(ArrayBuilder<ISymbol> hashedSymbols, ISymbol member)
{
foreach (var symbol in hashedSymbols)
{
if (Equals(symbol, member))
{
return false;
}
}
hashedSymbols.Add(member);
return true;
}
private static bool IsLiteralNumber(IOperation value)
{
value = Unwrap(value);
return value is IUnaryOperation unary
? unary.OperatorKind == UnaryOperatorKind.Minus && IsLiteralNumber(unary.Operand)
: value.IsNumericLiteral();
}
private static bool IsLocalReference(IOperation value, ILocalSymbol accumulatorVariable)
=> Unwrap(value) is ILocalReferenceOperation localReference && accumulatorVariable.Equals(localReference.Local);
private static IOperation Unwrap(IOperation value)
{
while (true)
{
if (value is IConversionOperation conversion)
{
value = conversion.Operand;
}
else if (value is IParenthesizedOperation parenthesized)
{
value = parenthesized.Operand;
}
else
{
return value;
}
}
}
public static bool OverridesSystemObject(IMethodSymbol objectGetHashCode, IMethodSymbol method)
{
for (var current = method; current != null; current = current.OverriddenMethod)
{
if (objectGetHashCode.Equals(current))
{
return true;
}
}
return false;
}
}
}
// 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.Linq;
using System.Net.Mime;
using System.Text;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.UseSystemHashCode
{
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
internal class UseSystemHashCodeDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer
{
public UseSystemHashCodeDiagnosticAnalyzer()
: base(IDEDiagnosticIds.UseSystemHashCode,
CodeStyleOptions.PreferSystemHashCode,
new LocalizableResourceString(nameof(FeaturesResources.Use_System_HashCode), FeaturesResources.ResourceManager, typeof(FeaturesResources)))
{
}
public override DiagnosticAnalyzerCategory GetAnalyzerCategory()
=> DiagnosticAnalyzerCategory.SemanticSpanAnalysis;
protected override void InitializeWorker(AnalysisContext context)
{
context.RegisterCompilationStartAction(c =>
{
// var hashCodeType = c.Compilation.GetTypeByMetadataName("System.HashCode");
var objectType = c.Compilation.GetSpecialType(SpecialType.System_Object);
var objectGetHashCode = objectType?.GetMembers(nameof(GetHashCode)).FirstOrDefault() as IMethodSymbol;
var equalityComparerTypeOpt = c.Compilation.GetTypeByMetadataName(typeof(EqualityComparer<>).FullName);
if (// hashCodeType != null &&
objectGetHashCode != null)
{
c.RegisterOperationBlockAction(c2 =>
AnalyzeOperationBlock(c2, objectGetHashCode, equalityComparerTypeOpt));
}
});
}
private void AnalyzeOperationBlock(
OperationBlockAnalysisContext context, IMethodSymbol objectGetHashCode, INamedTypeSymbol equalityComparerTypeOpt)
{
if (!(context.OwningSymbol is IMethodSymbol method))
{
return;
}
if (method.Name != nameof(GetHashCode))
{
return;
}
if (!method.IsOverride)
{
return;
}
if (method.Locations.Length != 1 || method.DeclaringSyntaxReferences.Length != 1)
{
return;
}
var location = method.Locations[0];
if (!location.IsInSource)
{
return;
}
if (context.OperationBlocks.Length != 1)
{
return;
}
var operation = context.OperationBlocks[0];
if (!(operation is IBlockOperation blockOperation))
{
return;
}
if (!Analyzer.OverridesSystemObject(objectGetHashCode, method))
{
return;
}
var cancellationToken = context.CancellationToken;
var optionSet = context.Options.GetDocumentOptionSetAsync(location.SourceTree, cancellationToken).GetAwaiter().GetResult();
if (optionSet == null)
{
return;
}
var option = optionSet.GetOption(CodeStyleOptions.PreferSystemHashCode, operation.Language);
if (!option.Value)
{
return;
}
var analyzer = new Analyzer(method, objectGetHashCode, equalityComparerTypeOpt);
var hashedMembers = analyzer.GetHashedMembers(blockOperation);
if (!hashedMembers.IsDefaultOrEmpty)
{
context.ReportDiagnostic(DiagnosticHelper.Create(
this.Descriptor, location, option.Notification.Severity,
new[] { operation.Syntax.GetLocation() }, ImmutableDictionary<string, string>.Empty));
}
}
}
}
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">Použijte doporučený vzor vyřazení, abyste měli jistotu, že objekty, které lze vyřadit v místním oboru, se vyřadí na všech cestách. Pokud je to možné, zabalte vytváření do příkazu nebo deklarace using. Jinak použijte vzor try-finally s vyhrazenou místní proměnnou deklarovanou před oblastí try a nepodmíněným voláním Dispose pro hodnotu, která není null, v oblasti finally, třeba x?.Dispose(). Pokud se objekt explicitně vyřadí v oblasti try nebo se vlastnictví vyřazení převede na jiný objekt nebo metodu, přiřaďte ihned po takové operaci místní proměnné hodnotu null, aby ve finally nedošlo k dvojímu vyřazení.</target> <target state="needs-review-translation">Použijte doporučený vzor vyřazení, abyste měli jistotu, že objekty, které lze vyřadit v místním oboru, se vyřadí na všech cestách. Pokud je to možné, zabalte vytváření do příkazu nebo deklarace using. Jinak použijte vzor try-finally s vyhrazenou místní proměnnou deklarovanou před oblastí try a nepodmíněným voláním Dispose pro hodnotu, která není null, v oblasti finally, třeba x?.Dispose(). Pokud se objekt explicitně vyřadí v oblasti try nebo se vlastnictví vyřazení převede na jiný objekt nebo metodu, přiřaďte ihned po takové operaci místní proměnné hodnotu null, aby ve finally nedošlo k dvojímu vyřazení.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">Pro lambda výrazy používat text bloku</target> <target state="translated">Pro lambda výrazy používat text bloku</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">Verwenden Sie das empfohlene Dispose-Muster, um sicherzustellen, dass löschbare Objekte für den lokalen Bereich in allen Pfaden gelöscht werden. Schließen Sie die Erstellung nach Möglichkeit in einer using-Anweisung oder einer using-Deklaration ein. Verwenden Sie andernfalls ein try-finally-Muster mit einer vor dem try-Bereich deklarierten dedizierten lokalen Variablen und einem Dispose-Aufruf ohne Bedingung für den Nicht-NULL-Wert im finally-Bereich, beispielsweise "x?.Dispose()". Wenn das Objekt explizit innerhalb des try-Bereichs gelöscht oder der Dispose-Besitz auf ein anderes Objekt oder eine andere Methode übertragen wird, weisen Sie der lokalen Variablen gleich nach einem solchen Vorgang NULL zu, um einen doppelten Löschvorgang in "finally" zu vermeiden.</target> <target state="needs-review-translation">Verwenden Sie das empfohlene Dispose-Muster, um sicherzustellen, dass löschbare Objekte für den lokalen Bereich in allen Pfaden gelöscht werden. Schließen Sie die Erstellung nach Möglichkeit in einer using-Anweisung oder einer using-Deklaration ein. Verwenden Sie andernfalls ein try-finally-Muster mit einer vor dem try-Bereich deklarierten dedizierten lokalen Variablen und einem Dispose-Aufruf ohne Bedingung für den Nicht-NULL-Wert im finally-Bereich, beispielsweise "x?.Dispose()". Wenn das Objekt explizit innerhalb des try-Bereichs gelöscht oder der Dispose-Besitz auf ein anderes Objekt oder eine andere Methode übertragen wird, weisen Sie der lokalen Variablen gleich nach einem solchen Vorgang NULL zu, um einen doppelten Löschvorgang in "finally" zu vermeiden.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">Blockkörper für Lambdaausdrücke verwenden</target> <target state="translated">Blockkörper für Lambdaausdrücke verwenden</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">Use el patrón Dispose recomendado para asegurarse de que los objetos descartables de ámbito local se desechan en todas las rutas de acceso. Si es posible, incluya la creación en una instrucción "using" o una declaración "using". En caso contrario, use un patrón try-finally, con la declaración de una variable local dedicada antes de la región "try" y una invocación de Dispose incondicional en un valor no nulo en la región "finally", por ejemplo, "x?.Dispose()". Si el objeto se desecha de forma explícita en la región "try" o la pertenencia de Dispose se transfiere a otro objeto o método, asigne "null" a la variable local justo después de tal operación para evitar un doble Dispose en "finally".</target> <target state="needs-review-translation">Use el patrón Dispose recomendado para asegurarse de que los objetos descartables de ámbito local se desechan en todas las rutas de acceso. Si es posible, incluya la creación en una instrucción "using" o una declaración "using". En caso contrario, use un patrón try-finally, con la declaración de una variable local dedicada antes de la región "try" y una invocación de Dispose incondicional en un valor no nulo en la región "finally", por ejemplo, "x?.Dispose()". Si el objeto se desecha de forma explícita en la región "try" o la pertenencia de Dispose se transfiere a otro objeto o método, asigne "null" a la variable local justo después de tal operación para evitar un doble Dispose en "finally".</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">Usar cuerpo de bloque de expresiones lambda</target> <target state="translated">Usar cuerpo de bloque de expresiones lambda</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">Utilisez le modèle de suppression recommandé pour vérifier que les objets supprimables de l'étendue locale sont bien supprimés sur tous les chemins. Si possible, incluez la création dans un wrapper au sein d'une instruction 'using' ou d'une déclaration 'using'. Sinon, utilisez un modèle try-finally avec une variable locale dédiée déclarée avant la région try et un appel inconditionnel de Dispose sur une valeur non null dans la région 'finally', par exemple 'x?.Dispose()'. Si l'objet est explicitement supprimé dans la région try ou si la propriété de suppression est transférée vers un autre objet ou une autre méthode, affectez la valeur 'null' à la variable locale juste après cette opération pour éviter une double suppression dans 'finally'</target> <target state="needs-review-translation">Utilisez le modèle de suppression recommandé pour vérifier que les objets supprimables de l'étendue locale sont bien supprimés sur tous les chemins. Si possible, incluez la création dans un wrapper au sein d'une instruction 'using' ou d'une déclaration 'using'. Sinon, utilisez un modèle try-finally avec une variable locale dédiée déclarée avant la région try et un appel inconditionnel de Dispose sur une valeur non null dans la région 'finally', par exemple 'x?.Dispose()'. Si l'objet est explicitement supprimé dans la région try ou si la propriété de suppression est transférée vers un autre objet ou une autre méthode, affectez la valeur 'null' à la variable locale juste après cette opération pour éviter une double suppression dans 'finally'</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">Utiliser le corps de bloc pour les expressions lambda</target> <target state="translated">Utiliser le corps de bloc pour les expressions lambda</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">Usare il criterio dispose consigliato per garantire che gli oggetti eliminabili con ambito locale vengano eliminati in tutti i percorsi. Se possibile, eseguire il wrapping della creazione in un'istruzione 'using' o una dichiarazione 'using'. In caso contrario, usare un criterio try-finally, con una variabile locale dedicata dichiarata prima dell'area try e una chiamata Dispose non condizionale al valore non Null nell'area 'finally', ad esempio 'x?.Dispose()'. Se l'oggetto viene eliminato in modo esplicito nell'area try oppure la proprietà di dispose viene trasferita a un altro oggetto o metodo, assegnare 'null' alla variabile locale subito dopo una tale operazione per evitare di raddoppiare dispose in 'finally'.</target> <target state="needs-review-translation">Usare il criterio dispose consigliato per garantire che gli oggetti eliminabili con ambito locale vengano eliminati in tutti i percorsi. Se possibile, eseguire il wrapping della creazione in un'istruzione 'using' o una dichiarazione 'using'. In caso contrario, usare un criterio try-finally, con una variabile locale dedicata dichiarata prima dell'area try e una chiamata Dispose non condizionale al valore non Null nell'area 'finally', ad esempio 'x?.Dispose()'. Se l'oggetto viene eliminato in modo esplicito nell'area try oppure la proprietà di dispose viene trasferita a un altro oggetto o metodo, assegnare 'null' alla variabile locale subito dopo una tale operazione per evitare di raddoppiare dispose in 'finally'.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">Usa il corpo del blocco per le espressioni lambda</target> <target state="translated">Usa il corpo del blocco per le espressioni lambda</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">推奨される dispose パターンを使用して、ローカル スコープの破棄可能なオブジェクトがすべてのパスで破棄されるようにします。可能なら、'using' ステートメントまたは 'using' 宣言内で作成をラップします。または、try-finally パターンを、try 領域の前で宣言された専用のローカル変数と、'finally' 領域の非 null 値での条件なしの Dispose の呼び出し (例: 'x?.Dispose()') とともに使用します。オブジェクトが try 領域内で明示的に破棄されるか、dispose の所有権が他のオブジェクトまたはメソッドに移される場合、その操作のすぐ後で 'null' をローカル変数に割り当てて、'finally' 内での dispose の重複を回避します</target> <target state="needs-review-translation">推奨される dispose パターンを使用して、ローカル スコープの破棄可能なオブジェクトがすべてのパスで破棄されるようにします。可能なら、'using' ステートメントまたは 'using' 宣言内で作成をラップします。または、try-finally パターンを、try 領域の前で宣言された専用のローカル変数と、'finally' 領域の非 null 値での条件なしの Dispose の呼び出し (例: 'x?.Dispose()') とともに使用します。オブジェクトが try 領域内で明示的に破棄されるか、dispose の所有権が他のオブジェクトまたはメソッドに移される場合、その操作のすぐ後で 'null' をローカル変数に割り当てて、'finally' 内での dispose の重複を回避します</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">ラムダ式にブロック本体を使用する</target> <target state="translated">ラムダ式にブロック本体を使用する</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">권장 dispose 패턴을 사용하여 로컬로 범위가 지정된 삭제 가능한 개체가 모든 경로에서 삭제되도록 합니다. 가능한 경우 'using' 문이나 'using' 선언 내에서 생성을 래핑합니다. 그러지 않으면 try 영역 앞에 선언된 전용 지역 변수 및 'finally' 영역에 있는 null이 아닌 값의 비조건부 Dispose 호출('x?.Dispose()')과 함께 try-finally 패턴을 사용하세요. 개체가 try 영역 내에서 명시적으로 삭제되거나 삭제 소유권이 다른 개체나 메서드로 이전되면 해당 작업 바로 뒤의 지역 변수에 'null'을 할당하여 'finally'에서 이중 삭제를 방지하세요.</target> <target state="needs-review-translation">권장 dispose 패턴을 사용하여 로컬로 범위가 지정된 삭제 가능한 개체가 모든 경로에서 삭제되도록 합니다. 가능한 경우 'using' 문이나 'using' 선언 내에서 생성을 래핑합니다. 그러지 않으면 try 영역 앞에 선언된 전용 지역 변수 및 'finally' 영역에 있는 null이 아닌 값의 비조건부 Dispose 호출('x?.Dispose()')과 함께 try-finally 패턴을 사용하세요. 개체가 try 영역 내에서 명시적으로 삭제되거나 삭제 소유권이 다른 개체나 메서드로 이전되면 해당 작업 바로 뒤의 지역 변수에 'null'을 할당하여 'finally'에서 이중 삭제를 방지하세요.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">람다 식에 블록 본문 사용</target> <target state="translated">람다 식에 블록 본문 사용</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">Użyj zalecanego wzorca dispose, aby upewnić się, że obiekty możliwe do likwidacji w lokalnym zakresie są likwidowane we wszystkich ścieżkach. Jeśli to możliwe, opakuj tworzenie w instrukcji „using” lub deklaracji „using”. W przeciwnym razie użyj wzorca try-finally, z dedykowaną zmienną lokalną zadeklarowaną przed regionem try i bezwarunkowym wywołaniem metody Dispose dla wartości innej niż null w regionie „finally”, na przykład „x?.Dispose()”. Jeśli obiekt jest jawnie likwidowany w regionie try lub własność dispose jest przenoszona do innego obiektu lub metody, przypisz wartość „null” do zmiennej lokalnej zaraz po takiej operacji, aby zapobiec podwójnemu wywołaniu dispose w regionie „finally”.</target> <target state="needs-review-translation">Użyj zalecanego wzorca dispose, aby upewnić się, że obiekty możliwe do likwidacji w lokalnym zakresie są likwidowane we wszystkich ścieżkach. Jeśli to możliwe, opakuj tworzenie w instrukcji „using” lub deklaracji „using”. W przeciwnym razie użyj wzorca try-finally, z dedykowaną zmienną lokalną zadeklarowaną przed regionem try i bezwarunkowym wywołaniem metody Dispose dla wartości innej niż null w regionie „finally”, na przykład „x?.Dispose()”. Jeśli obiekt jest jawnie likwidowany w regionie try lub własność dispose jest przenoszona do innego obiektu lub metody, przypisz wartość „null” do zmiennej lokalnej zaraz po takiej operacji, aby zapobiec podwójnemu wywołaniu dispose w regionie „finally”.</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">Użyj treści bloku dla wyrażeń lambda</target> <target state="translated">Użyj treści bloku dla wyrażeń lambda</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">Use o padrão de descarte recomendado para garantir que os objetos descartáveis no escopo local sejam descartados em todos os caminhos. Se possível, encapsule a criação em uma instrução 'using' ou em uma declaração 'using'. Caso contrário, use um padrão try-finally, com uma variável local dedicada declarada antes da região try e uma invocação de Dispose incondicional em um valor que não seja nulo na região 'finally', como x?.Dispose()'. Se o objeto for descartado explicitamente dentro da região try ou se a propriedade de descarte for transferida para outro objeto ou método, atribua 'null' à variável local logo após essa operação para evitar um descarte duplo em 'finally'</target> <target state="needs-review-translation">Use o padrão de descarte recomendado para garantir que os objetos descartáveis no escopo local sejam descartados em todos os caminhos. Se possível, encapsule a criação em uma instrução 'using' ou em uma declaração 'using'. Caso contrário, use um padrão try-finally, com uma variável local dedicada declarada antes da região try e uma invocação de Dispose incondicional em um valor que não seja nulo na região 'finally', como x?.Dispose()'. Se o objeto for descartado explicitamente dentro da região try ou se a propriedade de descarte for transferida para outro objeto ou método, atribua 'null' à variável local logo após essa operação para evitar um descarte duplo em 'finally'</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">Usar o corpo do bloco para expressões lambda</target> <target state="translated">Usar o corpo do bloco para expressões lambda</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">Используйте рекомендуемый шаблон Dispose, чтобы убедиться, что все освобождаемые объекты в локальной области освобождены для всех путей. Если это возможно, заключите создание объекта в оператор "using" или в объявление "using". В противном случае используйте шаблон try-finally с выделенной локальной переменной, объявляемой до области try, и безусловным вызовом Dispose для отличного от NULL значения в области "finally", например "x?.Dispose()". Если объект явно освобождается в области try или если права владения для операции освобождения передаются другому объекту или методу, присвойте значение "null" локальной переменной сразу после такой операции, чтобы предотвратить двойное освобождение в области "finally".</target> <target state="needs-review-translation">Используйте рекомендуемый шаблон Dispose, чтобы убедиться, что все освобождаемые объекты в локальной области освобождены для всех путей. Если это возможно, заключите создание объекта в оператор "using" или в объявление "using". В противном случае используйте шаблон try-finally с выделенной локальной переменной, объявляемой до области try, и безусловным вызовом Dispose для отличного от NULL значения в области "finally", например "x?.Dispose()". Если объект явно освобождается в области try или если права владения для операции освобождения передаются другому объекту или методу, присвойте значение "null" локальной переменной сразу после такой операции, чтобы предотвратить двойное освобождение в области "finally".</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">Использовать тело блока для лямбда-выражений</target> <target state="translated">Использовать тело блока для лямбда-выражений</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">Yerel olarak kapsamı oluşturulan nesnelerin tüm yollarda atıldığından emin olmak için önerilen atma desenini kullanın. Mümkünse, oluşturulan nesneyi 'using' deyimi veya 'using' bildirimiyle sarmalayın. Aksi halde, try bölgesinden önce bildirilen ayrılmış bir yerel değişkeni ve 'finally' bölgesinde null olmayan değer üzerinde koşulsuz bir Dispose çağrısı (örneğin, 'x?.Dispose()') olan bir try-finally deseni kullanın. Nesne try bölgesi içinde açıkça atıldıysa veya atma sahipliği başka bir nesne ya da metoda aktarıldıysa, 'finally' bölgesinde çift atma gerçekleşmesini önlemek için bu tür bir işlemden hemen sonra yerel değişkene 'null' atayın</target> <target state="needs-review-translation">Yerel olarak kapsamı oluşturulan nesnelerin tüm yollarda atıldığından emin olmak için önerilen atma desenini kullanın. Mümkünse, oluşturulan nesneyi 'using' deyimi veya 'using' bildirimiyle sarmalayın. Aksi halde, try bölgesinden önce bildirilen ayrılmış bir yerel değişkeni ve 'finally' bölgesinde null olmayan değer üzerinde koşulsuz bir Dispose çağrısı (örneğin, 'x?.Dispose()') olan bir try-finally deseni kullanın. Nesne try bölgesi içinde açıkça atıldıysa veya atma sahipliği başka bir nesne ya da metoda aktarıldıysa, 'finally' bölgesinde çift atma gerçekleşmesini önlemek için bu tür bir işlemden hemen sonra yerel değişkene 'null' atayın</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">Lambda ifadeleri için blok vücut kullanımı</target> <target state="translated">Lambda ifadeleri için blok vücut kullanımı</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">使用推荐的 Dispose 模式以确保在所有路径中释放局部可释放对象。如果可能,请将创建包装在 "using" 语句或 "using" 声明中。否则,请使用 try-finally 模式,在 try 区域之前声明一个专用的局部变量,在 "finally" 区域中对非 null 值进行无条件 Dispose 调用,比如,"x?.Dispose()"。如果对象显式释放在 try 区域内或释放所有权转让给另一个对象或方法,则在这样的操作之后立即将 "null" 分配给局部变量,以防止在 "finally" 中进行双重释放。</target> <target state="needs-review-translation">使用推荐的 Dispose 模式以确保在所有路径中释放局部可释放对象。如果可能,请将创建包装在 "using" 语句或 "using" 声明中。否则,请使用 try-finally 模式,在 try 区域之前声明一个专用的局部变量,在 "finally" 区域中对非 null 值进行无条件 Dispose 调用,比如,"x?.Dispose()"。如果对象显式释放在 try 区域内或释放所有权转让给另一个对象或方法,则在这样的操作之后立即将 "null" 分配给局部变量,以防止在 "finally" 中进行双重释放。</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">对 lambda 表达式使用块正文</target> <target state="translated">对 lambda 表达式使用块正文</target>
......
...@@ -542,6 +542,11 @@ ...@@ -542,6 +542,11 @@
<target state="needs-review-translation">請使用建議的處置模式,確保區域範圍的可處置物件在所有路徑上均會經過處置。在可能的情況下,請將建立包在 'using' 陳述式或 'using' 宣告內。否則,請使用 try-finally 模式,同時在 try 區域之前先宣告專用的區域變數,並在 'finally' 區域中的非 null 值上,設定無條件 Dispose 引動過程,比如 'x?.Dispose()'。如果 try 區域內已明確地處置了該物件,或是處置擁有權已轉移到另一個物件或方法,則請在這類作業之後,對區域變數指派 'null',以避免在 'finally' 中發生雙重處置</target> <target state="needs-review-translation">請使用建議的處置模式,確保區域範圍的可處置物件在所有路徑上均會經過處置。在可能的情況下,請將建立包在 'using' 陳述式或 'using' 宣告內。否則,請使用 try-finally 模式,同時在 try 區域之前先宣告專用的區域變數,並在 'finally' 區域中的非 null 值上,設定無條件 Dispose 引動過程,比如 'x?.Dispose()'。如果 try 區域內已明確地處置了該物件,或是處置擁有權已轉移到另一個物件或方法,則請在這類作業之後,對區域變數指派 'null',以避免在 'finally' 中發生雙重處置</target>
<note /> <note />
</trans-unit> </trans-unit>
<trans-unit id="Use_System_HashCode">
<source>Use 'System.HashCode'</source>
<target state="new">Use 'System.HashCode'</target>
<note />
</trans-unit>
<trans-unit id="Use_block_body_for_lambda_expressions"> <trans-unit id="Use_block_body_for_lambda_expressions">
<source>Use block body for lambda expressions</source> <source>Use block body for lambda expressions</source>
<target state="translated">使用 Lambda 運算式的區體主體</target> <target state="translated">使用 Lambda 運算式的區體主體</target>
......
...@@ -358,6 +358,13 @@ private static string GetAccessibilityModifiersRequiredEditorConfigString(CodeSt ...@@ -358,6 +358,13 @@ private static string GetAccessibilityModifiersRequiredEditorConfigString(CodeSt
KeyValuePairUtil.Create("all", UnusedParametersPreference.AllMethods), KeyValuePairUtil.Create("all", UnusedParametersPreference.AllMethods),
}); });
internal static readonly PerLanguageOption<CodeStyleOption<bool>> PreferSystemHashCode = new PerLanguageOption<CodeStyleOption<bool>>(
nameof(CodeStyleOptions),
nameof(PreferSystemHashCode),
defaultValue: TrueWithSuggestionEnforcement,
storageLocations: new OptionStorageLocation[]{
new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreferSystemHashCode") });
static CodeStyleOptions() static CodeStyleOptions()
{ {
// Note that the static constructor executes after all the static field initializers for the options have executed, // Note that the static constructor executes after all the static field initializers for the options have executed,
......
// 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 Microsoft.CodeAnalysis.Operations;
namespace Microsoft.CodeAnalysis.Shared.Extensions
{
internal static class OperationExtensions
{
public static bool IsNumericLiteral(this IOperation operation)
=> operation.Kind == OperationKind.Literal && operation.Type.IsNumericType();
public static bool IsNullLiteral(this IOperation operand)
=> operand is ILiteralOperation literal &&
literal.ConstantValue.HasValue &&
literal.ConstantValue.Value == null;
}
}
...@@ -18,8 +18,7 @@ internal static partial class SyntaxGeneratorExtensions ...@@ -18,8 +18,7 @@ internal static partial class SyntaxGeneratorExtensions
Compilation compilation, Compilation compilation,
INamedTypeSymbol containingType, INamedTypeSymbol containingType,
ImmutableArray<ISymbol> members, ImmutableArray<ISymbol> members,
bool justMemberReference, bool justMemberReference)
CancellationToken cancellationToken)
{ {
var result = ArrayBuilder<SyntaxNode>.GetInstance(); var result = ArrayBuilder<SyntaxNode>.GetInstance();
...@@ -46,11 +45,10 @@ internal static partial class SyntaxGeneratorExtensions ...@@ -46,11 +45,10 @@ internal static partial class SyntaxGeneratorExtensions
Compilation compilation, Compilation compilation,
INamedTypeSymbol containingType, INamedTypeSymbol containingType,
ImmutableArray<ISymbol> members, ImmutableArray<ISymbol> members,
bool useInt64, bool useInt64)
CancellationToken cancellationToken)
{ {
var components = GetGetHashCodeComponents( var components = GetGetHashCodeComponents(
factory, compilation, containingType, members, justMemberReference: false, cancellationToken); factory, compilation, containingType, members, justMemberReference: false);
if (components.Length == 0) if (components.Length == 0)
{ {
......
...@@ -197,10 +197,10 @@ internal static partial class SyntaxGeneratorExtensions ...@@ -197,10 +197,10 @@ internal static partial class SyntaxGeneratorExtensions
switch (operationKind) switch (operationKind)
{ {
case BinaryOperatorKind.LessThanOrEqual when IsNumericLiteral(rightOperand): case BinaryOperatorKind.LessThanOrEqual when rightOperand.IsNumericLiteral():
return CanSimplifyToLengthEqualsZeroExpression( return CanSimplifyToLengthEqualsZeroExpression(
leftOperand, (ILiteralOperation)rightOperand); leftOperand, (ILiteralOperation)rightOperand);
case BinaryOperatorKind.GreaterThanOrEqual when IsNumericLiteral(leftOperand): case BinaryOperatorKind.GreaterThanOrEqual when leftOperand.IsNumericLiteral():
return CanSimplifyToLengthEqualsZeroExpression( return CanSimplifyToLengthEqualsZeroExpression(
rightOperand, (ILiteralOperation)leftOperand); rightOperand, (ILiteralOperation)leftOperand);
} }
...@@ -208,9 +208,6 @@ internal static partial class SyntaxGeneratorExtensions ...@@ -208,9 +208,6 @@ internal static partial class SyntaxGeneratorExtensions
return false; return false;
} }
private static bool IsNumericLiteral(IOperation operation)
=> operation.Kind == OperationKind.Literal && operation.Type.IsNumericType();
private static IOperation RemoveImplicitConversion(IOperation operation) private static IOperation RemoveImplicitConversion(IOperation operation)
{ {
return operation is IConversionOperation conversion && conversion.IsImplicit return operation is IConversionOperation conversion && conversion.IsImplicit
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册