Skip to content
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
32 changes: 25 additions & 7 deletions src/D2L.CodeStyle.Analyzers/Async/Generator/FileCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;

namespace D2L.CodeStyle.Analyzers.Async.Generator;

Expand Down Expand Up @@ -56,18 +57,26 @@ public static implicit operator PieceOfSyntax( SyntaxList<UsingDirectiveSyntax>
private readonly LinkedList<PieceOfSyntax[]> m_preambles = new();

private readonly StringBuilder m_out = new();
private readonly string? m_endOfLine;
private readonly Encoding m_encoding;

private FileCollector(
CompilationUnitSyntax root,
Dictionary<TypeDeclarationSyntax, IEnumerable<string>> methods
Dictionary<TypeDeclarationSyntax, IEnumerable<string>> methods,
string? endOfLine,
Encoding encoding
) {
m_root = root;
m_methods = methods;
m_endOfLine = endOfLine;
m_encoding = encoding;
}

public static FileCollector Create(
CompilationUnitSyntax root,
ImmutableArray<(TypeDeclarationSyntax Parent, string Source)> methods
ImmutableArray<(TypeDeclarationSyntax Parent, string Source)> methods,
string? endOfLine,
Encoding encoding
) {
var groupedMethods = methods
.GroupBy( static m => m.Parent )
Expand All @@ -76,15 +85,24 @@ public static FileCollector Create(
static g => g.Select( static m => m.Source )
);

return new FileCollector( root, groupedMethods );
return new FileCollector( root, groupedMethods, endOfLine, encoding );
}

public string CollectSource() {
public SourceText CollectSource() {
// TODO: Remove this and modify XML param elements in generator when changed/removed
m_out.AppendLine( "#pragma warning disable CS1572" );
if( m_endOfLine != null ) {
m_out.Append( "#pragma warning disable CS1572" + m_endOfLine );
} else {
m_out.AppendLine( "#pragma warning disable CS1572" );
}
// This allows us to copy+paste annotations but otherwise does not emit diagnostics
// otherwise we get "CS8669: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source."
m_out.AppendLine( "#nullable enable annotations" );
if( m_endOfLine != null ) {
m_out.Append( "#nullable enable annotations" + m_endOfLine );
} else {
m_out.AppendLine( "#nullable enable annotations" );
}

// File-scoped usings:
m_out.Append( m_root.Usings.ToFullString() );

Expand All @@ -98,7 +116,7 @@ public string CollectSource() {
throw new BugException( "left over methods" );
}

return m_out.ToString();
return SourceText.From( m_out.ToString(), m_encoding );
}

private bool WriteChildren( SyntaxNode node ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;

namespace D2L.CodeStyle.Analyzers.Async.Generator;

Expand All @@ -23,7 +24,7 @@ ImmutableArray<Diagnostic> Diagnostics
/// </summary>
private readonly record struct FileGenerationResult(
string HintName,
string GeneratedSource,
SourceText GeneratedSource,
ImmutableArray<Diagnostic> Diagnostics
);
}
33 changes: 30 additions & 3 deletions src/D2L.CodeStyle.Analyzers/Async/Generator/SyncGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
Expand All @@ -8,6 +9,8 @@ namespace D2L.CodeStyle.Analyzers.Async.Generator;

[Generator]
internal sealed partial class SyncGenerator : IIncrementalGenerator {
private static readonly Encoding UTF8WithoutBom = new UTF8Encoding( encoderShouldEmitUTF8Identifier: false );

public void Initialize( IncrementalGeneratorInitializationContext context ) {
var options = context.AnalyzerConfigOptionsProvider
.Select( ParseConfig );
Expand Down Expand Up @@ -38,7 +41,8 @@ public void Initialize( IncrementalGeneratorInitializationContext context ) {
// that when any file with [GenerateSync] has changed.
IncrementalValuesProvider<FileGenerationResult> generatedFiles =
generatedMethods.Collect()
.SelectMany( GenerateFiles );
.Combine( context.AnalyzerConfigOptionsProvider )
.SelectMany( ( x, ct ) => GenerateFiles( x.Left, x.Right, ct ) );

context.RegisterSourceOutput( generatedFiles, WriteFiles );
}
Expand Down Expand Up @@ -132,6 +136,7 @@ CancellationToken cancellationToken

private static IEnumerable<FileGenerationResult> GenerateFiles(
ImmutableArray<MethodGenerationResult> methodResults,
AnalyzerConfigOptionsProvider configOptionsProvider,
CancellationToken cancellationToken
) {
var methodsByFile = methodResults
Expand Down Expand Up @@ -161,9 +166,31 @@ CancellationToken cancellationToken
generatedMethods.Add( ((method.Original.Parent as TypeDeclarationSyntax)!, method.GeneratedSyntax ) );
}

var fileOptions = configOptionsProvider.GetOptions( file.Data.Key.SyntaxTree );

fileOptions.TryGetValue( "end_of_line", out var endOfLineValue );
var endOfLine = endOfLineValue?.Trim() switch {
"crlf" => "\r\n",
"lf" => "\n",
"cr" => "\r",
_ => null,
};

fileOptions.TryGetValue( "charset", out var charsetValue );
var encoding = charsetValue?.Trim().ToLower() switch {
"latin-1" => Encoding.GetEncoding( "iso-8859-1" ),
"utf-8" => UTF8WithoutBom,
"utf-8-bom" => Encoding.UTF8,
"utf-16le" => Encoding.Unicode,
"utf-16be" => Encoding.BigEndianUnicode,
_ => Encoding.Default,
};

var collector = FileCollector.Create(
file.Data.Key,
generatedMethods.ToImmutable()
generatedMethods.ToImmutable(),
endOfLine,
encoding
);

var generatedFile = collector.CollectSource();
Expand All @@ -186,7 +213,7 @@ FileGenerationResult result

context.AddSource(
hintName: result.HintName,
source: result.GeneratedSource
sourceText: result.GeneratedSource
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Title>D2L.CodeStyle.Analyzers</Title>
<Product>D2L.CodeStyle</Product>
<Description>D2L.CodeStyle analyzers</Description>
<Version>0.220.0</Version>
<Version>0.221.0</Version>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/Brightspace/D2L.CodeStyle</PackageProjectUrl>
<Authors>D2L</Authors>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
Expand All @@ -20,12 +21,59 @@ void SomeMethod() {}

var collector = FileCollector.Create(
root,
ImmutableArray<(TypeDeclarationSyntax, string)>.Empty
ImmutableArray<(TypeDeclarationSyntax, string)>.Empty,
endOfLine: null,
encoding: Encoding.Default
);

Assert.AreEqual( @"#pragma warning disable CS1572
#nullable enable annotations
", collector.CollectSource() );
", collector.CollectSource().ToString() );
}

[TestCase( "\n" )]
[TestCase( "\r\n" )]
public void EndOfLine( string endOfLine ) {
var source = string.Join( endOfLine, [
"",
"using Foo;",
"",
"namespace X;",
"",
"public sealed class Y {",
" void MyMethodBefore() {",
" Console.WriteLine( \"Hello\" );",
" }",
"}",
] );

var root = CSharpSyntaxTree.ParseText( source ).GetCompilationUnitRoot();

SyntaxNode myMethodBefore = root.DescendantNodes().OfType<MethodDeclarationSyntax>().Single();

var collector = FileCollector.Create(
root,
ImmutableArray.Create(
((TypeDeclarationSyntax)myMethodBefore.Parent, "\tany text" + endOfLine)
),
endOfLine: endOfLine,
encoding: Encoding.Default
);

var expected = string.Join( endOfLine, [
"#pragma warning disable CS1572",
"#nullable enable annotations",
"",
"using Foo;",
"",
"namespace X;",
"",
"partial class Y {",
" any text",
"}",
] );

Assert.AreEqual( expected, collector.CollectSource().ToString() );
}

[Test]
Expand All @@ -49,7 +97,9 @@ void MyMethodBefore() {
root,
ImmutableArray.Create(
((TypeDeclarationSyntax)myMethodBefore.Parent, "\tany text\r\n")
)
),
endOfLine: null,
encoding: Encoding.Default
);

Assert.AreEqual( @"#pragma warning disable CS1572
Expand All @@ -62,7 +112,7 @@ namespace X;
partial class Y {
any text
}",
collector.CollectSource()
collector.CollectSource().ToString()
);
}

Expand All @@ -87,7 +137,9 @@ void MyMethodBefore() {
root,
ImmutableArray.Create(
((TypeDeclarationSyntax)myMethodBefore.Parent, "\tany text\r\n")
)
),
endOfLine: null,
encoding: Encoding.Default
);

Assert.AreEqual( @"#pragma warning disable CS1572
Expand All @@ -100,7 +152,7 @@ namespace X;
partial class Y<T, U> {
any text
}",
collector.CollectSource()
collector.CollectSource().ToString()
);
}
[TestCase( "class" )] // static/selaed come before partial and don't need to show up in the other partials
Expand All @@ -123,7 +175,9 @@ void MyMethodBefore() {{
root,
ImmutableArray.Create(
((TypeDeclarationSyntax)myMethodBefore.Parent, "\tany text\r\n")
)
),
endOfLine: null,
encoding: Encoding.Default
);

Assert.AreEqual( @$"#pragma warning disable CS1572
Expand All @@ -132,7 +186,7 @@ void MyMethodBefore() {{
partial {kind} X {{
any text
}}",
collector.CollectSource()
collector.CollectSource().ToString()
);
}

Expand Down Expand Up @@ -163,7 +217,9 @@ class Ignored2 {}
root,
ImmutableArray.Create(
((TypeDeclarationSyntax)myMethodBefore.Parent, "\t\t\t\tany text\r\n")
)
),
endOfLine: null,
encoding: Encoding.Default
);

Assert.AreEqual( @"#pragma warning disable CS1572
Expand All @@ -181,7 +237,7 @@ any text
}
}
}",
collector.CollectSource()
collector.CollectSource().ToString()
);
}

Expand Down Expand Up @@ -245,7 +301,9 @@ void MyBeforeMethod4() { }

var collector = FileCollector.Create(
root,
myMethodsBefore.ToImmutableArray()
myMethodsBefore.ToImmutableArray(),
endOfLine: null,
encoding: Encoding.Default
);

Assert.AreEqual( @"#pragma warning disable CS1572
Expand Down Expand Up @@ -284,7 +342,7 @@ any text3
}
}
",
collector.CollectSource()
collector.CollectSource().ToString()
);
}
}
Loading