Skip to content

Commit

Permalink
bugs: attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
beakona committed Mar 15, 2024
1 parent 7a45d90 commit 0441c4c
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 83 deletions.
11 changes: 7 additions & 4 deletions AutoInterfaceSample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public static void Main()
{
//System.Diagnostics.Debug.WriteLine(BeaKona.Output.Debug_TestRecord.Info);

ITestInterfaceObsolete r = new TestObsoleteRecord(null);
r.TestObsoleteMethod("");
// ITestable p = new TestRecord(new SimpleLogger());

// p.Test();
Expand All @@ -31,13 +33,14 @@ partial record TestObsoleteRecord(
interface ITestInterfaceObsolete
{
[Obsolete]
[return: System.Diagnostics.CodeAnalysis.MaybeNull]
[return: NotNullIfNotNullAttribute("test")]
[return: TestReturnAttribute]
[DoesNotReturn]
[return: MaybeNull]
[return: NotNullIfNotNull(nameof(test))]
[return: TestReturn]
ResObject? TestObsoleteMethod(string? test);

[Obsolete]
[System.Diagnostics.CodeAnalysis.DisallowNull]
[DisallowNull]
ResObject? TestObsoleteProperty { get; }


Expand Down
105 changes: 26 additions & 79 deletions BeaKona.AutoInterfaceGenerator/CSharpCodeTextWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,75 +11,19 @@ public CSharpCodeTextWriter(GeneratorExecutionContext context, Compilation compi
this.Context = context;
this.Compilation = compilation;

if (this.Compilation.GetTypeByMetadataName(typeof(ObsoleteAttribute).FullName) is INamedTypeSymbol obsoleteAttributeSymbol)
{
var forwardAttributeSymbols = new List<INamedTypeSymbol>();
if (this.Compilation.GetTypeByMetadataName(typeof(ObsoleteAttribute).FullName) is INamedTypeSymbol obsoleteAttributeSymbol)
{
forwardAttributeSymbols.Add(obsoleteAttributeSymbol);
}
if (this.Compilation.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.ExperimentalAttribute") is INamedTypeSymbol experimentalAttributeSymbol)
{
forwardAttributeSymbols.Add(experimentalAttributeSymbol);
}
if (this.Compilation.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute") is INamedTypeSymbol doesNotReturnAttributeSymbol)
{
forwardAttributeSymbols.Add(doesNotReturnAttributeSymbol);
}

this.forwardAttributeSymbols = [.. forwardAttributeSymbols];
}

{
var returnAttributeSymbols = new List<INamedTypeSymbol>();
if (this.Compilation.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.MaybeNullAttribute") is INamedTypeSymbol maybeNullAttributeSymbol)
{
returnAttributeSymbols.Add(maybeNullAttributeSymbol);
}
if (this.Compilation.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.NotNullAttribute") is INamedTypeSymbol notNullAttributeSymbol)
{
returnAttributeSymbols.Add(notNullAttributeSymbol);
}
if (this.Compilation.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute") is INamedTypeSymbol notNullIfNotNullAttributeSymbol)
{
returnAttributeSymbols.Add(notNullIfNotNullAttributeSymbol);
}

this.returnAttributeSymbols = [.. returnAttributeSymbols];
this.forwardAttributeSymbols.Add(obsoleteAttributeSymbol);
}

{
var parameterAttributeSymbols = new List<INamedTypeSymbol>();
if (this.Compilation.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute") is INamedTypeSymbol doesNotReturnIfAttributeSymbol)
{
parameterAttributeSymbols.Add(doesNotReturnIfAttributeSymbol);
}
if (this.Compilation.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute") is INamedTypeSymbol maybeNullWhenAttributeSymbol)
{
parameterAttributeSymbols.Add(maybeNullWhenAttributeSymbol);
}
if (this.Compilation.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.NotNullAttribute") is INamedTypeSymbol notNullAttributeSymbol)
{
parameterAttributeSymbols.Add(notNullAttributeSymbol);
}
if (this.Compilation.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute") is INamedTypeSymbol notNullIfNotNullAttributeSymbol)
{
parameterAttributeSymbols.Add(notNullIfNotNullAttributeSymbol);
}
if (this.Compilation.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.NotNullWhenAttribute") is INamedTypeSymbol notNullWhenAttributeSymbol)
{
parameterAttributeSymbols.Add(notNullWhenAttributeSymbol);
}

this.parameterAttributeSymbols = [.. parameterAttributeSymbols];
}
this.forwardAttributeNamespaces.Add("System.Diagnostics.CodeAnalysis");
}

public GeneratorExecutionContext Context { get; }
public Compilation Compilation { get; }

private readonly INamedTypeSymbol[] forwardAttributeSymbols;
private readonly INamedTypeSymbol[] returnAttributeSymbols;
private readonly INamedTypeSymbol[] parameterAttributeSymbols;
private readonly HashSet<INamedTypeSymbol> forwardAttributeSymbols = new(SymbolEqualityComparer.Default);
private readonly HashSet<string> forwardAttributeNamespaces = [];

public void WriteTypeReference(SourceBuilder builder, ITypeSymbol type, ScopeInfo scope)
{
Expand Down Expand Up @@ -375,58 +319,61 @@ private void WriteAttribute(SourceBuilder builder, AttributeData attribute, bool

private IEnumerable<AttributeData> GetParameterAttributes(IParameterSymbol parameter)
{
var attributes = parameter.GetAttributes().Where(IsPublicAccess).ToList();
var attributes = parameter.GetAttributes().Where(IsPublicAccess);

foreach (var attribute in attributes)
{
if (attribute.AttributeClass is INamedTypeSymbol attributeClass)
{
foreach (var typeSymbol in this.parameterAttributeSymbols)
if (this.forwardAttributeNamespaces.Contains(attributeClass.ContainingNamespace.ToDisplayString()))
{
if (attributeClass.Equals(typeSymbol, SymbolEqualityComparer.Default))
{
yield return attribute;
break;
}
yield return attribute;
}
}
}
}

private IEnumerable<AttributeData> GetForwardAttributes(ISymbol symbol)
{
var attributes = symbol.GetAttributes().Where(IsPublicAccess).ToList();
var attributes = symbol.GetAttributes().Where(IsPublicAccess);

foreach (var attribute in attributes)
{
if (attribute.AttributeClass is INamedTypeSymbol attributeClass)
{
foreach (var typeSymbol in this.forwardAttributeSymbols)
if (this.forwardAttributeNamespaces.Contains(attributeClass.ContainingNamespace.ToDisplayString()))
{
if (attributeClass.Equals(typeSymbol, SymbolEqualityComparer.Default))
{
yield return attribute;
break;
}
yield return attribute;
}
else if (this.forwardAttributeSymbols.Contains(attributeClass))
{
yield return attribute;
}
}
}
}

private IEnumerable<AttributeData> GetReturnAttributes(ISymbol symbol)
{
var attributes = symbol.GetAttributes().Where(IsPublicAccess).ToList();
return this.GetReturnAttributes(symbol.GetAttributes());
}

private IEnumerable<AttributeData> GetReturnAttributes(IMethodSymbol method)
{
return this.GetReturnAttributes(method.GetReturnTypeAttributes());
}

private IEnumerable<AttributeData> GetReturnAttributes(IEnumerable<AttributeData> attributes)
{
foreach (var attribute in attributes)
{
if (attribute.AttributeClass is INamedTypeSymbol attributeClass)
{
foreach (var typeSymbol in this.returnAttributeSymbols)
if ((attributeClass.GetAttributeUsages() & AttributeTargets.ReturnValue) == AttributeTargets.ReturnValue)
{
if (attributeClass.Equals(typeSymbol, SymbolEqualityComparer.Default))
if (this.forwardAttributeNamespaces.Contains(attributeClass.ContainingNamespace.ToDisplayString()))
{
yield return attribute;
break;
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions BeaKona.AutoInterfaceGenerator/CompilationExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace BeaKona.AutoInterfaceGenerator;

internal static class CompilationExtensions
{
public static INamespaceSymbol? GetNamespaceByMetadataName(this Compilation @this, string name)
{
var parts = name.Split(new char[] { '.' }, StringSplitOptions.None);

var @namespace = @this.GlobalNamespace;
foreach (var part in parts)
{
var next = @namespace.GetNamespace(part);
if (next == null)
{
return null;
}
@namespace = next;
}
return @namespace;
}
}
17 changes: 17 additions & 0 deletions BeaKona.AutoInterfaceGenerator/INamedTypeSymbolExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace BeaKona.AutoInterfaceGenerator;

public static class INamedTypeSymbolExtensions
{
public static AttributeTargets? GetAttributeUsages(this INamedTypeSymbol @this)
{
foreach (var attribute in @this.GetAttributes())
{
if (attribute.AttributeClass is INamedTypeSymbol attributeClass && attributeClass.ToDisplayString() == "System.AttributeUsageAttribute")
{
return (AttributeTargets)Convert.ToInt32(attribute.ConstructorArguments[0].Value);
}
}

return default;
}
}
13 changes: 13 additions & 0 deletions BeaKona.AutoInterfaceGenerator/INamespaceSymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,17 @@ public static INamespaceSymbol[] GetNamespaceElements(this INamespaceSymbol @thi
}
return [.. containingNamespaces];
}

public static INamespaceSymbol? GetNamespace(this INamespaceSymbol @this, string name)
{
foreach (var member in @this.GetNamespaceMembers())
{
if (member is INamespaceSymbol @namespace && @namespace.NamespaceKind == NamespaceKind.Module && @namespace.Name == name)
{
return @namespace;
}
}

return default;
}
}

0 comments on commit 0441c4c

Please sign in to comment.