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
19 changes: 9 additions & 10 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,16 @@
Package versions made consistent across all packages referenced in this repository
-->
<ItemGroup>
<!-- Roslyn Analyzers ***MUST*** target older framework -->
<PackageVersion Include="AnsiCodes" Version="0.2.1" />
<PackageVersion Include="DiffPlex" Version="1.9.0" />
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="6.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis" Version="5.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="5.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Features" Version="5.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing" Version="1.1.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic" Version="5.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic.Features" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing" Version="1.1.2" />
<PackageVersion Include="Basic.Reference.Assemblies" Version="1.8.4" />

<!-- Until https://github.com/jaredpar/basic-reference-assemblies/issues/78 is resolved these are a specific version ref -->
Expand All @@ -41,13 +38,13 @@
<PackageVersion Include="Basic.Reference.Assemblies.Net100" Version="1.8.4" />
<PackageVersion Include="PolySharp" Version="1.15.0" />
<PackageVersion Include="System.Buffers" Version="4.6.1" />
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
<PackageVersion Include="System.Collections.Immutable" Version="9.0.0" />
<PackageVersion Include="System.Memory" Version="4.5.5" />
<PackageVersion Include="System.CommandLine" Version="2.0.0" />
<PackageVersion Include="System.CommandLine" Version="2.0.1" />

<!-- Security vulnerability overrides -->
<!-- https://github.com/dotnet/roslyn-sdk/issues/1191 -->
<PackageVersion Include="System.Formats.Asn1" Version="10.0.0" />
<PackageVersion Include="System.Formats.Asn1" Version="10.0.1" />
<!-- https://github.com/advisories/GHSA-7jgj-8wvc-jh57 -->
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<!-- https://github.com/advisories/GHSA-cmhx-cq75-c4mj -->
Expand All @@ -66,8 +63,10 @@
<PackageVersion Include="MSTest.TestAdapter" Version="4.0.2" />
<PackageVersion Include="MSTest.TestFramework" Version="4.0.2" />
<PackageVersion Include="Tmds.ExecFunction" Version="0.8.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing" Version="1.1.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing" Version="1.1.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.CodeRefactoring.Testing" Version="1.1.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing" Version="1.1.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing" Version="1.1.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.CodeRefactoring.Testing" Version="1.1.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing" Version="1.1.3" />
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing" Version="1.1.3" />
</ItemGroup>
</Project>
</Project>
2 changes: 1 addition & 1 deletion Invoke-Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ try
try
{
dir (Join-Path $BuildInfo['BuildOutputPath'] 'bin' 'Ubiquity.NET.CommandLine.SrcGen.UT' "$Configuration" 'net10.0' 'Ubiquity.NET.CommandLine.*')
Invoke-External dotnet test Ubiquity.NET.Utils.slnx '-c' $Configuration '-tl:off' '--logger:trx' '--no-build' '-s' '.\x64.runsettings'
Invoke-External dotnet test Ubiquity.NET.Utils.slnx '-c' $Configuration '-tl:off' '--logger:trx' '--no-build' '-s' '.\.runsettings'
}
finally
{
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,13 @@ public static NamespaceQualifiedName GetNamespaceQualifiedName( this AttributeDa
? new( [], string.Empty )
: self.AttributeClass.GetNamespaceQualifiedName();
}

/// <summary>Gets the location from the <see cref="AttributeData.ApplicationSyntaxReference"/> if available</summary>
/// <param name="self"><see cref="AttributeData"/> to get the location from</param>
/// <returns>Location of the attribute or null if not available</returns>
public static Location? GetLocation( this AttributeData self )
{
return self.ApplicationSyntaxReference?.SyntaxTree.GetLocation( self.ApplicationSyntaxReference.Span );
}
}
}
9 changes: 9 additions & 0 deletions src/Ubiquity.NET.CodeAnalysis.Utils/CompilationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
// Mostly from: https://github.com/Sergio0694/PolySharp/blob/main/src/PolySharp.SourceGenerators/Extensions/CompilationExtensions.cs
// Reformatted and adapted to support repo guidelines

#if SUPPORT_VB
using Microsoft.CodeAnalysis.VisualBasic;
#endif

