Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.NetCore.Analyzers.Usage;

namespace Microsoft.NetCore.CSharp.Analyzers.Usage
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class CSharpImplementGenericMathInterfacesCorrectly : ImplementGenericMathInterfacesCorrectly
{
protected override SyntaxNode? FindTheTypeArgumentOfTheInterfaceFromTypeDeclaration(ISymbol typeSymbol, ISymbol anInterfaceSymbol)
{
foreach (SyntaxReference syntaxReference in typeSymbol.DeclaringSyntaxReferences)
{
SyntaxNode typeDefinition = syntaxReference.GetSyntax();
if (typeDefinition is ClassDeclarationSyntax classDeclaration)
{
return FindTypeArgumentFromBaseInterfaceList(classDeclaration.BaseList.Types, anInterfaceSymbol);
}
else if (typeDefinition is StructDeclarationSyntax structDeclaration)
{
return FindTypeArgumentFromBaseInterfaceList(structDeclaration.BaseList.Types, anInterfaceSymbol);
}
}

return null;
}

private static SyntaxNode? FindTypeArgumentFromBaseInterfaceList(SeparatedSyntaxList<BaseTypeSyntax> baseListTypes, ISymbol anInterfaceSymbol)
{
foreach (BaseTypeSyntax baseType in baseListTypes)
{
if (baseType is SimpleBaseTypeSyntax simpleBaseType &&
simpleBaseType.Type is GenericNameSyntax genericName &&
genericName.Identifier.ValueText == anInterfaceSymbol.Name)
{
return genericName.TypeArgumentList.Arguments[0];
}
}

return null;
}
}
}
1 change: 1 addition & 0 deletions src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ CA1854 | Performance | Info | PreferDictionaryTryGetValueAnalyzer, [Documentatio
CA1855 | Performance | Info | UseSpanClearInsteadOfFillAnalyzer, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1855)
CA2019 | Reliability | Info | UseThreadStaticCorrectly, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2019)
CA2259 | Usage | Warning | UseThreadStaticCorrectly, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2259)
CA2260 | Usage | Warning | UseCuriouslyRecurringTemplatePatternCorrectly, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2260)
CA5404 | Security | Disabled | DoNotDisableTokenValidationChecks, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca5404)
CA5405 | Security | Disabled | DoNotAlwaysSkipTokenValidationInDelegates, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca5405)
Original file line number Diff line number Diff line change
Expand Up @@ -1959,6 +1959,15 @@
<data name="ParenthesisWithPlaceHolder" xml:space="preserve">
<value> ({0})</value>
</data>
<data name="ImplementGenericMathInterfacesCorrectlyDesciption" xml:space="preserve">
<value>Generic math interfaces requires the derived type itself used for the self recurring type parameter</value>
</data>
<data name="ImplementGenericMathInterfacesCorrectlyMessage" xml:space="preserve">
<value>'{0}' interface requires the derived type '{1}' used for the '{2}' type parameter</value>
</data>
<data name="ImplementGenericMathInterfacesCorrectlyTitle" xml:space="preserve">
<value>Use correct type parameter</value>
</data>
<data name="UseSpanClearInsteadOfFillCodeFixTitle" xml:space="preserve">
<value>Use 'Clear()'</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Immutable;
using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;

namespace Microsoft.NetCore.Analyzers.Usage
{
using static MicrosoftNetCoreAnalyzersResources;

public abstract class ImplementGenericMathInterfacesCorrectly : DiagnosticAnalyzer
{
private const string RuleId = "CA2260";

internal static readonly DiagnosticDescriptor GMInterfacesRule = DiagnosticDescriptorHelper.Create(
RuleId,
CreateLocalizableResourceString(nameof(ImplementGenericMathInterfacesCorrectlyTitle)),
CreateLocalizableResourceString(nameof(ImplementGenericMathInterfacesCorrectlyMessage)),
DiagnosticCategory.Usage,
RuleLevel.BuildWarning,
description: CreateLocalizableResourceString(nameof(ImplementGenericMathInterfacesCorrectlyDesciption)),
isPortedFxCopRule: false,
isDataflowRule: false);

private static readonly ImmutableArray<string> s_knownInterfaces = ImmutableArray.Create("IParsable`1", "ISpanParsable`1", "IAdditionOperators`3", "IAdditiveIdentity`2",
"IBinaryFloatingPointIeee754`1", "IBinaryInteger`1", "IBinaryNumber`1", "IBitwiseOperators`3", "IComparisonOperators`2", "IDecrementOperators`1", "IDivisionOperators`3",
"IEqualityOperators`2", "IExponentialFunctions`1", "IFloatingPointIeee754`1", "IFloatingPoint`1", "IHyperbolicFunctions`1", "IIncrementOperators`1", "ILogarithmicFunctions`1",
"IMinMaxValue`1", "IModulusOperators`3", "IMultiplicativeIdentity`2", "IMultiplyOperators`3", "INumberBase`1", "INumber`1", "IPowerFunctions`1", "IRootFunctions`1", "IShiftOperators`2",
"ISignedNumber`1", "ISubtractionOperators`3", "ITrigonometricFunctions`1", "IUnaryNegationOperators`2", "IUnaryPlusOperators`2", "IUnsignedNumber`1", "IFloatingPointConstants`1");

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(GMInterfacesRule);

public override void Initialize(AnalysisContext context)
{
context.EnableConcurrentExecution();
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

context.RegisterCompilationStartAction(context =>
{
if (!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemIParsable1, out var iParsableInterface) ||
!context.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemNumericsIDecrementOperators1, out var iBinaryInteger1))
{
return;
}

context.RegisterSymbolAction(context =>
{
if (context.Symbol is INamedTypeSymbol ntSymbol && !ntSymbol.IsGenericType)
{
AnalyzeSymbol(context, ntSymbol, iParsableInterface.ContainingNamespace, iBinaryInteger1.ContainingNamespace);
}
}, SymbolKind.NamedType);
});
}

