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

Spellcheck file name #1368

Merged
merged 8 commits into from
Jan 21, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Publish NuGet packages that provide [refactorings](https://www.nuget.org/packages/roslynator.refactorings) and [code fixes for compiler diagnostics](https://www.nuget.org/packages/roslynator.codefixes) ([PR](https://github.com/dotnet/roslynator/pull/1358))
- These packages are recommended to be used in an environment where Roslynator IDE extension cannot be used, e.g. VS Code + C# Dev Kit (see related [issue](https://github.com/dotnet/vscode-csharp/issues/6790))
- Add analyzer "Remove redundant catch block" [RCS1265](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1265) ([PR](https://github.com/dotnet/roslynator/pull/1364) by @jakubreznak)
- [CLI] Spellcheck file names ([PR](https://github.com/dotnet/roslynator/pull/1368))
- `roslynator spellcheck --scope file-name`

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
_options,
context.CancellationToken);

if ((_options.ScopeFilter & SpellingScopeFilter.FileName) != 0)
analysisContext.AnalyzeFileName(tree);

CSharpSpellingWalker walker = CSharpSpellingWalker.Create(analysisContext);

walker.Visit(root);
Expand Down
9 changes: 3 additions & 6 deletions src/CommandLine/Commands/SpellcheckCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,6 @@ public override async Task<SpellcheckCommandResult> ExecuteAsync(ProjectOrSoluti
MinWordLength = Options.MinWordLength,
MaxWordLength = Options.MaxWordLength,
IncludeGeneratedCode = Options.IncludeGeneratedCode,
#if DEBUG
Autofix = !Options.NoAutofix,
#endif
Interactive = Options.Interactive,
DryRun = Options.DryRun,
};
Expand All @@ -87,7 +84,7 @@ public override async Task<SpellcheckCommandResult> ExecuteAsync(ProjectOrSoluti

Solution solution = project.Solution;

spellingFixer = GetSpellingFixer(solution);
spellingFixer = GetSpellcheckAnalyzer(solution);

WriteLine($"Analyze '{project.Name}'", ConsoleColors.Cyan, Verbosity.Minimal);

Expand All @@ -103,7 +100,7 @@ public override async Task<SpellcheckCommandResult> ExecuteAsync(ProjectOrSoluti
{
Solution solution = projectOrSolution.AsSolution();

spellingFixer = GetSpellingFixer(solution);
spellingFixer = GetSpellcheckAnalyzer(solution);

results = await spellingFixer.FixSolutionAsync(f => IsMatch(f), cancellationToken);
}
Expand All @@ -118,7 +115,7 @@ public override async Task<SpellcheckCommandResult> ExecuteAsync(ProjectOrSoluti
: CommandStatus.NotSuccess,
results);

SpellcheckAnalyzer GetSpellingFixer(Solution solution)
SpellcheckAnalyzer GetSpellcheckAnalyzer(Solution solution)
{
return new SpellcheckAnalyzer(
solution,
Expand Down
11 changes: 3 additions & 8 deletions src/CommandLine/Options/SpellcheckCommandLineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public sealed class SpellcheckCommandLineOptions : MSBuildCommandLineOptions

[Option(
longName: OptionNames.IgnoredScope,
HelpText = "Defines syntax that should not be analyzed. Allowed values are comment, type, member, local, parameter, literal, non-symbol and symbol.",
HelpText = "Defines syntax that should not be analyzed. Allowed values are comment, type, member, local, parameter, literal, non-symbol, symbol and file-name.",
MetaValue = "<SCOPE>")]
public IEnumerable<string> IgnoredScope { get; set; }

Expand All @@ -60,15 +60,10 @@ public sealed class SpellcheckCommandLineOptions : MSBuildCommandLineOptions
HelpText = "Specifies minimal word length to be checked. Default value is 3.",
MetaValue = "<NUM>")]
public int MinWordLength { get; set; }
#if DEBUG
[Option(
longName: OptionNames.NoAutofix,
HelpText = "Disable applying predefined fixes.")]
public bool NoAutofix { get; set; }
#endif

[Option(
longName: OptionNames.Scope,
HelpText = "Defines syntax that should be analyzed. Allowed values are comment, type, member, local, parameter, literal, non-symbol, symbol and all. Literals are not analyzed by default.",
HelpText = "Defines syntax that should be analyzed. Allowed values are comment, type, member, local, parameter, literal, non-symbol, symbol, file-name and all. Literals and file names are not analyzed by default.",
MetaValue = "<SCOPE>")]
public IEnumerable<string> Scope { get; set; }

Expand Down
14 changes: 13 additions & 1 deletion src/CommandLine/Rename/CliSymbolRenameState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ namespace Roslynator.CommandLine.Rename;

internal class CliSymbolRenameState : SymbolRenameState
{
private static readonly SymbolDisplayFormat _symbolDefinitionFormat = SymbolDisplayFormat.CSharpErrorMessageFormat.Update(
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
parameterOptions: SymbolDisplayParameterOptions.IncludeParamsRefOut
| SymbolDisplayParameterOptions.IncludeType
| SymbolDisplayParameterOptions.IncludeName
| SymbolDisplayParameterOptions.IncludeDefaultValue,
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers
| SymbolDisplayMiscellaneousOptions.UseSpecialTypes
| SymbolDisplayMiscellaneousOptions.UseErrorTypeSymbolName);

public CliSymbolRenameState(
Solution solution,
Func<ISymbol, bool> predicate,
Expand Down Expand Up @@ -103,7 +113,9 @@ public override async Task RenameSymbolsAsync(Project project, CancellationToken
Document document,
CancellationToken cancellationToken)
{
LogHelpers.WriteSymbolDefinition(symbol, baseDirectoryPath: Path.GetDirectoryName(document.Project.FilePath), " ", Verbosity.Normal);
string text = DiagnosticFormatter.FormatSymbolDefinition(symbol, baseDirectoryPath: Path.GetDirectoryName(document.Project.FilePath), " ", _symbolDefinitionFormat);

WriteLine(text, ConsoleColors.Cyan, Verbosity.Normal);

if (ShouldWrite(Verbosity.Detailed)
|| CodeContext >= 0)
Expand Down
29 changes: 29 additions & 0 deletions src/Core/FileSystemHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,33 @@ public static string DetermineRelativePath(string baseDirectoryPath, string file

return directoryUri.MakeRelativeUri(baseDirectoryUri).ToString().TrimEnd('/');
}

public static int LastIndexOfDirectorySeparator(string path)
{
for (int i = path.Length - 1; i >= 0; i--)
{
if (IsDirectorySeparator(path[i]))
return i;
}

return -1;
}

public static int GetExtensionIndex(string path)
{
int length = path.Length;

for (int i = length - 1; i >= 0; i--)
{
char ch = path[i];

if (ch == '.')
return i;

if (IsDirectorySeparator(ch))
break;
}

return path.Length;
}
}
164 changes: 138 additions & 26 deletions src/Workspaces.Core/DiagnosticFormatter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Diagnostics;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
Expand All @@ -13,28 +14,39 @@ internal static class DiagnosticFormatter
public static string FormatDiagnostic(
Diagnostic diagnostic,
string? baseDirectoryPath = null,
IFormatProvider? formatProvider = null)
IFormatProvider? formatProvider = null,
bool omitSpan = false)
{
StringBuilder sb = StringBuilderCache.GetInstance();

FormatLocation(diagnostic.Location, baseDirectoryPath, ref sb);
FormatLocation(diagnostic.Location, baseDirectoryPath, ref sb, omitSpan);

sb.Append(GetSeverityText(diagnostic.Severity));
sb.Append(' ');
sb.Append(diagnostic.Id);
sb.Append(": ");

string message = diagnostic.GetMessage(formatProvider);

sb.Append(message);
sb.Append(diagnostic.GetMessage(formatProvider));

return StringBuilderCache.GetStringAndFree(sb);

static string GetSeverityText(DiagnosticSeverity severity)
{
return severity switch
{
DiagnosticSeverity.Hidden => "hidden",
DiagnosticSeverity.Info => "info",
DiagnosticSeverity.Warning => "warning",
DiagnosticSeverity.Error => "error",
_ => throw new InvalidOperationException(),
};
}
}

internal static void FormatLocation(
private static void FormatLocation(
Location location,
string? baseDirectoryPath,
ref StringBuilder sb)
ref StringBuilder sb,
bool omitSpan = false)
{
switch (location.Kind)
{
Expand All @@ -48,34 +60,134 @@ internal static class DiagnosticFormatter
{
sb.Append(PathUtilities.TrimStart(span.Path, baseDirectoryPath));

LinePosition linePosition = span.StartLinePosition;
if (omitSpan)
{
sb.Append(": ");
}
else
{
LinePosition linePosition = span.StartLinePosition;

sb.Append('(');
sb.Append(linePosition.Line + 1);
sb.Append(',');
sb.Append(linePosition.Character + 1);
sb.Append("): ");
sb.Append('(');
sb.Append(linePosition.Line + 1);
sb.Append(',');
sb.Append(linePosition.Character + 1);
sb.Append("): ");
}
}

break;
}
}
}

private static string GetSeverityText(DiagnosticSeverity diagnosticSeverity)
public static string FormatSymbolDefinition(
ISymbol symbol,
string? baseDirectoryPath = null,
string? indentation = null,
SymbolDisplayFormat? format = null)
{
switch (diagnosticSeverity)
StringBuilder sb = StringBuilderCache.GetInstance();

sb.Append(indentation);

FormatLocation(symbol.Locations[0], baseDirectoryPath, ref sb);

sb.Append(GetSymbolTitle(symbol));

if (symbol.IsKind(SymbolKind.Parameter, SymbolKind.TypeParameter))
{
case DiagnosticSeverity.Hidden:
return "hidden";
case DiagnosticSeverity.Info:
return "info";
case DiagnosticSeverity.Warning:
return "warning";
case DiagnosticSeverity.Error:
return "error";
default:
throw new InvalidOperationException();
sb.Append(" '");
sb.Append(symbol.Name);
sb.Append("': ");

if (symbol.ContainingSymbol is IMethodSymbol { MethodKind: MethodKind.LambdaMethod })
{
sb.Append("anonymous function");
}
else
{
Debug.Assert(symbol.ContainingSymbol.IsKind(SymbolKind.NamedType, SymbolKind.Method, SymbolKind.Property), symbol.Kind.ToString());

sb.Append(symbol.ContainingSymbol.ToDisplayString(format));
}
}
else
{
sb.Append(": ");
sb.Append(symbol.ToDisplayString(format));
}

return StringBuilderCache.GetStringAndFree(sb);

static string GetSymbolTitle(ISymbol symbol)
{
switch (symbol.Kind)
{
case SymbolKind.Event:
{
return "event";
}
case SymbolKind.Field:
{
return (symbol.ContainingType.TypeKind == TypeKind.Enum) ? "enum field" : "field";
}
case SymbolKind.Local:
{
return "local";
}
case SymbolKind.Method:
{
var methodSymbol = (IMethodSymbol)symbol;

switch (methodSymbol.MethodKind)
{
case MethodKind.Ordinary:
return "method";
case MethodKind.LocalFunction:
return "local function";
}

Debug.Fail(methodSymbol.MethodKind.ToString());
break;
}
case SymbolKind.NamedType:
{
var typeSymbol = (INamedTypeSymbol)symbol;

switch (typeSymbol.TypeKind)
{
case TypeKind.Class:
return "class";
case TypeKind.Delegate:
return "delegate";
case TypeKind.Enum:
return "enum";
case TypeKind.Interface:
return "interface";
case TypeKind.Struct:
return "struct";
}

Debug.Fail(typeSymbol.TypeKind.ToString());
break;
}
case SymbolKind.Parameter:
{
return "parameter";
}
case SymbolKind.Property:
{
return (((IPropertySymbol)symbol).IsIndexer) ? "indexer" : "property";
}
case SymbolKind.TypeParameter:
{
return "type parameter";
}
}

Debug.Fail(symbol.Kind.ToString());
return symbol.Kind.ToString();
}
}
}