Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move DescriptorFactory and DiagnosticAnalyzers to namespaces #9294

Merged
merged 3 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using SonarAnalyzer.Analyzers;

namespace SonarAnalyzer.CSharp.Styling.Common;

internal static class DescriptorFactory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using SonarAnalyzer.Analyzers;

namespace SonarAnalyzer.CSharp.Styling.Common;

public abstract class StylingAnalyzer : SonarDiagnosticAnalyzer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

namespace SonarAnalyzer
namespace SonarAnalyzer.Common;

internal static class DescriptorFactory
{
internal static class DescriptorFactory
{
public static DiagnosticDescriptor Create(string id, string messageFormat, bool? isEnabledByDefault = null, bool fadeOutCode = false) =>
// RuleCatalog class is created from SonarAnalyzer.SourceGenerator
DiagnosticDescriptorFactory.Create(AnalyzerLanguage.CSharp, RuleCatalog.Rules[id], messageFormat, isEnabledByDefault, fadeOutCode);
}
public static DiagnosticDescriptor Create(string id, string messageFormat, bool? isEnabledByDefault = null, bool fadeOutCode = false) =>
// RuleCatalog class is created from SonarAnalyzer.SourceGenerator
DiagnosticDescriptorFactory.Create(AnalyzerLanguage.CSharp, RuleCatalog.Rules[id], messageFormat, isEnabledByDefault, fadeOutCode);
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<Using Include="Microsoft.CodeAnalysis.CSharp.Syntax" />
<Using Include="Microsoft.CodeAnalysis.CSharp.Extensions" />
<Using Include="SonarAnalyzer.AnalysisContext" />
<Using Include="SonarAnalyzer.Analyzers" />
<Using Include="SonarAnalyzer.Common" />
<Using Include="SonarAnalyzer.Extensions" />
<Using Include="SonarAnalyzer.Helpers" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
using System.IO;
using System.Runtime.CompilerServices;
using Roslyn.Utilities;
using static SonarAnalyzer.Helpers.DiagnosticDescriptorFactory;
using static SonarAnalyzer.Analyzers.DiagnosticDescriptorFactory;

namespace SonarAnalyzer.AnalysisContext;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* SonarAnalyzer for .NET
* Copyright (C) 2015-2024 SonarSource SA
* mailto: contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

namespace SonarAnalyzer.Analyzers;

public static class DiagnosticDescriptorFactory
{
public static readonly string SonarWayTag = "SonarWay";
public static readonly string UtilityTag = "Utility";
public static readonly string MainSourceScopeTag = "MainSourceScope";
public static readonly string TestSourceScopeTag = "TestSourceScope";

public static DiagnosticDescriptor CreateUtility(string diagnosticId, string title) =>
new(diagnosticId,
title,
string.Empty,
string.Empty,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
customTags: BuildUtilityTags());

public static DiagnosticDescriptor Create(AnalyzerLanguage language, RuleDescriptor rule, string messageFormat, bool? isEnabledByDefault, bool fadeOutCode) =>
new(rule.Id,
rule.Title,
messageFormat,
rule.Category,
fadeOutCode ? DiagnosticSeverity.Info : DiagnosticSeverity.Warning,
rule.IsHotspot || (isEnabledByDefault ?? rule.SonarWay),
rule.Description,
language.HelpLink(rule.Id),
BuildTags(language, rule, fadeOutCode));

private static string[] BuildTags(AnalyzerLanguage language, RuleDescriptor rule, bool fadeOutCode)
{
var tags = new List<string> { language.LanguageName };
tags.AddRange(rule.Scope.ToTags());
Add(rule.SonarWay, SonarWayTag);
Add(fadeOutCode, WellKnownDiagnosticTags.Unnecessary);
return tags.ToArray();

void Add(bool condition, string tag)
{
if (condition)
{
tags.Add(tag);
}
}
}

private static IEnumerable<string> ToTags(this SourceScope sourceScope) =>
sourceScope switch
{
SourceScope.Main => new[] { MainSourceScopeTag },
SourceScope.Tests => new[] { TestSourceScopeTag },
SourceScope.All => new[] { MainSourceScopeTag, TestSourceScopeTag },
_ => throw new NotSupportedException($"{sourceScope} is not supported 'SourceScope' value."),
};

private static string[] BuildUtilityTags() =>
SourceScope.All.ToTags().Concat(new[] { UtilityTag })
#if !DEBUG
// Allow to configure the analyzers in debug mode only. This allows to run test selectively (for example to test only one rule)
.Union(new[] { WellKnownDiagnosticTags.NotConfigurable })
#endif
.ToArray();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,18 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

namespace SonarAnalyzer.Helpers
namespace SonarAnalyzer.Analyzers;

public abstract class HotspotDiagnosticAnalyzer : SonarDiagnosticAnalyzer
{
public abstract class HotspotDiagnosticAnalyzer : SonarDiagnosticAnalyzer
{
protected IAnalyzerConfiguration Configuration { get; }
protected IAnalyzerConfiguration Configuration { get; }

protected HotspotDiagnosticAnalyzer(IAnalyzerConfiguration configuration) =>
Configuration = configuration;
protected HotspotDiagnosticAnalyzer(IAnalyzerConfiguration configuration) =>
Configuration = configuration;

protected bool IsEnabled(AnalyzerOptions options)
{
Configuration.Initialize(options);
return SupportedDiagnostics.Any(d => Configuration.IsEnabled(d.Id));
}
protected bool IsEnabled(AnalyzerOptions options)
{
Configuration.Initialize(options);
return SupportedDiagnostics.Any(x => Configuration.IsEnabled(x.Id));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,22 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

namespace SonarAnalyzer.Helpers
namespace SonarAnalyzer.Analyzers;

public abstract class ParametrizedDiagnosticAnalyzer : SonarDiagnosticAnalyzer
{
public abstract class ParametrizedDiagnosticAnalyzer : SonarDiagnosticAnalyzer
{
protected abstract void Initialize(SonarParametrizedAnalysisContext context);
protected abstract void Initialize(SonarParametrizedAnalysisContext context);

protected sealed override void Initialize(SonarAnalysisContext context)
{
var parameterContext = new SonarParametrizedAnalysisContext(context);
Initialize(parameterContext);
protected sealed override void Initialize(SonarAnalysisContext context)
{
var parameterContext = new SonarParametrizedAnalysisContext(context);
Initialize(parameterContext);

context.RegisterCompilationStartAction(
c =>
{
ParameterLoader.SetParameterValues(this, c.SonarLintXml());
parameterContext.ExecutePostponedActions(c);
});
}
context.RegisterCompilationStartAction(
c =>
{
ParameterLoader.SetParameterValues(this, c.SonarLintXml());
parameterContext.ExecutePostponedActions(c);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* SonarAnalyzer for .NET
* Copyright (C) 2015-2024 SonarSource SA
* mailto: contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using RoslynAnalysisContext = Microsoft.CodeAnalysis.Diagnostics.AnalysisContext;

namespace SonarAnalyzer.Analyzers;

public abstract class SonarDiagnosticAnalyzer : DiagnosticAnalyzer
{
public static readonly string EnableConcurrentExecutionVariable = "SONAR_DOTNET_ENABLE_CONCURRENT_EXECUTION";

protected abstract void Initialize(SonarAnalysisContext context);

protected virtual bool EnableConcurrentExecution => IsConcurrentExecutionEnabled();

public sealed override void Initialize(RoslynAnalysisContext context)
{
// The default values are Analyze | ReportDiagnostics. We do this call to make sure it will be still enabled even if the default values changed. (Needed for the razor analysis)
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
if (EnableConcurrentExecution)
{
context.EnableConcurrentExecution();
}
Initialize(new SonarAnalysisContext(context, SupportedDiagnostics));
}

protected static bool IsConcurrentExecutionEnabled()
{
var value = Environment.GetEnvironmentVariable(EnableConcurrentExecutionVariable);
return value is null || !bool.TryParse(value, out var result) || result;
}
}

public abstract class SonarDiagnosticAnalyzer<TSyntaxKind> : SonarDiagnosticAnalyzer
where TSyntaxKind : struct
{
protected abstract string MessageFormat { get; }
protected abstract ILanguageFacade<TSyntaxKind> Language { get; }
protected DiagnosticDescriptor Rule { get; }
public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

protected SonarDiagnosticAnalyzer(string diagnosticId) =>
Rule = Language.CreateDescriptor(diagnosticId, MessageFormat);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* SonarAnalyzer for .NET
* Copyright (C) 2015-2024 SonarSource SA
* mailto: contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

namespace SonarAnalyzer.Analyzers;

public abstract class TrackerHotspotDiagnosticAnalyzer<TSyntaxKind> : HotspotDiagnosticAnalyzer where TSyntaxKind : struct
{
protected abstract ILanguageFacade<TSyntaxKind> Language { get; }
protected abstract void Initialize(TrackerInput input);

protected DiagnosticDescriptor Rule { get; }

public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
sebastien-marichal marked this conversation as resolved.
Show resolved Hide resolved

protected TrackerHotspotDiagnosticAnalyzer(IAnalyzerConfiguration configuration, string diagnosticId, string messageFormat) : base(configuration) =>
Rule = Language.CreateDescriptor(diagnosticId, messageFormat);

protected override void Initialize(SonarAnalysisContext context) =>
Initialize(new TrackerInput(context, Configuration, Rule));
}

This file was deleted.

Loading
Loading