Skip to content

Commit

Permalink
Fixed issues around types in the global namespace.
Browse files Browse the repository at this point in the history
  • Loading branch information
MeltyPlayer committed Jan 3, 2025
1 parent e632e63 commit 7a2ff4c
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 43 deletions.
2 changes: 1 addition & 1 deletion Schema Tests/autoInterface/ConstraintTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ namespace foo.bar;
public partial class Circular<TMutable, TInterface, TImpl> : ICircular<TMutable, TInterface, TImpl>;
#nullable enable
public interface ICircular<TMutable, TInterface, TImpl> where TMutable : Circular<TMutable, TInterface, TImpl>, TInterface where TInterface : foo.bar.ICircular<TMutable, TInterface, TImpl> {
public interface ICircular<TMutable, TInterface, TImpl> where TMutable : Circular<TMutable, TInterface, TImpl>, TInterface where TInterface : ICircular<TMutable, TInterface, TImpl> {
public TMutable Foo(TInterface other);
public TMutable Foo(in TImpl other);
}
Expand Down
122 changes: 122 additions & 0 deletions Schema Tests/binary/generator/NamespaceGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,126 @@ public void Write(IBinaryWriter bw) {
""");
}

[Test]
public void TestBothInGlobalNamespace() {
BinarySchemaTestUtil.AssertGenerated(
"""
using schema.binary;
public enum A : byte {
}
[BinarySchema]
public partial class Wrapper : IBinaryConvertible {
public A Field { get; set; }
}
""",
"""
using System;
using schema.binary;
public partial class Wrapper {
public void Read(IBinaryReader br) {
this.Field = (A) br.ReadByte();
}
}
""",
"""
using System;
using schema.binary;
public partial class Wrapper {
public void Write(IBinaryWriter bw) {
bw.WriteByte((byte) this.Field);
}
}
""");
}

[Test]
public void TestFromGlobalNamespace() {
BinarySchemaTestUtil.AssertGenerated(
"""
using schema.binary;
namespace foo {
public enum A : byte {
}
}
[BinarySchema]
public partial class Wrapper : IBinaryConvertible {
public foo.A Field { get; set; }
}
""",
"""
using System;
using schema.binary;
public partial class Wrapper {
public void Read(IBinaryReader br) {
this.Field = (foo.A) br.ReadByte();
}
}
""",
"""
using System;
using schema.binary;
public partial class Wrapper {
public void Write(IBinaryWriter bw) {
bw.WriteByte((byte) this.Field);
}
}
""");
}

[Test]
public void TestInGlobalNamespace() {
BinarySchemaTestUtil.AssertGenerated(
"""
using schema.binary;
public enum A : byte {
}
namespace foo {
[BinarySchema]
public partial class Wrapper : IBinaryConvertible {
public A Field { get; set; }
}
}
""",
"""
using System;
using schema.binary;
namespace foo;
public partial class Wrapper {
public void Read(IBinaryReader br) {
this.Field = (global::A) br.ReadByte();
}
}
""",
"""
using System;
using schema.binary;
namespace foo;
public partial class Wrapper {
public void Write(IBinaryWriter bw) {
bw.WriteByte((byte) this.Field);
}
}
""");
}
}
20 changes: 14 additions & 6 deletions Schema/src/autoInterface/AutoInterfaceTypeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,15 @@ public string GenerateSourceForNamedType(INamedTypeSymbol typeSymbol,
var sb = new StringBuilder();
using var sw = new SourceWriter(new StringWriter(sb));

var interfaceName = typeSymbol.GetInterfaceName();
var context = new GeneratorUtilContext(
new Dictionary<(string name, int arity), IEnumerable<string>?> {
[(interfaceName, typeSymbol.Arity)] = typeSymbol.GetContainingNamespaces(),
});

sw.WriteNamespaceAndParentTypeBlocks(
typeSymbol,
() => {
var interfaceName = typeSymbol.GetInterfaceName();

// Class
{
var blockPrefix =
Expand Down Expand Up @@ -126,7 +130,8 @@ var interfaceMembers
blockPrefix += typeSymbol.GetTypeConstraintsOrReadonly(
typeSymbol.TypeParameters,
semanticModel,
syntax);
syntax,
context);

if (interfaceMembers.Length == 0) {
sw.Write(blockPrefix).WriteLine(";");
Expand All @@ -136,7 +141,8 @@ var interfaceMembers
typeSymbol,
interfaceMembers,
semanticModel,
syntax);
syntax,
context);
sw.ExitBlock();
}
}
Expand All @@ -150,7 +156,8 @@ private static void WriteMembers_(
INamedTypeSymbol typeSymbol,
IReadOnlyList<ISymbol> constMembers,
SemanticModel semanticModel,
TypeDeclarationSyntax syntax) {
TypeDeclarationSyntax syntax,
GeneratorUtilContext context) {
foreach (var memberSymbol in constMembers) {
switch (memberSymbol) {
case IPropertySymbol propertySymbol: {
Expand Down Expand Up @@ -290,7 +297,8 @@ private static void WriteMembers_(
sw.Write(typeSymbol.GetTypeConstraintsOrReadonly(
methodSymbol.TypeParameters,
semanticModel,
syntax));
syntax,
context));

sw.WriteLine(";");
break;
Expand Down
36 changes: 23 additions & 13 deletions Schema/src/readOnly/ReadOnlyTypeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ var parentInterfaces
}
}

internal class GeneratorUtilContext(IReadOnlyDictionary<(string name, int arity), IEnumerable<string>?> knownNamespaces) {
public IReadOnlyDictionary<(string name, int arity), IEnumerable<string>?> KnownNamespaces { get; } = knownNamespaces;
}

internal static class ReadOnlyTypeGeneratorUtil {
public const string PREFIX = "IReadOnly";

Expand Down Expand Up @@ -463,13 +467,14 @@ public static string GetTypeConstraintsOrReadonly(
this ITypeSymbol sourceSymbol,
IReadOnlyList<ITypeParameterSymbol> typeParameters,
SemanticModel semanticModel,
TypeDeclarationSyntax syntax) {
TypeDeclarationSyntax syntax,
GeneratorUtilContext? context = null) {
var sb = new StringBuilder();

foreach (var typeParameter in typeParameters) {
var typeConstraintNames
= sourceSymbol
.GetTypeConstraintNames_(typeParameter, semanticModel, syntax)
.GetTypeConstraintNames_(typeParameter, semanticModel, syntax, context)
.ToArray();
if (typeConstraintNames.Length == 0) {
continue;
Expand All @@ -495,7 +500,8 @@ private static IEnumerable<string> GetTypeConstraintNames_(
this ITypeSymbol sourceSymbol,
ITypeParameterSymbol typeParameter,
SemanticModel semanticModel,
TypeDeclarationSyntax sourceDeclarationSyntax) {
TypeDeclarationSyntax sourceDeclarationSyntax,
GeneratorUtilContext? context = null) {
if (typeParameter.HasNotNullConstraint) {
yield return "notnull";
}
Expand Down Expand Up @@ -530,7 +536,8 @@ private static IEnumerable<string> GetTypeConstraintNames_(
ConvertName_,
r => GetNamespaceOfType(r,
semanticModel,
sourceDeclarationSyntax));
sourceDeclarationSyntax,
context));

yield return typeParameter.ConstraintNullableAnnotations[i] ==
NullableAnnotation.Annotated
Expand Down Expand Up @@ -608,22 +615,25 @@ public static IEnumerable<INamedTypeSymbol> LookupTypesWithNameAndArity(
=> semanticModel
.LookupNamespacesAndTypes(syntax.SpanStart, null, searchString)
.Where(symbol => symbol.HasAttribute<GenerateReadOnlyAttribute>())
.Where(symbol => symbol is INamedTypeSymbol)
.Select(symbol => symbol as INamedTypeSymbol)
.OfType<INamedTypeSymbol>()
.Where(symbol => symbol.Arity == arity);

public static IEnumerable<string> GetNamespaceOfType(
public static IEnumerable<string>? GetNamespaceOfType(
this ITypeSymbol typeSymbol,
SemanticModel semanticModel,
TypeDeclarationSyntax syntax) {
TypeDeclarationSyntax syntax,
GeneratorUtilContext? context = null) {
if (!typeSymbol.Exists()) {
var typeName = typeSymbol.Name;
if (typeName.StartsWith(
ReadOnlyTypeGeneratorUtil.PREFIX)) {
var arity = typeSymbol.GetArity();

if (context?.KnownNamespaces.TryGetValue((typeName, arity), out var knownNamespace) ?? false) {
return knownNamespace;
}

if (typeName.StartsWith(ReadOnlyTypeGeneratorUtil.PREFIX)) {
var nameWithoutPrefix
= typeName.Substring(
ReadOnlyTypeGeneratorUtil.PREFIX.Length);
var arity = typeSymbol.GetArity();
= typeName.Substring(ReadOnlyTypeGeneratorUtil.PREFIX.Length);

var typesWithName
= LookupTypesWithNameAndArity(semanticModel,
Expand Down
7 changes: 3 additions & 4 deletions Schema/src/util/NameofUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public static class NameofUtil {
private struct TypeAndNamespace {
public bool Defined { get; set; }
public string Name { get; set; }
public string[] NamespaceParts { get; set; }
public string[]? NamespaceParts { get; set; }
}

public static string GetChainedAccessFromCallerArgumentExpression(
Expand All @@ -28,8 +28,7 @@ public static string GetChainedAccessFromCallerArgumentExpression(
new TypeAndNamespace {
Defined = true,
Name = parent.Name,
NamespaceParts =
parent.Namespace?.Split('.') ?? [],
NamespaceParts = parent.Namespace?.Split('.'),
},
text);

Expand All @@ -40,7 +39,7 @@ public static string GetChainedAccessFromCallerArgumentExpression(
new TypeAndNamespace {
Defined = true,
Name = parent.Name,
NamespaceParts = parent.GetContainingNamespaces().ToArray(),
NamespaceParts = parent.GetContainingNamespaces()?.ToArray(),
},
text);

Expand Down
38 changes: 30 additions & 8 deletions Schema/src/util/symbols/NamespaceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

using Microsoft.CodeAnalysis;

using schema.util.asserts;


namespace schema.util.symbols;

Expand Down Expand Up @@ -61,26 +63,46 @@ internal static bool IsInNamespace(this ISymbol symbol,
currentNamespace.ContainingNamespace.Name.Length == 0;
}

public static string? GetFullyQualifiedNamespace(this ISymbol symbol) {
var containingNamespaces = symbol.GetContainingNamespaces().ToArray();
public static string? GetNamespaceBlockLabel(this ISymbol symbol) {
var containingNamespaces
= Asserts.CastNonnull(symbol.GetContainingNamespaces()).ToArray();
if (containingNamespaces.Length == 0) {
return null;
}

return string.Join(".", containingNamespaces);
}

public static IEnumerable<string> GetContainingNamespaces(
this ISymbol symbol)
=> symbol.GetContainingNamespacesReversed_().Reverse();
public static string? GetFullyQualifiedNamespace(this ISymbol symbol) {
var containingNamespaces = symbol.GetContainingNamespaces()?.ToArray();
if (containingNamespaces == null) {
return null;
}

private static IEnumerable<string> GetContainingNamespacesReversed_(
if (containingNamespaces.Length == 0) {
return "global::";
}

return string.Join(".", containingNamespaces!);
}

public static IEnumerable<string>? GetContainingNamespaces(
this ISymbol symbol) {
var namespaceSymbol = symbol.ContainingNamespace;
if (namespaceSymbol?.IsGlobalNamespace ?? true) {
yield break;
if (namespaceSymbol == null) {
return null;
}

if (namespaceSymbol.IsGlobalNamespace) {
return [];
}

return symbol.GetContainingNamespacesReversed_().Reverse();
}

private static IEnumerable<string> GetContainingNamespacesReversed_(
this ISymbol symbol) {
var namespaceSymbol = symbol.ContainingNamespace;
while (!namespaceSymbol?.IsGlobalNamespace ?? true) {
if (namespaceSymbol.Name.Length > 0) {
yield return namespaceSymbol.Name.EscapeKeyword();
Expand Down
Loading

0 comments on commit 7a2ff4c

Please sign in to comment.