Skip to content
This repository was archived by the owner on Jul 12, 2022. It is now read-only.

Commit 875e611

Browse files
committed
Straw man design for preprocessor directives
This is a straw man design for the problem being discussed in issue #38. Essentially let the developer specify on the command line what configurations they want the code to be formatted under. This is much safer than assuming all configurations in the file are valid.
1 parent 23e3dca commit 875e611

File tree

6 files changed

+43
-31
lines changed

6 files changed

+43
-31
lines changed

src/CodeFormatter/Program.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ private static int Main(string[] args)
3737
var filenames = new List<string>();
3838
var disableCopyright = false;
3939
var comparer = StringComparer.OrdinalIgnoreCase;
40+
var preprocessorConfigurations = new List<string[]>();
4041

4142
for (int i = 1; i < args.Length; i++)
4243
{
@@ -54,6 +55,12 @@ private static int Main(string[] args)
5455
{
5556
disableCopyright = true;
5657
}
58+
else if (arg.StartsWith("/c:", StringComparison.OrdinalIgnoreCase))
59+
{
60+
var all = arg.Substring(3);
61+
var configs = all.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
62+
preprocessorConfigurations.Add(configs);
63+
}
5764
else
5865
{
5966
ruleTypes.Add(arg);
@@ -65,16 +72,18 @@ private static int Main(string[] args)
6572

6673
Console.CancelKeyPress += delegate { cts.Cancel(); };
6774

68-
RunAsync(projectOrSolutionPath, ruleTypes, filenames, disableCopyright, ct).Wait(ct);
75+
RunAsync(projectOrSolutionPath, ruleTypes, filenames, disableCopyright, ImmutableArray.CreateRange(preprocessorConfigurations), ct).Wait(ct);
6976
Console.WriteLine("Completed formatting.");
7077
return 0;
7178
}
7279

73-
private static async Task RunAsync(string projectOrSolutionPath, IEnumerable<string> ruleTypes, IEnumerable<string> filenames, bool disableCopright, CancellationToken cancellationToken)
80+
private static async Task RunAsync(string projectOrSolutionPath, IEnumerable<string> ruleTypes, IEnumerable<string> filenames, bool disableCopright, ImmutableArray<string[]> preprocessorConfigurations, CancellationToken cancellationToken)
7481
{
7582
var workspace = MSBuildWorkspace.Create();
7683
var engine = FormattingEngine.Create(ruleTypes, filenames);
7784
engine.Verbose = true;
85+
engine.PreprocessorConfigurations = preprocessorConfigurations;
86+
7887
if (disableCopright)
7988
{
8089
engine.CopyrightHeader = ImmutableArray<string>.Empty;

src/Microsoft.DotNet.CodeFormatting/FormattingEngineImplementation.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ public ImmutableArray<string> CopyrightHeader
3434
set { _options.CopyrightHeader = value; }
3535
}
3636

37+
public ImmutableArray<string[]> PreprocessorConfigurations
38+
{
39+
get { return _options.PreprocessorConfigurations; }
40+
set { _options.PreprocessorConfigurations = value; }
41+
}
42+
3743
public IFormatLogger FormatLogger
3844
{
3945
get { return _options.FormatLogger; }

src/Microsoft.DotNet.CodeFormatting/IFormattingEngine.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ namespace Microsoft.DotNet.CodeFormatting
1313
public interface IFormattingEngine
1414
{
1515
ImmutableArray<string> CopyrightHeader { get; set; }
16+
ImmutableArray<string[]> PreprocessorConfigurations { get; set; }
1617
bool Verbose { get; set; }
18+
1719
Task FormatSolutionAsync(Solution solution, CancellationToken cancellationToken);
1820
Task FormatProjectAsync(Project porject, CancellationToken cancellationToken);
1921
}

src/Microsoft.DotNet.CodeFormatting/Options.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ internal sealed class Options
2121
};
2222

2323
internal ImmutableArray<string> CopyrightHeader { get; set; }
24+
internal ImmutableArray<string[]> PreprocessorConfigurations { get; set; }
2425
internal IFormatLogger FormatLogger { get; set; }
2526

2627
[ImportingConstructor]
2728
internal Options()
2829
{
2930
CopyrightHeader = ImmutableArray.Create(s_defaultCopyrightHeader);
31+
PreprocessorConfigurations = ImmutableArray<string[]>.Empty;
3032
FormatLogger = new ConsoleFormatLogger();
3133
}
3234
}

src/Microsoft.DotNet.CodeFormatting/Rules/IsFormattedFormattingRule.cs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,31 @@ namespace Microsoft.DotNet.CodeFormatting.Rules
1717
[LocalSemanticRuleOrder(LocalSemanticRuleOrder.IsFormattedFormattingRule)]
1818
internal sealed class IsFormattedFormattingRule : ILocalSemanticFormattingRule
1919
{
20+
private readonly Options _options;
21+
22+
[ImportingConstructor]
23+
internal IsFormattedFormattingRule(Options options)
24+
{
25+
_options = options;
26+
}
27+
2028
public async Task<SyntaxNode> ProcessAsync(Document document, SyntaxNode syntaxNode, CancellationToken cancellationToken)
2129
{
22-
var newDocument = await Formatter.FormatAsync(document, cancellationToken: cancellationToken);
23-
// TODO Bug 1076609: Roslyn formatter doesn't format code in #if false as it's considered as DisabledTextTrivia. Will be removed after the bug is fixed.
24-
// Doing that manually here
25-
var preprocessorNames = document.DefinedProjectPreprocessorNames();
26-
newDocument = await newDocument.GetNewDocumentWithPreprocessorSymbols(preprocessorNames, cancellationToken);
27-
newDocument = await Formatter.FormatAsync(newDocument, cancellationToken: cancellationToken);
30+
document = await Formatter.FormatAsync(document, cancellationToken: cancellationToken);
31+
32+
if (!_options.PreprocessorConfigurations.IsDefaultOrEmpty)
33+
{
34+
var project = document.Project;
35+
var parseOptions = (CSharpParseOptions)document.Project.ParseOptions;
36+
foreach (var configuration in _options.PreprocessorConfigurations)
37+
{
38+
var newParseOptions = parseOptions.WithPreprocessorSymbols(configuration);
39+
document = project.WithParseOptions(newParseOptions).GetDocument(document.Id);
40+
document = await Formatter.FormatAsync(document, cancellationToken: cancellationToken);
41+
}
42+
}
2843

29-
return await newDocument.GetOriginalDocumentWithPreprocessorSymbols(preprocessorNames).GetSyntaxRootAsync(cancellationToken);
44+
return await document.GetSyntaxRootAsync(cancellationToken);
3045
}
3146
}
3247
}

