Skip to content

Commit 7d37b97

Browse files
authored
Updated extension analyzer to latest support (#340)
* Sadly not only the use of the `extension` keyword has issues but so do analyzers intended to find such usage. - For now the only options is a RegEx source level find across the entire solution for `extension(?([^\r\n])\s)*\(` [Match case] * Updated System.CommandLine to latest build - Updated tests to account for known issues resolved - Still has [Bug 2664](dotnet/command-line-api#2664) where it treats `--version` as a value of a preceding property instead of an error that the option isn't used alone. * Added comments to various extension classes why it is NOT allowed to use the `extension` keyword yet. - Hopefully this changes soon after launch of .NET 10, we'll see.
1 parent 4e55266 commit 7d37b97

File tree

85 files changed

+267
-188
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+267
-188
lines changed

Directory.Packages.props

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@
2727
<PackageVersion Include="Basic.Reference.Assemblies.Net80" Version="1.8.3" />
2828
<PackageVersion Include="System.Buffers" Version="4.6.1" />
2929
<PackageVersion Include="System.Collections.Immutable" Version="9.0.8" />
30-
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta7.25380.108" />
30+
<PackageVersion Include="System.CommandLine" Version="2.0.0-rc.2.25502.107" />
3131

32+
<!-- Security vulnerability overrides -->
3233
<!-- Workaround(2): https://github.com/dotnet/roslyn-sdk/issues/1191 -->
3334
<PackageVersion Include="System.Formats.Asn1" Version="9.0.10" />
3435

src/Analyzers/ReadMe.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Repository Analyzers
2+
This folder contains the analyzers that are specific to this repository. They are not
3+
generalized to a package as they are very specific to the code in this repo.
4+
5+
## Extension Keyword Analyzer
6+
This repository does NOT use the new C# 14 extension syntax due to several reasons.
7+
1) Code lens does not work https://github.com/dotnet/roslyn/issues/79006
8+
1. Sadly marked as "not planned" - e.g., dead-end
9+
1. [New issue created](https://developercommunity.visualstudio.com/t/VS2026-Codelens-does-not-appearwork-f/10988233)
10+
2) MANY analyzers get things wrong and need to be supressed
11+
1. (CA1000, CA1034, and many others [SAxxxx])
12+
3) Many tools (like docfx) don't support the new syntax yet.
13+
4) No clear support for Caller* attributes on the extended symbol
14+
1. Example: `[CallerArgumentExpression(...)]`.
15+
16+
Bottom line it's a good idea with an incomplete implementation lacking support in the
17+
overall ecosystem. Don't use it unless you absolutely have to until all of that is sorted
18+
out.
19+
20+
>[!IMPORTANT]
21+
>Due to a [bug](https://developercommunity.visualstudio.com/t/VS2026--NET-10-Cant-test-analyzer-fo/10989212),
22+
>the extension keyword banned analyzer doesn't actually run and is not testable. Hopefully,
23+
>this is fixed soon as it's a major PITA not to work correctly for any new syntax. For now,
24+
>a Regex search using `extension(?([^\r\n])\s)*\(` is all that can be done...
25+
26+
# Reference Equality Analyzer
27+
Reference equality is usually the wrong behavior for comparing wrapped LLVM types. This, is
28+
a significant breaking change from older releases of this library. However, due to issues
29+
with cacheing (and more importantly, resolving) the correct thing (disposable or just an
30+
alias?) - the behavior had to change and reference equality is broken. This analyzer reports
31+
issues if the code contains a reference equality (operator == on a ref type) when the type
32+
implements `IEquatable<T>`. This eliminates source use assumptions in this library making
33+
the transition easier and preventing new cases of problems.

src/Analyzers/RepositoryVerifier.UT/ExtensionsKeywordAnalyzerTests.cs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
22
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.
33

4-
// due to bug in Nuget publication, this can't be tested yet...
5-
// see: https://developercommunity.visualstudio.com/t/VS2026--NET-10-Cant-build-analyzier/10989212
6-
#if NET10_0_OR_GREATER
4+
// This isn't a normal built-in define; but follows the pattern for built-in defines and expresses the intent.
5+
// There is no Known way to "light up" at runtime for functionality available in newer versions
6+
#if COMPILER_5_OR_GREATER
77
using System.Threading.Tasks;
88

99
using Microsoft.CodeAnalysis;
@@ -25,7 +25,7 @@ public class ExtensionsKeywordAnalyzerTests
2525
public async Task EmptySourceAnalyzesClean( )
2626
{
2727
var analyzerTest = CreateTestRunner(string.Empty);
28-
await analyzerTest.RunAsync( TestContext.CancellationTokenSource.Token );
28+
await analyzerTest.RunAsync( TestContext.CancellationToken );
2929
}
3030

3131
[TestMethod]
@@ -34,11 +34,11 @@ public async Task UsingKeywordReportsDiagnostic( )
3434
var analyzerTest = CreateTestRunner(ExtensionKeywordUsed);
3535
analyzerTest.ExpectedDiagnostics.AddRange(
3636
[
37-
new DiagnosticResult("UNL002", DiagnosticSeverity.Error).WithLocation(5, 5)
37+
new DiagnosticResult("UNL002", DiagnosticSeverity.Error).WithLocation( 5, 5 ),
3838
]
3939
);
4040

41-
await analyzerTest.RunAsync( TestContext.CancellationTokenSource.Token );
41+
await analyzerTest.RunAsync( TestContext.CancellationToken );
4242
}
4343