private void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol symbol, INamespaceSymbol systemNS, INamespaceSymbol systemNumericsNS)
{
if (!CheckInterfacesForViolation(symbol))
{
INamedTypeSymbol? baseType = symbol.BaseType;
if (baseType != null && baseType.IsGenericType)
{
CheckInterfacesForViolation(baseType);
}
}

bool CheckInterfacesForViolation(INamedTypeSymbol lookup)
{
foreach (INamedTypeSymbol anInterface in lookup.Interfaces)
{
if (anInterface.IsGenericType)
{
if (IsKnownInterface(anInterface, systemNS, systemNumericsNS) &&
FirstTypeParameterNameIsNotTheSymbolName(symbol, anInterface))
{
SyntaxNode? typeParameter = FindTheTypeArgumentOfTheInterfaceFromTypeDeclaration(symbol, symbol.Equals(lookup, SymbolEqualityComparer.Default) ? anInterface : lookup);
if (typeParameter != null)
{
context.ReportDiagnostic(typeParameter.CreateDiagnostic(GMInterfacesRule, anInterface.Name, symbol.Name, GetTSelfParameterName(lookup, anInterface)));
}
else
{
context.ReportDiagnostic(symbol.CreateDiagnostic(GMInterfacesRule, anInterface.Name, symbol.Name, GetTSelfParameterName(lookup, anInterface)));
}

return true;
}
else if (CheckInterfacesForViolation(anInterface))
{
return true;
}
}
}
return false;
}

string GetTSelfParameterName(INamedTypeSymbol symbol, INamedTypeSymbol anInterface) =>
symbol.IsGenericType ? symbol.OriginalDefinition.TypeParameters[0].Name : anInterface.OriginalDefinition.TypeParameters[0].Name;
}

protected abstract SyntaxNode? FindTheTypeArgumentOfTheInterfaceFromTypeDeclaration(ISymbol typeSymbol, ISymbol theInterfaceSymbol);

private bool IsKnownInterface(INamedTypeSymbol anInterface, INamespaceSymbol systemNS, INamespaceSymbol systemNumericsNS)
{
var iNamespace = anInterface.ContainingNamespace;

return s_knownInterfaces.Contains(anInterface.MetadataName) &&
(iNamespace.Equals(systemNS, SymbolEqualityComparer.Default) ||
iNamespace.Equals(systemNumericsNS, SymbolEqualityComparer.Default));
}

