Skip to content

Commit d1c820f

Browse files
ngrusonWhitWaldo
andauthored
Add Roslyn analyzer for workflows (#1440)
Introduced two diagnostic analyzers: `WorkflowRegistrationAnalyzer` and `WorkflowActivityRegistrationAnalyzer` that validate that both any types that implement `Workflow<,>` or `WorkflowActivity<,>` have a corresponding registration entry in the DI provider. This PR also includes a code fix provider for either analyzer that provides a remedial registration for the developer. Signed-off-by: Nils Gruson <[email protected]> Co-authored-by: Whit Waldo <[email protected]>
1 parent 34f36d9 commit d1c820f

37 files changed

+1749
-173
lines changed

all.sln

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JobsSample", "examples\Jobs
155155
EndProject
156156
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Workflow.Test", "test\Dapr.Workflow.Test\Dapr.Workflow.Test.csproj", "{E90114C6-86FC-43B8-AE5C-D9273CF21FE4}"
157157
EndProject
158+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Workflow.Analyzers", "src\Dapr.Workflow.Analyzers\Dapr.Workflow.Analyzers.csproj", "{55A7D436-CC8C-47E6-B43A-DFE32E0FE38C}"
159+
EndProject
160+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Workflow.Analyzers.Test", "test\Dapr.Workflow.Analyzers.Test\Dapr.Workflow.Analyzers.Test.csproj", "{CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539}"
161+
EndProject
158162
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzers", "src\Dapr.Jobs.Analyzer\Dapr.Jobs.Analyzers.csproj", "{28B87C37-4B52-400F-B84D-64F134931BDC}"
159163
EndProject
160164
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzers.Test", "test\Dapr.Jobs.Analyzer.Test\Dapr.Jobs.Analyzers.Test.csproj", "{CADEAE45-8981-4723-B641-9C28251C7D3B}"
@@ -163,6 +167,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Actors.Analyzers", "sr
163167
EndProject
164168
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Actors.Analyzers.Test", "test\Dapr.Actors.Analyzers.Test\Dapr.Actors.Analyzers.Test.csproj", "{A2C0F203-11FF-4B7F-A94F-B9FD873573FE}"
165169
EndProject
170+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Analyzers.Common", "test\Dapr.Analyzers.Common\Dapr.Analyzers.Common.csproj", "{7E23E229-6823-4D84-AF3A-AE14CEAEF52A}"
171+
EndProject
166172
Global
167173
GlobalSection(SolutionConfigurationPlatforms) = preSolution
168174
Debug|Any CPU = Debug|Any CPU
@@ -411,6 +417,14 @@ Global
411417
{E90114C6-86FC-43B8-AE5C-D9273CF21FE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
412418
{E90114C6-86FC-43B8-AE5C-D9273CF21FE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
413419
{E90114C6-86FC-43B8-AE5C-D9273CF21FE4}.Release|Any CPU.Build.0 = Release|Any CPU
420+
{55A7D436-CC8C-47E6-B43A-DFE32E0FE38C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
421+
{55A7D436-CC8C-47E6-B43A-DFE32E0FE38C}.Debug|Any CPU.Build.0 = Debug|Any CPU
422+
{55A7D436-CC8C-47E6-B43A-DFE32E0FE38C}.Release|Any CPU.ActiveCfg = Release|Any CPU
423+
{55A7D436-CC8C-47E6-B43A-DFE32E0FE38C}.Release|Any CPU.Build.0 = Release|Any CPU
424+
{CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
425+
{CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539}.Debug|Any CPU.Build.0 = Debug|Any CPU
426+
{CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539}.Release|Any CPU.ActiveCfg = Release|Any CPU
427+
{CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539}.Release|Any CPU.Build.0 = Release|Any CPU
414428
{28B87C37-4B52-400F-B84D-64F134931BDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
415429
{28B87C37-4B52-400F-B84D-64F134931BDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
416430
{28B87C37-4B52-400F-B84D-64F134931BDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -427,6 +441,10 @@ Global
427441
{A2C0F203-11FF-4B7F-A94F-B9FD873573FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
428442
{A2C0F203-11FF-4B7F-A94F-B9FD873573FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
429443
{A2C0F203-11FF-4B7F-A94F-B9FD873573FE}.Release|Any CPU.Build.0 = Release|Any CPU
444+
{7E23E229-6823-4D84-AF3A-AE14CEAEF52A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
445+
{7E23E229-6823-4D84-AF3A-AE14CEAEF52A}.Debug|Any CPU.Build.0 = Debug|Any CPU
446+
{7E23E229-6823-4D84-AF3A-AE14CEAEF52A}.Release|Any CPU.ActiveCfg = Release|Any CPU
447+
{7E23E229-6823-4D84-AF3A-AE14CEAEF52A}.Release|Any CPU.Build.0 = Release|Any CPU
430448
EndGlobalSection
431449
GlobalSection(SolutionProperties) = preSolution
432450
HideSolutionNode = FALSE
@@ -500,10 +518,13 @@ Global
500518
{D9697361-232F-465D-A136-4561E0E88488} = {D687DDC4-66C5-4667-9E3A-FD8B78ECAA78}
501519
{9CAF360E-5AD3-4C4F-89A0-327EEB70D673} = {D9697361-232F-465D-A136-4561E0E88488}
502520
{E90114C6-86FC-43B8-AE5C-D9273CF21FE4} = {DD020B34-460F-455F-8D17-CF4A949F100B}
521+
{55A7D436-CC8C-47E6-B43A-DFE32E0FE38C} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
522+
{CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539} = {DD020B34-460F-455F-8D17-CF4A949F100B}
503523
{28B87C37-4B52-400F-B84D-64F134931BDC} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
504524
{CADEAE45-8981-4723-B641-9C28251C7D3B} = {DD020B34-460F-455F-8D17-CF4A949F100B}
505525
{E49C822C-E921-48DF-897B-3E603CA596D2} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
506526
{A2C0F203-11FF-4B7F-A94F-B9FD873573FE} = {DD020B34-460F-455F-8D17-CF4A949F100B}
527+
{7E23E229-6823-4D84-AF3A-AE14CEAEF52A} = {DD020B34-460F-455F-8D17-CF4A949F100B}
507528
EndGlobalSection
508529
GlobalSection(ExtensibilityGlobals) = postSolution
509530
SolutionGuid = {65220BF2-EAE1-4CB2-AA58-EBE80768CB40}

daprdocs/content/en/dotnet-sdk-docs/dotnet-code-analysis/_index.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ is subject to change in the future as more analyzers are developed.
3333
The following packages will be available via NuGet following the v1.16 Dapr release:
3434
- Dapr.Actors.Analyzers
3535
- Dapr.Jobs.Analyzers
36+
- Dapr.Workflow.Analyzers
3637

3738
Install each NuGet package on every project where you want the analyzers to run. The package will be installed as a
3839
project dependency and analyzers will run as you write your code or as part of a CI/CD build. The analyzers will flag
@@ -56,13 +57,15 @@ the `EnableNETAnalyzers` property to `false` in your csproj file.
5657

5758
## Available Analyzers
5859

59-
| Diagnostic ID | Dapr Package | Category | Severity | Version Added | Description | Code Fix Available |
60-
| -- | -- |------------------| -- | -- | -- | -- |
61-
| DAPR1401 | Dapr.Actors | Usage | Warning | 1.16 | Actor timer method invocations require the named callback method to exist on type | No |
62-
| DAPR1402 | Dapr.Actors | Usage | Warning | The actor type is not registered with dependency injection | Yes |
63-
| DAPR1403 | Dapr.Actors | Interoperability | Info | Set options.UseJsonSerialization to true to support interoperability with non-.NET actors | Yes |
64-
| DAPR1404 | Dapr.Actors | Usage | Warning | Call app.MapActorsHandlers to map endpoints for Dapr actors | Yes |
65-
| DAPR1501 | Dapr.Jobs | Usage | Warning | Job invocations require the MapDaprScheduledJobHandler to be set and configured for each anticipated job on IEndpointRouteBuilder | No |
60+
| Diagnostic ID | Dapr Package | Category | Severity | Version Added | Description | Code Fix Available |
61+
| -- | -- |------------------|--------------|-----------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------| -- |
62+
| DAPR1301 | Dapr.Workflow | Usage | Warning | 1.16 | The workflow type is not registered with the dependency injection provider | Yes |
63+
| DAPR1302 | Dapr.Workflow | Usage | Warning | 1.16 | The workflow activity type is not registered with the dependency injection provider | Yes |
64+
| DAPR1401 | Dapr.Actors | Usage | Warning | 1.16 | Actor timer method invocations require the named callback method to exist on type | No |
65+
| DAPR1402 | Dapr.Actors | Usage | Warning | The actor type is not registered with dependency injection | Yes |
66+
| DAPR1403 | Dapr.Actors | Interoperability | Info | Set options.UseJsonSerialization to true to support interoperability with non-.NET actors | Yes |
67+
| DAPR1404 | Dapr.Actors | Usage | Warning | Call app.MapActorsHandlers to map endpoints for Dapr actors | Yes |
68+
| DAPR1501 | Dapr.Jobs | Usage | Warning | Job invocations require the MapDaprScheduledJobHandler to be set and configured for each anticipated job on IEndpointRouteBuilder | No |
6669

6770
## Analyzer Categories
6871
The following are each of the eligible categories that an analyzer can be assigned to and are modeled after the

src/Dapr.Actors.Analyzers/Dapr.Actors.Analyzers/Resources.Designer.cs

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Dapr.Actors.Analyzers/Dapr.Actors.Analyzers/Resources.resx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
<value>Actor timer method invocations require the named callback '{0}' method to exist on type '{1}'</value>
2626
</data>
2727
<data name="DAPR1402Title" xml:space="preserve">
28-
<value>The actor type is not registered with dependency injection</value>
28+
<value>The actor type is not registered with the dependency injection provider</value>
2929
</data>
3030
<data name="DAPR1402MessageFormat" xml:space="preserve">
31-
<value>The actor type '{0}' is not registered with dependency injection</value>
31+
<value>The actor type '{0}' is not registered with the dependency injection provider</value>
3232
</data>
3333
<data name="DAPR1403MessageFormat" xml:space="preserve">
3434
<value>Set options.UseJsonSerialization to true to support interoperability with non-.NET actors</value>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## Release 1.16
2+
3+
### New Rules
4+
5+
Rule ID | Category | Severity | Notes
6+
--------|----------|----------|--------------------
7+
DAPR1301 | Usage | Warning | The workflow class '{0}' is not registered
8+
DAPR1302 | Usage | Warning | The workflow activity class '{0}' is not registered
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
; Unshipped analyzer release
2+
; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md
3+
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<TargetFrameworks></TargetFrameworks>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" />
13+
</ItemGroup>
14+
15+
<PropertyGroup>
16+
<!-- Suppress false-positive error NU5128 when packing analyzers with no lib/ref files. -->
17+
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
18+
19+
<!-- Suppress generation of symbol package (.snupkg). -->
20+
<IncludeSymbols>false</IncludeSymbols>
21+
22+
<!-- Do not include the generator as a lib dependency -->
23+
<IncludeBuildOutput>false</IncludeBuildOutput>
24+
25+
<!-- Additional NuGet package properties. -->
26+
<Description>This package contains analyzers for interacting with Dapr workflows.</Description>
27+
<NoWarn>$(NoWarn);RS1038</NoWarn>
28+
</PropertyGroup>
29+
30+
<ItemGroup>
31+
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
32+
</ItemGroup>
33+
34+
<ItemGroup>
35+
<InternalsVisibleTo Include="$(AssemblyName).Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b1f597635c44597fcecb493e2b1327033b29b1a98ac956a1a538664b68f87d45fbaada0438a15a6265e62864947cc067d8da3a7d93c5eb2fcbb850e396c8684dba74ea477d82a1bbb18932c0efb30b64ff1677f85ae833818707ac8b49ad8062ca01d2c89d8ab1843ae73e8ba9649cd28666b539444dcdee3639f95e2a099bb2"/>
36+
</ItemGroup>
37+
38+
<ItemGroup>
39+
<EmbeddedResource Update="Resources.resx">
40+
<Generator>ResXFileCodeGenerator</Generator>
41+
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
42+
</EmbeddedResource>
43+
</ItemGroup>
44+
45+
<ItemGroup>
46+
<Compile Update="Resources.Designer.cs">
47+
<DesignTime>True</DesignTime>
48+
<AutoGen>True</AutoGen>
49+
<DependentUpon>Resources.resx</DependentUpon>
50+
</Compile>
51+
</ItemGroup>
52+
53+
</Project>

src/Dapr.Workflow.Analyzers/Resources.Designer.cs

Lines changed: 98 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
3+
<root>
4+
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
5+
<xsd:element name="root" msdata:IsDataSet="true">
6+
7+
</xsd:element>
8+
</xsd:schema>
9+
<resheader name="resmimetype">
10+
<value>text/microsoft-resx</value>
11+
</resheader>
12+
<resheader name="version">
13+
<value>1.3</value>
14+
</resheader>
15+
<resheader name="reader">
16+
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
17+
</resheader>
18+
<resheader name="writer">
19+
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
20+
</resheader>
21+
<data name="DAPR1301Title" xml:space="preserve">
22+
<value>The workflow type is not registered with the dependency injection provider</value>
23+
</data>
24+
<data name="DAPR1301MessageFormat" xml:space="preserve">
25+
<value>The workflow type '{0}' is not registered with the dependency injection provider</value>
26+
</data>
27+
<data name="DAPR1302Title" xml:space="preserve">
28+
<value>The workflow activity type is not registered with the dependency injection provider</value>
29+
</data>
30+
<data name="DAPR1302MessageFormat" xml:space="preserve">
31+
<value>The workflow activity type '{0}' is not registered with the dependency injection provider</value>
32+
</data>
33+
</root>

0 commit comments

Comments
 (0)