Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fully qualify type references; remove usings #60

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
53 changes: 19 additions & 34 deletions AutomaticInterface/AutomaticInterface/Builder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ public static class Builder
| SymbolDisplayParameterOptions.IncludeParamsRefOut
);

private static readonly SymbolDisplayFormat TypeDisplayFormat =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New display format for types. Based on SymbolDisplayFormat.FullyQualifiedFormat, but with support for nullables, and without unnecessary non-type parameters

new(
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Included,
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes
| SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier
);

public static string BuildInterfaceFor(ITypeSymbol typeSymbol)
{
if (
Expand All @@ -34,7 +43,6 @@ is not ClassDeclarationSyntax classSyntax

var interfaceGenerator = new InterfaceBuilder(namespaceName, interfaceName);

interfaceGenerator.AddUsings(GetUsings(typeSymbol));
interfaceGenerator.AddClassDocumentation(GetDocumentationForClass(classSyntax));
interfaceGenerator.AddGeneric(GetGeneric(classSyntax));
AddPropertiesToInterface(typeSymbol, interfaceGenerator);
Expand Down Expand Up @@ -102,16 +110,13 @@ private static void AddMethod(InterfaceBuilder codeGenerator, IMethodSymbol meth

var typedArgs = method
.TypeParameters.Select(arg =>
(
arg.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
arg.GetWhereStatement()
)
(arg.ToDisplayString(TypeDisplayFormat), arg.GetWhereStatement(TypeDisplayFormat))
)
.ToList();

codeGenerator.AddMethodToInterface(
name,
returnType.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
returnType.ToDisplayString(TypeDisplayFormat),
InheritDoc,
paramResult,
typedArgs
Expand Down Expand Up @@ -189,7 +194,11 @@ InterfaceBuilder codeGenerator

ActivateNullableIfNeeded(codeGenerator, type);

codeGenerator.AddEventToInterface(name, type.ToDisplayString(), InheritDoc);
codeGenerator.AddEventToInterface(
name,
type.ToDisplayString(TypeDisplayFormat),
InheritDoc
);
});
}

Expand All @@ -199,7 +208,7 @@ private static string GetMethodSignature(IParameterSymbol x)
var refKindText = GetRefKind(x);
var optionalValue = GetMethodOptionalValue(x);

return $"{refKindText}{x.Type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)} {name}{optionalValue}";
return $"{refKindText}{x.Type.ToDisplayString(TypeDisplayFormat)} {name}{optionalValue}";
}

private static string GetMethodOptionalValue(IParameterSymbol x)
Expand All @@ -215,7 +224,7 @@ private static string GetMethodOptionalValue(IParameterSymbol x)
bool value => $" = {(value ? "true" : "false")}",
// struct
null when x.Type.IsValueType
=> $" = default({x.Type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)})",
=> $" = default({x.Type.ToDisplayString(TypeDisplayFormat)})",
null => " = null",
_ => $" = {x.ExplicitDefaultValue}"
};
Expand Down Expand Up @@ -272,7 +281,7 @@ InterfaceBuilder interfaceGenerator

interfaceGenerator.AddPropertyToInterface(
name,
type.ToDisplayString(),
type.ToDisplayString(TypeDisplayFormat),
hasGet,
hasSet,
isRef,
Expand Down Expand Up @@ -330,30 +339,6 @@ private static string GetDocumentationForClass(CSharpSyntaxNode classSyntax)
return trivia.ToFullString().Trim();
}

private static IEnumerable<string> GetUsings(ISymbol classSymbol)
{
var allUsings = SyntaxFactory.List<UsingDirectiveSyntax>();
foreach (var syntaxRef in classSymbol.DeclaringSyntaxReferences)
{
allUsings = syntaxRef
.GetSyntax()
.Ancestors(false)
.Aggregate(
allUsings,
(current, parent) =>
parent switch
{
NamespaceDeclarationSyntax ndSyntax
=> current.AddRange(ndSyntax.Usings),
CompilationUnitSyntax cuSyntax => current.AddRange(cuSyntax.Usings),
_ => current
}
);
}

return [.. allUsings.Select(x => x.ToString())];
}

