Skip to content

Commit

Permalink
Merge pull request #61 from AndrewKeepCoding/file-scoped-namespaces
Browse files Browse the repository at this point in the history
File scoped namespaces
  • Loading branch information
nmetulev authored Dec 19, 2024
2 parents 907e6b9 + f576cbb commit cda4a4d
Show file tree
Hide file tree
Showing 105 changed files with 6,414 additions and 6,515 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ csharp_style_prefer_readonly_struct_member = true
# Code-block preferences
csharp_prefer_braces = true:silent
csharp_prefer_simple_using_statement = true:suggestion
csharp_style_namespace_declarations = block_scoped:warning
csharp_style_namespace_declarations = file_scoped:warning
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_prefer_top_level_statements = true:silent
Expand Down
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Switch to file-scoped namespaces
52b04efcd96584a68740f17ea34b3430b288285c
81 changes: 40 additions & 41 deletions AIDevGallery.SourceGenerator/DependencyVersionsSourceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,62 +6,61 @@
using System.Collections.Generic;
using System.Text;

namespace AIDevGallery.SourceGenerator
namespace AIDevGallery.SourceGenerator;

[Generator(LanguageNames.CSharp)]
internal class DependencyVersionsSourceGenerator : IIncrementalGenerator
{
[Generator(LanguageNames.CSharp)]
internal class DependencyVersionsSourceGenerator : IIncrementalGenerator
{
private Dictionary<string, string>? packageVersions = null;
private Dictionary<string, string>? packageVersions = null;

public void Initialize(IncrementalGeneratorInitializationContext context)
{
packageVersions = Helpers.GetPackageVersions();
public void Initialize(IncrementalGeneratorInitializationContext context)
{
packageVersions = Helpers.GetPackageVersions();

context.RegisterPostInitializationOutput(Execute);
}
context.RegisterPostInitializationOutput(Execute);
}

public void Execute(IncrementalGeneratorPostInitializationContext context)
public void Execute(IncrementalGeneratorPostInitializationContext context)
{
if (packageVersions == null)
{
if (packageVersions == null)
{
return;
}

GeneratePackageVersionsFile(context, packageVersions);
return;
}

private static void GeneratePackageVersionsFile(IncrementalGeneratorPostInitializationContext context, Dictionary<string, string> packageVersions)
{
var sourceBuilder = new StringBuilder();
GeneratePackageVersionsFile(context, packageVersions);
}

sourceBuilder.AppendLine(
$$""""
#nullable enable
private static void GeneratePackageVersionsFile(IncrementalGeneratorPostInitializationContext context, Dictionary<string, string> packageVersions)
{
var sourceBuilder = new StringBuilder();

using System.Collections.Generic;
using AIDevGallery.Models;
sourceBuilder.AppendLine(
$$""""
#nullable enable
namespace AIDevGallery.Samples;
using System.Collections.Generic;
using AIDevGallery.Models;
internal static partial class PackageVersionHelpers
{
"""");
namespace AIDevGallery.Samples;
sourceBuilder.AppendLine(" internal static Dictionary<string, string> PackageVersions { get; } = new ()");
sourceBuilder.AppendLine(" {");
foreach (var packageVersion in packageVersions)
internal static partial class PackageVersionHelpers
{
sourceBuilder.AppendLine(
$$""""
{ "{{packageVersion.Key}}", "{{packageVersion.Value}}" },
"""");
}
"""");

sourceBuilder.AppendLine(" };");
sourceBuilder.AppendLine(" internal static Dictionary<string, string> PackageVersions { get; } = new ()");
sourceBuilder.AppendLine(" {");
foreach (var packageVersion in packageVersions)
{
sourceBuilder.AppendLine(
$$""""
{ "{{packageVersion.Key}}", "{{packageVersion.Value}}" },
"""");
}

sourceBuilder.AppendLine("}");
sourceBuilder.AppendLine(" };");

context.AddSource($"PackageVersionHelpers.g.cs", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
}
sourceBuilder.AppendLine("}");

context.AddSource($"PackageVersionHelpers.g.cs", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,60 +8,59 @@
using System.Collections.Immutable;
using System.Linq;

namespace AIDevGallery.SourceGenerator.Diagnostics.Analyzers
namespace AIDevGallery.SourceGenerator.Diagnostics.Analyzers;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class NonUniqueIdAnalyzer : DiagnosticAnalyzer
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class NonUniqueIdAnalyzer : DiagnosticAnalyzer
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [DiagnosticDescriptors.NonUniqueId];

public override void Initialize(AnalysisContext context)
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [DiagnosticDescriptors.NonUniqueId];
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
context.EnableConcurrentExecution();

public override void Initialize(AnalysisContext context)
context.RegisterCompilationStartAction(static context =>
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
context.EnableConcurrentExecution();

context.RegisterCompilationStartAction(static context =>
// Get the [GallerySample] attribute type symbol
if (context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.GallerySampleAttribute) is not INamedTypeSymbol gallerySampleAttributeSymbol)
{
// Get the [GallerySample] attribute type symbol
if (context.Compilation.GetTypeByMetadataName(WellKnownTypeNames.GallerySampleAttribute) is not INamedTypeSymbol gallerySampleAttributeSymbol)
{
return;
}
return;
}

var locations = new ConcurrentDictionary<string, Location>();
var locations = new ConcurrentDictionary<string, Location>();

context.RegisterSymbolAction(
context =>
context.RegisterSymbolAction(
context =>
{
if (context.Symbol is not INamedTypeSymbol { TypeKind: TypeKind.Class, IsImplicitlyDeclared: false })
{
return;
}

if (context.Symbol.TryGetAttributeWithType(gallerySampleAttributeSymbol, out AttributeData? attribute) &&
attribute != null &&
attribute.NamedArguments.FirstOrDefault(a => a.Key == "Id").Value.Value is string id &&
!string.IsNullOrEmpty(id) &&
attribute.GetLocation() is Location location)
{
if (context.Symbol is not INamedTypeSymbol { TypeKind: TypeKind.Class, IsImplicitlyDeclared: false })
// Check if the id is unique
if (locations.TryAdd(id, location))
{
// ID is unique so far, do nothing
return;
}

if (context.Symbol.TryGetAttributeWithType(gallerySampleAttributeSymbol, out AttributeData? attribute) &&
attribute != null &&
attribute.NamedArguments.FirstOrDefault(a => a.Key == "Id").Value.Value is string id &&
!string.IsNullOrEmpty(id) &&
attribute.GetLocation() is Location location)
else
{
// Check if the id is unique
if (locations.TryAdd(id, location))
{
// ID is unique so far, do nothing
return;
}
else
{
context.ReportDiagnostic(Diagnostic.Create(
DiagnosticDescriptors.NonUniqueId,
location,
[locations[id]],
id));
}
context.ReportDiagnostic(Diagnostic.Create(
DiagnosticDescriptors.NonUniqueId,
location,
[locations[id]],
id));
}
},
SymbolKind.NamedType);
});
}
}
},
SymbolKind.NamedType);
});
}
}
39 changes: 19 additions & 20 deletions AIDevGallery.SourceGenerator/Diagnostics/DiagnosticDescriptors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,25 @@

