|
// 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.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.EditorConfig.Parsing;
using Microsoft.CodeAnalysis.EditorConfig.Parsing.NamingStyles;
using Microsoft.CodeAnalysis.NamingStyles;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles
{
internal static partial class EditorConfigNamingStyleParser
{
internal static bool TryGetNamingStyleData(
Section section,
string namingRuleName,
IReadOnlyDictionary<string, (string value, TextLine? line)> properties,
[NotNullWhen(true)] out NamingScheme? namingScheme)
{
return TryGetNamingStyleData(
namingRuleName,
properties,
s => s.value,
x => x.line,
s => (s.value, s.line),
(nameTuple, prefixTuple, suffixTuple, wordSeparatorTuple, capitalizationTuple) =>
{
var (name, nameTextLine) = nameTuple;
var (prefix, prefixTextLine) = prefixTuple;
var (suffix, suffixTextLine) = suffixTuple;
var (wordSeparator, wordSeparatorTextLine) = wordSeparatorTuple;
var (capitalization, capitalizationTextLine) = capitalizationTuple;
return new NamingScheme(
OptionName: (section, nameTextLine?.Span, name),
Prefix: (section, prefixTextLine?.Span, prefix),
Suffix: (section, suffixTextLine?.Span, suffix),
WordSeparator: (section, wordSeparatorTextLine?.Span, wordSeparator),
Capitalization: (section, capitalizationTextLine?.Span, capitalization));
},
out namingScheme);
}
private static bool TryGetNamingStyleData(
string namingRuleName,
IReadOnlyDictionary<string, string> rawOptions,
out NamingStyle namingStyle)
{
return TryGetNamingStyleData<string, object?, NamingStyle>(
namingRuleName,
rawOptions,
s => s,
x => null,
s => (s ?? string.Empty, null),
(nameTuple, prefixTuple, suffixTuple, wordSeparatorTuple, capitalizationTuple) =>
{
var (namingStyleName, _) = nameTuple;
var (prefix, _) = prefixTuple;
var (suffix, _) = suffixTuple;
var (wordSeparator, _) = wordSeparatorTuple;
var (capitalization, _) = capitalizationTuple;
return new NamingStyle(
Guid.NewGuid(),
namingStyleName,
prefix,
suffix,
wordSeparator,
capitalization);
},
out namingStyle);
}
private static bool TryGetNamingStyleData<T, TData, TResult>(
string namingRuleName,
IReadOnlyDictionary<string, T> rawOptions,
Func<T, string> nameSelector,
Func<T, TData> dataSelector,
Func<T?, (string value, TData data)> tupleSelector,
Func<(string namingStyleName, TData data),
(string prefix, TData data),
(string suffix, TData data),
(string wordSeparator, TData data),
(Capitalization capitalization, TData data), TResult> constructor,
[NotNullWhen(true)] out TResult? namingStyle)
{
namingStyle = default;
if (!TryGetNamingStyleTitle(namingRuleName, rawOptions, nameSelector, dataSelector, out var namingStyleTitle))
{
return false;
}
var requiredPrefix = GetNamingRequiredPrefix(namingStyleTitle.name, rawOptions, tupleSelector);
var requiredSuffix = GetNamingRequiredSuffix(namingStyleTitle.name, rawOptions, tupleSelector);
var wordSeparator = GetNamingWordSeparator(namingStyleTitle.name, rawOptions, tupleSelector);
if (!TryGetNamingCapitalization(namingStyleTitle.name, rawOptions, tupleSelector, out var capitalization))
{
return false;
}
namingStyle = constructor(namingStyleTitle, requiredPrefix, requiredSuffix, wordSeparator, capitalization);
return namingStyle is not null;
}
private static bool TryGetNamingStyleTitle<T, TData>(
string namingRuleName,
IReadOnlyDictionary<string, T> conventionsDictionary,
Func<T, string> nameSelector,
Func<T, TData> dataSelector,
out (string name, TData data) result)
{
if (conventionsDictionary.TryGetValue($"dotnet_naming_rule.{namingRuleName}.style", out var namingStyleName))
{
var name = nameSelector(namingStyleName);
result = (name, dataSelector(namingStyleName));
return name != null;
}
result = default;
return false;
}
private static (string prefix, TData data) GetNamingRequiredPrefix<T, TData>(
string namingStyleName,
IReadOnlyDictionary<string, T> properties,
Func<T?, (string value, TData data)> tupleSelector)
=> GetValueFromDictionary(namingStyleName, "required_prefix", properties, tupleSelector);
private static (string suffix, TData data) GetNamingRequiredSuffix<T, TData>(
string namingStyleName,
IReadOnlyDictionary<string, T> properties,
Func<T?, (string value, TData data)> tupleSelector)
=> GetValueFromDictionary(namingStyleName, "required_suffix", properties, tupleSelector);
private static (string wordSeparator, TData data) GetNamingWordSeparator<T, TData>(
string namingStyleName,
IReadOnlyDictionary<string, T> properties,
Func<T?, (string value, TData data)> tupleSelector)
=> GetValueFromDictionary(namingStyleName, "word_separator", properties, tupleSelector);
private static bool TryGetNamingCapitalization<T, TData>(
string namingStyleName,
IReadOnlyDictionary<string, T> properties,
Func<T?, (string value, TData data)> tupleSelector,
out (Capitalization capitalization, TData data) result)
{
var (value, data) = GetValueFromDictionary(namingStyleName, "capitalization", properties, tupleSelector);
if (TryParseCapitalizationScheme(value, out var capitalization))
{
result = (capitalization.Value, data);
return true;
}
result = default;
return false;
}
private static (string value, TData data) GetValueFromDictionary<T, TData>(
string namingStyleName,
string optionName,
IReadOnlyDictionary<string, T> conventionsDictionary,
Func<T?, (string value, TData data)> tupleSelector)
{
_ = conventionsDictionary.TryGetValue($"dotnet_naming_style.{namingStyleName}.{optionName}", out var result);
return tupleSelector(result);
}
private static bool TryParseCapitalizationScheme(
string namingStyleCapitalization,
[NotNullWhen(true)] out Capitalization? capitalization)
{
capitalization = namingStyleCapitalization switch
{
"pascal_case" => Capitalization.PascalCase,
"camel_case" => Capitalization.CamelCase,
"first_word_upper" => Capitalization.FirstUpper,
"all_upper" => Capitalization.AllUpper,
"all_lower" => Capitalization.AllLower,
_ => null,
};
return capitalization is not null;
}
public static string ToEditorConfigString(this Capitalization capitalization)
=> capitalization switch
{
Capitalization.PascalCase => "pascal_case",
Capitalization.CamelCase => "camel_case",
Capitalization.FirstUpper => "first_word_upper",
Capitalization.AllUpper => "all_upper",
Capitalization.AllLower => "all_lower",
_ => throw ExceptionUtilities.UnexpectedValue(capitalization),
};
}
}
|