namespace Ubiquity.NET.CodeAnalysis.Utils
{
Expand All @@ -28,6 +30,12 @@ public static bool HasLanguageVersionAtLeastEqualTo( this Compilation compilatio
: csharpCompilation.LanguageVersion >= languageVersion;
}

// Support of VB is problematic as [RS1038](https://github.com/dotnet/roslyn/blob/main/docs/roslyn-analyzers/rules/RS1038.md)
// is aggressive and tests for ALL dependencies. So inclusion of a reference in a dependent assembly will trigger that
// To fully resolve this in a general means the language specific parts would need to pull out of this assembly and
// into a distinct one for that language. This is a bit overkill given the need to target any language other than C#
// is rather limited... Until such is needed, just leave out the VB support
#if SUPPORT_VB
/// <summary>Checks whether a given VB compilation is using at least a given language version.</summary>
/// <param name="compilation">The <see cref="Compilation"/> to consider for analysis.</param>
/// <param name="languageVersion">The minimum language version to check.</param>
Expand All @@ -39,6 +47,7 @@ public static bool HasLanguageVersionAtLeastEqualTo( this Compilation compilatio
? throw new ArgumentNullException( nameof( compilation ) )
: vbCompilation.LanguageVersion >= languageVersion;
}
#endif

/// <summary>Gets the runtime version by extracting the version from the assembly implementing <see cref="System.Object"/></summary>
/// <param name="self">Compilation to get the version information from</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,16 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Bcl.HashCode" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" />
<PackageReference Include="Microsoft.Bcl.HashCode" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" />
<!--
Support of VB is problematic as [RS1038](https://github.com/dotnet/roslyn/blob/main/docs/roslyn-analyzers/rules/RS1038.md)
is aggressive and tests for ALL dependencies. So inclusion of a reference in a dependent assembly will trigger that
To fully resolve this in a general means the language specific parts would need to pull out of this assembly and
into a distinct one for that language. This is a bit overkill given the need to target any language other than C#
is rather limited... Until such is needed, just leave out the VB support
-->
<!--<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" />-->
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ To support a meta package where the referenced packages may not exist at build t
The Build process for CSPROJ files will require resolving the referenced packages before it "generates" the NuSpec file.
The CSPROJ system for MSBUILD will try to restore referenced packages etc... and ultimately requires the ability to find
the listed dependencies. (They won't exist yet for this build/repo!) so either a mechanism to control build ordering EVEN
on NuGetRestore is needed, or this approach is used. Given the complexities of trying the former, this approach is used
on NuGet Restore is needed, or this approach is used. Given the complexities of trying the former, this approach is used
as it is simpler.
-->
<Project Sdk="Microsoft.Build.NoTargets">
Expand Down
121 changes: 121 additions & 0 deletions src/Ubiquity.NET.CommandLine.SrcGen.UT/CommandAnalyzerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.

namespace Ubiquity.NET.CommandLine.SrcGen.UT
{
[TestClass]
public class CommandAnalyzerTests
{
public TestContext TestContext { get; set; }

[TestMethod]
[DataRow( TestRuntime.Net8_0 )]
[DataRow( TestRuntime.Net10_0 )]
public async Task Empty_source_analyzes_clean( TestRuntime testRuntime )
{
var analyzerTest = CreateTestRunner( string.Empty, testRuntime );
await analyzerTest.RunAsync( TestContext.CancellationToken );
}

[TestMethod]
[DataRow( TestRuntime.Net8_0 )]
[DataRow( TestRuntime.Net10_0 )]
public async Task Option_attribute_without_command_triggers_diagnostic( TestRuntime testRuntime )
{
SourceText txt = GetSourceText( nameof(Option_attribute_without_command_triggers_diagnostic), "input.cs" );
var analyzerTest = CreateTestRunner( txt, testRuntime );

// (9,6): warning UNC001: Property attribute OptionAttribute is only allowed on a property in a type attributed with a command attribute. This use will be ignored by the generator.
analyzerTest.ExpectedDiagnostics.AddRange(
[
new DiagnosticResult("UNC001", DiagnosticSeverity.Warning).WithLocation(9, 6),
]
);

await analyzerTest.RunAsync( TestContext.CancellationToken );
}

[TestMethod]
[DataRow( TestRuntime.Net8_0 )]
[DataRow( TestRuntime.Net10_0 )]
public async Task FileValidation_attribute_without_command_triggers_diagnostic( TestRuntime testRuntime )
{
SourceText txt = GetSourceText( nameof(FileValidation_attribute_without_command_triggers_diagnostic), "input.cs" );
var analyzerTest = CreateTestRunner( txt, testRuntime );

// (10,6): warning UNC001: Property attribute FileValidationAttribute is only allowed on a property in a type attributed with a command attribute. This use will be ignored by the generator.
// (10,6): error UNC002: Property attribute FileValidationAttribute is not allowed on a property independent of a qualifying attribute such as OptionAttribute.
analyzerTest.ExpectedDiagnostics.AddRange(
[
new DiagnosticResult("UNC001", DiagnosticSeverity.Warning).WithLocation(10, 6),
new DiagnosticResult("UNC002", DiagnosticSeverity.Error).WithLocation(10, 6),
]
);

await analyzerTest.RunAsync( TestContext.CancellationToken );
}

[TestMethod]
[DataRow( TestRuntime.Net8_0 )]
[DataRow( TestRuntime.Net10_0 )]
public async Task FolderValidation_attribute_without_command_triggers_diagnostic( TestRuntime testRuntime )
{
SourceText txt = GetSourceText( nameof(FolderValidation_attribute_without_command_triggers_diagnostic), "input.cs" );
var analyzerTest = CreateTestRunner( txt, testRuntime );

// (10,6): warning UNC001: Property attribute FolderValidationAttribute is only allowed on a property in a type attributed with a command attribute. This use will be ignored by the generator.
// (10,6): error UNC002: Property attribute FolderValidationAttribute is not allowed on a property independent of a qualifying attribute such as OptionAttribute.
analyzerTest.ExpectedDiagnostics.AddRange(
[
new DiagnosticResult("UNC001", DiagnosticSeverity.Warning).WithLocation(10, 6),
new DiagnosticResult("UNC002", DiagnosticSeverity.Error).WithLocation(10, 6),
]
);

await analyzerTest.RunAsync( TestContext.CancellationToken );
}

[TestMethod]
[DataRow( TestRuntime.Net8_0 )]
[DataRow( TestRuntime.Net10_0 )]
public async Task GoldenPath_produces_no_diagnostics( TestRuntime testRuntime )
{
SourceText txt = GetSourceText( nameof(GoldenPath_produces_no_diagnostics), "input.cs" );

var analyzerTest = CreateTestRunner( txt, testRuntime );
await analyzerTest.RunAsync( TestContext.CancellationToken );
}

private AnalyzerTest<MsTestVerifier> CreateTestRunner( string source, TestRuntime testRuntime )
{
return CreateTestRunner( SourceText.From( source ), testRuntime );
}

private AnalyzerTest<MsTestVerifier> CreateTestRunner( SourceText source, TestRuntime testRuntime )
{
// Use a test analyzer with language and reference assemblies that match the runtime for the test run
return new SourceAnalyzerTest<CommandLineAnalyzer, MsTestVerifier>( testRuntime.DefaultLangVersion )
{
TestState =
{
Sources = { source },
ReferenceAssemblies = testRuntime.ReferenceAssemblies,
AdditionalReferences =
{
TestContext.GetUbiquityNetCommandLineLib( testRuntime )
},
OutputKind = OutputKind.DynamicallyLinkedLibrary, // Don't require a Main() method
},

// Allow ALL diagnostics for testing, input source should contain valid C# code
// but might otherwise trigger the tested analyzer.
CompilerDiagnostics = CompilerDiagnostics.All,
};
}

private static SourceText GetSourceText( params string[] nameParts )
{
return TestHelpers.GetTestText( nameof( CommandAnalyzerTests ), nameParts );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
global using System.Collections.Immutable;
global using System.Diagnostics.CodeAnalysis;
global using System.IO;
global using System.Linq;
global using System.Runtime.InteropServices;
global using System.Text;

global using Basic.Reference.Assemblies;
global using System.Threading.Tasks;

global using Microsoft.CodeAnalysis;
global using Microsoft.CodeAnalysis.CSharp;
global using Microsoft.CodeAnalysis.Testing;
global using Microsoft.CodeAnalysis.Text;
global using Microsoft.VisualStudio.TestTools.UnitTesting;

global using Ubiquity.NET.SourceGenerator.Test.Utils;
global using Ubiquity.NET.SourceGenerator.Test.Utils.CSharp;
2 changes: 0 additions & 2 deletions src/Ubiquity.NET.CommandLine.SrcGen.UT/GlobalSuppression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,5 @@
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.

using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage( "StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Unit Tests" )]
[assembly: SuppressMessage( "StyleCop.CSharp.DocumentationRules", "SA1652:Enable XML documentation output", Justification = "Unit Tests" )]
Loading
Loading