Skip to content

Commit

Permalink
Merge pull request #60 from kysect/feat/enhance-ide-parsing
Browse files Browse the repository at this point in the history
Implement parsing for IDE* examples
  • Loading branch information
FrediKats authored Sep 8, 2023
2 parents 3b9c662 + 67b6405 commit dfd2a53
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,21 @@ public string FormatStyleRule(CodeStyleRoslynStyleRuleConfiguration rule)
builder.AddText($"Severity: {rule.Severity}");
builder.AddEmptyLine();
builder.AddText(rule.Rule.Overview);
builder.AddEmptyLine();
if (rule.Rule.Example is not null)
{
builder.AddEmptyLine();
builder.AddCode(rule.Rule.Example);
}

foreach (CodeStyleRoslynOptionConfiguration optionConfiguration in rule.Options)
{
builder.AddH3($"{optionConfiguration.Option.Name} = {optionConfiguration.SelectedValue}");
builder.AddEmptyLine();
builder.AddH3($"{optionConfiguration.Option.Name} = {optionConfiguration.SelectedValue}");
if (optionConfiguration.Option.CsharpCodeSample is not null)
{
builder.AddEmptyLine();
builder.AddCode(optionConfiguration.Option.CsharpCodeSample);
}
}

return builder.Build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ public IReadOnlyCollection<RoslynStyleRule> ParseStyleRules(string info)
.ToList();

string overviewText = GetStyleOverviewText(markdownHeadedBlocks);
string? csharpCodeSample = FindIdeExample(markdownHeadedBlocks);

IReadOnlyCollection<RoslynStyleRuleOption> roslynStyleRuleOptions = ParseOptions(markdownHeadedBlocks);

return roslynStyleRuleInformationTables
.Select(table => ConvertToRule(table, overviewText, roslynStyleRuleOptions))
.Select(table => ConvertToRule(table, overviewText, csharpCodeSample, roslynStyleRuleOptions))
.ToList();
}

Expand Down Expand Up @@ -101,15 +103,15 @@ private RoslynStyleRuleInformationTable ParseInformationTable(Table tableBlock)
private RoslynStyleRule ConvertToRule(
RoslynStyleRuleInformationTable roslynStyleRuleInformationTable,
string overviewText,
string? example,
IReadOnlyCollection<RoslynStyleRuleOption> roslynStyleRuleOptions)
{
return new RoslynStyleRule(
roslynStyleRuleInformationTable.RuleId,
roslynStyleRuleInformationTable.Title,
roslynStyleRuleInformationTable.Category,
overviewText,
// TODO: #39 support this
example: string.Empty,
example: example,
roslynStyleRuleOptions);
}

Expand Down Expand Up @@ -186,6 +188,15 @@ private string GetStyleOverviewText(IReadOnlyCollection<MarkdownHeadedBlock> mar
return overviewText;
}

private string? FindIdeExample(IReadOnlyCollection<MarkdownHeadedBlock> markdownHeadedBlocks)
{
MarkdownHeadedBlock? exampleBlock = markdownHeadedBlocks.FirstOrDefault(h => h.HeaderText == "Example");
if (exampleBlock is null)
return null;

return TryExtractCsharpCodeBlock(exampleBlock);
}

private IReadOnlyCollection<RoslynStyleRuleOption> ParseOptions(IReadOnlyCollection<MarkdownHeadedBlock> markdownHeadedBlocks)
{
return markdownHeadedBlocks
Expand Down Expand Up @@ -214,14 +225,7 @@ private RoslynStyleRuleOption ParseOption(MarkdownHeadedBlock optionBlock)
MarkdownTableContent markdownTableContent = _markdownTableParser.ParseToSimpleContent(tables.Single());
MsLearnPropertyValueDescriptionTable table = _msLearnTableParser.Parse(markdownTableContent);

var codeBlocks = optionBlock.Content.OfType<CodeBlock>().ToList();
CodeBlock? csharpCodeBlock = codeBlocks
.OfType<FencedCodeBlock>()
.FirstOrDefault(cb => cb.Info == "csharp");

string? csharpCodeSample = csharpCodeBlock is null
? null
: _textExtractor.ExtractText(csharpCodeBlock);
string? csharpCodeSample = TryExtractCsharpCodeBlock(optionBlock);

MsLearnPropertyValueDescriptionTableRow optionName = table.GetSingleValue("Option name");
IReadOnlyList<MsLearnPropertyValueDescriptionTableRow> optionValues = table.FindValues("Option values");
Expand All @@ -233,4 +237,16 @@ private RoslynStyleRuleOption ParseOption(MarkdownHeadedBlock optionBlock)
defaultValue?.Value,
csharpCodeSample);
}