private bool FirstTypeParameterNameIsNotTheSymbolName(INamedTypeSymbol symbol, INamedTypeSymbol anInterface) =>
anInterface.TypeArguments[0].Name != symbol.Name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,21 @@
<target state="translated">Nepoužívat pevně zakódované hodnoty SslProtocols</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyDesciption">
<source>Generic math interfaces requires the derived type itself used for the self recurring type parameter</source>
<target state="new">Generic math interfaces requires the derived type itself used for the self recurring type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyMessage">
<source>'{0}' interface requires the derived type '{1}' used for the '{2}' type parameter</source>
<target state="new">'{0}' interface requires the derived type '{1}' used for the '{2}' type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyTitle">
<source>Use correct type parameter</source>
<target state="new">Use correct type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementISerializableCorrectlyDescription">
<source>To fix a violation of this rule, make the GetObjectData method visible and overridable, and make sure that all instance fields are included in the serialization process or explicitly marked by using the NonSerializedAttribute attribute.</source>
<target state="translated">Pokud chcete porušení tohoto pravidla opravit, nastavte metodu GetObjectData jako viditelnou a přepsatelnou a ujistěte se, že všechna pole instance jsou součástí procesu serializace nebo explicitně označená atributem NonSerializedAttribute.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,21 @@
<target state="translated">Hartcodierte SslProtocols-Werte vermeiden</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyDesciption">
<source>Generic math interfaces requires the derived type itself used for the self recurring type parameter</source>
<target state="new">Generic math interfaces requires the derived type itself used for the self recurring type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyMessage">
<source>'{0}' interface requires the derived type '{1}' used for the '{2}' type parameter</source>
<target state="new">'{0}' interface requires the derived type '{1}' used for the '{2}' type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyTitle">
<source>Use correct type parameter</source>
<target state="new">Use correct type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementISerializableCorrectlyDescription">
<source>To fix a violation of this rule, make the GetObjectData method visible and overridable, and make sure that all instance fields are included in the serialization process or explicitly marked by using the NonSerializedAttribute attribute.</source>
<target state="translated">Um einen Verstoß gegen diese Regel zu beheben, legen Sie die GetObjectData-Methode als sichtbar und überschreibbar fest, und stellen Sie sicher, dass alle Instanzfelder in den Serialisierungsvorgang eingeschlossen oder durch das NonSerializedAttribute-Attribut explizit markiert werden.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,21 @@
<target state="translated">Evitar valores de SslProtocols codificados de forma rígida</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyDesciption">
<source>Generic math interfaces requires the derived type itself used for the self recurring type parameter</source>
<target state="new">Generic math interfaces requires the derived type itself used for the self recurring type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyMessage">
<source>'{0}' interface requires the derived type '{1}' used for the '{2}' type parameter</source>
<target state="new">'{0}' interface requires the derived type '{1}' used for the '{2}' type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyTitle">
<source>Use correct type parameter</source>
<target state="new">Use correct type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementISerializableCorrectlyDescription">
<source>To fix a violation of this rule, make the GetObjectData method visible and overridable, and make sure that all instance fields are included in the serialization process or explicitly marked by using the NonSerializedAttribute attribute.</source>
<target state="translated">Para corregir una infracción de esta regla, haga que el método GetObjectData sea visible y se pueda reemplazar; además, asegúrese de que todos los campos de la instancia se incluyen en el proceso de serialización o se marcan explícitamente con el atributo NonSerializedAttribute.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,21 @@
<target state="translated">Évitez de coder en dur les valeurs de SslProtocols</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyDesciption">
<source>Generic math interfaces requires the derived type itself used for the self recurring type parameter</source>
<target state="new">Generic math interfaces requires the derived type itself used for the self recurring type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyMessage">
<source>'{0}' interface requires the derived type '{1}' used for the '{2}' type parameter</source>
<target state="new">'{0}' interface requires the derived type '{1}' used for the '{2}' type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyTitle">
<source>Use correct type parameter</source>
<target state="new">Use correct type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementISerializableCorrectlyDescription">
<source>To fix a violation of this rule, make the GetObjectData method visible and overridable, and make sure that all instance fields are included in the serialization process or explicitly marked by using the NonSerializedAttribute attribute.</source>
<target state="translated">Pour corriger toute violation de cette règle, rendez la méthode GetObjectData visible et substituable. De plus, vérifiez que tous les champs d'instance sont inclus dans le processus de sérialisation ou qu'ils sont marqués explicitement avec l'attribut NonSerializedAttribute.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,21 @@
<target state="translated">Evitare di impostare i valori di SslProtocols come hardcoded</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyDesciption">
<source>Generic math interfaces requires the derived type itself used for the self recurring type parameter</source>
<target state="new">Generic math interfaces requires the derived type itself used for the self recurring type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyMessage">
<source>'{0}' interface requires the derived type '{1}' used for the '{2}' type parameter</source>
<target state="new">'{0}' interface requires the derived type '{1}' used for the '{2}' type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementGenericMathInterfacesCorrectlyTitle">
<source>Use correct type parameter</source>
<target state="new">Use correct type parameter</target>
<note />
</trans-unit>
<trans-unit id="ImplementISerializableCorrectlyDescription">
<source>To fix a violation of this rule, make the GetObjectData method visible and overridable, and make sure that all instance fields are included in the serialization process or explicitly marked by using the NonSerializedAttribute attribute.</source>
<target state="translated">Per correggere una violazione di questa regola, impostare il metodo GetObjectData come visibile e sottoponibile a override e assicurarsi che tutti i campi di istanza siano inclusi nel processo di serializzazione o contrassegnati in modo esplicito usando l'attributo NonSerializedAttribute.</target>
Expand Down
Loading