4444
[TestMethod]
@@ -47,7 +47,7 @@ public async Task StructEquatableIsNotReferenceEquality( )
4747
var analyzerTest = CreateTestRunner(NoExtensionKeywordUsed);
4848

4949
// no diagnostics expected
50-
await analyzerTest.RunAsync( TestContext.CancellationTokenSource.Token );
50+
await analyzerTest.RunAsync( TestContext.CancellationToken );
5151
}
5252

5353
private static AnalyzerTest<DefaultVerifier> CreateTestRunner( string source )
@@ -62,17 +62,17 @@ private static AnalyzerTest<DefaultVerifier> CreateTestRunner( string source )
6262
};
6363
}
6464

65-
private class ExtensionKeywordAnalyzerTest
66-
: CSharpAnalyzerTest<ExtensionKeywordAnalyzer, DefaultVerifier>
65+
private class ExtensionKeywordAnalyzerTest
66+
: CSharpAnalyzerTest<ExtensionKeywordAnalyzer, DefaultVerifier>
6767
{
6868
protected override ParseOptions CreateParseOptions( )
6969
{
70-
// Until C# 14 and .NET SDK 10 is formally released, it is considered "Preview"
71-
return new CSharpParseOptions(LanguageVersion.Preview, DocumentationMode.Diagnose);
70+
// Until C# 14 and .NET SDK 10 is formally released, the language version is considered "Preview"
71+
return new CSharpParseOptions( LanguageVersion.Preview, DocumentationMode.Diagnose );
7272
}
7373
}
7474

