Skip to content

Commit b3079db

Browse files
authored
Add DiagnosticSuppressor to suppress the IDE0002 Style Hint in the IDE (#9310)
Context: #8381 Add a `DiagnosticSuppressor` to "turn off" the `IDE0002` style diagnostic message which incorrectly tells users to use the `_Microsoft.Android.Resource.Designer.ResourceConstant` type directly. This can cause allot of annoyance with our users because it appears on EVERY single usage of `Resource.*`. So you end up with what looks like code spagetti. So we need to start shipping an `Analyzer` assembly along with the `Ref` framework pack. This is the place these things need to go. Unfortunately it means that the older frameworks will not get this analyzer. Only the current one. On the packaging side, the Analyzer assembly has to go in a `analyzers/dotnet/<language>` folder in the .Ref Nuget Package. There also needs to be an entry in the `FrameworkList.xml` file which has a `Type="Analyzer" ` and a `Language="cs"`. This allows the IDE's to pickup the code. We can ship both regular Analyzers and the DiagnosticSuppressors in the same assembly. So we can extend this with more if needed. How this works is we use Rosyln to look for the IDE0002 diagnsotic message, we then check the code and see if it is refering to a `_Microsoft.Android.Resource.Designer.*` derived class. If it is , we add a suppression. This will stop the hint appearing in the IDE. I have tested this on VS in devbox and it appears to work . Also we generate a Resource Designer assembly and an Intermediate source file at build time. Both of these contain classes which should have the `GeneratedCode` Attribute. So lets add it. The version will be the same as the build assembly used to generate it.
1 parent 27b5d2e commit b3079db

11 files changed

+139
-6
lines changed

Configuration.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
<MicrosoftAndroidx64PackDir>$(BuildOutputDirectory)lib\packs\Microsoft.Android.Runtime.$(AndroidApiLevel).android-x64\$(AndroidPackVersion)\runtimes\android-x64\</MicrosoftAndroidx64PackDir>
7070
<MicrosoftAndroidSdkPackDir>$(BuildOutputDirectory)lib\packs\$(MicrosoftAndroidSdkPackName)\$(AndroidPackVersion)\</MicrosoftAndroidSdkPackDir>
7171
<MicrosoftAndroidSdkOutDir>$(MicrosoftAndroidSdkPackDir)\tools\</MicrosoftAndroidSdkOutDir>
72+
<MicrosoftAndroidSdkAnalysisOutDir>$(BuildOutputDirectory)lib\packs\Microsoft.Android.Ref.$(AndroidApiLevel)\$(AndroidPackVersion)\analyzers\dotnet\cs\</MicrosoftAndroidSdkAnalysisOutDir>
7273
<MakeConcurrency Condition=" '$(MakeConcurrency)' == '' And '$(HostCpuCount)' != '' ">-j$(HostCpuCount)</MakeConcurrency>
7374
<ManagedRuntime Condition=" '$(ManagedRuntime)' == '' And '$(OS)' != 'Windows_NT' ">mono</ManagedRuntime>
7475
<ManagedRuntimeArgs Condition=" '$(ManagedRuntimeArgs)' == '' And '$(ManagedRuntime)' == 'mono' ">--debug=casts</ManagedRuntimeArgs>

Xamarin.Android.Build.Tasks.sln

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Android.Build.Bas
2525
EndProject
2626
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.AndroidSdk", "external\xamarin-android-tools\src\Xamarin.Android.Tools.AndroidSdk\Xamarin.Android.Tools.AndroidSdk.csproj", "{E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}"
2727
EndProject
28+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4A5EE838-A906-4711-972E-E680B0AA68BD}"
29+
EndProject
30+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Android.Sdk.Analysis", "src\Microsoft.Android.Sdk.Analysis\Microsoft.Android.Sdk.Analysis.csproj", "{0D00DD34-3E94-4166-9DEE-12355E4C98A0}"
31+
EndProject
2832
Global
2933
GlobalSection(SharedMSBuildProjectFiles) = preSolution
3034
src\Xamarin.Android.NamingCustomAttributes\Xamarin.Android.NamingCustomAttributes.projitems*{3f1f2f50-af1a-4a5a-bedb-193372f068d7}*SharedItemsImports = 5
@@ -74,6 +78,10 @@ Global
7478
{E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.Debug|Any CPU.Build.0 = Debug|Any CPU
7579
{E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.Release|Any CPU.ActiveCfg = Release|Any CPU
7680
{E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.Release|Any CPU.Build.0 = Release|Any CPU
81+
{0D00DD34-3E94-4166-9DEE-12355E4C98A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
82+
{0D00DD34-3E94-4166-9DEE-12355E4C98A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
83+
{0D00DD34-3E94-4166-9DEE-12355E4C98A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
84+
{0D00DD34-3E94-4166-9DEE-12355E4C98A0}.Release|Any CPU.Build.0 = Release|Any CPU
7785
EndGlobalSection
7886
GlobalSection(SolutionProperties) = preSolution
7987
HideSolutionNode = FALSE
@@ -84,6 +92,7 @@ Global
8492
{DE40756E-57F6-4AF2-B155-55E3A88CCED8} = {385E71CC-BAE5-488B-805E-ACAE55F01DF5}
8593
{3DE17662-DCD6-4F49-AF06-D39AACC8649A} = {385E71CC-BAE5-488B-805E-ACAE55F01DF5}
8694
{E34BCFA0-CAA4-412C-AA1C-75DB8D67D157} = {385E71CC-BAE5-488B-805E-ACAE55F01DF5}
95+
{0D00DD34-3E94-4166-9DEE-12355E4C98A0} = {4A5EE838-A906-4711-972E-E680B0AA68BD}
8796
EndGlobalSection
8897
GlobalSection(ExtensibilityGlobals) = postSolution
8998
SolutionGuid = {F32556C5-6FD4-4F1D-884A-DEDF2EE865F6}

Xamarin.Android.sln

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "create-android-api", "build
121121
EndProject
122122
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.Aidl-Tests", "tests\Xamarin.Android.Tools.Aidl-Tests\Xamarin.Android.Tools.Aidl-Tests.csproj", "{A39B6D7C-6616-40D6-8AE4-C6CEE93D2708}"
123123
EndProject
124+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{FFCF518F-2A4A-40A2-9174-2EE13B76C723}"
125+
EndProject
126+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Android.Sdk.Analysis", "src\Microsoft.Android.Sdk.Analysis\Microsoft.Android.Sdk.Analysis.csproj", "{5E806C9F-1B67-4B6B-A6AB-258834250DBB}"
127+
EndProject
124128
Global
125129
GlobalSection(SolutionConfigurationPlatforms) = preSolution
126130
Debug|AnyCPU = Debug|AnyCPU
@@ -335,6 +339,10 @@ Global
335339
{A39B6D7C-6616-40D6-8AE4-C6CEE93D2708}.Debug|AnyCPU.Build.0 = Debug|Any CPU
336340
{A39B6D7C-6616-40D6-8AE4-C6CEE93D2708}.Release|AnyCPU.ActiveCfg = Release|Any CPU
337341
{A39B6D7C-6616-40D6-8AE4-C6CEE93D2708}.Release|AnyCPU.Build.0 = Release|Any CPU
342+
{5E806C9F-1B67-4B6B-A6AB-258834250DBB}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
343+
{5E806C9F-1B67-4B6B-A6AB-258834250DBB}.Debug|AnyCPU.Build.0 = Debug|Any CPU
344+
{5E806C9F-1B67-4B6B-A6AB-258834250DBB}.Release|AnyCPU.ActiveCfg = Release|Any CPU
345+
{5E806C9F-1B67-4B6B-A6AB-258834250DBB}.Release|AnyCPU.Build.0 = Release|Any CPU
338346
EndGlobalSection
339347
GlobalSection(SolutionProperties) = preSolution
340348
HideSolutionNode = FALSE
@@ -393,6 +401,7 @@ Global
393401
{C0E44558-FEE3-4DD3-986A-3F46DD1BF41B} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
394402
{BA4D889D-066B-4C2C-A973-09E319CBC396} = {E351F97D-EA4F-4E7F-AAA0-8EBB1F2A4A62}
395403
{A39B6D7C-6616-40D6-8AE4-C6CEE93D2708} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}
404+
{5E806C9F-1B67-4B6B-A6AB-258834250DBB} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723}
396405
EndGlobalSection
397406
GlobalSection(ExtensibilityGlobals) = postSolution
398407
SolutionGuid = {53A1F287-EFB2-4D97-A4BB-4A5E145613F6}

build-tools/create-packs/ConfigureLocalWorkload.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
<ItemGroup>
44
<_FrameworkListInputs Include="$(MicrosoftAndroidRefPackDir)**" />
5+
<_FrameworkListInputs Include="$(MicrosoftAndroidSdkAnalysisOutDir)Microsoft.Android.Sdk.Analysis.dll" />
56
<_FrameworkListOutputs Include="$(BuildOutputDirectory)lib\packs\Microsoft.Android.Ref.$(AndroidDefaultTargetDotnetApiLevel)\$(AndroidPackVersion)\data\FrameworkList.xml" />
67
<_FrameworkListOutputs Include="$(BuildOutputDirectory)lib\packs\Microsoft.Android.Ref.$(AndroidLatestStableApiLevel)\$(AndroidPackVersion)\data\FrameworkList.xml" />
78
<_FrameworkListOutputs Include="$(BuildOutputDirectory)lib\packs\Microsoft.Android.Ref.$(AndroidLatestUnstableApiLevel)\$(AndroidPackVersion)\data\FrameworkList.xml" />

build-tools/create-packs/Directory.Build.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
Files="@(_PackageFiles)"
2929
FileClassifications="@(FrameworkListFileClass)"
3030
TargetFile="$(FrameworkListFile)"
31-
TargetFilePrefixes="ref;runtimes"
31+
TargetFilePrefixes="ref;runtimes;analyzers"
3232
RootAttributes="@(FrameworkListRootAttributes)"
3333
/>
3434
<ItemGroup>

build-tools/create-packs/Microsoft.Android.Ref.proj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ by projects that use the Microsoft.Android framework in .NET 6+.
1313
<PackageId>Microsoft.Android.Ref.$(AndroidApiLevel)</PackageId>
1414
<Description>Microsoft.Android reference assemblies for API $(AndroidApiLevel). Please do not reference directly.</Description>
1515
<_AndroidRefPackAssemblyPath>ref\$(DotNetTargetFramework)</_AndroidRefPackAssemblyPath>
16+
<_AndroidRefPackAnalyzersPath>analyzers\dotnet\cs</_AndroidRefPackAnalyzersPath>
1617
</PropertyGroup>
1718

1819
<PropertyGroup>
@@ -36,11 +37,14 @@ by projects that use the Microsoft.Android framework in .NET 6+.
3637
<_AndroidRefPackAssemblies Include="$(_MonoAndroidNETDefaultOutDir)ref\Mono.Android.Runtime.dll" />
3738
<!-- Always include stable Mono.Android.Export.dll -->
3839
<_AndroidRefPackAssemblies Include="$(_MonoAndroidNETOutputRoot)$(AndroidLatestStableApiLevel)\ref\Mono.Android.Export.dll" />
40+
<_AndroidRefPackAnalyzers Include="$(MicrosoftAndroidSdkAnalysisOutDir)Microsoft.Android.Sdk.Analysis.dll" />
3941
<FrameworkListFileClass Include="@(_AndroidRefPackAssemblies->'%(Filename)%(Extension)')" Profile="Android" />
42+
<FrameworkListFileClass Include="@(_AndroidRefPackAnalyzers->'%(Filename)%(Extension)')" Profile="Android" />
4043
</ItemGroup>
4144

4245
<ItemGroup>
4346
<_PackageFiles Include="@(_AndroidRefPackAssemblies)" PackagePath="$(_AndroidRefPackAssemblyPath)" TargetPath="$(_AndroidRefPackAssemblyPath)" />
47+
<_PackageFiles Include="@(_AndroidRefPackAnalyzers)" PackagePath="$(_AndroidRefPackAnalyzersPath)" TargetPath="$(_AndroidRefPackAnalyzersPath)" />
4448
<_PackageFiles Include="$(_MonoAndroidNETDefaultOutDir)Java.Interop.xml" PackagePath="$(_AndroidRefPackAssemblyPath)" />
4549
<_PackageFiles Include="$(_MonoAndroidNETDefaultOutDir)Mono.Android.xml" PackagePath="$(_AndroidRefPackAssemblyPath)" />
4650
<_PackageFiles Include="$(_MonoAndroidNETDefaultOutDir)mono.android.jar" PackagePath="$(_AndroidRefPackAssemblyPath)" />

eng/Versions.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<MicrosoftNETILLinkTasksPackageVersion>9.0.0-rtm.24473.2</MicrosoftNETILLinkTasksPackageVersion>
77
<MicrosoftNETCoreAppRefPackageVersion>9.0.0-rtm.24473.2</MicrosoftNETCoreAppRefPackageVersion>
88
<MicrosoftDotNetApiCompatPackageVersion>7.0.0-beta.22103.1</MicrosoftDotNetApiCompatPackageVersion>
9-
<MicrosoftDotNetBuildTasksFeedPackageVersion>9.0.0-beta.24408.2</MicrosoftDotNetBuildTasksFeedPackageVersion>
9+
<MicrosoftDotNetBuildTasksFeedPackageVersion>10.0.0-beta.24476.2</MicrosoftDotNetBuildTasksFeedPackageVersion>
1010
<MicrosoftNETWorkloadEmscriptenCurrentManifest90100TransportVersion>9.0.0-rtm.24469.1</MicrosoftNETWorkloadEmscriptenCurrentManifest90100TransportVersion>
1111
<MicrosoftNETWorkloadEmscriptenPackageVersion>$(MicrosoftNETWorkloadEmscriptenCurrentManifest90100TransportVersion)</MicrosoftNETWorkloadEmscriptenPackageVersion>
1212
<MicrosoftTemplateEngineTasksPackageVersion>7.0.100-rc.1.22410.7</MicrosoftTemplateEngineTasksPackageVersion>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<Import Project="..\..\Configuration.props" />
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
6+
<OutputPath>$(MicrosoftAndroidSdkAnalysisOutDir)</OutputPath>
7+
<IsRoslynComponent>true</IsRoslynComponent>
8+
<LangVersion>latest</LangVersion>
9+
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
10+
<AssemblyOriginatorKeyFile>..\..\product.snk</AssemblyOriginatorKeyFile>
11+
</PropertyGroup>
12+
<ItemGroup>
13+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" />
14+
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
15+
</ItemGroup>
16+
<ItemGroup>
17+
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
18+
</ItemGroup>
19+
</Project>
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System.Linq;
2+
using System.Collections.Immutable;
3+
using System.Threading;
4+
using Microsoft.CodeAnalysis;
5+
using Microsoft.CodeAnalysis.CSharp.Syntax;
6+
using Microsoft.CodeAnalysis.Diagnostics;
7+
using Microsoft.CodeAnalysis.Text;
8+
9+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
10+
public class ResourceDesignerDiagnosticSuppressor : DiagnosticSuppressor
11+
{
12+
private const string DesignerNamespace = "_Microsoft.Android.Resource.Designer";
13+
private static readonly SuppressionDescriptor Rule = new(
14+
"XAD0001",
15+
"IDE0002",
16+
"The Resource Designer class should not be simplified."
17+
);
18+
19+
public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions
20+
=> ImmutableArray.Create(Rule);
21+
22+
public override void ReportSuppressions(SuppressionAnalysisContext context)
23+
{
24+
foreach (var diagnostic in context.ReportedDiagnostics)
25+
{
26+
if (diagnostic.Id != Rule.SuppressedDiagnosticId)
27+
continue;
28+
Location location = diagnostic.Location;
29+
SyntaxTree syntaxTree = location.SourceTree;
30+
if (syntaxTree is null)
31+
continue;
32+
33+
SyntaxNode root = syntaxTree.GetRoot(context.CancellationToken);
34+
SyntaxNode syntaxNode = root.FindNode(location.SourceSpan)
35+
.DescendantNodesAndSelf()
36+
.FirstOrDefault ();
37+
38+
if (syntaxNode is null)
39+
continue;
40+
41+
SemanticModel model = context.GetSemanticModel(syntaxTree);
42+
ISymbol typeSymbol = model.GetSymbolInfo (syntaxNode).Symbol;
43+
if (typeSymbol is not INamedTypeSymbol namedTypeSymbol)
44+
continue;
45+
46+
if (IsResourceDesignerDerivedType(namedTypeSymbol))
47+
{
48+
Suppression suppression = Suppression.Create(Rule, diagnostic);
49+
context.ReportSuppression(suppression);
50+
}
51+
}
52+
}
53+
54+
private static bool IsResourceDesignerDerivedType(INamedTypeSymbol typeSymbol)
55+
{
56+
return IsDerivedFrom(typeSymbol, DesignerNamespace);
57+
}
58+
59+
private static bool IsDerivedFrom(INamedTypeSymbol typeSymbol, string baseClassName)
60+
{
61+
while (typeSymbol != null)
62+
{
63+
if (typeSymbol.ToDisplayString().StartsWith(baseClassName))
64+
{
65+
return true;
66+
}
67+
typeSymbol = typeSymbol.BaseType;
68+
}
69+
return false;
70+
}
71+
}

src/Xamarin.Android.Build.Tasks/Tasks/GenerateResourceDesignerAssembly.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ bool Run (DirectoryAssemblyResolver res)
123123
TypeReference e = ImportType ("System.ComponentModel.EditorBrowsableState", module, netstandardDef.MainModule);
124124
var editorBrowserAttr = new CustomAttribute (editorBrowserConstructor);
125125
editorBrowserAttr.ConstructorArguments.Add (new CustomAttributeArgument (e, System.ComponentModel.EditorBrowsableState.Never));
126+
127+
MethodReference generatedCodeConstructor = ImportCustomAttributeConstructor (cache, "System.CodeDom.Compiler.GeneratedCodeAttribute", module, netstandardDef.MainModule, argCount: 2);
128+
var generatedCodeAttr = new CustomAttribute (generatedCodeConstructor);
129+
generatedCodeAttr.ConstructorArguments.Add (new CustomAttributeArgument (module.TypeSystem.String, nameof(GenerateResourceDesignerAssembly)));
130+
var version = typeof(GenerateResourceDesignerAssembly).Assembly.GetName().Version;
131+
generatedCodeAttr.ConstructorArguments.Add (new CustomAttributeArgument (module.TypeSystem.String, version.ToString ()));
126132

127133
var att = TypeAttributes.AutoClass | TypeAttributes.AnsiClass | TypeAttributes.Public | TypeAttributes.BeforeFieldInit;
128134

@@ -139,6 +145,7 @@ bool Run (DirectoryAssemblyResolver res)
139145
);
140146
CreateCtor (cache, resourceDesigner, module);
141147
resourceDesigner.CustomAttributes.Add (editorBrowserAttr);
148+
resourceDesigner.CustomAttributes.Add (generatedCodeAttr);
142149
module.Types.Add (resourceDesigner);
143150
TypeDefinition constDesigner = null;
144151
if (IsApplication) {
@@ -152,6 +159,7 @@ bool Run (DirectoryAssemblyResolver res)
152159
);
153160
CreateCtor (cache, constDesigner, module);
154161
constDesigner.CustomAttributes.Add (editorBrowserAttr);
162+
constDesigner.CustomAttributes.Add (generatedCodeAttr);
155163
module.Types.Add (constDesigner);
156164
}
157165

0 commit comments

Comments
 (0)