Browse Source

Add Analyzers project to the main package

pull/11029/head
Max Katz 3 years ago
parent
commit
dbc3c802a3
  1. 2
      Avalonia.sln
  2. 2
      build/DevAnalyzers.props
  3. 4
      packages/Avalonia/Avalonia.csproj
  4. 2
      src/tools/Avalonia.Analyzers/Avalonia.Analyzers.csproj
  5. 0
      src/tools/Avalonia.Analyzers/AvaloniaPropertyAnalyzer.CompileAnalyzer.cs
  6. 1
      src/tools/Avalonia.Analyzers/AvaloniaPropertyAnalyzer.cs
  7. 8
      src/tools/Avalonia.Analyzers/GlobalSuppressions.cs
  8. 59
      src/tools/Avalonia.Analyzers/OnPropertyChangedOverrideAnalyzer.cs

2
Avalonia.sln

@ -233,7 +233,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUIDemo", "samples\R
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GpuInterop", "samples\GpuInterop\GpuInterop.csproj", "{C810060E-3809-4B74-A125-F11533AF9C1B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\PublicAnalyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{176582E8-46AF-416A-85C1-13A5C6744497}"
ProjectSection(SolutionItems) = preProject

2
build/DevAnalyzers.props

@ -5,7 +5,7 @@
ReferenceOutputAssembly="false"
OutputItemType="Analyzer"
SetTargetFramework="TargetFramework=netstandard2.0"/>
<ProjectReference Include="$(MSBuildThisFileDirectory)..\src\tools\PublicAnalyzers\Avalonia.Analyzers.csproj"
<ProjectReference Include="$(MSBuildThisFileDirectory)..\src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj"
PrivateAssets="all"
ReferenceOutputAssembly="false"
OutputItemType="Analyzer"

4
packages/Avalonia/Avalonia.csproj

@ -15,6 +15,10 @@
ReferenceOutputAssembly="false"
PrivateAssets="all"
OutputItemType="Analyzer" />
<ProjectReference Include="..\..\src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj"
ReferenceOutputAssembly="false"
PrivateAssets="all"
OutputItemType="Analyzer" />
</ItemGroup>
<PropertyGroup>

2
src/tools/PublicAnalyzers/Avalonia.Analyzers.csproj → src/tools/Avalonia.Analyzers/Avalonia.Analyzers.csproj

@ -11,7 +11,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" />
</ItemGroup>
</Project>

0
src/tools/PublicAnalyzers/AvaloniaPropertyAnalyzer.CompileAnalyzer.cs → src/tools/Avalonia.Analyzers/AvaloniaPropertyAnalyzer.CompileAnalyzer.cs

1
src/tools/PublicAnalyzers/AvaloniaPropertyAnalyzer.cs → src/tools/Avalonia.Analyzers/AvaloniaPropertyAnalyzer.cs

@ -14,7 +14,6 @@ using Microsoft.CodeAnalysis.Operations;
namespace Avalonia.Analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
[SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008:Enable analyzer release tracking")]
public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
{
private const string Category = "AvaloniaProperty";

8
src/tools/Avalonia.Analyzers/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")]

59
src/tools/Avalonia.Analyzers/OnPropertyChangedOverrideAnalyzer.cs

@ -0,0 +1,59 @@
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Avalonia.Analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class OnPropertyChangedOverrideAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = "AVA2001";
private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
DiagnosticId,
"Missing invoke base.OnPropertyChanged",
"Method '{0}' do not invoke base.{0}",
"Potential issue",
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
description: "The OnPropertyChanged of the base class was not invoked in the override method declaration, which could lead to unwanted behavior.");
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterSyntaxNodeAction(AnalyzeMethod, SyntaxKind.MethodDeclaration);
}
private static void AnalyzeMethod(SyntaxNodeAnalysisContext context)
{
var method = (MethodDeclarationSyntax)context.Node;
if (context.SemanticModel.GetDeclaredSymbol(method, context.CancellationToken) is IMethodSymbol currentMethod
&& currentMethod.Name == "OnPropertyChanged"
&& currentMethod.OverriddenMethod is IMethodSymbol originalMethod)
{
var baseInvocations = method.Body?.DescendantNodes().OfType<BaseExpressionSyntax>();
if (baseInvocations?.Any() == true)
{
foreach (var baseInvocation in baseInvocations)
{
if (baseInvocation.Parent is SyntaxNode parent)
{
var targetSymbol = context.SemanticModel.GetSymbolInfo(parent, context.CancellationToken);
if (SymbolEqualityComparer.Default.Equals(targetSymbol.Symbol, originalMethod))
{
return;
}
}
}
}
context.ReportDiagnostic(Diagnostic.Create(Rule, currentMethod.Locations[0], currentMethod.Name));
}
}
}
Loading…
Cancel
Save