Просмотр исходного кода

Added generic virtual methods analyzer.

Added a new `DevAnalyzers` project with a single analyzer to detect generic virtual/interface methods.
Steven Kirk 3 лет назад
Родитель
Сommit
f682f5af7c
28 измененных файлов с 133 добавлено и 6 удалено
  1. 29 1
      Avalonia.sln
  2. 9 0
      build/DevAnalyzers.props
  3. 1 0
      src/Android/Avalonia.Android/Avalonia.Android.csproj
  4. 1 0
      src/Avalonia.Animation/Avalonia.Animation.csproj
  5. 1 0
      src/Avalonia.Base/Avalonia.Base.csproj
  6. 1 0
      src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
  7. 1 0
      src/Avalonia.Controls/Avalonia.Controls.csproj
  8. 1 0
      src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
  9. 1 0
      src/Avalonia.Dialogs/Avalonia.Dialogs.csproj
  10. 1 0
      src/Avalonia.Input/Avalonia.Input.csproj
  11. 1 0
      src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
  12. 1 0
      src/Avalonia.Layout/Avalonia.Layout.csproj
  13. 2 0
      src/Avalonia.Native/Avalonia.Native.csproj
  14. 3 1
      src/Avalonia.OpenGL/Avalonia.OpenGL.csproj
  15. 1 0
      src/Avalonia.Styling/Avalonia.Styling.csproj
  16. 1 0
      src/Avalonia.Visuals/Avalonia.Visuals.csproj
  17. 2 1
      src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj
  18. 1 0
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  19. 1 0
      src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
  20. 1 1
      src/Shared/ModuleInitializer.cs
  21. 2 1
      src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
  22. 1 0
      src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
  23. 1 0
      src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj
  24. 2 1
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  25. 2 0
      src/iOS/Avalonia.iOS/Avalonia.iOS.csproj
  26. 17 0
      src/tools/DevAnalyzers/DevAnalyzers.csproj
  27. 40 0
      src/tools/DevAnalyzers/GenericVirtualAnalyzer.cs
  28. 8 0
      src/tools/DevAnalyzers/GlobalSuppressions.cs

+ 29 - 1
Avalonia.sln

@@ -117,6 +117,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
 		build\Base.props = build\Base.props
 		build\Binding.props = build\Binding.props
 		build\CoreLibraries.props = build\CoreLibraries.props
+		build\DevAnalyzers.props = build\DevAnalyzers.props
 		build\EmbedXaml.props = build\EmbedXaml.props
 		build\HarfBuzzSharp.props = build\HarfBuzzSharp.props
 		build\JetBrains.Annotations.props = build\JetBrains.Annotations.props
