Skip to content

Commit

Permalink
Making some progress on edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
belav committed Aug 21, 2021
1 parent 2534fe6 commit 7d7d2e1
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 42 deletions.
27 changes: 25 additions & 2 deletions Src/CSharpier.Tests/CommandLineFormatterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ public void Format_Writes_Failed_To_Compile()
{
WhenAFileExists("Invalid.cs", "asdfasfasdf");

var result = this.Format();
var (_, lines) = this.Format();

result.lines.First()
lines.First()
.Should()
.Be(
$"Warn {Path.DirectorySeparatorChar}Invalid.cs - Failed to compile so was not formatted."
Expand Down Expand Up @@ -248,6 +248,29 @@ public void File_With_Mismatched_Line_Endings_In_Verbatim_String_Should_Pass_Val
exitCode.Should().Be(0);
}

[Test]
public void File_With_Compilation_Error_In_If_Should_Not_Lose_Code()
{
var contents =
@"#if DEBUG
?using System;
#endif
";
WhenAFileExists("Invalid.cs", contents);

var (_, lines) = this.Format();

var result = GetFileContent("Invalid.cs");

result.Should().Be(contents);

lines.First()
.Should()
.Be(
$"Warn {Path.DirectorySeparatorChar}Invalid.cs - Failed to compile so was not formatted."
);
}

[Test]
public void File_Should_Format_With_Supplied_Symbols()
{
Expand Down
93 changes: 93 additions & 0 deletions Src/CSharpier.Tests/DisabledTextComparerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,98 @@ public void IsCodeBasicallyEqual_Should_Return_True_For_Basic_Case()

DisabledTextComparer.IsCodeBasicallyEqual(before, after).Should().BeTrue();
}

[Test]
public void Squash_Should_Work_With_Pointer_Stuff()
{
var before =
@" [MethodImpl (MethodImplOptions.InternalCall)]
private static unsafe extern void ApplyUpdate_internal (IntPtr base_assm, byte* dmeta_bytes, int dmeta_length, byte *dil_bytes, int dil_length, byte *dpdb_bytes, int dpdb_length);";

var after =
@"[MethodImpl(MethodImplOptions.InternalCall)]
private static unsafe extern void ApplyUpdate_internal(
IntPtr base_assm,
byte* dmeta_bytes,
int dmeta_length,
byte* dil_bytes,
int dil_length,
byte* dpdb_bytes,
int dpdb_length
);
";
Squash(before).Should().Be(Squash(after));
}

[Test]
public void Squash_Should_Work_With_Commas()
{
var before =
@"
TypeBuilder typeBuilder = moduleBuilder.DefineType(assemblyName.FullName
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, null);
";

var after =
@"
TypeBuilder typeBuilder = moduleBuilder.DefineType(
assemblyName.FullName,
TypeAttributes.Public
| TypeAttributes.Class
| TypeAttributes.AutoClass
| TypeAttributes.AnsiClass
| TypeAttributes.BeforeFieldInit
| TypeAttributes.AutoLayout,
null
);
";
Squash(before).Should().Be(Squash(after));
}

[Test]
public void Squash_Should_Work_With_Period()
{
var before =
@"
var options2 = (ProxyGenerationOptions)proxy.GetType().
GetField(""proxyGenerationOptions"", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
";

var after =
@"
var options2 = (ProxyGenerationOptions)proxy.GetType()
.GetField(""proxyGenerationOptions"", BindingFlags.Static | BindingFlags.NonPublic)
.GetValue(null);
";
Squash(before).Should().Be(Squash(after));
}

[Test]
public void Squash_Should_Work_With_Starting_Indent()
{
var before = @"array = new ulong[] { (ulong)dy.Property_ulong };";

var after = @" array = new ulong[] { (ulong)dy.Property_ulong };";
Squash(before).Should().Be(Squash(after));
}

private static string Squash(string value)
{
return TestableDisabledTextComparer.TestSquash(value);
}

private class TestableDisabledTextComparer : DisabledTextComparer
{
public static string TestSquash(string value)
{
return Squash(value);
}
}
}
}
36 changes: 27 additions & 9 deletions Src/CSharpier/CodeFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,30 @@ SyntaxTree ParseText(string codeToFormat, params string[] preprocessorSymbols)
return new CSharpierResult { Code = code };
}

