Skip to content

Commit

Permalink
Ability to control using position with file scoped namespaces (#170)
Browse files Browse the repository at this point in the history
* Slight refactor of the compilation unit strategies, ability to control using position with file scoped namespaces

* Switching to replacenode for target types

* Adding more regen tests

* VS2019 compatibility

* Stop filescoped tests running in 2019 build

* Urgh
  • Loading branch information
mattwhitfield authored Dec 16, 2022
1 parent efbdf70 commit 2e9b3ee
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 61 deletions.
71 changes: 71 additions & 0 deletions src/Unitverse.Core.Tests/RegenerationTestClasses.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/Unitverse.Core.Tests/RegenerationTestClasses.resx
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@
<data name="Regeneration-AutoFixture" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\Regeneration-AutoFixture.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="Regeneration-FileScopedUsingsOutside" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\Regeneration-FileScopedUsingsOutside.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="Regeneration-FileScopedUsingsOutsideMultipleClasses" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\Regeneration-FileScopedUsingsOutsideMultipleClasses.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="Regeneration-SampleClass" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\Regeneration-SampleClass.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// # EmitUsingsOutsideNamespace=true
// # GenerateFileScopedNamespaces=true
namespace TestNamespace.SubNameSpace;

public class TestClass
{
public TestClass(string stringProp)
{

}

public void ThisIsAMethod(string methodName, int methodValue)
{
System.Console.WriteLine("Testing this");
}

public string WillReturnAString()
{
return "Hello";
}
}
-------------------
namespace TestNamespace.SubNameSpace;

public class TestClass
{
public TestClass(string stringProp)
{

}

public void ThisIsAMethod(string methodName, int methodValue)
{
System.Console.WriteLine("Testing this");
}

public string WillReturnAString()
{
return "Hello";
}

public string WillAlsoReturnAString(string input)
{
return "Hello";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// # EmitUsingsOutsideNamespace=true
// # GenerateFileScopedNamespaces=true
namespace TestNamespace.SubNameSpace;

public class TestClass
{
public TestClass(string stringProp)
{

}

public void ThisIsAMethod(string methodName, int methodValue)
{
System.Console.WriteLine("Testing this");
}

public string WillReturnAString()
{
return "Hello";
}
}

public class C2
{
public void SomeMethod() { }
}
-------------------
namespace TestNamespace.SubNameSpace;

public class TestClass
{
public TestClass(string stringProp)
{

}

public void ThisIsAMethod(string methodName, int methodValue)
{
System.Console.WriteLine("Testing this");
}

public string WillReturnAString()
{
return "Hello";
}

public string WillAlsoReturnAString(string input)
{
return "Hello";
}
}

public class C2
{
public void SomeMethod() { }

public void SomeOtherMethod() { }
}
2 changes: 1 addition & 1 deletion src/Unitverse.Core.Tests/UnitTestGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public static IEnumerable<object[]> TestClassResourceNames
foreach (var resourceName in entryKeys)
{
#if VS2019
if (resourceName.StartsWith("FileScopedNamespaces", StringComparison.OrdinalIgnoreCase))
if (resourceName.IndexOf("FileScoped", StringComparison.OrdinalIgnoreCase) >= 0)
{
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Unitverse.Core.Tests/UnitTestRegenerationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public static IEnumerable<object[]> TestClassResourceNames
foreach (var resourceName in entryKeys)
{
#if VS2019
if (resourceName.StartsWith("FileScopedNamespaces", StringComparison.OrdinalIgnoreCase))
if (resourceName.IndexOf("FileScoped", StringComparison.OrdinalIgnoreCase) >= 0)
{
continue;
}
Expand Down
40 changes: 9 additions & 31 deletions src/Unitverse.Core/Generation/BlockScopedNamespaceStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,60 +8,38 @@
public class BlockScopedNamespaceStrategy : CompilationUnitStrategy
{
public BlockScopedNamespaceStrategy(SemanticModel sourceModel, SyntaxNode? targetNode, IGenerationItem generationItem, DocumentOptionSet? documentOptions, CompilationUnitSyntax targetCompilationUnit, NamespaceDeclarationSyntax targetNamespace, NamespaceDeclarationSyntax? originalTargetNamespace)
: base(sourceModel, targetNode, generationItem, documentOptions)
: base(sourceModel, targetNode, generationItem, documentOptions, targetCompilationUnit, targetNamespace, originalTargetNamespace)
{
_targetNamespace = targetNamespace;
_compilation = targetCompilationUnit;
_originalTargetNamespace = originalTargetNamespace;
}

private NamespaceDeclarationSyntax _targetNamespace;

private CompilationUnitSyntax _compilation;

private NamespaceDeclarationSyntax? _originalTargetNamespace;

public override SyntaxNode TargetRoot => _targetNamespace;
public override SyntaxNode TargetRoot => TargetNamespace;

public override void AddTypeToTarget(TypeDeclarationSyntax targetType, TypeDeclarationSyntax? originalTargetType)
{
if (originalTargetType == null)
{
originalTargetType = _targetNamespace.DescendantNodes().OfType<TypeDeclarationSyntax>().FirstOrDefault(x => x.Identifier.ValueText == targetType.Identifier.ValueText);
originalTargetType = TargetNamespace.DescendantNodes().OfType<TypeDeclarationSyntax>().FirstOrDefault(x => x.Identifier.ValueText == targetType.Identifier.ValueText);
}

if (originalTargetType != null)
{
var newTargetNamespace = _targetNamespace.RemoveNode(originalTargetType, SyntaxRemoveOptions.KeepNoTrivia);
_targetNamespace = newTargetNamespace ?? _targetNamespace;
var newTargetNamespace = TargetNamespace.RemoveNode(originalTargetType, SyntaxRemoveOptions.KeepNoTrivia);
TargetNamespace = newTargetNamespace ?? TargetNamespace;
}

_targetNamespace = _targetNamespace.AddMembers(targetType);
}

protected override void AddUsingToTarget(UsingDirectiveSyntax usingDirective)
{
if (GenerationItem.Options.GenerationOptions.EmitUsingsOutsideNamespace)
{
_compilation = _compilation.AddUsings(usingDirective);
}
else
{
_targetNamespace = _targetNamespace.AddUsings(usingDirective);
}
TargetNamespace = TargetNamespace.AddMembers(targetType);
}

public override CompilationUnitSyntax RenderCompilationUnit()
{
EmitUsingStatements();

if (_originalTargetNamespace != null)
if (OriginalTargetNamespace != null)
{
var newCompilation = _compilation.RemoveNode(_originalTargetNamespace, SyntaxRemoveOptions.KeepNoTrivia);
_compilation = newCompilation ?? _compilation;
return Compilation.ReplaceNode(OriginalTargetNamespace, TargetNamespace);
}

return _compilation.AddMembers(_targetNamespace);
return Compilation.AddMembers(TargetNamespace);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ protected override ICompilationUnitStrategy InitializeInternal(SyntaxNode? targe

if (targetTree != null)
{
compilation = targetTree.AncestorsAndSelf().OfType<CompilationUnitSyntax>().FirstOrDefault() ?? SyntaxFactory.CompilationUnit();
compilation = targetTree.AncestorsAndSelf().OfType<CompilationUnitSyntax>().FirstOrDefault();
originalTargetNamespace = targetNamespace = targetTree.DescendantNodesAndSelf().OfType<NamespaceDeclarationSyntax>().FirstOrDefault(x => string.Equals(x.Name.ToString(), TargetNamespaceName, StringComparison.OrdinalIgnoreCase)) ?? targetTree.DescendantNodesAndSelf().OfType<NamespaceDeclarationSyntax>().FirstOrDefault();
}

Expand Down
30 changes: 28 additions & 2 deletions src/Unitverse.Core/Generation/CompilationUnitStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@
using Unitverse.Core.Helpers;
using Unitverse.Core.Models;

#if VS2022
using BaseNamespace = Microsoft.CodeAnalysis.CSharp.Syntax.BaseNamespaceDeclarationSyntax;
#else
using BaseNamespace = Microsoft.CodeAnalysis.CSharp.Syntax.NamespaceDeclarationSyntax;
#endif

public abstract class CompilationUnitStrategy : ICompilationUnitStrategy
{
public CompilationUnitStrategy(SemanticModel sourceModel, SyntaxNode? targetTree, IGenerationItem generationItem, DocumentOptionSet? documentOptions)
public CompilationUnitStrategy(SemanticModel sourceModel, SyntaxNode? targetTree, IGenerationItem generationItem, DocumentOptionSet? documentOptions, CompilationUnitSyntax compilation, BaseNamespace targetNamespace, BaseNamespace? originalTargetNamespace)
{
SourceModel = sourceModel;
GenerationItem = generationItem;
Expand All @@ -25,6 +31,10 @@ public CompilationUnitStrategy(SemanticModel sourceModel, SyntaxNode? targetTree
_usingsEmitted.Add(syntax.NormalizeWhitespace().ToFullString());
}
}

Compilation = compilation;
TargetNamespace = targetNamespace;
OriginalTargetNamespace = originalTargetNamespace;
}

public SemanticModel SourceModel { get; }
Expand All @@ -33,6 +43,12 @@ public CompilationUnitStrategy(SemanticModel sourceModel, SyntaxNode? targetTree

public DocumentOptionSet? DocumentOptions { get; }

protected CompilationUnitSyntax Compilation { get; set; }

protected BaseNamespace TargetNamespace { get; set; }

protected BaseNamespace? OriginalTargetNamespace { get; set; }

private HashSet<string> _usingsEmitted = new HashSet<string>();

private List<UsingDirectiveSyntax> _addedUsings = new List<UsingDirectiveSyntax>();
Expand Down Expand Up @@ -96,7 +112,17 @@ protected void EmitUsingStatements()
}
}

protected abstract void AddUsingToTarget(UsingDirectiveSyntax usingDirective);
protected void AddUsingToTarget(UsingDirectiveSyntax usingDirective)
{
if (GenerationItem.Options.GenerationOptions.EmitUsingsOutsideNamespace)
{
Compilation = Compilation.AddUsings(usingDirective);
}
else
{
TargetNamespace = TargetNamespace.AddUsings(usingDirective);
}
}

public abstract void AddTypeToTarget(TypeDeclarationSyntax targetType, TypeDeclarationSyntax? originalTargetType);

Expand Down
Loading

0 comments on commit 2e9b3ee

Please sign in to comment.