From c4fd0f3cd120357d387161573d848e16aa93b8f0 Mon Sep 17 00:00:00 2001 From: Owen Smith Date: Sat, 28 Nov 2020 19:13:53 -0500 Subject: [PATCH] OnlyIf'd type parameters should be considered immutable (#666) GetImmutabilityFromAttributes is used when checking type parameters. Forgot to add the addtribute here --- .../Immutability/ImmutabilityContext.cs | 4 + .../TypeDeclarationImmutabilityAnalyzer.cs | 205 ++++++++++++++++++ 2 files changed, 209 insertions(+) diff --git a/src/D2L.CodeStyle.Analyzers/Immutability/ImmutabilityContext.cs b/src/D2L.CodeStyle.Analyzers/Immutability/ImmutabilityContext.cs index c839add02..de796579d 100644 --- a/src/D2L.CodeStyle.Analyzers/Immutability/ImmutabilityContext.cs +++ b/src/D2L.CodeStyle.Analyzers/Immutability/ImmutabilityContext.cs @@ -218,6 +218,10 @@ ITypeSymbol type return ImmutableTypeKind.Total; } + if( Attributes.Objects.OnlyIf.IsDefined( type ) ) { + return ImmutableTypeKind.Total; + } + if ( Attributes.Objects.ImmutableBaseClass.IsDefined( type ) ) { return ImmutableTypeKind.Instance; } diff --git a/tests/D2L.CodeStyle.Analyzers.Test/Specs/TypeDeclarationImmutabilityAnalyzer.cs b/tests/D2L.CodeStyle.Analyzers.Test/Specs/TypeDeclarationImmutabilityAnalyzer.cs index d1a3be779..bb5c425d3 100644 --- a/tests/D2L.CodeStyle.Analyzers.Test/Specs/TypeDeclarationImmutabilityAnalyzer.cs +++ b/tests/D2L.CodeStyle.Analyzers.Test/Specs/TypeDeclarationImmutabilityAnalyzer.cs @@ -764,6 +764,211 @@ public sealed class AnalyzedImmutableGenericClassRestrictingT<[Immutable] T, U> } } + [ConditionallyImmutable] + public sealed class AnalyzedImmutableGenericClassGivenT<[ConditionallyImmutable.OnlyIf] T, U> { + + + + static T /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly T m_field; + T /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly T m_field; + T Property { get; } + T Property { get { return default; } } + + + + static T /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/ = new T(); + static readonly T m_field = new T(); + T /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/ = new T(); + readonly T m_field = new T(); + T Property { get; } = new T() + T Property { get { return new T(); } } + + + + static /* TypeParameterIsNotKnownToBeImmutable(U) */ U /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly /* TypeParameterIsNotKnownToBeImmutable(U) */ U /**/ m_field; + /* TypeParameterIsNotKnownToBeImmutable(U) */ U /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + [Mutability.Unaudited( Because.ItHasntBeenLookedAt )] + U m_field; + [Mutability.Audited] + U m_field; + readonly /* TypeParameterIsNotKnownToBeImmutable(U) */ U /**/ m_field; + [Mutability.Unaudited( Because.ItHasntBeenLookedAt )] + readonly U m_field; + [Mutability.Audited] + readonly U m_field; + /* TypeParameterIsNotKnownToBeImmutable(U) */ U /**/ Property { get; } + [Mutability.Unaudited( Because.ItHasntBeenLookedAt )] + U Property { get; } + [Mutability.Audited] + U Property { get; } + U Property { get { return default; } } + + + + static U /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/ = /* TypeParameterIsNotKnownToBeImmutable(U) */ new U() /**/; + static readonly U m_field = /* TypeParameterIsNotKnownToBeImmutable(U) */ new U() /**/; + U /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/ = /* TypeParameterIsNotKnownToBeImmutable(U) */ new U() /**/; + [Mutability.Unaudited( Because.ItHasntBeenLookedAt )] + U m_field = new U(); + [Mutability.Audited] + U m_field = new U(); + readonly U m_field = /* TypeParameterIsNotKnownToBeImmutable(U) */ new U() /**/; + [Mutability.Unaudited( Because.ItHasntBeenLookedAt )] + readonly U m_field = new U(); + [Mutability.Audited] + readonly U m_field = new U(); + U Property { get; } = /* TypeParameterIsNotKnownToBeImmutable(U) */ new U() /**/; + [Mutability.Unaudited( Because.ItHasntBeenLookedAt )] + U Property { get; } = new U(); + [Mutability.Audited] + U Property { get; } = new U(); + + + + static Types.SomeImmutableGenericInterfaceGivenT /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly Types.SomeImmutableGenericInterfaceGivenT m_field; + Types.SomeImmutableGenericInterfaceGivenT /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly Types.SomeImmutableGenericInterfaceGivenT m_field; + Types.SomeImmutableGenericInterfaceGivenT Property { get; } + Types.SomeImmutableGenericInterfaceGivenT Property { get { return default; } } + + + + static /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenT /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenT /**/ m_field; + /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenT /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenT /**/ m_field; + /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenT /**/ Property { get; } + Types.SomeImmutableGenericInterfaceGivenT Property { get { return default; } } + + + static Types.SomeImmutableGenericInterfaceGivenU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly Types.SomeImmutableGenericInterfaceGivenU m_field; + Types.SomeImmutableGenericInterfaceGivenU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly Types.SomeImmutableGenericInterfaceGivenU m_field; + Types.SomeImmutableGenericInterfaceGivenU Property { get; } + Types.SomeImmutableGenericInterfaceGivenU Property { get { return default; } } + + + + static /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenU /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenU /**/ m_field; + /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenU /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenU /**/ m_field; + /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenU /**/ Property { get; } + Types.SomeImmutableGenericInterfaceGivenU Property { get { return default; } } + + + + static Types.SomeImmutableGenericInterfaceGivenTU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly Types.SomeImmutableGenericInterfaceGivenTU m_field; + Types.SomeImmutableGenericInterfaceGivenTU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly Types.SomeImmutableGenericInterfaceGivenTU m_field; + Types.SomeImmutableGenericInterfaceGivenTU Property { get; } + Types.SomeImmutableGenericInterfaceGivenTU Property { get { return default; } } + + + + static /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU /**/ m_field; + /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU /**/ m_field; + /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU /**/ Property { get; } + Types.SomeImmutableGenericInterfaceGivenTU Property { get { return default; } } + + + static /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU /**/ m_field; + /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU /**/ m_field; + /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU /**/ Property { get; } + Types.SomeImmutableGenericInterfaceGivenTU Property { get { return default; } } + + + + static Types.SomeImmutableGenericInterfaceRestrictingT /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly Types.SomeImmutableGenericInterfaceRestrictingT m_field; + Types.SomeImmutableGenericInterfaceRestrictingT /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly Types.SomeImmutableGenericInterfaceRestrictingT m_field; + Types.SomeImmutableGenericInterfaceRestrictingT Property { get; } + Types.SomeImmutableGenericInterfaceRestrictingT Property { get { return default; } } + + + + static Types.SomeImmutableGenericInterfaceRestrictingT /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly Types.SomeImmutableGenericInterfaceRestrictingT m_field; + Types.SomeImmutableGenericInterfaceRestrictingT/* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly Types.SomeImmutableGenericInterfaceRestrictingT m_field; + Types.SomeImmutableGenericInterfaceRestrictingT Property { get; } + Types.SomeImmutableGenericInterfaceRestrictingT Property { get { return default; } } + + + static Types.SomeImmutableGenericInterfaceRestrictingU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly Types.SomeImmutableGenericInterfaceRestrictingU m_field; + Types.SomeImmutableGenericInterfaceRestrictingU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly Types.SomeImmutableGenericInterfaceRestrictingU m_field; + Types.SomeImmutableGenericInterfaceRestrictingU Property { get; } + Types.SomeImmutableGenericInterfaceRestrictingU Property { get { return default; } } + + + + static Types.SomeImmutableGenericInterfaceRestrictingU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly Types.SomeImmutableGenericInterfaceRestrictingU m_field; + Types.SomeImmutableGenericInterfaceRestrictingU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly Types.SomeImmutableGenericInterfaceRestrictingU m_field; + Types.SomeImmutableGenericInterfaceRestrictingU Property { get; } + Types.SomeImmutableGenericInterfaceRestrictingU Property { get { return default; } } + + + + static Types.SomeImmutableGenericInterfaceRestrictingTU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly Types.SomeImmutableGenericInterfaceRestrictingTU m_field; + Types.SomeImmutableGenericInterfaceRestrictingTU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly Types.SomeImmutableGenericInterfaceRestrictingTU m_field; + Types.SomeImmutableGenericInterfaceRestrictingTU Property { get; } + Types.SomeImmutableGenericInterfaceRestrictingTU Property { get { return default; } } + + + + static Types.SomeImmutableGenericInterfaceRestrictingTU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly Types.SomeImmutableGenericInterfaceRestrictingTU m_field; + Types.SomeImmutableGenericInterfaceRestrictingTU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly Types.SomeImmutableGenericInterfaceRestrictingTU m_field; + Types.SomeImmutableGenericInterfaceRestrictingTU Property { get; } + Types.SomeImmutableGenericInterfaceRestrictingTU Property { get { return default; } } + + + static Types.SomeImmutableGenericInterfaceRestrictingTU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + static readonly Types.SomeImmutableGenericInterfaceRestrictingTU m_field; + Types.SomeImmutableGenericInterfaceRestrictingTU /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/; + readonly Types.SomeImmutableGenericInterfaceRestrictingTU m_field; + Types.SomeImmutableGenericInterfaceRestrictingTU Property { get; } + Types.SomeImmutableGenericInterfaceRestrictingTU Property { get { return default; } } + + + void Method() { + Types.SomeGenericMethod(); + Types.SomeGenericMethod(); + Types.SomeGenericMethod(); + Types.SomeGenericMethod(); + Types.SomeGenericMethodRestrictingT(); + Types.SomeGenericMethodRestrictingT(); + Types.SomeGenericMethodRestrictingT(); + Types.SomeGenericMethodRestrictingT(); + Types.SomeGenericMethodRestrictingU(); + Types.SomeGenericMethodRestrictingU(); + Types.SomeGenericMethodRestrictingU(); + Types.SomeGenericMethodRestrictingU(); + Types.SomeGenericMethodRestrictingTU(); + Types.SomeGenericMethodRestrictingTU(); + Types.SomeGenericMethodRestrictingTU(); + Types.SomeGenericMethodRestrictingTU(); + } + } + public static class StaticAudits { [Statics.Audited] static int staticint1;