Skip to content
This repository was archived by the owner on Jul 12, 2022. It is now read-only.
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
34 changes: 31 additions & 3 deletions src/CodeFormatter/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ private static int Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("CodeFormatter <project or solution> [<rule types>] [/file:<filename>] [/nocopyright] [/c:<config1,config2> [/copyright:file]");
Console.WriteLine(" <rule types> - Rule types to use in addition to the default ones.");
Console.WriteLine(" Use ConvertTests to convert MSTest tests to xUnit.");
Console.WriteLine("CodeFormatter <project or solution> [/file:<filename>] [/nocopyright] [/nounicode] [/tables] [/c:<config1,config2> [/copyright:file] [/verbose]");
Console.WriteLine(" <filename> - Only apply changes to files with specified name.");
Console.WriteLine(" <configs> - Additional preprocessor configurations the formatter");
Console.WriteLine(" should run under.");
Console.WriteLine(" <copyright> - Specifies file containing copyright header.");
Console.WriteLine(" Use ConvertTests to convert MSTest tests to xUnit.");
Console.WriteLine(" <tables> - Let tables opt out of formatting by defining DOTNET_FORMATTER");
Console.WriteLine(" <verbose> - Verbose output");
Console.WriteLine(" <nounicode> - Do not convert unicode strings to escape sequences");
Console.WriteLine(" <nocopyright>- Do not update the copyright message.");
return -1;
}

Expand All @@ -45,6 +48,9 @@ private static int Main(string[] args)
var ruleTypeBuilder = ImmutableArray.CreateBuilder<string>();
var configBuilder = ImmutableArray.CreateBuilder<string[]>();
var copyrightHeader = FormattingConstants.DefaultCopyrightHeader;
var convertUnicode = true;
var allowTables = false;
var verbose = false;
var comparer = StringComparer.OrdinalIgnoreCase;