using Microsoft.CodeAnalysis;

namespace AIDevGallery.SourceGenerator.Diagnostics
namespace AIDevGallery.SourceGenerator.Diagnostics;

internal static class DiagnosticDescriptors
{
internal static class DiagnosticDescriptors
{
public static readonly DiagnosticDescriptor NonUniqueId = new(
id: "AIDevGallery0001",
title: "Duplicate Id for [GallerySample] sample",
messageFormat: "Id '{0}' is used more than once",
category: nameof(SamplesSourceGenerator),
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: "All gallery samples must have unique ids.");
public static readonly DiagnosticDescriptor NonUniqueId = new(
id: "AIDevGallery0001",
title: "Duplicate Id for [GallerySample] sample",
messageFormat: "Id '{0}' is used more than once",
category: nameof(SamplesSourceGenerator),
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: "All gallery samples must have unique ids.");

public static readonly DiagnosticDescriptor NugetPackageNotUsed = new(
id: "AIDevGallery0002",
title: "Nuget package not used",
messageFormat: "Nuget package '{0}' is not used in the Gallery app",
category: nameof(SamplesSourceGenerator),
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: "Nuget package references must be used in the sample app to be used by a sample.");
}
public static readonly DiagnosticDescriptor NugetPackageNotUsed = new(
id: "AIDevGallery0002",
title: "Nuget package not used",
messageFormat: "Nuget package '{0}' is not used in the Gallery app",
category: nameof(SamplesSourceGenerator),
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: "Nuget package references must be used in the sample app to be used by a sample.");
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@

using Microsoft.CodeAnalysis;

namespace AIDevGallery.SourceGenerator.Extensions
namespace AIDevGallery.SourceGenerator.Extensions;

internal static class AttributeDataExtensions
{
internal static class AttributeDataExtensions
public static Location? GetLocation(this AttributeData attributeData)
{
public static Location? GetLocation(this AttributeData attributeData)
if (attributeData.ApplicationSyntaxReference is { } syntaxReference)
{
if (attributeData.ApplicationSyntaxReference is { } syntaxReference)
{
return syntaxReference.SyntaxTree.GetLocation(syntaxReference.Span);
}

return null;
return syntaxReference.SyntaxTree.GetLocation(syntaxReference.Span);
}

return null;
}
}
57 changes: 28 additions & 29 deletions AIDevGallery.SourceGenerator/Extensions/ISymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,44 @@

using Microsoft.CodeAnalysis;

namespace AIDevGallery.SourceGenerator.Extensions
namespace AIDevGallery.SourceGenerator.Extensions;

/// <summary>
/// Extension methods for the <see cref="ISymbol"/> type.
/// </summary>
internal static class ISymbolExtensions
{
/// <summary>
/// Extension methods for the <see cref="ISymbol"/> type.
/// Gets the fully qualified name for a given symbol.
/// </summary>
internal static class ISymbolExtensions
/// <param name="symbol">The input <see cref="ISymbol"/> instance.</param>
/// <returns>The fully qualified name for <paramref name="symbol"/>.</returns>
public static string GetFullyQualifiedName(this ISymbol symbol)
{
/// <summary>
/// Gets the fully qualified name for a given symbol.
/// </summary>
/// <param name="symbol">The input <see cref="ISymbol"/> instance.</param>
/// <returns>The fully qualified name for <paramref name="symbol"/>.</returns>
public static string GetFullyQualifiedName(this ISymbol symbol)
{
return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
}
return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
}

/// <summary>
/// Tries to get an attribute with the specified type.
/// </summary>
/// <param name="symbol">The input <see cref="ISymbol"/> instance to check.</param>
/// <param name="typeSymbol">The <see cref="ITypeSymbol"/> instance for the attribute type to look for.</param>
/// <param name="attributeData">The resulting attribute, if it was found.</param>
/// <returns>Whether or not <paramref name="symbol"/> has an attribute with the specified name.</returns>
public static bool TryGetAttributeWithType(this ISymbol symbol, ITypeSymbol typeSymbol, out AttributeData? attributeData)
/// <summary>
/// Tries to get an attribute with the specified type.
/// </summary>
/// <param name="symbol">The input <see cref="ISymbol"/> instance to check.</param>
/// <param name="typeSymbol">The <see cref="ITypeSymbol"/> instance for the attribute type to look for.</param>
/// <param name="attributeData">The resulting attribute, if it was found.</param>
/// <returns>Whether or not <paramref name="symbol"/> has an attribute with the specified name.</returns>
public static bool TryGetAttributeWithType(this ISymbol symbol, ITypeSymbol typeSymbol, out AttributeData? attributeData)
{
foreach (AttributeData attribute in symbol.GetAttributes())
{
foreach (AttributeData attribute in symbol.GetAttributes())
if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, typeSymbol))
{
if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, typeSymbol))
{
attributeData = attribute;
attributeData = attribute;

return true;
}
return true;
}
}

attributeData = null;
attributeData = null;

return false;
}
return false;
}
}
Loading

0 comments on commit cda4a4d

Please sign in to comment.