Skip to content

Commit

Permalink
Added test coverage for built-in types that should be mutable.
Browse files Browse the repository at this point in the history
  • Loading branch information
MeltyPlayer committed Apr 24, 2024
1 parent 4a9b9a1 commit 8049052
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 10 deletions.
63 changes: 63 additions & 0 deletions Schema Tests/readOnly/BuiltInTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,68 @@ public interface IReadOnlyWrapper {
""");
}

[Test]
[TestCase("System.Span<int>")]
[TestCase("System.Collections.Generic.ICollection<int>")]
[TestCase("System.Collections.Generic.IList<int>")]
public void TestDoesNotConvertBuiltInsForMutableProperties(string mutable) {
ReadOnlyGeneratorTestUtil.AssertGenerated(
$$"""
using schema.readOnly;
namespace foo.bar {
[GenerateReadOnly]
public partial interface IWrapper {
[KeepMutableType]
{{mutable}} Property { get; set; }
}
}
""",
$$"""
namespace foo.bar {
public partial interface IWrapper : IReadOnlyWrapper {
{{mutable}} IReadOnlyWrapper.Property => Property;
}
public interface IReadOnlyWrapper {
public {{mutable}} Property { get; }
}
}
""");
}

[Test]
[TestCase("System.Span<int>")]
[TestCase("System.Collections.Generic.ICollection<int>")]
[TestCase("System.Collections.Generic.IList<int>")]
public void TestDoesNotConvertBuiltInsForMutableMethods(string mutable) {
ReadOnlyGeneratorTestUtil.AssertGenerated(
$$"""
using schema.readOnly;
namespace foo.bar {
[GenerateReadOnly]
public partial interface IWrapper {
[Const]
[KeepMutableType]
{{mutable}} Convert({{mutable}} value);
}
}
""",
$$"""
namespace foo.bar {
public partial interface IWrapper : IReadOnlyWrapper {
{{mutable}} IReadOnlyWrapper.Convert({{mutable}} value) => Convert(value);
}
public interface IReadOnlyWrapper {
public {{mutable}} Convert({{mutable}} value);
}
}
""");
}
}
}
4 changes: 2 additions & 2 deletions Schema Tests/readOnly/ReadOnlySubstitutionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,11 @@ public partial interface IWrapper {
"""
namespace foo.bar {
public partial interface IWrapper : IReadOnlyWrapper {
schema.readOnly.IReadOnlyValue IReadOnlyWrapper.Foo() => Foo();
schema.readOnly.IValue IReadOnlyWrapper.Foo() => Foo();
}
public interface IReadOnlyWrapper {
public schema.readOnly.IReadOnlyValue Foo();
public schema.readOnly.IValue Foo();
}
}
Expand Down
23 changes: 15 additions & 8 deletions Schema/src/readOnly/ReadOnlyTypeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ private static void WriteMembers_(
memberTypeSymbol,
semanticModel,
syntax,
associatedPropertySymbol))
(ISymbol?) associatedPropertySymbol ?? memberSymbol))
.Write(" ");

if (interfaceName != null) {
Expand Down Expand Up @@ -288,6 +288,7 @@ var isIndexer
} else {
cbsb.Write(" => ")
.Write(typeSymbol.GetCStyleCastToReadOnlyIfNeeded(
associatedPropertySymbol,
memberSymbol.ReturnType,
semanticModel,
syntax))
Expand Down Expand Up @@ -377,6 +378,7 @@ var isIndexer
} else {
cbsb.Write(" => ")
.Write(typeSymbol.GetCStyleCastToReadOnlyIfNeeded(
memberSymbol,
memberSymbol.ReturnType,
semanticModel,
syntax))
Expand Down Expand Up @@ -532,9 +534,9 @@ private static IEnumerable<string> GetTypeConstraintNames_(
}

private static string ConvertName_(ITypeSymbol typeSymbol,
ISymbol? typeSymbolForAttributeChecks) {
ISymbol? symbolForAttributeChecks) {
var defaultName = typeSymbol.Name.EscapeKeyword();
if ((typeSymbolForAttributeChecks ?? typeSymbol)
if ((symbolForAttributeChecks ?? typeSymbol)
.HasAttribute<KeepMutableTypeAttribute>()) {
return defaultName;
}
Expand Down Expand Up @@ -684,13 +686,14 @@ var allParentTypes

public static string GetCStyleCastToReadOnlyIfNeeded(
this ITypeSymbol sourceSymbol,
ISymbol? symbolForAttributeChecks,
ITypeSymbol symbol,
SemanticModel semanticModel,
TypeDeclarationSyntax syntax) {
// TODO: Only allow casts if generics are covariant, otherwise report
// diagnostic error
var sb = new StringBuilder();
if (symbol.IsCastNeeded()) {
if (symbol.IsCastNeeded(symbolForAttributeChecks)) {
sb.Append("(")
.Append(
sourceSymbol
Expand All @@ -704,16 +707,20 @@ public static string GetCStyleCastToReadOnlyIfNeeded(
return sb.ToString();
}

public static bool IsCastNeeded(this ITypeSymbol symbol) {
public static bool IsCastNeeded(this ITypeSymbol symbol,
ISymbol? symbolForAttributeChecks) {
if ((symbolForAttributeChecks ?? symbol)
.HasAttribute<KeepMutableTypeAttribute>()) {
return false;
}

if (symbol.IsGeneric(out _, out var typeArguments) &&
typeArguments.Any(typeArgument => typeArgument
.HasAttribute<GenerateReadOnlyAttribute>())) {
return true;
}

return
!symbol.HasAttribute<KeepMutableTypeAttribute>() &&
symbol.HasBuiltInReadOnlyType_(out _, out var canImplicitlyConvert) &&
return symbol.HasBuiltInReadOnlyType_(out _, out var canImplicitlyConvert) &&
!canImplicitlyConvert;
}
}
Expand Down

0 comments on commit 8049052

Please sign in to comment.