src/Microsoft.DotNet.CodeFormatting/Rules/RuleExtensions.cs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,5 @@ public static IEnumerable<SyntaxTrivia> AddWhiteSpaceTrivia(this IEnumerable<Syn
2929
{
3030
return trivia.Concat(new[] { SyntaxFactory.Tab });
3131
}
32-
33-
public async static Task<Document> GetNewDocumentWithPreprocessorSymbols(this Document document, IEnumerable<string> preprocessorNamesDefined, CancellationToken cancellationToken)
34-
{
35-
var syntaxRoot = await document.GetSyntaxRootAsync(cancellationToken) as CSharpSyntaxNode;
36-
var preprocessorNamesToAdd = syntaxRoot.DescendantTrivia().Where(trivia => trivia.CSharpKind() == SyntaxKind.IfDirectiveTrivia)
37-
.SelectMany(trivia => trivia.GetStructure().DescendantNodes().OfType<IdentifierNameSyntax>())
38-
.Select(identifier => identifier.Identifier.Text).Distinct().Where((name) => !preprocessorNamesDefined.Contains(name));
39-
40-
var newParseOptions = new CSharpParseOptions().WithPreprocessorSymbols(preprocessorNamesToAdd);
41-
42-
return document.Project.WithParseOptions(newParseOptions).GetDocument(document.Id);
43-
}
44-
45-
public static IEnumerable<string> DefinedProjectPreprocessorNames(this Document document)
46-
{
47-
return document.Project.ParseOptions.PreprocessorSymbolNames;
48-
}
49-
50-
public static Document GetOriginalDocumentWithPreprocessorSymbols(this Document document, IEnumerable<string> preprocessorNamesDefined)
51-
{
52-
return document.Project.WithParseOptions(new CSharpParseOptions().WithPreprocessorSymbols(preprocessorNamesDefined)).GetDocument(document.Id);
53-
}
5432
}
5533
}

0 commit comments

Comments
 (0)