-
Notifications
You must be signed in to change notification settings - Fork 511
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[RGen] First inclusion of a roslyn generator for the bindings. (#21389)
We are doing the following: 1. Adding the rgen directory with the following solutions: * Analyzer: Analyzer that will catch errors in the bindings. At the moment it provides a single error when the BindingTypeAttribute is used in a nont partial type. * Analyzer Tests: Allows tests for the analyzer. * Analyzer Sample: Sample project to test the analyzer. * Code Generator: A code generator that adds the BindingTypeAttribute to the compilcation. * Code Generator Tests: Allows tests for the generator. * Code Sample: Sample project for the code generator. 2. Make rule to build the roslyn code generator. 3. Makefile changes to add the code generator as part as the second compilation of the bindings. This changes add the starting gounds to move to roslyn. --------- Co-authored-by: GitHub Actions Autoformatter <github-actions-autoformatter@xamarin.com> Co-authored-by: Rolf Bjarne Kvinge <rolf@xamarin.com> Co-authored-by: Alex Soto <alex@soto.dev>
- Loading branch information
1 parent
6abfff6
commit 0f35909
Showing
49 changed files
with
1,176 additions
and
156 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Roslyn code generator | ||
ROSLYN_GENERATOR=$(DOTNET_BUILD_DIR)/common/rgen/Microsoft.Macios.Generator.dll | ||
ROSLYN_GENERATOR_FILES := $(wildcard rgen/Microsoft.Macios.Generator/*.cs) | ||
|
||
$(ROSLYN_GENERATOR): Makefile.rgenerator $(ROSLYN_GENERATOR_FILES) | ||
$(Q_DOTNET_BUILD) $(DOTNET) publish rgen/Microsoft.Macios.Generator/Microsoft.Macios.Generator.csproj $(DOTNET_BUILD_VERBOSITY) /p:Configuration=Debug /p:IntermediateOutputPath=$(abspath $(DOTNET_BUILD_DIR)/IDE/obj/common/rgen)/ /p:OutputPath=$(abspath $(DOTNET_BUILD_DIR)/IDE/bin/common/rgen/)/ | ||
@mkdir -p $(dir $@) | ||
$(Q) $(CP) -r $(DOTNET_BUILD_DIR)/IDE/bin/common/rgen/publish/* $(dir $@) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System; | ||
using System.Reflection; | ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace ObjCBindings { | ||
|
||
/// <summary> | ||
/// Attribute that indicates that a class or enum is a binding type. This attribute is used by the binding generator | ||
/// to generate all the necessary code for the binding. The attribute can be used in a class or enum and it is required. | ||
/// | ||
/// If the attribute is used in a class, the class must be partial otherwise the generator will fail. | ||
/// </summary> | ||
[Experimental ("APL0003")] | ||
[AttributeUsage (AttributeTargets.Class | System.AttributeTargets.Enum, AllowMultiple = false)] | ||
public class BindingTypeAttribute : Attribute { | ||
|
||
/// <summary> | ||
/// Indicates the name of the binding type. This is the name that will be used by the registrar to make the | ||
/// class available in the ObjC runtime. The default value is string.Empty, in that case the generator | ||
/// will use the name of the C# class. | ||
/// </summary> | ||
public string Name { get; set; } = string.Empty; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
src/rgen/Microsoft.Macios.Bindings.Analyzer.Sample/Examples.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
namespace Microsoft.Macios.Bindings.Analyzer.Sample; | ||
|
||
// If you don't see warnings, build the Analyzers Project. | ||
|
||
[BindingType] | ||
public class Examples { | ||
} | ||
|
||
[BindingType] | ||
public class Foo { | ||
|
||
} |
19 changes: 19 additions & 0 deletions
19
...icrosoft.Macios.Bindings.Analyzer.Sample/Microsoft.Macios.Bindings.Analyzer.Sample.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)</TargetFramework> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\Microsoft.Macios.Generator\Microsoft.Macios.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/> | ||
<ProjectReference Include="..\Microsoft.Macios.Bindings.Analyzer\Microsoft.Macios.Bindings.Analyzer.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Compile Include="..\..\..\src\bgen\Attributes.cs" > | ||
<Link>external\Attributes.cs</Link> | ||
</Compile> | ||
</ItemGroup> | ||
|
||
</Project> |
7 changes: 7 additions & 0 deletions
7
src/rgen/Microsoft.Macios.Bindings.Analyzer/AnalyzerReleases.Shipped.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
## Release 1.0 | ||
|
||
### New Rules | ||
|
||
| Rule ID | Category | Severity | Notes | | ||
|---------|----------|----------|------------------------------------------------------| | ||
| RBI0001 | Usage | Error | Binding types should be declared as partial classes. | |
4 changes: 4 additions & 0 deletions
4
src/rgen/Microsoft.Macios.Bindings.Analyzer/AnalyzerReleases.Unshipped.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
### New Rules | ||
|
||
| Rule ID | Category | Severity | Notes | | ||
|---------|----------|----------|-------| |
59 changes: 59 additions & 0 deletions
59
src/rgen/Microsoft.Macios.Bindings.Analyzer/BindingTypeCodeFixProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
using System.Collections.Immutable; | ||
using System.Composition; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CodeActions; | ||
using Microsoft.CodeAnalysis.CodeFixes; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
|
||
using SyntaxFactory = Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | ||
using SyntaxKind = Microsoft.CodeAnalysis.CSharp.SyntaxKind; | ||
|
||
namespace Microsoft.Macios.Bindings.Analyzer; | ||
|
||
/// <summary> | ||
/// Code fix provider that adds the 'partial' modifier to the class decorated with BindingTypeAttribute. | ||
/// </summary> | ||
[ExportCodeFixProvider (LanguageNames.CSharp, Name = nameof (BindingTypeCodeFixProvider)), Shared] | ||
public class BindingTypeCodeFixProvider : CodeFixProvider { | ||
// Specify the diagnostic IDs of analyzers that are expected to be linked. | ||
public sealed override ImmutableArray<string> FixableDiagnosticIds { get; } = | ||
ImmutableArray.Create (BindingTypeSemanticAnalyzer.DiagnosticId); | ||
|
||
// If you don't need the 'fix all' behaviour, return null. | ||
public override FixAllProvider? GetFixAllProvider () => null; | ||
|
||
public sealed override async Task RegisterCodeFixesAsync (CodeFixContext context) | ||
{ | ||
var diagnostic = context.Diagnostics.Single (); | ||
var diagnosticSpan = diagnostic.Location.SourceSpan; | ||
var root = await context.Document.GetSyntaxRootAsync (context.CancellationToken).ConfigureAwait (false); | ||
var diagnosticNode = root?.FindNode (diagnosticSpan); | ||
|
||
// To get the required metadata, we should match the Node to the specific type: 'ClassDeclarationSyntax'. | ||
if (diagnosticNode is not ClassDeclarationSyntax declaration) | ||
return; | ||
|
||
// Register a code action that will invoke the fix. | ||
context.RegisterCodeFix ( | ||
CodeAction.Create ( | ||
title: Resources.RBI0001CodeFixTitle, | ||
createChangedDocument: c => MakePartialClassAsync (context.Document, declaration, c), | ||
equivalenceKey: nameof (Resources.RBI0001CodeFixTitle)), | ||
diagnostic); | ||
} | ||
|
||
async Task<Document> MakePartialClassAsync (Document document, | ||
ClassDeclarationSyntax classDeclarationSyntax, CancellationToken cancellationToken) | ||
{ | ||
var partialClass = classDeclarationSyntax.AddModifiers (SyntaxFactory.Token (SyntaxKind.PartialKeyword)); | ||
var oldRoot = await document.GetSyntaxRootAsync (cancellationToken).ConfigureAwait (false); | ||
if (oldRoot is null) | ||
return document; | ||
|
||
var newRoot = oldRoot.ReplaceNode (classDeclarationSyntax, partialClass); | ||
return document.WithSyntaxRoot (newRoot); | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
src/rgen/Microsoft.Macios.Bindings.Analyzer/BindingTypeSemanticAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
|
||
namespace Microsoft.Macios.Bindings.Analyzer; | ||
|
||
/// <summary> | ||
/// Analyzer that ensures that the types that have been declared as binding types are partial and follow the correct | ||
/// pattern. | ||
/// </summary> | ||
[DiagnosticAnalyzer (LanguageNames.CSharp)] | ||
public class BindingTypeSemanticAnalyzer : DiagnosticAnalyzer { | ||
internal const string DiagnosticId = "RBI0001"; | ||
static readonly LocalizableString Title = new LocalizableResourceString (nameof (Resources.RBI0001Title), | ||
Resources.ResourceManager, typeof (Resources)); | ||
static readonly LocalizableString MessageFormat = | ||
new LocalizableResourceString (nameof (Resources.RBI0001MessageFormat), Resources.ResourceManager, | ||
typeof (Resources)); | ||
static readonly LocalizableString Description = | ||
new LocalizableResourceString (nameof (Resources.RBI0001Description), Resources.ResourceManager, | ||
typeof (Resources)); | ||
const string Category = "Usage"; | ||
|
||
static readonly DiagnosticDescriptor RBI0001 = new (DiagnosticId, Title, MessageFormat, Category, | ||
DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description); | ||
|
||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = | ||
ImmutableArray.Create (RBI0001); | ||
|
||
public override void Initialize (AnalysisContext context) | ||
{ | ||
context.ConfigureGeneratedCodeAnalysis (GeneratedCodeAnalysisFlags.None); | ||
context.EnableConcurrentExecution (); | ||
context.RegisterSyntaxNodeAction (AnalysisContext, SyntaxKind.ClassDeclaration); | ||
} | ||
|
||
void AnalysisContext (SyntaxNodeAnalysisContext context) | ||
{ | ||
// only care about classes | ||
if (context.Node is not ClassDeclarationSyntax classDeclarationNode) | ||
return; | ||
|
||
var classSymbol = context.SemanticModel.GetDeclaredSymbol (classDeclarationNode); | ||
if (classSymbol is null) | ||
return; | ||
|
||
var boundAttributes = classSymbol.GetAttributes (); | ||
if (boundAttributes.Length == 0) { | ||
return; | ||
} | ||
|
||
// the c# syntax is a a list of lists of attributes. That is why we need to iterate through the list of lists | ||
foreach (var attributeData in boundAttributes) { | ||
// based on the type use the correct parser to retrieve the data | ||
var attributeType = attributeData.AttributeClass?.ToDisplayString (); | ||
switch (attributeType) { | ||
case "ObjCBindings.BindingTypeAttribute": | ||
// validate that the class is partial, else we need to report an error | ||
if (!classDeclarationNode.Modifiers.Any (x => x.IsKind (SyntaxKind.PartialKeyword))) { | ||
var diagnostic = Diagnostic.Create (RBI0001, | ||
classDeclarationNode.Identifier.GetLocation (), // point to where the 'class' keyword is used | ||
classSymbol.ToDisplayString ()); | ||
context.ReportDiagnostic (diagnostic); | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
src/rgen/Microsoft.Macios.Bindings.Analyzer/Microsoft.Macios.Bindings.Analyzer.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)</TargetFramework> | ||
<IsPackable>false</IsPackable> | ||
<Nullable>enable</Nullable> | ||
<LangVersion>latest</LangVersion> | ||
|
||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules> | ||
<IsRoslynComponent>true</IsRoslynComponent> | ||
|
||
<RootNamespace>Microsoft.Macios.Bindings.Analyzer</RootNamespace> | ||
<AssemblyName>Microsoft.Macios.Bindings.Analyzer</AssemblyName> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4"> | ||
<PrivateAssets>all</PrivateAssets> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
</PackageReference> | ||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.0"/> | ||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.3.0"/> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute"> | ||
<_Parameter1>Microsoft.Macios.Bindings.Analyzer.Tests</_Parameter1> | ||
</AssemblyAttribute> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<EmbeddedResource Update="Resources.resx"> | ||
<Generator>ResXFileCodeGenerator</Generator> | ||
<LastGenOutput>Resources.Designer.cs</LastGenOutput> | ||
</EmbeddedResource> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Compile Update="Resources.Designer.cs"> | ||
<DesignTime>True</DesignTime> | ||
<AutoGen>True</AutoGen> | ||
<DependentUpon>Resources.resx</DependentUpon> | ||
</Compile> | ||
</ItemGroup> | ||
|
||
</Project> |
9 changes: 9 additions & 0 deletions
9
src/rgen/Microsoft.Macios.Bindings.Analyzer/Properties/launchSettings.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/launchsettings.json", | ||
"profiles": { | ||
"DebugRoslynAnalyzers": { | ||
"commandName": "DebugRoslynComponent", | ||
"targetProject": "../Microsoft.Macios.Bindings.Analyzer.Sample/Microsoft.Macios.Bindings.Analyzer.Sample.csproj" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Roslyn Analyzers Sample | ||
|
||
Roslyn analyzer to be installed along side the Roslyn Conde generator that will help developers work on Microsoft.Macios bindings. | ||
|
||
## Content | ||
### Microsoft.Macios.Bindings.Analyzer | ||
|
||
A .NET Standard project with implementations of sample analyzers and code fix providers. | ||
**You must build this project to see the results (warnings) in the IDE.** | ||
|
||
### Microsoft.Macios.Bindings.Analyzer.Sample | ||
A project that references the sample analyzers. Note the parameters of `ProjectReference` in [Microsoft.Macios.Bindings.Analyzer.Sample.csproj](../Microsoft.Macios.Bindings.Analyzer.Sample/Microsoft.Macios.Bindings.Analyzer.Sample.csproj), they make sure that the project is referenced as a set of analyzers. | ||
|
||
### Microsoft.Macios.Bindings.Analyzer.Tests | ||
Unit tests for the sample analyzers and code fix provider. The easiest way to develop language-related features is to start with unit tests. | ||
|
||
## How To? | ||
### How to debug? | ||
- Use the [launchSettings.json](Properties/launchSettings.json) profile. | ||
- Debug tests (in VSCode). | ||
|
||
### How can I determine which syntax nodes I should expect? | ||
Consider installing the Roslyn syntax tree viewer plugin [Rossynt](https://plugins.jetbrains.com/plugin/16902-rossynt/). | ||
|
||
### Learn more about wiring analyzers | ||
The complete set of information is available at [roslyn github repo wiki](https://github.com/dotnet/roslyn/blob/main/docs/wiki/README.md). |
Oops, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.
This comment was marked as outdated.
Sorry, something went wrong.