for (int i = 1; i < args.Length; i++)
Expand Down Expand Up @@ -80,6 +86,18 @@ private static int Main(string[] args)
{
copyrightHeader = ImmutableArray<string>.Empty;
}
else if (comparer.Equals(arg, "/nounicode"))
{
convertUnicode = false;
}
else if (comparer.Equals(arg, "/verbose"))
{
verbose = true;
}
else if (comparer.Equals(arg, "/tables"))
{
allowTables = true;
}
else
{
ruleTypeBuilder.Add(arg);
Expand All @@ -99,6 +117,9 @@ private static int Main(string[] args)
fileNamesBuilder.ToImmutableArray(),
configBuilder.ToImmutableArray(),
copyrightHeader,
allowTables,
convertUnicode,
verbose,
ct).Wait(ct);
Console.WriteLine("Completed formatting.");
return 0;
Expand All @@ -124,14 +145,21 @@ private static async Task RunAsync(
ImmutableArray<string> fileNames,
ImmutableArray<string[]> preprocessorConfigurations,
ImmutableArray<string> copyrightHeader,
bool allowTables,
bool convertUnicode,
bool verbose,
CancellationToken cancellationToken)
{
var workspace = MSBuildWorkspace.Create();
var engine = FormattingEngine.Create(ruleTypes);
engine.PreprocessorConfigurations = preprocessorConfigurations;
engine.FileNames = fileNames;
engine.CopyrightHeader = copyrightHeader;
engine.AllowTables = allowTables;
engine.ConvertUnicodeCharacters = convertUnicode;
engine.Verbose = verbose;

Console.WriteLine(Path.GetFileName(projectOrSolutionPath));
string extension = Path.GetExtension(projectOrSolutionPath);
if (StringComparer.OrdinalIgnoreCase.Equals(extension, ".sln"))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Microsoft.DotNet.CodeFormatting.Tests
/// <summary>
/// A test which runs all rules on a given piece of code
/// </summary>
public sealed class CombinationTest : CodeFormattingTestBase
public sealed class CombinationTest : CodeFormattingTestBase, IDisposable
{
private static FormattingEngineImplementation s_formattingEngine;

Expand All @@ -25,10 +25,16 @@ static CombinationTest()
public CombinationTest()
{
s_formattingEngine.CopyrightHeader = ImmutableArray.Create("// header");
s_formattingEngine.AllowTables = true;
s_formattingEngine.FormatLogger = new EmptyFormatLogger();
s_formattingEngine.PreprocessorConfigurations = ImmutableArray<string[]>.Empty;
}

public void Dispose()
{
s_formattingEngine.AllowTables = false;
}

protected override async Task<Document> RewriteDocumentAsync(Document document)
{
var solution = await s_formattingEngine.FormatCoreAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class NonAsciiCharactersAreEscapedInLiteralsTests : SyntaxRuleTestBase
{
internal override ISyntaxFormattingRule Rule
{
get { return new Rules.NonAsciiCharactersAreEscapedInLiterals(); }
get { return new Rules.NonAsciiCharactersAreEscapedInLiterals(new Options() { ConvertUnicodeCharacters = true }); }
}

[Fact]
Expand Down
38 changes: 1 addition & 37 deletions src/Microsoft.DotNet.CodeFormatting/FormattingEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,45 +17,9 @@ public static class FormattingEngine
public static IFormattingEngine Create(ImmutableArray<string> ruleTypes)
{
var catalog = new AssemblyCatalog(typeof(FormattingEngine).Assembly);

var ruleTypesHash = new HashSet<string>(ruleTypes, StringComparer.InvariantCultureIgnoreCase);
var notFoundRuleTypes = new HashSet<string>(ruleTypes, StringComparer.InvariantCultureIgnoreCase);

var filteredCatalog = new FilteredCatalog(catalog, cpd =>
{
if (cpd.ExportDefinitions.Any(em =>
em.ContractName == AttributedModelServices.GetContractName(typeof(ISyntaxFormattingRule)) ||
em.ContractName == AttributedModelServices.GetContractName(typeof(ILocalSemanticFormattingRule)) ||
em.ContractName == AttributedModelServices.GetContractName(typeof(IGlobalSemanticFormattingRule)) ||
em.ContractName == AttributedModelServices.GetContractName(typeof(IFormattingFilter))))
{
object ruleType;
if (cpd.Metadata.TryGetValue(RuleTypeConstants.PartMetadataKey, out ruleType))
{
if (ruleType is string)
{
notFoundRuleTypes.Remove((string)ruleType);
if (!ruleTypesHash.Contains((string)ruleType))
{
return false;
}
}
}
}

return true;
});

var container = new CompositionContainer(filteredCatalog);
var container = new CompositionContainer(catalog);
var engine = container.GetExportedValue<IFormattingEngine>();
var consoleFormatLogger = new ConsoleFormatLogger();

// Need to do this after the catalog is queried, otherwise the lambda won't have been run
foreach (var notFoundRuleType in notFoundRuleTypes)
{
consoleFormatLogger.WriteErrorLine("The specified rule type was not found: {0}", notFoundRuleType);
}

return engine;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ internal sealed class FormattingEngineImplementation : IFormattingEngine
private readonly IEnumerable<ILocalSemanticFormattingRule> _localSemanticRules;
private readonly IEnumerable<IGlobalSemanticFormattingRule> _globalSemanticRules;
private readonly Stopwatch _watch = new Stopwatch();
private bool _allowTables;
private bool _verbose;

public ImmutableArray<string> CopyrightHeader
{
Expand All @@ -58,6 +60,24 @@ public IFormatLogger FormatLogger
set { _options.FormatLogger = value; }
}

public bool AllowTables
{
get { return _allowTables; }
set { _allowTables = value; }
}

public bool Verbose
{
get { return _verbose; }
set { _verbose = value; }
}

public bool ConvertUnicodeCharacters
{
get { return _options.ConvertUnicodeCharacters; }
set { _options.ConvertUnicodeCharacters = value; }
}

[ImportingConstructor]
internal FormattingEngineImplementation(
Options options,
Expand Down Expand Up @@ -142,11 +162,21 @@ private Solution RemoveTablePreprocessorSymbol(Solution newSolution, Solution ol
internal async Task<Solution> FormatCoreAsync(Solution originalSolution, IReadOnlyList<DocumentId> documentIds, CancellationToken cancellationToken)
{
var solution = originalSolution;
solution = AddTablePreprocessorSymbol(originalSolution);

if (_allowTables)
{
solution = AddTablePreprocessorSymbol(originalSolution);
}

solution = await RunSyntaxPass(solution, documentIds, cancellationToken);
solution = await RunLocalSemanticPass(solution, documentIds, cancellationToken);
solution = await RunGlobalSemanticPass(solution, documentIds, cancellationToken);
solution = RemoveTablePreprocessorSymbol(solution, originalSolution);

if (_allowTables)
{
solution = RemoveTablePreprocessorSymbol(solution, originalSolution);
}

return solution;
}

Expand Down Expand Up @@ -190,7 +220,10 @@ private void StartDocument()
private void EndDocument(Document document)
{
_watch.Stop();
FormatLogger.WriteLine(" {0} {1} seconds", document.Name, _watch.Elapsed.TotalSeconds);
if (_verbose)
{
FormatLogger.WriteLine(" {0} {1} seconds", document.Name, _watch.Elapsed.TotalSeconds);
}
}

/// <summary>
Expand All @@ -201,7 +234,7 @@ private void EndDocument(Document document)
/// </summary>
private async Task<Solution> RunSyntaxPass(Solution originalSolution, IReadOnlyList<DocumentId> documentIds, CancellationToken cancellationToken)
{
FormatLogger.WriteLine("Syntax Pass");
FormatLogger.WriteLine("\tSyntax Pass");

var currentSolution = originalSolution;
foreach (var documentId in documentIds)
Expand Down Expand Up @@ -241,7 +274,7 @@ private SyntaxNode RunSyntaxPass(SyntaxNode root, string languageName)

private async Task<Solution> RunLocalSemanticPass(Solution solution, IReadOnlyList<DocumentId> documentIds, CancellationToken cancellationToken)
{
FormatLogger.WriteLine("Local Semantic Pass");
FormatLogger.WriteLine("\tLocal Semantic Pass");
foreach (var localSemanticRule in _localSemanticRules)
{
solution = await RunLocalSemanticPass(solution, documentIds, localSemanticRule, cancellationToken);
Expand All @@ -252,7 +285,11 @@ private async Task<Solution> RunLocalSemanticPass(Solution solution, IReadOnlyLi

private async Task<Solution> RunLocalSemanticPass(Solution originalSolution, IReadOnlyList<DocumentId> documentIds, ILocalSemanticFormattingRule localSemanticRule, CancellationToken cancellationToken)
{
FormatLogger.WriteLine(" {0}", localSemanticRule.GetType().Name);
if (_verbose)
{
FormatLogger.WriteLine(" {0}", localSemanticRule.GetType().Name);
}

var currentSolution = originalSolution;
foreach (var documentId in documentIds)
{
Expand All @@ -278,7 +315,7 @@ private async Task<Solution> RunLocalSemanticPass(Solution originalSolution, IRe

private async Task<Solution> RunGlobalSemanticPass(Solution solution, IReadOnlyList<DocumentId> documentIds, CancellationToken cancellationToken)
{
FormatLogger.WriteLine("Global Semantic Pass");
FormatLogger.WriteLine("\tGlobal Semantic Pass");
foreach (var globalSemanticRule in _globalSemanticRules)
{
solution = await RunGlobalSemanticPass(solution, documentIds, globalSemanticRule, cancellationToken);
Expand All @@ -289,7 +326,11 @@ private async Task<Solution> RunGlobalSemanticPass(Solution solution, IReadOnlyL

private async Task<Solution> RunGlobalSemanticPass(Solution solution, IReadOnlyList<DocumentId> documentIds, IGlobalSemanticFormattingRule globalSemanticRule, CancellationToken cancellationToken)
{
FormatLogger.WriteLine(" {0}", globalSemanticRule.GetType().Name);
if (_verbose)
{
FormatLogger.WriteLine(" {0}", globalSemanticRule.GetType().Name);
}

foreach (var documentId in documentIds)
{
var document = solution.GetDocument(documentId);
Expand Down
3 changes: 3 additions & 0 deletions src/Microsoft.DotNet.CodeFormatting/IFormattingEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ public interface IFormattingEngine
ImmutableArray<string> CopyrightHeader { get; set; }
ImmutableArray<string[]> PreprocessorConfigurations { get; set; }
ImmutableArray<string> FileNames { get; set; }
bool AllowTables { get; set; }
bool ConvertUnicodeCharacters { get; set; }
bool Verbose { get; set; }
Task FormatSolutionAsync(Solution solution, CancellationToken cancellationToken);
Task FormatProjectAsync(Project porject, CancellationToken cancellationToken);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@
<Compile Include="Rules\NonAsciiCharactersAreEscapedInLiteralsRule.cs" />
<Compile Include="Rules\ExplicitThisRule.cs" />
<Compile Include="Rules\RuleOrder.cs" />
<Compile Include="RuleTypeConstants.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
Expand Down
3 changes: 3 additions & 0 deletions src/Microsoft.DotNet.CodeFormatting/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ internal sealed class Options

internal IFormatLogger FormatLogger { get; set; }

internal bool ConvertUnicodeCharacters { get; set; }

[ImportingConstructor]
internal Options()
{
CopyrightHeader = FormattingConstants.DefaultCopyrightHeader;
FileNames = ImmutableArray<string>.Empty;
PreprocessorConfigurations = ImmutableArray<string[]>.Empty;
FormatLogger = new ConsoleFormatLogger();
ConvertUnicodeCharacters = true;
}
}
}
18 changes: 0 additions & 18 deletions src/Microsoft.DotNet.CodeFormatting/RuleTypeConstants.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,21 @@ namespace Microsoft.DotNet.CodeFormatting.Rules
[SyntaxRuleOrder(SyntaxRuleOrder.NonAsciiChractersAreEscapedInLiterals)]
internal sealed class NonAsciiCharactersAreEscapedInLiterals : CSharpOnlyFormattingRule, ISyntaxFormattingRule
{
private readonly Options _options;

[ImportingConstructor]
internal NonAsciiCharactersAreEscapedInLiterals(Options options)
{
_options = options;
}

public SyntaxNode Process(SyntaxNode root, string languageName)
{
if (!_options.ConvertUnicodeCharacters)
{
return root;
}

return UnicodeCharacterEscapingSyntaxRewriter.Rewriter.Visit(root);
}

Expand Down