private string? TryExtractCsharpCodeBlock(MarkdownHeadedBlock block)
{
FencedCodeBlock? codeBlock = block.Content
.OfType<FencedCodeBlock>()
.FirstOrDefault(cb => cb.Info == "csharp");

if (codeBlock is null)
return null;

return _textExtractor.ExtractText(codeBlock);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ public class RoslynStyleRule
public string Title { get; }
public string Category { get; }
public string Overview { get; }
public string Example { get; }
public string? Example { get; }
public IReadOnlyCollection<RoslynStyleRuleOption> Options { get; }

public RoslynStyleRule(RoslynRuleId ruleId, string title, string category, string overview, string example, IReadOnlyCollection<RoslynStyleRuleOption> options)
public RoslynStyleRule(RoslynRuleId ruleId, string title, string category, string overview, string? example, IReadOnlyCollection<RoslynStyleRuleOption> options)
{
RuleId = ruleId;
Title = title;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,42 @@ public class MarkdownCodeStyleFormatterTests
{
private readonly MarkdownCodeStyleFormatter _formatter = new MarkdownCodeStyleFormatter(TestLogger.ProviderForTests());

[Test]
public void FormatStyleRule_ForIDE0001_ReturnExpected()
{
const string expected = """
## Simplify name (IDE0001)

Severity: Warning

This rule concerns the use of simplified type names in declarations and executable code, when possible. You can remove unnecessary name qualification to simplify code and improve readability.

```csharp
using System.IO;
class C
{
// IDE0001: 'System.IO.FileInfo' can be simplified to 'FileInfo'
System.IO.FileInfo file;

// Fixed code
FileInfo file;
}
```

""";

RoslynStyleRule ide0040 = WellKnownRoslynRuleDefinitions.IDE0001();

var styleRoslynStyleRuleConfiguration = new CodeStyleRoslynStyleRuleConfiguration(
ide0040,
RoslynRuleSeverity.Warning,
Options: Array.Empty<CodeStyleRoslynOptionConfiguration>());

string formatterRule = _formatter.FormatStyleRule(styleRoslynStyleRuleConfiguration);

formatterRule.Should().Be(expected);
}

[Test]
public void FormatStyleRule_ForIDE0040_ReturnExpected()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ public class MsLearnDocumentationParserTests

private readonly MsLearnDocumentationParser _parser = new MsLearnDocumentationParser(TestImplementations.GetTextExtractor(), TestLogger.ProviderForTests());

[Test]
public void ParseStyleRule_IDE0001_ReturnExpectedResult()
{
string fileText = GetIdeDescription("ide0001.md");

RoslynStyleRule expected = WellKnownRoslynRuleDefinitions.IDE0001();

IReadOnlyCollection<RoslynStyleRule> roslynStyleRules = _parser.ParseStyleRules(fileText);

roslynStyleRules.Should().HaveCount(1)
.And.Subject.ElementAt(0).Should().BeEquivalentTo(expected);
}

[Test]
public void ParseStyleRule_IDE0040_ReturnExpectedResult()
{
Expand Down Expand Up @@ -110,15 +123,15 @@ These two rules define whether or not you prefer the use of this (C#) and Me. (V
"Remove this or Me qualification",
"Style",
overview,
string.Empty,
null,
options);

var ide0009 = new RoslynStyleRule(
RoslynRuleId.Parse("IDE0009"),
"Add this or Me qualification",
"Style",
overview,
string.Empty,
null,
options);

IReadOnlyCollection<RoslynStyleRule> roslynStyleRules = _parser.ParseStyleRules(fileText);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,28 @@ namespace Kysect.Configuin.Tests.Resources;

public static class WellKnownRoslynRuleDefinitions
{
public static RoslynStyleRule IDE0001()
{
return new RoslynStyleRule(
ruleId: RoslynRuleId.Parse("IDE0001"),
title: "Simplify name",
category: "Style",
overview: "This rule concerns the use of simplified type names in declarations and executable code, when possible. You can remove unnecessary name qualification to simplify code and improve readability.",
example: """
using System.IO;
class C
{
// IDE0001: 'System.IO.FileInfo' can be simplified to 'FileInfo'
System.IO.FileInfo file;

// Fixed code
FileInfo file;
}
""",
options: Array.Empty<RoslynStyleRuleOption>());
}


public static RoslynStyleRule IDE0040()
{
string codeSample = """
Expand Down Expand Up @@ -40,7 +62,7 @@ class MyClass
"Add accessibility modifiers",
"Style",
"This style rule concerns requiring accessibility modifiers in declarations.",
string.Empty,
null,
new[] { expectedOption });
}

Expand Down

0 comments on commit dfd2a53

Please sign in to comment.