var diagnostics = syntaxTree.GetDiagnostics(cancellationToken)
.Where(o => o.Severity == DiagnosticSeverity.Error && o.Id != "CS1029")
.ToList();
if (diagnostics.Any())
bool TryGetCompilationFailure(out CSharpierResult? compilationResult)
{
return new CSharpierResult
var diagnostics = syntaxTree!.GetDiagnostics(cancellationToken)
.Where(o => o.Severity == DiagnosticSeverity.Error && o.Id != "CS1029")
.ToList();
if (diagnostics.Any())
{
Code = code,
Errors = diagnostics,
AST = printerOptions.IncludeAST ? this.PrintAST(rootNode) : string.Empty
};
compilationResult = new CSharpierResult
{
Code = code,
Errors = diagnostics,
AST = printerOptions.IncludeAST ? this.PrintAST(rootNode) : string.Empty
};

return true;
}

compilationResult = null;
return false;
}

if (TryGetCompilationFailure(out var result))
{
return result!;
}

try
Expand Down Expand Up @@ -97,6 +110,11 @@ SyntaxTree ParseText(string codeToFormat, params string[] preprocessorSymbols)
{
syntaxTree = ParseText(formattedCode, symbolSet);

if (TryGetCompilationFailure(out result))
{
return result!;
}

document = Node.Print(await syntaxTree.GetRootAsync(cancellationToken));
formattedCode = DocPrinter.DocPrinter.Print(
document,
Expand Down
59 changes: 41 additions & 18 deletions Src/CSharpier/DisabledTextComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ namespace CSharpier
{
public class DisabledTextComparer
{
// when we encounter disabled text, it is inside an #if when the condition on the #if is false
// we format all that code by doing multiple passes of csharpier
// SyntaxNodeComparer is very slow, and running it after every pass on a file would take a long time
// so we do this quick version of validating that the code is basically the same besides
// line breaks and spaces
public static bool IsCodeBasicallyEqual(string code, string formattedCode)
{
var squashCode = Squash(code);
Expand All @@ -13,7 +18,7 @@ public static bool IsCodeBasicallyEqual(string code, string formattedCode)
return result;
}

private static string Squash(string code)
protected static string Squash(string code)
{
var result = new StringBuilder();
for (var index = 0; index < code.Length; index++)
Expand All @@ -22,23 +27,31 @@ private static string Squash(string code)
if (nextChar is ' ' or '\t' or '\r' or '\n')
{
if (
index != code.Length - 1
&& (
result.Length == 0
|| result[^1]
is not (' '
or '('
or ')'
or '{'
or '}'
or '['
or ']'
or '<'
or '>'
or ','
or ':'
or ';')
)
result.Length > 0
&& index != code.Length - 1
&& result[^1]
is not (' '
or '('
or ')'
or '{'
or '}'
or '['
or ']'
or '.'
or ','
or '*'
or '+'
or '-'
or '='
or '/'
or '%'
or '|'
or '&'
or '!'
or '<'
or '>'
or ':'
or ';')
) {
result.Append(' ');
}
Expand All @@ -52,6 +65,16 @@ is not (' '
or ']'
or '['
or '.'
or ','
or '*'
or '+'
or '-'
or '='
or '/'
or '%'
or '|'
or '&'
or '!'
or '<'
or '>'
or ';'
Expand Down
5 changes: 0 additions & 5 deletions Src/CSharpier/SyntaxNodeComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,6 @@ private CompareResult Compare(

private CompareResult Compare(SyntaxTrivia originalTrivia, SyntaxTrivia formattedTrivia)
{
// when we encounter disabled text, it is inside an #if when the condition on the #if is false
// we format all that code by doing multiple passes of csharpier
// this comparer is very slow, and running it after every pass on a file would take a long time
// so we do this quick version of validating that the code is basically the same besides
// line breaks and spaces
if (originalTrivia.Kind() is SyntaxKind.DisabledTextTrivia)
{
return DisabledTextComparer.IsCodeBasicallyEqual(
Expand Down
13 changes: 5 additions & 8 deletions Src/CSharpier/SyntaxPrinter/PreprocessorSymbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@

namespace CSharpier.SyntaxPrinter
{
// TODO these files fail validation
// \Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonTypeReflector.cs
// \aspnetcore\src\Razor\Microsoft.AspNetCore.Razor.Language\src\Legacy\CSharpLanguageCharacteristics.cs
// \runtime\src\libraries\Common\src\Microsoft\Win32\SafeHandles\SafeX509Handles.Unix.cs
// \runtime\src\libraries\System.Text.RegularExpressions\src\System\Text\RegularExpressions\RegexBoyerMoore.cs

// plus some files fail to compile, compare that list

// the usage or this is a little wonky right now.
// the next iteration of this should find all #if and relates directives
// before we ever format a file
// come up with the symbol sets, and use those in code formatter
// that will get rid of the ugly threadStatic/reset/stopCollecting stuff
public class PreprocessorSymbols
{
[ThreadStatic]
Expand Down

0 comments on commit 7d7d2e1

Please sign in to comment.