75-
private const string ExtensionKeywordUsed = """
75+
private const string ExtensionKeywordUsed = """
7676
using System;
7777
7878
public static class TestExtension
@@ -85,9 +85,13 @@ public string MyExtension()
8585
}
8686
}
8787
}
88+
89+
file class Foo
90+
{
91+
}
8892
""";
8993

90-
private const string NoExtensionKeywordUsed = """
94+
private const string NoExtensionKeywordUsed = """
9195
using System;
9296
9397
public static class TestExtension

src/Analyzers/RepositoryVerifier/ExtensionKeywordAnalyzer.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
22
// Licensed under the Apache-2.0 WITH LLVM-exception license. See the LICENSE.md file in the project root for full license information.
33

4+
// This isn't a normal built-in define; but follows the pattern for built-in defines and expresses the intent.
5+
// There is no Known way to "light up" at runtime for functionality available in newer versions
6+
#if COMPILER_5_OR_GREATER
47
using System.Collections.Immutable;
58

69
using Microsoft.CodeAnalysis;
@@ -23,7 +26,7 @@ public override void Initialize( AnalysisContext context )
2326
// ignore generated code
2427
context.ConfigureGeneratedCodeAnalysis( GeneratedCodeAnalysisFlags.None );
2528
context.EnableConcurrentExecution();
26-
context.RegisterSyntaxNodeAction( OnExtensionKeyword, SyntaxKind.ExtensionKeyword, SyntaxKind.ExtensionDeclaration );
29+
context.RegisterSyntaxNodeAction( OnExtensionKeyword, SyntaxKind.ExtensionKeyword, SyntaxKind.ExtensionBlockDeclaration );
2730
}
2831

2932
private void OnExtensionKeyword( SyntaxNodeAnalysisContext context )
@@ -32,3 +35,4 @@ private void OnExtensionKeyword( SyntaxNodeAnalysisContext context )
3235
}
3336
}
3437
}
38+
#endif

src/Analyzers/RepositoryVerifier/ReadMe.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ C# 14 `extension` keyword used. This is currently blocked in this repository. Ho
2626
this is short term but is not allowed. This prevents any current/experimental use and any
2727
future use. The experiments with using it have unveiled a lot of issues that make that an
2828
incomplete feature. "Complete" requires proper support in the majority of analyzers and
29-
third party tools.
29+
third party tools. That support does not exist yet.
3030

3131
## ReferenceEqualityAnalyzer
3232
This analyzer was designed to identify places within the Ubiquity.NET.Llvm library where the

src/Analyzers/RepositoryVerifier/ReferenceEqualityAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ private void BinaryOpAction( OperationAnalysisContext context )
4545
{
4646
try
4747
{
48-
if(!(context.Operation is IBinaryOperation op))
48+
if(context.Operation is not IBinaryOperation op)
4949
{
5050
throw new InvalidOperationException( "Unknown case; non-binary operation..." );
5151
}

src/Analyzers/RepositoryVerifier/RepositoryVerifier.csproj

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,13 @@
44
<TargetFramework>netstandard2.0</TargetFramework>
55
<LangVersion>12.0</LangVersion>
66
<Nullable>enable</Nullable>
7-
87
<IsPackable>false</IsPackable>
98
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
109
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
11-
12-
<!-- Avoid ID conflicts with the package project. -->
13-
<PackageId>*$(MSBuildProjectFile)*</PackageId>
1410
<NeutralLanguage>en-US</NeutralLanguage>
1511
</PropertyGroup>
1612

1713
<ItemGroup>
18-
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers">
19-
<PrivateAssets>all</PrivateAssets>
20-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
21-
</PackageReference>
2214
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
2315
</ItemGroup>
2416

src/Interop/LlvmBindingsGenerator/LlvmBindingsGenerator.csproj

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@
2020
<PackageReference Include="CppSharp" PrivateAssets="all" />
2121
<PackageReference Include="System.CodeDom" PrivateAssets="all" />
2222

23-
<!-- Sadly, the version range syntax doesn't work for Directory.Package.props so it must be provided here-->
23+
<!-- Sadly, the version range syntax doesn't work for Directory.Package.props so it must be provided here -->
2424
<!--
2525
NOTE: This isn't directly used by this project. However, it allows for scripts to restore this project, which
26-
guarantees the package is available, so they can use the contained headers as input to the application built
27-
by this project.
26+
guarantees the package is available, so that running it can use the contained headers as input.
2827
-->
2928
<PackageReference Include="Ubiquity.NET.LibLLVM" VersionOverride="20.1.*-*" GeneratePathProperty="true" PrivateAssets="all" />
3029
</ItemGroup>
@@ -57,10 +56,10 @@
5756
<!--
5857
This target is triggered externally to generate the response file for an invocation of the generator.
5958
The response file provides the paths for the headers based on the location of the package used by
60-
the build. Restoring this project will download and cache the package. This target allows creation
61-
of the response file to use for involving the application built by this project so that it has the
62-
actual headers from the package as input to the generator. This is all automated by the developer
63-
facing script to generate the headers.
59+
the build. Restoring this project will download and cache the LLVM package that includes the headers.
60+
This target allows creation of the response file to use for invoking the application built by this
61+
project so that it has the actual headers from the package as input to the generator. This is all
62+
automated by the developer facing script to generate the headers.
6463
SEE: Generate-HandleWrappers.ps1
6564
-->
6665
<Target Name="GenerateResponseFile">

src/Interop/Ubiquity.NET.Llvm.Interop/ArchitectureExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33

44
namespace Ubiquity.NET.Llvm.Interop
55
{
6+
// This does NOT use the new C# 14 extension syntax due to several reasons
7+
// 1) Code lens does not work https://github.com/dotnet/roslyn/issues/79006 [Sadly, marked as "not planned" - e.g., dead-end]
8+
// 2) MANY analyzers get things wrong and need to be supressed (CA1000, CA1034, and many others [SAxxxx])
9+
// 3) Many tools (like docfx) don't support the new syntax yet and it isn't clear if they will in the future.
10+
// 4) No clear support for Caller* attributes ([CallerArgumentExpression(...)]).
11+
//
12+
// Bottom line it's a good idea with an incomplete implementation lacking support
13+
// in the overall ecosystem. Don't use it unless you absolutely have to until all
14+
// of that is sorted out.
15+
616
/// <summary>Utility class to implement extensions of <see cref="Architecture"/></summary>
717
public static class ArchitectureExtensions
818
{

src/Interop/Ubiquity.NET.Llvm.Interop/ContextHandleExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33

44
namespace Ubiquity.NET.Llvm.Interop
55
{
6+
// This does NOT use the new C# 14 extension syntax due to several reasons
7+
// 1) Code lens does not work https://github.com/dotnet/roslyn/issues/79006 [Sadly, marked as "not planned" - e.g., dead-end]
8+
// 2) MANY analyzers get things wrong and need to be supressed (CA1000, CA1034, and many others [SAxxxx])
9+
// 3) Many tools (like docfx) don't support the new syntax yet and it isn't clear if they will in the future.
10+
// 4) No clear support for Caller* attributes ([CallerArgumentExpression(...)]).
11+
//
12+
// Bottom line it's a good idea with an incomplete implementation lacking support
13+
// in the overall ecosystem. Don't use it unless you absolutely have to until all
14+
// of that is sorted out.
15+
616
/// <summary>Utility class to host extensions for an <see cref="IWrappedHandle{THandle}"/></summary>
717
public static class ContextHandleExtensions
818
{

0 commit comments

Comments
 (0)