private static string GetGeneric(TypeDeclarationSyntax classSyntax)
{
if (classSyntax.TypeParameterList?.Parameters.Count == 0)
Expand Down
20 changes: 3 additions & 17 deletions AutomaticInterface/AutomaticInterface/InterfaceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ public class InterfaceBuilder(string nameSpaceName, string interfaceName)

""";

private readonly HashSet<string> usings = ["using System.CodeDom.Compiler;"];
private readonly List<PropertyInfo> propertyInfos = [];
private readonly List<MethodInfo> methodInfos = [];
private readonly List<EventInfo> events = [];
Expand Down Expand Up @@ -69,14 +68,6 @@ public void AddClassDocumentation(string documentation)
classDocumentation = documentation;
}

public void AddUsings(IEnumerable<string> additionalUsings)
{
foreach (var usg in additionalUsings)
{
usings.Add(usg);
}
}

public void AddMethodToInterface(
string name,
string returnType,
Expand All @@ -103,21 +94,16 @@ public string Build()
cb.AppendLine("#nullable enable");
}

foreach (var usg in usings)
{
cb.AppendLine(usg);
}

cb.AppendLine("");

cb.AppendLine($"namespace {nameSpaceName}");
cb.AppendLine("{");

cb.Indent();

cb.AppendAndNormalizeMultipleLines(classDocumentation);

cb.AppendLine($"[GeneratedCode(\"AutomaticInterface\", \"\")]");
cb.AppendLine(
"[global::System.CodeDom.Compiler.GeneratedCode(\"AutomaticInterface\", \"\")]"
Copy link
Contributor Author

@simonmckenzie simonmckenzie Aug 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a choice - it seemed simpler and more concise to fully qualify this too, since otherwise there's only be one using in the interface file, using System.CodeDom.Compiler;

If you don't like this choice, just say and I'll change it back :)

);
cb.AppendLine($"public partial interface {interfaceName}{genericType}");
cb.AppendLine("{");

Expand Down
26 changes: 17 additions & 9 deletions AutomaticInterface/AutomaticInterface/RoslynExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ public static string GetClassName(this ClassDeclarationSyntax proxy)
/// <summary>
/// Thanks to https://www.codeproject.com/Articles/871704/Roslyn-Code-Analysis-in-Easy-Samples-Part-2
/// </summary>
/// <param name="typeParameterSymbol"></param>
/// <returns></returns>
public static string GetWhereStatement(this ITypeParameterSymbol typeParameterSymbol)
public static string GetWhereStatement(
this ITypeParameterSymbol typeParameterSymbol,
SymbolDisplayFormat typeDisplayFormat
)
{
var result = $"where {typeParameterSymbol.Name} : ";

Expand Down Expand Up @@ -69,7 +70,7 @@ public static string GetWhereStatement(this ITypeParameterSymbol typeParameterSy
isFirstConstraint = false;
}

constraints += constraintType.GetFullTypeString();
constraints += constraintType.GetFullTypeString(typeDisplayFormat);
}

if (string.IsNullOrEmpty(constraints))
Expand All @@ -82,14 +83,21 @@ public static string GetWhereStatement(this ITypeParameterSymbol typeParameterSy
return result;
}

private static string GetFullTypeString(this ISymbol type)
private static string GetFullTypeString(
this ISymbol type,
SymbolDisplayFormat typeDisplayFormat
)
{
return type.Name
+ type.GetTypeArgsStr(symbol => ((INamedTypeSymbol)symbol).TypeArguments);
return type.ToDisplayString(typeDisplayFormat)
+ type.GetTypeArgsStr(
typeDisplayFormat,
symbol => ((INamedTypeSymbol)symbol).TypeArguments
);
}

private static string GetTypeArgsStr(
this ISymbol symbol,
SymbolDisplayFormat typeDisplayFormat,
Func<ISymbol, ImmutableArray<ITypeSymbol>> typeArgGetter
)
{
Expand All @@ -106,13 +114,13 @@ Func<ISymbol, ImmutableArray<ITypeSymbol>> typeArgGetter
if (arg is ITypeParameterSymbol typeParameterSymbol)
{
// this is a generic argument
strToAdd = typeParameterSymbol.Name;
strToAdd = typeParameterSymbol.ToDisplayString(typeDisplayFormat);
}
else
{
// this is a generic argument value.
var namedTypeSymbol = arg as INamedTypeSymbol;
strToAdd = namedTypeSymbol!.GetFullTypeString();
strToAdd = namedTypeSymbol!.GetFullTypeString(typeDisplayFormat);
}

stringsToAdd.Add(strToAdd);
Expand Down
63 changes: 12 additions & 51 deletions AutomaticInterface/Tests/GeneratorTests.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,9 @@ class DemoClass
// </auto-generated>
//--------------------------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using AutomaticInterface;

namespace AutomaticInterfaceExample
{
[GeneratedCode("AutomaticInterface", "")]
[global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")]
public partial interface IDemoClass
{
/// <inheritdoc />
Expand Down Expand Up @@ -83,12 +80,9 @@ class DemoClass
// </auto-generated>
//--------------------------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using AutomaticInterface;

namespace AutomaticInterfaceExample
{
[GeneratedCode("AutomaticInterface", "")]
[global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")]
public partial interface IDemoClass
{
/// <inheritdoc />
Expand Down Expand Up @@ -137,16 +131,12 @@ class DemoClass
//--------------------------------------------------------------------------------------------------

#nullable enable
using System.CodeDom.Compiler;
using AutomaticInterface;
using System;

namespace AutomaticInterfaceExample
{
/// <summary>
/// Bla bla
/// </summary>
[GeneratedCode("AutomaticInterface", "")]
[global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")]
public partial interface IDemoClass
{
/// <inheritdoc />
Expand Down Expand Up @@ -197,21 +187,16 @@ class DemoClass
//--------------------------------------------------------------------------------------------------

#nullable enable
using System.CodeDom.Compiler;
using AutomaticInterface;
using System;
using System.Threading.Tasks;

namespace AutomaticInterfaceExample
{
/// <summary>
/// Bla bla
/// </summary>
[GeneratedCode("AutomaticInterface", "")]
[global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")]
public partial interface IDemoClass
{
/// <inheritdoc />
System.Threading.Tasks.Task<string?> NullableProperty { get; set; }
global::System.Threading.Tasks.Task<string?> NullableProperty { get; set; }

}
}
Expand Down Expand Up @@ -253,13 +238,9 @@ public partial class SecondClass : FirstClass
// </auto-generated>
//--------------------------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using AutomaticInterface;
using System.Threading.Tasks;

namespace AutomaticInterfaceExample
{
[GeneratedCode("AutomaticInterface", "")]
[global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")]
public partial interface ISecondClass
{
/// <inheritdoc />
Expand Down Expand Up @@ -302,13 +283,9 @@ public class DemoClass : BaseClass
// </auto-generated>
//--------------------------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using AutomaticInterface;
using System;

namespace AutomaticInterfaceExample
{
[GeneratedCode("AutomaticInterface", "")]
[global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")]
public partial interface IDemoClass
{
/// <inheritdoc />
Expand Down Expand Up @@ -352,13 +329,9 @@ public class DemoClass : BaseClass
// </auto-generated>
//--------------------------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using AutomaticInterface;
using System;

namespace AutomaticInterfaceExample
{
[GeneratedCode("AutomaticInterface", "")]
[global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")]
public partial interface IDemoClass
{
/// <inheritdoc />
Expand Down Expand Up @@ -399,12 +372,9 @@ class DemoClass
// </auto-generated>
//--------------------------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using AutomaticInterface;

namespace AutomaticInterfaceExample
{
[GeneratedCode("AutomaticInterface", "")]
[global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")]
public partial interface IDemoClass
{
/// <inheritdoc />
Expand Down Expand Up @@ -446,12 +416,9 @@ class DemoClass
// </auto-generated>
//--------------------------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using AutomaticInterface;

namespace AutomaticInterfaceExample
{
[GeneratedCode("AutomaticInterface", "")]
[global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")]
public partial interface IDemoClass
{
/// <inheritdoc />
Expand Down Expand Up @@ -493,12 +460,9 @@ class DemoClass
// </auto-generated>
//--------------------------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using AutomaticInterface;

namespace AutomaticInterfaceExample
{
[GeneratedCode("AutomaticInterface", "")]
[global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")]
public partial interface IDemoClass
{
/// <inheritdoc />
Expand Down Expand Up @@ -539,12 +503,9 @@ class DemoClass
// </auto-generated>
//--------------------------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using AutomaticInterface;

namespace AutomaticInterfaceExample
{
[GeneratedCode("AutomaticInterface", "")]
[global::System.CodeDom.Compiler.GeneratedCode("AutomaticInterface", "")]
public partial interface IDemoClass
{
/// <inheritdoc />
Expand Down
Loading
Loading