Merge pull request #4 from unoplatform/dev/jela/static-validation

feat: Add UNOM0003 for large static classes validation
This commit is contained in:
Jérôme Laban 2020-08-14 15:46:37 -04:00 коммит произвёл GitHub
Родитель 8cb581ceea 2fa8a86510
Коммит 4294aee15b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 133 добавлений и 18 удалений

Просмотреть файл

@ -10,17 +10,11 @@ jobs:
steps:
- checkout: self
clean: true
- task: NuGetToolInstaller@0
inputs:
versionSpec: 4.9.1
checkLatest: false
- task: GitVersion@4
# Ignore gitversion for forks, until this is fixed:
# https://developercommunity.visualstudio.com/content/problem/284991/public-vsts-previouw-cant-set-build-number-of-pr-b.html
condition: eq(variables['System.PullRequest.IsFork'], 'False')
- task: GitVersion@5
inputs:
useConfigFile: true
configFilePath: gitversion.yml
updateAssemblyInfo: false
- task: DotNetCoreInstaller@0

Просмотреть файл

@ -28,3 +28,9 @@ Should become:
var s = "";
s.TrimStart(new char[0]);
```
## UNOM0003 Large number of static methods in a type with a static initializer
This analyzer flags type with a static initializer and a large number of static methods.
Such a pattern can create a very large set of boiler plate code that can be avoided by either removing static type initializers, or move static methods to instance methods and use a singleton.

Просмотреть файл

@ -1,21 +1,54 @@
assembly-versioning-scheme: MajorMinorPatch
mode: ContinuousDeployment
next-version: 1.0.0
continuous-delivery-fallback-tag: ""
mode: Mainline
next-version: 1.1
branches:
master:
mode: ContinuousDeployment
regex: master
tag: dev
increment: Minor
is-source-branch-for: ['beta', 'stable']
pull-request:
regex: ^(pull|pull\-requests|pr)[/-]
mode: ContinuousDeployment
tag: 'PullRequest'
tag-number-pattern: '[/-](?<number>\d+)[-/]'
increment: Inherit
beta:
mode: ContinuousDeployment
regex: ^release/beta/.*
tag: beta
increment: none
source-branches: ['master']
stable:
tag: ""
regex: stable
source-branches: ['master']
regex: ^release/stable/.*
tag: ''
increment: Patch
source-branches: ['master','beta']
is-mainline: true
dev:
mode: ContinuousDeployment
regex: ^dev/.*?/(.*?)
tag: dev.{BranchName}
regex: dev/.*?/(.*?)
source-branches: ['master']
source-branches: ['master', 'release', 'projects', 'feature']
increment: none
projects:
tag: proj-{BranchName}
regex: projects/(.*?)
regex: ^projects/(.*?)
source-branches: ['master']
increment: none
feature:
tag: feature.{BranchName}
regex: ^feature/(.*?)
source-branches: ['master']
increment: none
ignore:
sha: []

Просмотреть файл

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Uno.Analyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class StaticClassInitializerAnalyzer : DiagnosticAnalyzer
{
internal const string Title = "Large number of static methods in a type with a static initializer";
internal const string MessageFormat = "{0} has a static type initializer and contains too many static methods. Refactor to use instance methods or remove the static type initializer.";
internal const string Description = "This type has a static type initializer and contains too many static methods; this creates a large boiler plate code in every static method";
internal const string Category = "Performance";
internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(
"UNOM0003",
Title,
MessageFormat,
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
description: Description
);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.EnableConcurrentExecution();
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze);
context.RegisterCompilationStartAction(csa =>
{
var container = new Container(csa.Compilation, this);
csa.RegisterSymbolAction(c => container.OnSymbolAction(c), SymbolKind.NamedType);
});
}
public class Container
{
private readonly StaticClassInitializerAnalyzer _owner;
public Container(Compilation compilation, StaticClassInitializerAnalyzer owner)
{
_owner = owner;
}
internal void OnSymbolAction(SymbolAnalysisContext contextAnalysis)
{
if(contextAnalysis.Symbol is INamedTypeSymbol namedTypeSymbol)
{
var hasStaticInitializer = namedTypeSymbol.Constructors.Any(c => c.IsStatic);
var staticMethodsCound = namedTypeSymbol
.GetMembers()
.Count(m => m.Kind == SymbolKind.Method && m.IsStatic);
if(hasStaticInitializer && staticMethodsCound > 50)
{
var diagnostic = Diagnostic.Create(
_owner.SupportedDiagnostics.First(),
namedTypeSymbol.Locations.FirstOrDefault(),
namedTypeSymbol.ToDisplayString()
);
contextAnalysis.ReportDiagnostic(diagnostic);
}
}
}
}
}
}