Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
Expand Up @@ -29,5 +29,8 @@ public static class DiagnosticIds
public const string CannotReduceVisibility = "CP0019";
public const string CannotExpandVisibility = "CP0020";
public const string CannotChangeGenericConstraint = "CP0021";
public const string CannotAddStaticToMember = "CP0022";
public const string CannotRemoveStaticFromMember = "CP0023";
public const string CannotAddStaticToType = "CP0024";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -225,4 +225,13 @@
<data name="CannotReduceVisibility" xml:space="preserve">
<value>Visibility of '{0}' reduced from '{1}' to '{2}'.</value>
</data>
<data name="CannotAddStaticToMember" xml:space="preserve">
<value>Cannot add static keyword to member '{0}'.</value>
</data>
<data name="CannotRemoveStaticFromMember" xml:space="preserve">
<value>Cannot remove static keyword from member '{0}'.</value>
</data>
<data name="CannotAddStaticToType" xml:space="preserve">
<value>Cannot add static keyword to type '{0}'.</value>
</data>
</root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.CodeAnalysis;

namespace Microsoft.DotNet.ApiCompatibility.Rules
{
/// <summary>
/// This class implements a rule to check that the 'static' keyword is not added to
/// or removed from a member or type.
/// </summary>
public class CannotAddOrRemoveStaticKeyword : IRule
{
private readonly IRuleSettings _settings;

public CannotAddOrRemoveStaticKeyword(IRuleSettings settings, IRuleRegistrationContext context)
{
_settings = settings;
context.RegisterOnMemberSymbolAction(RunOnMemberSymbol);
context.RegisterOnTypeSymbolAction(RunOnTypeSymbol);
}

private void RunOnMemberSymbol(ISymbol? left, ISymbol? right, MetadataInformation leftMetadata, MetadataInformation rightMetadata, IList<CompatDifference> differences)
{
// Members must exist
if (left is null || right is null)
{
return;
}

// Check if static modifier changed on the member
if (left.IsStatic && !right.IsStatic)
{
// Removing static is always breaking (both binary and source breaking)
differences.Add(new CompatDifference(
leftMetadata,
rightMetadata,
DiagnosticIds.CannotRemoveStaticFromMember,
string.Format(Resources.CannotRemoveStaticFromMember, right),
DifferenceType.Removed,
right));
}
else if (!left.IsStatic && right.IsStatic)
{
// Adding static is always breaking (binary breaking)
differences.Add(new CompatDifference(
leftMetadata,
rightMetadata,
DiagnosticIds.CannotAddStaticToMember,
string.Format(Resources.CannotAddStaticToMember, right),
DifferenceType.Added,
right));
}
}

private void RunOnTypeSymbol(ITypeSymbol? left, ITypeSymbol? right, MetadataInformation leftMetadata, MetadataInformation rightMetadata, IList<CompatDifference> differences)
{
// Types must exist
if (left is null || right is null)
{
return;
}

// Check if static modifier was added to the type
// Adding static to a type is breaking since static types cannot be used as
// return types, generic parameters, or arguments
// Removing static from a type is compatible (members will be checked separately)
if (!left.IsStatic && right.IsStatic)
{
differences.Add(new CompatDifference(
leftMetadata,
rightMetadata,
DiagnosticIds.CannotAddStaticToType,
string.Format(Resources.CannotAddStaticToType, right),
DifferenceType.Added,
right));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ private void CompareTypeParameters(
// we could allow an addition if removals are allowed, and the addition is a less-derived base type or interface
// for example: changing a constraint from MemoryStream to Stream on a sealed type, or non-virtual member
// but we'll leave this to suppressions

addedConstraints.AddRange(rightOnlyConstraints.Select(x => x.GetDocumentationCommentId()!));

// additions
foreach(var addedConstraint in addedConstraints)
foreach (var addedConstraint in addedConstraints)
{
differences.Add(new CompatDifference(
leftMetadata,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public IRule[] CreateRules(IRuleSettings settings, IRuleRegistrationContext cont
new CannotAddAbstractMember(settings, context),
new CannotAddMemberToInterface(settings, context),
new CannotAddOrRemoveVirtualKeyword(settings, context),
new CannotAddOrRemoveStaticKeyword(settings, context),
new CannotRemoveBaseTypeOrInterface(settings, context),
new CannotSealType(settings, context),
new EnumsMustMatch(settings, context),
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading