Skip to content

Commit

Permalink
Merge pull request #58075 from jmarolf/features/editorconfig-naming-s…
Browse files Browse the repository at this point in the history
…tyle-support
  • Loading branch information
jmarolf committed Dec 7, 2021
2 parents a3a6230 + 86ef543 commit 032a9be
Show file tree
Hide file tree
Showing 69 changed files with 5,256 additions and 182 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ internal partial class SettingsAggregator : ISettingsAggregator
private readonly Workspace _workspace;
private readonly ISettingsProviderFactory<AnalyzerSetting> _analyzerProvider;
private ISettingsProviderFactory<WhitespaceSetting> _whitespaceProvider;
private ISettingsProviderFactory<NamingStyleSetting> _namingStyleProvider;
private ISettingsProviderFactory<CodeStyleSetting> _codeStyleProvider;

public SettingsAggregator(Workspace workspace)
Expand All @@ -24,6 +25,7 @@ public SettingsAggregator(Workspace workspace)
_workspace.WorkspaceChanged += UpdateProviders;
_whitespaceProvider = GetOptionsProviderFactory<WhitespaceSetting>(_workspace);
_codeStyleProvider = GetOptionsProviderFactory<CodeStyleSetting>(_workspace);
_namingStyleProvider = GetOptionsProviderFactory<NamingStyleSetting>(_workspace);
_analyzerProvider = GetOptionsProviderFactory<AnalyzerSetting>(_workspace);
}

Expand All @@ -41,6 +43,7 @@ private void UpdateProviders(object? sender, WorkspaceChangeEventArgs e)
case WorkspaceChangeKind.ProjectChanged:
_whitespaceProvider = GetOptionsProviderFactory<WhitespaceSetting>(_workspace);
_codeStyleProvider = GetOptionsProviderFactory<CodeStyleSetting>(_workspace);
_namingStyleProvider = GetOptionsProviderFactory<NamingStyleSetting>(_workspace);
break;
default:
break;
Expand All @@ -59,6 +62,11 @@ private void UpdateProviders(object? sender, WorkspaceChangeEventArgs e)
return (ISettingsProvider<TData>)_whitespaceProvider.GetForFile(fileName);
}

if (typeof(TData) == typeof(NamingStyleSetting))
{
return (ISettingsProvider<TData>)_namingStyleProvider.GetForFile(fileName);
}

if (typeof(TData) == typeof(CodeStyleSetting))
{
return (ISettingsProvider<TData>)_codeStyleProvider.GetForFile(fileName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater;
using Microsoft.CodeAnalysis.EditorConfig;

namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Linq;
using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater;
using Microsoft.CodeAnalysis.EditorConfig.Parsing.NamingStyles;
using Microsoft.CodeAnalysis.NamingStyles;

namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data
{
internal class NamingStyleSetting
{
private NamingStyle[] _allStyles;
private readonly NamingStyleSettingsUpdater? _settingsUpdater;

public NamingStyleSetting(
NamingRule namingRule,
NamingStyle[] allStyles,
NamingStyleSettingsUpdater settingsUpdater,
string? fileName = null)
{
Style = namingRule.NamingStyle;
_allStyles = allStyles;
Type = namingRule.SymbolSpecification;
Severity = namingRule.EnforcementLevel;
_settingsUpdater = settingsUpdater;
Location = new SettingLocation(fileName is null ? LocationKind.VisualStudio : LocationKind.EditorConfig, fileName);
}

private NamingStyleSetting()
{
_allStyles = Array.Empty<NamingStyle>();
}

public event EventHandler<EventArgs>? SettingChanged;

internal static NamingStyleSetting FromParseResult(NamingStyleOption namingStyleOption)
{
return new NamingStyleSetting
{
Style = namingStyleOption.NamingScheme.AsNamingStyle(),
Type = namingStyleOption.ApplicableSymbolInfo.AsSymbolSpecification(),
Severity = namingStyleOption.Severity,
Location = new SettingLocation(LocationKind.EditorConfig, namingStyleOption.Section.FilePath)
};
}

internal NamingStyle Style { get; set; }
internal SymbolSpecification? Type { get; set; }

public string StyleName => Style.Name;
public string[] AllStyles => _allStyles.Select(style => style.Name).ToArray();
public string TypeName => Type?.Name ?? string.Empty;
public ReportDiagnostic Severity { get; private set; }
public SettingLocation? Location { get; protected set; }

private void OnSettingChanged((object, object?) setting)
{
if (setting is (ReportDiagnostic severity, _))
{
Severity = severity;
SettingChanged?.Invoke(this, EventArgs.Empty);
}

if (setting is (NamingStyle style, NamingStyle[] allStyles))
{
Style = style;
_allStyles = allStyles;
SettingChanged?.Invoke(this, EventArgs.Empty);
}
}

internal void ChangeSeverity(ReportDiagnostic severity)
{
if (Location is not null)
{
Location = Location with { LocationKind = LocationKind.EditorConfig };
_settingsUpdater?.QueueUpdate((OnSettingChanged, this), severity);
}
}

internal void ChangeStyle(int selectedIndex)
{
if (selectedIndex > -1 && selectedIndex < _allStyles.Length && Location is not null)
{
Location = Location with { LocationKind = LocationKind.EditorConfig };
_settingsUpdater?.QueueUpdate((OnSettingChanged, this), _allStyles[selectedIndex]);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data;
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions;
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater;
using Microsoft.CodeAnalysis.EditorConfig;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data;
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Extensions;
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;

namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.NamingStyles
{
internal class NamingStyleSettingsProvider : SettingsProviderBase<NamingStyleSetting, NamingStyleSettingsUpdater, (Action<(object, object?)>, NamingStyleSetting), object>
{
public NamingStyleSettingsProvider(string fileName, NamingStyleSettingsUpdater settingsUpdater, Workspace workspace)
: base(fileName, settingsUpdater, workspace)
{
Update();
}

protected override void UpdateOptions(AnalyzerConfigOptions _, OptionSet optionSet)
{
var solution = Workspace.CurrentSolution;
var projects = solution.GetProjectsUnderEditorConfigFile(FileName);
var project = projects.FirstOrDefault();
if (project is null)
{
return;
}

var options = project.State.AnalyzerOptions;
var document = project.Documents.FirstOrDefault();
if (document is null)
{
return;
}

var sourceTree = document.GetRequiredSyntaxTreeSynchronously(default(CancellationToken));
if (options.TryGetEditorConfigOption(NamingStyleOptions.NamingPreferences, sourceTree, out NamingStylePreferences? namingPreferences) &&
namingPreferences is not null)
{
AddNamingStylePreferences(namingPreferences, isInEditorConfig: true);
}
else
{
namingPreferences = optionSet.GetOption(NamingStyleOptions.NamingPreferences, project.Language);
if (namingPreferences is null)
{
return;
}

AddNamingStylePreferences(namingPreferences, isInEditorConfig: false);
}

void AddNamingStylePreferences(NamingStylePreferences namingPreferences, bool isInEditorConfig)
{
var namingRules = namingPreferences.NamingRules.Select(r => r.GetRule(namingPreferences));
var allStyles = namingPreferences.NamingStyles.DistinctBy(s => s.Name).ToArray();
var namingStyles = namingRules
.Select(namingRule =>
{
var style = namingRule.NamingStyle;
var type = namingRule.SymbolSpecification;
return isInEditorConfig
? new NamingStyleSetting(namingRule, allStyles, SettingsUpdater, FileName)
: new NamingStyleSetting(namingRule, allStyles, SettingsUpdater);
});

AddRange(namingStyles);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data;
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater;

namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.NamingStyles
{
internal class NamingStyleSettingsProviderFactory : IWorkspaceSettingsProviderFactory<NamingStyleSetting>
{
private readonly Workspace _workspace;

public NamingStyleSettingsProviderFactory(Workspace workspace) => _workspace = workspace;

public ISettingsProvider<NamingStyleSetting> GetForFile(string filePath)
{
var updater = new NamingStyleSettingsUpdater(_workspace, filePath);
return new NamingStyleSettingsProvider(filePath, updater, _workspace);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Composition;
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;

namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.DataProvider.NamingStyles
{
[ExportWorkspaceServiceFactory(typeof(IWorkspaceSettingsProviderFactory<NamingStyleSetting>)), Shared]
internal class NamingStyleSettingsWorkspaceServiceFactory : IWorkspaceServiceFactory
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public NamingStyleSettingsWorkspaceServiceFactory()
{
}

public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
=> new NamingStyleSettingsProviderFactory(workspaceServices.Workspace);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
using Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Data;
using Microsoft.CodeAnalysis.EditorConfig.Parsing.NamingStyles;
using Microsoft.CodeAnalysis.NamingStyles;

namespace Microsoft.CodeAnalysis.Editor.EditorConfigSettings.Updater
{
internal static class EditorConfigNamingStylesExtensions
{
public static bool TryGetParseResultForRule(
this EditorConfigNamingStyles editorConfigNamingStyles,
NamingStyleSetting namingStyleSetting,
[NotNullWhen(true)] out NamingStyleOption? namingStyleOption)
{
namingStyleOption = null;
foreach (var (option, optionAsNamingStyle) in editorConfigNamingStyles.Rules.AsNamingStyleSettings())
{
if (AreSameRule(optionAsNamingStyle, namingStyleSetting))
{
namingStyleOption = option;
return true;
}
}

return false;

static bool AreSameRule(NamingStyleSetting left, NamingStyleSetting right)
=> left.Severity == right.Severity &&
AreSameSymbolSpec(left.Type, right.Type) &&
AreSameNamingStyle(left.Style, right.Style);

static bool AreSameSymbolSpec(SymbolSpecification? left, SymbolSpecification? right)
{
if (left is null && right is null)
{
return true;
}

if (left is null || right is null)
{
return false;
}

return left.ApplicableSymbolKindList.SequenceEqual(right!.ApplicableSymbolKindList) &&
left.ApplicableAccessibilityList.SequenceEqual(right.ApplicableAccessibilityList) &&
left.RequiredModifierList.SequenceEqual(right.RequiredModifierList);
}

static bool AreSameNamingStyle(NamingStyle left, NamingStyle right)
=> left.Prefix == right.Prefix &&
left.Suffix == right.Suffix &&
left.WordSeparator == right.WordSeparator &&
left.CapitalizationScheme == right.CapitalizationScheme;
}

public static ImmutableArray<(NamingStyleOption namingStyleOption, NamingStyleSetting namingStyleSetting)> AsNamingStyleSettings(this ImmutableArray<NamingStyleOption> namingStyleOptions)
=> namingStyleOptions.SelectAsArray(rule => (rule, NamingStyleSetting.FromParseResult(rule)));

public static NamingStyle AsNamingStyle(this NamingScheme namingScheme)
=> new(
Guid.NewGuid(),
namingScheme.OptionName,
namingScheme.Prefix,
namingScheme.Suffix,
namingScheme.WordSeparator,
namingScheme.Capitalization);

public static SymbolSpecification AsSymbolSpecification(this ApplicableSymbolInfo applicableSymbolInfo)
=> new(
Guid.NewGuid(),
applicableSymbolInfo.OptionName,
applicableSymbolInfo.SymbolKinds,
applicableSymbolInfo.Accessibilities,
applicableSymbolInfo.Modifiers);
}
}
Loading

0 comments on commit 032a9be

Please sign in to comment.