Skip to content

Commit

Permalink
Add GlobalScope tests
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrstenke committed Jan 8, 2025
1 parent 0fba62c commit a65fc48
Show file tree
Hide file tree
Showing 21 changed files with 1,068 additions and 110 deletions.
15 changes: 15 additions & 0 deletions Durian.sln
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GlobalScope", "GlobalScope"
docs\GlobalScope\DUR0502.md = docs\GlobalScope\DUR0502.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Durian.GlobalScope.Tests", "tests\Durian.GlobalScope.Tests\Durian.GlobalScope.Tests.csproj", "{85288F0D-D16A-4C75-85E6-58B22F067604}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -458,6 +460,18 @@ Global
{643FFE0C-B641-4504-8F6A-0EA694F3DEF7}.Release|x64.Build.0 = Release|Any CPU
{643FFE0C-B641-4504-8F6A-0EA694F3DEF7}.Release|x86.ActiveCfg = Release|Any CPU
{643FFE0C-B641-4504-8F6A-0EA694F3DEF7}.Release|x86.Build.0 = Release|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Debug|x64.ActiveCfg = Debug|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Debug|x64.Build.0 = Debug|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Debug|x86.ActiveCfg = Debug|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Debug|x86.Build.0 = Debug|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Release|Any CPU.Build.0 = Release|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Release|x64.ActiveCfg = Release|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Release|x64.Build.0 = Release|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Release|x86.ActiveCfg = Release|Any CPU
{85288F0D-D16A-4C75-85E6-58B22F067604}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -492,6 +506,7 @@ Global
{9C383ACD-8C9E-4C24-B2EA-4326C7553866} = {D98DD137-AADE-4474-86EF-9F0874607687}
{643FFE0C-B641-4504-8F6A-0EA694F3DEF7} = {74D7ECF9-D1F6-46FA-B8D8-D34F86F713EA}
{A04BF577-5DEB-477A-A22C-3557852AC25B} = {BA3DE2E2-7B32-4612-8219-24FBCF850813}
{85288F0D-D16A-4C75-85E6-58B22F067604} = {F6EC89D8-4343-42A1-B6D6-B0022D3004A0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {09524C45-0D6D-4456-B89D-9673853B9FA0}
Expand Down
25 changes: 23 additions & 2 deletions src/Durian.AnalysisServices/DurianIncrementalGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,24 @@ namespace Durian.Analysis;
/// </summary>
public abstract class DurianIncrementalGenerator : DurianGeneratorBase, IIncrementalGenerator
{
private IHintNameProvider _hintNameProvider;

/// <summary>
/// <see cref="IHintNameProvider"/> that creates hint names for the generated source.
/// </summary>
/// <exception cref="ArgumentNullException">Value is <see langword="null"/>.</exception>
public IHintNameProvider HintNameProvider
{
get => _hintNameProvider;
set => _hintNameProvider = value ?? throw new ArgumentNullException(nameof(HintNameProvider));
}

/// <summary>
/// Initializes a new instance of the <see cref="DurianIncrementalGenerator"/> class.
/// </summary>
protected DurianIncrementalGenerator()
{
_hintNameProvider = CreateHintNameProvider();
}

/// <summary>
Expand All @@ -26,6 +39,7 @@ protected DurianIncrementalGenerator()
/// <exception cref="ArgumentNullException"><paramref name="logHandler"/> is <see langword="null"/>.</exception>
protected DurianIncrementalGenerator(IGeneratorLogHandler logHandler) : base(logHandler)
{
_hintNameProvider = CreateHintNameProvider();
}

/// <summary>
Expand All @@ -34,6 +48,7 @@ protected DurianIncrementalGenerator(IGeneratorLogHandler logHandler) : base(log
/// <param name="context">Configures how this generator is initialized.</param>
protected DurianIncrementalGenerator(in GeneratorLogCreationContext context) : base(in context)
{
_hintNameProvider = CreateHintNameProvider();
}

/// <summary>
Expand All @@ -42,6 +57,7 @@ protected DurianIncrementalGenerator(in GeneratorLogCreationContext context) : b
/// <param name="loggingConfiguration">Determines how the source generator should behave when logging information.</param>
protected DurianIncrementalGenerator(LoggingConfiguration? loggingConfiguration) : base(loggingConfiguration)
{
_hintNameProvider = CreateHintNameProvider();
}

/// <inheritdoc/>
Expand All @@ -65,7 +81,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
/// </summary>
/// <param name="compilation">Current compilation.</param>
/// <param name="context">The <see cref="IncrementalGeneratorInitializationContext"/> to register callbacks on</param>
protected abstract void Register(IncrementalValueProvider<Compilation> compilation, IncrementalGeneratorInitializationContext context);
protected internal abstract void Register(IncrementalValueProvider<Compilation> compilation, IncrementalGeneratorInitializationContext context);

/// <summary>
/// Adds the specified <paramref name="source"/> to the <paramref name="context"/>.
Expand All @@ -79,7 +95,7 @@ protected virtual void AddSource(string hintName, string source, SourceProductio
AddSource(hintName, tree, context);
}

/// <summary>
/// <summary>
/// Adds the specified <paramref name="source"/> to the <paramref name="context"/>.
/// </summary>
/// <param name="hintName">An identifier that can be used to reference this source text, must be unique within this generator.</param>
Expand All @@ -102,4 +118,9 @@ protected virtual void AddSource(string hintName, SyntaxTree syntaxTree, SourceP
context.AddSource(hintName, syntaxTree.GetText(context.CancellationToken));
LogSource(hintName, syntaxTree, context.CancellationToken);
}

private static SymbolNameHintProvider CreateHintNameProvider()
{
return new();
}
}
2 changes: 1 addition & 1 deletion src/Durian.AnalysisServices/DurianSourceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ protected internal override void BeforeFiltersWithGeneratedSymbols(TContext cont
pass.State = GeneratorState.Running;

pass.ParseOptions ??= context.ParseOptions;
pass.FileNameProvider ??= new SymbolNameToFile();
pass.FileNameProvider ??= new SymbolNameHintProvider();

FillContext(pass);

Expand Down
62 changes: 62 additions & 0 deletions src/Durian.AnalysisServices/StaticHintNameProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using Microsoft.CodeAnalysis;

namespace Durian.Analysis;

/// <summary>
/// <see cref="IHintNameProvider"/> implementation that always returns the same hint name.
/// </summary>
public sealed class StaticHintNameProvider : IHintNameProvider
{
private readonly string _hintName;

/// <summary>
/// Initializes a new instance of the <see cref="StaticHintNameProvider"/> class.
/// </summary>
/// <param name="hintName">Hint name to always return.</param>
public StaticHintNameProvider(string hintName)
{
if (string.IsNullOrWhiteSpace(hintName))
{
throw new ArgumentException("Value cannot be null or empty", nameof(hintName));
}

_hintName = hintName;
}

/// <summary>
/// Returns the current hint name.
/// </summary>
public string GetHintName()
{
return _hintName;
}

/// <inheritdoc/>
public void Initialize()
{
// Do nothing.
}

/// <inheritdoc/>
public void Reset()
{
// Do nothing.
}

/// <inheritdoc/>
public void Success()
{
// Do nothing.
}

string IHintNameProvider.GetHintName(ISymbol symbol)
{
return GetHintName();
}

string IHintNameProvider.GetHintName(string symbolName)
{
return GetHintName();
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
using System;
using Microsoft.CodeAnalysis;

namespace Durian.Analysis.Logging;
namespace Durian.Analysis;

/// <summary>
/// A <see cref="IHintNameProvider"/> that returns the name of the specified <see cref="ISymbol"/>.
/// </summary>
public sealed class SymbolNameToFile : IHintNameProvider
public sealed class SymbolNameHintProvider : IHintNameProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="SymbolNameToFile"/> class.
/// Initializes a new instance of the <see cref="SymbolNameHintProvider"/> class.
/// </summary>
public SymbolNameToFile()
public SymbolNameHintProvider()
{
}

Expand All @@ -23,11 +23,9 @@ public string GetHintName(ISymbol symbol)
throw new ArgumentNullException(nameof(symbol));
}

string name = symbol.ToString()
return symbol.ToString()
.Replace('<', '{')
.Replace('>', '}');

return name;
}

/// <inheritdoc/>
Expand All @@ -47,4 +45,14 @@ public void Success()
{
// Do nothing.
}

string IHintNameProvider.GetHintName()
{
throw new NotImplementedException($"{nameof(SymbolNameHintProvider)} does not support default hint names");
}

string IHintNameProvider.GetHintName(string symbolName)
{
return symbolName;
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis;
using System;

namespace Durian.Analysis.Logging;
namespace Durian.Analysis;

/// <summary>
/// Provides a method that creates a hint name for a specified <see cref="ISymbol"/>.
/// </summary>
public interface IHintNameProvider
{
/// <summary>
/// Returns the default hint name.
/// </summary>
string GetHintName();

/// <summary>
/// Returns a hint name for the specified <paramref name="symbol"/>.
/// </summary>
/// <param name="symbol"><see cref="ISymbol"/> to get the hint name for.</param>
/// <exception cref="ArgumentNullException"><paramref name="symbol"/> is <see langword="null"/>.</exception>
string GetHintName(ISymbol symbol);

/// <summary>
/// Returns a hint name for the specified <paramref name="symbolName"/>.
/// </summary>
/// <param name="symbolName">Symbol name.</param>
/// <exception cref="ArgumentException"><paramref name="symbolName"/> is <see langword="null"/> or empty.</exception>
string GetHintName(string symbolName);

/// <summary>
/// Initializes the provider.
/// </summary>
Expand Down
13 changes: 10 additions & 3 deletions src/Durian.GlobalScope/GlobalScopeDeclarationAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ protected override GlobalScopeCompilationData CreateCompilation(CSharpCompilatio

internal static bool Analyze(ISymbol symbol)
{
return symbol is INamedTypeSymbol type && Analyze(type, null);
return Analyze(symbol, null);
}

internal static bool Analyze(ISymbol symbol, Action<Diagnostic>? reportDiagnostic)
{
return symbol is INamedTypeSymbol type && Analyze(type, reportDiagnostic);
}

private static void Analyze(SymbolAnalysisContext context, GlobalScopeCompilationData compilation)
Expand All @@ -65,6 +70,7 @@ private static bool Analyze(INamedTypeSymbol type, Action<Diagnostic>? reportDia
{
Location? location = null;
string? name = null;
bool isValid = true;

if (!type.IsStatic && !ReportDiagnostic(DUR0501_TypeIsNotStaticClass))
{
Expand All @@ -76,17 +82,18 @@ private static bool Analyze(INamedTypeSymbol type, Action<Diagnostic>? reportDia
return false;
}

return true;
return isValid;

bool ReportDiagnostic(DiagnosticDescriptor descriptor)
{
isValid = false;

if (reportDiagnostic is not null)
{
location ??= type.Locations.FirstOrDefault();
name ??= type.GetFullyQualifiedName();

reportDiagnostic.Invoke(Diagnostic.Create(descriptor, location, name));

return true;
}

Expand Down
Loading

0 comments on commit a65fc48

Please sign in to comment.