@@ -234,7 +235,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.PlatformSupport",
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.PlatformSupport.UnitTests", "tests\Avalonia.PlatformSupport.UnitTests\Avalonia.PlatformSupport.UnitTests.csproj", "{CE910927-CE5A-456F-BC92-E4C757354A5C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.PlatformSupport.UnitTests", "tests\Avalonia.PlatformSupport.UnitTests\Avalonia.PlatformSupport.UnitTests.csproj", "{CE910927-CE5A-456F-BC92-E4C757354A5C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevAnalyzers", "src\tools\DevAnalyzers\DevAnalyzers.csproj", "{2B390431-288C-435C-BB6B-A374033BD8D1}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -2238,6 +2241,30 @@ Global
 		{CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|iPhone.Build.0 = Release|Any CPU
 		{CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 		{CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|iPhone.Build.0 = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhone.Build.0 = Release|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -2303,6 +2330,7 @@ Global
 		{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{CE910927-CE5A-456F-BC92-E4C757354A5C} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
+		{2B390431-288C-435C-BB6B-A374033BD8D1} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

+ 9 - 0
build/DevAnalyzers.props

@@ -0,0 +1,9 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ProjectReference Include="$(MSBuildThisFileDirectory)..\src\Tools\DevAnalyzers\DevAnalyzers.csproj"
+                      PrivateAssets="all"
+                      ReferenceOutputAssembly="false"
+                      OutputItemType="Analyzer"
+                      SetTargetFramework="TargetFramework=netstandard2.0"/>
+  </ItemGroup>
+</Project>

+ 1 - 0
src/Android/Avalonia.Android/Avalonia.Android.csproj

@@ -16,4 +16,5 @@
     <ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />
     <ProjectReference Include="..\..\Skia\Avalonia.Skia\Avalonia.Skia.csproj" />
   </ItemGroup>
+  <Import Project="..\..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Avalonia.Animation/Avalonia.Animation.csproj

@@ -11,4 +11,5 @@
   <Import Project="..\..\build\Rx.props" />
   <Import Project="..\..\build\ApiDiff.props" />
   <Import Project="..\..\build\NullableEnable.props" />
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Avalonia.Base/Avalonia.Base.csproj

@@ -12,4 +12,5 @@
   <Import Project="..\..\build\System.Memory.props" />
   <Import Project="..\..\build\ApiDiff.props" />
   <Import Project="..\..\build\NullableEnable.props" />
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj

@@ -23,4 +23,5 @@
   <Import Project="..\..\build\JetBrains.Annotations.props" />
   <Import Project="..\..\build\BuildTargets.targets" />
   <Import Project="..\..\build\ApiDiff.props" />
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Avalonia.Controls/Avalonia.Controls.csproj

@@ -19,4 +19,5 @@
   <Import Project="..\..\build\JetBrains.Annotations.props" />
   <Import Project="..\..\build\ApiDiff.props" />
   <Import Project="..\..\build\NullableEnable.props" />
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj

@@ -34,4 +34,5 @@
   <Import Project="..\..\build\BuildTargets.targets" />
   <Import Project="..\..\build\ApiDiff.props" />
   <Import Project="..\..\build\NullableEnable.props" />
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Avalonia.Dialogs/Avalonia.Dialogs.csproj

@@ -15,4 +15,5 @@
   </ItemGroup>
 
   <Import Project="..\..\build\ApiDiff.props" />
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Avalonia.Input/Avalonia.Input.csproj

@@ -15,4 +15,5 @@
   <Import Project="..\..\build\Rx.props" />
   <Import Project="..\..\build\ApiDiff.props" />
   <Import Project="..\..\build\NullableEnable.props" />
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Avalonia.Interactivity/Avalonia.Interactivity.csproj

@@ -11,4 +11,5 @@
   <Import Project="..\..\build\Rx.props" />
   <Import Project="..\..\build\ApiDiff.props" />
   <Import Project="..\..\build\NullableEnable.props" />
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Avalonia.Layout/Avalonia.Layout.csproj

@@ -10,4 +10,5 @@
   <Import Project="..\..\build\Rx.props" />
   <Import Project="..\..\build\ApiDiff.props" />
   <Import Project="..\..\build\NullableEnable.props" />
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 2 - 0
src/Avalonia.Native/Avalonia.Native.csproj

@@ -28,4 +28,6 @@
     <PackageReference Include="MicroCom.CodeGenerator.MSBuild" Version="0.10.4" PrivateAssets="all" />
     <MicroComIdl Include="avn.idl" CSharpInteropPath="Interop.Generated.cs" />
   </ItemGroup>
+
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 3 - 1
src/Avalonia.OpenGL/Avalonia.OpenGL.csproj

@@ -9,5 +9,7 @@
       <ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
       <ProjectReference Include="..\Avalonia.Controls\Avalonia.Controls.csproj" />
       <ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
-    </ItemGroup>    
+    </ItemGroup>
+
+    <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Avalonia.Styling/Avalonia.Styling.csproj

@@ -10,4 +10,5 @@
   </ItemGroup>
   <Import Project="..\..\build\ApiDiff.props" />
   <Import Project="..\..\build\NullableEnable.props" />
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Avalonia.Visuals/Avalonia.Visuals.csproj

@@ -19,4 +19,5 @@
   <Import Project="..\..\build\System.Memory.props" />
   <Import Project="..\..\build\ApiDiff.props" />
   <Import Project="..\..\build\NullableEnable.props" />
+  <Import Project="..\..\build\DevAnalyzers.props" />
 </Project>

+ 2 - 1
src/Markup/Avalonia.Markup.Xaml.Loader/Avalonia.Markup.Xaml.Loader.csproj

@@ -12,5 +12,6 @@
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
-  </ItemGroup>  
+  </ItemGroup>
+  <Import Project="..\..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@@ -68,4 +68,5 @@
   </ItemGroup>
   <Import Project="..\..\..\build\Rx.props" />
   <Import Project="..\..\..\build\ApiDiff.props" />
+  <Import Project="..\..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Markup/Avalonia.Markup/Avalonia.Markup.csproj

@@ -18,4 +18,5 @@
   <Import Project="..\..\..\build\System.Memory.props" />
   <Import Project="..\..\..\build\ApiDiff.props" />
   <Import Project="..\..\..\build\NullableEnable.props" />
+  <Import Project="..\..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 1
src/Shared/ModuleInitializer.cs

@@ -3,7 +3,7 @@ namespace System.Runtime.CompilerServices
 #if !NET5_0_OR_GREATER
     internal class ModuleInitializerAttribute : Attribute
     {
-        
+
     }
 #endif
 }

+ 2 - 1
src/Skia/Avalonia.Skia/Avalonia.Skia.csproj

@@ -16,5 +16,6 @@
   </ItemGroup>
   
   <Import Project="..\..\..\build\SkiaSharp.props" />
-  <Import Project="..\..\..\build\HarfBuzzSharp.props" />  
+  <Import Project="..\..\..\build\HarfBuzzSharp.props" />
+  <Import Project="..\..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj

@@ -18,4 +18,5 @@
   <Import Project="..\..\..\build\SharpDX.props" />
   <Import Project="..\..\..\build\HarfBuzzSharp.props" />
   <Import Project="..\..\..\build\JetBrains.Annotations.props" />
+  <Import Project="..\..\..\build\DevAnalyzers.props" />
 </Project>

+ 1 - 0
src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj

@@ -18,4 +18,5 @@
   </ItemGroup>
 
   <Import Project="..\..\..\build\SharpDX.props" />
+  <Import Project="..\..\..\build\DevAnalyzers.props" />
 </Project>

+ 2 - 1
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@@ -16,5 +16,6 @@
     <MicroComIdl Include="WinRT\winrt.idl" CSharpInteropPath="WinRT\WinRT.Generated.cs" />
     <MicroComIdl Include="Win32Com\win32.idl" CSharpInteropPath="Win32Com\Win32.Generated.cs" />
   </ItemGroup>
-  <Import Project="$(MSBuildThisFileDirectory)\..\..\..\build\System.Drawing.Common.props" />    
+  <Import Project="$(MSBuildThisFileDirectory)\..\..\..\build\System.Drawing.Common.props" />
+  <Import Project="..\..\..\build\DevAnalyzers.props" />
 </Project>

+ 2 - 0
src/iOS/Avalonia.iOS/Avalonia.iOS.csproj

@@ -19,4 +19,6 @@
       <BuiltProjectOutputGroupOutput Remove="$(ProjectDir)$(OutDir)$(_DeploymentTargetApplicationManifestFileName)" />
     </ItemGroup>
   </Target>
+
+  <Import Project="..\..\..\build\DevAnalyzers.props" />
 </Project>

+ 17 - 0
src/tools/DevAnalyzers/DevAnalyzers.csproj

@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <LangVersion>10</LangVersion>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" />
+  </ItemGroup>
+
+</Project>

+ 40 - 0
src/tools/DevAnalyzers/GenericVirtualAnalyzer.cs

@@ -0,0 +1,40 @@
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace DevAnalyzers;
+
+[DiagnosticAnalyzer(LanguageNames.CSharp)]
+public class GenericVirtualAnalyzer : DiagnosticAnalyzer
+{
+    public const string DiagnosticId = "AVADEV1001";
+
+    private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
+        DiagnosticId,
+        "Do not use generic virtual methods",
+        "Method '{0}' is a generic virtual method",
+        "Performance",
+        DiagnosticSeverity.Warning,
+        isEnabledByDefault: true,
+        description: "Generic virtual methods affect JIT startup time adversly and should be avoided.");
+
+    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+    public override void Initialize(AnalysisContext context)
+    {
+        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+        context.EnableConcurrentExecution();
+        context.RegisterSymbolAction(AnalyzeMethod, SymbolKind.Method);
+    }
+
+    private static void AnalyzeMethod(SymbolAnalysisContext context)
+    {
+        var symbol = (IMethodSymbol)context.Symbol;
+
+        if (symbol.IsGenericMethod &&
+            (symbol.IsVirtual || symbol.ContainingType.TypeKind == TypeKind.Interface))
+        {
+            context.ReportDiagnostic(Diagnostic.Create(Rule, symbol.Locations[0], symbol.Name));
+        }
+    }
+}

+ 8 - 0
src/tools/DevAnalyzers/GlobalSuppressions.cs

@@ -0,0 +1,8 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// 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("MicrosoftCodeAnalysisReleaseTracking", "RS2008:Enable analyzer release tracking")]