diff --git a/.github/workflows/format_repositories.yml b/.github/workflows/format_repositories.yml index 69e7009cc..5eb8823e8 100644 --- a/.github/workflows/format_repositories.yml +++ b/.github/workflows/format_repositories.yml @@ -12,9 +12,7 @@ jobs: - uses: actions/checkout@v2 with: path: csharpier - - uses: actions/setup-dotnet@v1 - with: - dotnet-version: '7.0.304' + - uses: actions/setup-dotnet@v3 - uses: actions/checkout@v2 with: repository: belav/csharpier-repos diff --git a/.github/workflows/publish_nuget.yml b/.github/workflows/publish_nuget.yml index ba9d593d4..e0ddc3a9e 100644 --- a/.github/workflows/publish_nuget.yml +++ b/.github/workflows/publish_nuget.yml @@ -8,11 +8,7 @@ jobs: name: test steps: - uses: actions/checkout@v2 - - uses: actions/setup-dotnet@v1 - with: - dotnet-version: | - 7.0.304 - 6.0.300 + - uses: actions/setup-dotnet@v3 - run: > dotnet test Src/CSharpier.Tests/CSharpier.Tests.csproj --configuration Release @@ -29,11 +25,7 @@ jobs: NUGET_KEY: ${{secrets.NUGET_API_KEY}} steps: - uses: actions/checkout@v2 - - uses: actions/setup-dotnet@v1 - with: - dotnet-version: | - 7.0.304 - 6.0.300 + - uses: actions/setup-dotnet@v3 - name: Publish CSharpier.Core library on version change uses: alirezanet/publish-nuget@v3.0.4 with: diff --git a/.github/workflows/validate_pull_request.yml b/.github/workflows/validate_pull_request.yml index f3248bdda..b69013ff1 100644 --- a/.github/workflows/validate_pull_request.yml +++ b/.github/workflows/validate_pull_request.yml @@ -8,11 +8,7 @@ jobs: name: Run Tests steps: - uses: actions/checkout@v2 - - uses: actions/setup-dotnet@v1 - with: - dotnet-version: | - 7.0.304 - 6.0.300 + - uses: actions/setup-dotnet@v3 - run: > dotnet test CSharpier.sln --configuration Release @@ -25,11 +21,7 @@ jobs: name: Check Formatting steps: - uses: actions/checkout@v2 - - uses: actions/setup-dotnet@v1 - with: - dotnet-version: | - 7.0.304 - 6.0.300 + - uses: actions/setup-dotnet@v3 - run: | dotnet tool restore dotnet csharpier . --check @@ -38,10 +30,6 @@ jobs: name: Build CSharpier.MSBuild steps: - uses: actions/checkout@v2 - - uses: actions/setup-dotnet@v1 - with: - dotnet-version: | - 7.0.304 - 6.0.300 + - uses: actions/setup-dotnet@v3 - run: | dotnet build Src/CSharpier.MsBuild/CSharpier.MsBuild.csproj diff --git a/Directory.Packages.props b/Directory.Packages.props index 37383771f..3241fa18d 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,10 +13,10 @@ - - + + - + @@ -29,8 +29,8 @@ - + - + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 52c861fc3..d58a812e4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base WORKDIR /app EXPOSE 80 -FROM mcr.microsoft.com/dotnet/sdk:7.0.304 AS build +FROM mcr.microsoft.com/dotnet/sdk:7.0.400 AS build RUN apt-get update && \ apt-get install curl gnupg -yq && \ diff --git a/Scripts/UpdateCSharpierRepos.ps1 b/Scripts/UpdateCSharpierRepos.ps1 deleted file mode 100644 index 1753f8668..000000000 --- a/Scripts/UpdateCSharpierRepos.ps1 +++ /dev/null @@ -1,65 +0,0 @@ -$repositories = @() -$repositories += "https://github.com/dotnet/aspnetcore.git" -$repositories += "https://github.com/aspnet/AspNetWebStack.git" -$repositories += "https://github.com/AutoMapper/AutoMapper.git" -$repositories += "https://github.com/castleproject/Core.git" -$repositories += "https://github.com/dotnet/command-line-api.git" -$repositories += "https://github.com/dotnet/format.git" -$repositories += "https://github.com/dotnet/efcore.git" -$repositories += "https://github.com/moq/moq4.git" -$repositories += "https://github.com/JamesNK/Newtonsoft.Json.git" -$repositories += "https://github.com/dotnet/roslyn.git" -$repositories += "https://github.com/dotnet/runtime.git" -$repositories += "https://github.com/mono/mono.git" -$repositories += "https://github.com/increase-POS/Res-Server.git" - -$tempLocation = "c:\temp\UpdateRepos" - -if (-not (Test-Path $tempLocation)) { - New-Item $tempLocation -Force -ItemType Directory -} - -Set-Location $tempLocation - -$ErrorActionPreference = "Continue" - -foreach ($repository in $repositories) { - $repoFolder = $tempLocation + "/" + (Split-Path $repositories -Leaf).Replace(".git", "") - if (Test-Path $repoFolder) { - Set-Location $repoFolder - & git pull origin - Set-Location $tempLocation - } - else { - & git clone $repository - } -} - -$destination = "C:\projects\csharpier-repos\" -Set-Location $destination -& git checkout main - -Get-ChildItem $tempLocation | Copy-Item -Destination $destination -Filter *.cs -Recurse -Force - -$items = Get-ChildItem -Recurse C:\projects\csharpier-repos -File -foreach ($item in $items) { - if ($item.Name -eq ".git") { - Remove-Item -Force -Recurse $item.FullName - } - if ($item.Extension -ne ".cs" -and $item.Name -ne ".csharpierignore") { - Remove-Item $item.FullName - } -} - -$items = Get-ChildItem C:\projects\csharpier-repos -Directory -Recurse -foreach ($item in $items) { - if ($item.Name -eq ".git") { - Remove-Item -Force -Recurse $item.FullName - } -} - -Set-Location $destination - -& git add . -& git commit -m "Updating repos" -& git push origin \ No newline at end of file diff --git a/Shell/UpdateCSharpierRepos.psm1 b/Shell/UpdateCSharpierRepos.psm1 new file mode 100644 index 000000000..2998e0bba --- /dev/null +++ b/Shell/UpdateCSharpierRepos.psm1 @@ -0,0 +1,93 @@ +function CSH-UpdateCSharpierRepos() +{ + + $repositories = @() + $repositories += "https://github.com/dotnet/aspnetcore.git" + $repositories += "https://github.com/aspnet/AspNetWebStack.git" + $repositories += "https://github.com/AutoMapper/AutoMapper.git" + $repositories += "https://github.com/castleproject/Core.git" + $repositories += "https://github.com/dotnet/command-line-api.git" + $repositories += "https://github.com/dotnet/format.git" + $repositories += "https://github.com/dotnet/efcore.git" + $repositories += "https://github.com/moq/moq4.git" + $repositories += "https://github.com/JamesNK/Newtonsoft.Json.git" + $repositories += "https://github.com/dotnet/roslyn.git" + $repositories += "https://github.com/dotnet/runtime.git" + $repositories += "https://github.com/mono/mono.git" + $repositories += "https://github.com/increase-POS/Res-Server.git" + + $tempLocation = "c:\temp\UpdateRepos" + + if (-not(Test-Path $tempLocation)) + { + New-Item $tempLocation -Force -ItemType Directory + } + + Set-Location $tempLocation + + $ErrorActionPreference = "Continue" + + foreach ($repository in $repositories) + { + $repoFolder = $tempLocation + "/" + (Split-Path $repositories -Leaf).Replace(".git", "") + if (Test-Path $repoFolder) + { + Set-Location $repoFolder + & git pull origin + Set-Location $tempLocation + } + else + { + & git clone $repository + } + } + + $destination = "C:\projects\csharpier-repos\" + Set-Location $destination + & git checkout main + + Get-ChildItem $tempLocation | Copy-Item -Destination $destination -Filter *.cs -Recurse -Force + + $items = Get-ChildItem -Recurse C:\projects\csharpier-repos -File + $count = 0 + foreach ($item in $items) + { + if ($item.Name -eq ".git") + { + Remove-Item -Force -Recurse $item.FullName + } + elseif ($item.Extension -ne ".cs") + { + if ($item.Name -ne ".csharpierignore") + { + Remove-Item $item.FullName + } + } + else + { + # we don't really need all of these files, let's just cut out every other one + if ($count % 2 -eq 0) + { + Remove-Item $item.FullName + } + $count++ + } + } + + $items = Get-ChildItem C:\projects\csharpier-repos -Directory -Recurse + foreach ($item in $items) + { + if ($item.Name -eq ".git") + { + Remove-Item -Force -Recurse $item.FullName + } + } + + Set-Location $destination + + & git add . + & git commit -m "Updating repos" + & git push origin +} + +Export-ModuleMember -Function CSH-* \ No newline at end of file diff --git a/Src/CSharpier.Cli/EditorConfig/EditorConfigParser.cs b/Src/CSharpier.Cli/EditorConfig/EditorConfigParser.cs index b609e37ac..124699c5e 100644 --- a/Src/CSharpier.Cli/EditorConfig/EditorConfigParser.cs +++ b/Src/CSharpier.Cli/EditorConfig/EditorConfigParser.cs @@ -70,7 +70,6 @@ IFileSystem fileSystem { var configFile = ConfigFileParser.Parse(potentialPath, fileSystem); - DebugLogger.Log(potentialPath); yield return configFile; if (configFile.IsRoot) { diff --git a/Src/CSharpier.Cli/FormattingCache.cs b/Src/CSharpier.Cli/FormattingCache.cs index d8418f34c..c49597b09 100644 --- a/Src/CSharpier.Cli/FormattingCache.cs +++ b/Src/CSharpier.Cli/FormattingCache.cs @@ -114,7 +114,6 @@ public bool CanSkipFormatting(FileToFormatInfo fileToFormatInfo) var currentHash = Hash(fileToFormatInfo.FileContents) + this.optionsHash; if (this.cacheDictionary.TryGetValue(fileToFormatInfo.Path, out var cachedHash)) { - DebugLogger.Log(fileToFormatInfo.Path + " " + currentHash + " " + cachedHash); if (currentHash == cachedHash) { return true; diff --git a/Src/CSharpier.Cli/IgnoreFile.cs b/Src/CSharpier.Cli/IgnoreFile.cs index 62e584df0..236fabb4c 100644 --- a/Src/CSharpier.Cli/IgnoreFile.cs +++ b/Src/CSharpier.Cli/IgnoreFile.cs @@ -46,8 +46,6 @@ public static async Task Create( CancellationToken cancellationToken ) { - DebugLogger.Log("Creating ignore file for " + baseDirectoryPath); - var ignore = new Ignore.Ignore(); foreach (var name in alwaysIgnored) diff --git a/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/CollectionExpressions.test b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/CollectionExpressions.test new file mode 100644 index 000000000..041770be4 --- /dev/null +++ b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/CollectionExpressions.test @@ -0,0 +1,18 @@ +int[] a = [ 1, 2, 3, 4, 5, 6, 7, 8 ]; + +Span b = [ 'a', 'b', 'c', 'd', 'e', 'f', 'h', 'i' ]; + +string[] c = +[ + "________________________", + "________________________", + "________________________", + "________________________" +]; + +int[][] d = +[ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9] +]; diff --git a/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/MemberChain_ArraysConsistent.test b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/MemberChain_ArraysConsistent.test new file mode 100644 index 000000000..c48758912 --- /dev/null +++ b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/MemberChain_ArraysConsistent.test @@ -0,0 +1,15 @@ +var x = someLongNameField + .CallMethod____________________________________() + .AccessArray[1] + .Property_______________; + +var x = someLongNameField + .CallMethod____________________________________() + .CallMethod(1) + .Property_______________; + +new Action(AssertConfigurationIsValid) + .ShouldThrow() + .Errors[0] + .UnmappedPropertyNames[0] + .ShouldBe(nameof(Destination.Count)); diff --git a/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/MemberChain_PropertiesConsistent.test b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/MemberChain_PropertiesConsistent.test new file mode 100644 index 000000000..2dda4e8e7 --- /dev/null +++ b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/MemberChain_PropertiesConsistent.test @@ -0,0 +1,33 @@ +var someVariable = someObject + .Property + .CallMethod(someValue => someValue.SomeProperty == someOtherValue___________________________); + +var someVariable = someObject + .Property() + .CallMethod(someValue => someValue.SomeProperty == someOtherValue___________________________); + +var someVariable = someObject + .Property + .CallMethod(someValue => someValue.SomeProperty == someOtherValue___________________________) + .CallMethod(); + +var someVariable = someObject + .Property() + .CallMethod(someValue => someValue.SomeProperty == someOtherValue___________________________) + .CallMethod(); + +// TODO too hard to change this for now, will do it in https://github.com/belav/csharpier/issues/451 +var someVariable = this.Property.CallMethod( + someValue => someValue.SomeProperty == someOtherValue___________________________ +); + +var someVariable = this.Property() + .CallMethod(someValue => someValue.SomeProperty == someOtherValue___________________________); + +var someVariable = this.Property + .CallMethod(someValue => someValue.SomeProperty == someOtherValue___________________________) + .CallMethod(); + +var someVariable = this.Property() + .CallMethod(someValue => someValue.SomeProperty == someOtherValue___________________________) + .CallMethod(); diff --git a/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/InvocationExpressions.test b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/MemberChains.test similarity index 92% rename from Src/CSharpier.Tests/FormattingTests/TestFiles/cs/InvocationExpressions.test rename to Src/CSharpier.Tests/FormattingTests/TestFiles/cs/MemberChains.test index a1ababd92..aa0d4309a 100644 --- a/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/InvocationExpressions.test +++ b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/MemberChains.test @@ -51,11 +51,13 @@ class ClassName .Where(o => someLongCondition__________________________) .Where(o => someLongCondition__________________________); - var someValue = someOtherValue!.Thing! + var someValue = someOtherValue! + .Thing! .Where(o => someLongCondition__________________________) .Where(o => someLongCondition__________________________); - var someValue = someOtherValue.Thing + var someValue = someOtherValue + .Thing .Where(o => someLongCondition__________________________) .Where(o => someLongCondition__________________________); @@ -81,7 +83,8 @@ class ClassName this.SomeProperty.Setup(o => longThing_______________________________________) ); - roleNames.Value + roleNames + .Value .Where(o => o.SomeProperty____________________________________) .Select(o => o.SomethingElse); @@ -110,9 +113,12 @@ class ClassName someParameter____________________________________ )!; - var someVariable = someObject.Property.CallMethod( - someValue => someValue.SomeProperty == someOtherValue___________________________________ - ); + var someVariable = someObject + .Property + .CallMethod( + someValue => + someValue.SomeProperty == someOtherValue___________________________________ + ); CallMethod( firstParameter____________________________, @@ -231,11 +237,18 @@ class ClassName ) .CallMethod__________________(); - someThing_______________________.Property + someThing_______________________ + .Property + .CallMethod__________________() + .CallMethod__________________(); + + someThing_______________________ + ?.Property .CallMethod__________________() .CallMethod__________________(); - someThing_______________________?.Property + someThing_______________________ + .Property! .CallMethod__________________() .CallMethod__________________(); } diff --git a/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/StructDeclarations.test b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/StructDeclarations.test index afc2499d6..7a2d25180 100644 --- a/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/StructDeclarations.test +++ b/Src/CSharpier.Tests/FormattingTests/TestFiles/cs/StructDeclarations.test @@ -1,3 +1,12 @@ struct BasicStruct { } public readonly struct ReadonlyStruct { } + +public struct NamedItem2( + string name1________________________________, + string name2________________________________ +) +{ + public string Name1 => name1; + public string Name2 => name1; +} diff --git a/Src/CSharpier/DocTypes/Doc.cs b/Src/CSharpier/DocTypes/Doc.cs index 1ef6eb456..199cef6a3 100644 --- a/Src/CSharpier/DocTypes/Doc.cs +++ b/Src/CSharpier/DocTypes/Doc.cs @@ -2,6 +2,11 @@ namespace CSharpier.DocTypes; internal abstract class Doc { + public string Print() + { + return DocPrinter.DocPrinter.Print(this, new PrinterOptions(), Environment.NewLine); + } + public override string ToString() { return DocSerializer.Serialize(this); diff --git a/Src/CSharpier/SyntaxNodeComparer.generated.cs b/Src/CSharpier/SyntaxNodeComparer.generated.cs index d10ee7533..522dcb733 100644 --- a/Src/CSharpier/SyntaxNodeComparer.generated.cs +++ b/Src/CSharpier/SyntaxNodeComparer.generated.cs @@ -114,6 +114,8 @@ private CompareResult Compare( return this.CompareClassDeclarationSyntax(classDeclarationSyntax, formattedNode as ClassDeclarationSyntax); case ClassOrStructConstraintSyntax classOrStructConstraintSyntax: return this.CompareClassOrStructConstraintSyntax(classOrStructConstraintSyntax, formattedNode as ClassOrStructConstraintSyntax); + case CollectionExpressionSyntax collectionExpressionSyntax: + return this.CompareCollectionExpressionSyntax(collectionExpressionSyntax, formattedNode as CollectionExpressionSyntax); case CompilationUnitSyntax compilationUnitSyntax: return this.CompareCompilationUnitSyntax(compilationUnitSyntax, formattedNode as CompilationUnitSyntax); case ConditionalAccessExpressionSyntax conditionalAccessExpressionSyntax: @@ -196,6 +198,8 @@ private CompareResult Compare( return this.CompareExplicitInterfaceSpecifierSyntax(explicitInterfaceSpecifierSyntax, formattedNode as ExplicitInterfaceSpecifierSyntax); case ExpressionColonSyntax expressionColonSyntax: return this.CompareExpressionColonSyntax(expressionColonSyntax, formattedNode as ExpressionColonSyntax); + case ExpressionElementSyntax expressionElementSyntax: + return this.CompareExpressionElementSyntax(expressionElementSyntax, formattedNode as ExpressionElementSyntax); case ExpressionStatementSyntax expressionStatementSyntax: return this.CompareExpressionStatementSyntax(expressionStatementSyntax, formattedNode as ExpressionStatementSyntax); case ExternAliasDirectiveSyntax externAliasDirectiveSyntax: @@ -416,6 +420,8 @@ private CompareResult Compare( return this.CompareSkippedTokensTriviaSyntax(skippedTokensTriviaSyntax, formattedNode as SkippedTokensTriviaSyntax); case SlicePatternSyntax slicePatternSyntax: return this.CompareSlicePatternSyntax(slicePatternSyntax, formattedNode as SlicePatternSyntax); + case SpreadElementSyntax spreadElementSyntax: + return this.CompareSpreadElementSyntax(spreadElementSyntax, formattedNode as SpreadElementSyntax); case StackAllocArrayCreationExpressionSyntax stackAllocArrayCreationExpressionSyntax: return this.CompareStackAllocArrayCreationExpressionSyntax(stackAllocArrayCreationExpressionSyntax, formattedNode as StackAllocArrayCreationExpressionSyntax); case StructDeclarationSyntax structDeclarationSyntax: @@ -1041,6 +1047,20 @@ private CompareResult CompareClassOrStructConstraintSyntax(ClassOrStructConstrai if (result.IsInvalid) return result; return Equal; } + private CompareResult CompareCollectionExpressionSyntax(CollectionExpressionSyntax originalNode, CollectionExpressionSyntax formattedNode) + { + CompareResult result; + result = this.Compare(originalNode.CloseBracketToken, formattedNode.CloseBracketToken, originalNode, formattedNode); + if (result.IsInvalid) return result; + result = this.CompareLists(originalNode.Elements, formattedNode.Elements, null, o => o.Span, originalNode.Span, formattedNode.Span); + if (result.IsInvalid) return result; + result = this.CompareLists(originalNode.Elements.GetSeparators().ToList(), formattedNode.Elements.GetSeparators().ToList(), Compare, o => o.Span, originalNode.Span, formattedNode.Span); + if (result.IsInvalid) return result; + if (originalNode.IsMissing != formattedNode.IsMissing) return NotEqual(originalNode, formattedNode); + result = this.Compare(originalNode.OpenBracketToken, formattedNode.OpenBracketToken, originalNode, formattedNode); + if (result.IsInvalid) return result; + return Equal; + } private CompareResult CompareCompilationUnitSyntax(CompilationUnitSyntax originalNode, CompilationUnitSyntax formattedNode) { CompareResult result; @@ -1624,6 +1644,14 @@ private CompareResult CompareExpressionColonSyntax(ExpressionColonSyntax origina if (originalNode.IsMissing != formattedNode.IsMissing) return NotEqual(originalNode, formattedNode); return Equal; } + private CompareResult CompareExpressionElementSyntax(ExpressionElementSyntax originalNode, ExpressionElementSyntax formattedNode) + { + CompareResult result; + originalStack.Push((originalNode.Expression, originalNode)); + formattedStack.Push((formattedNode.Expression, formattedNode)); + if (originalNode.IsMissing != formattedNode.IsMissing) return NotEqual(originalNode, formattedNode); + return Equal; + } private CompareResult CompareExpressionStatementSyntax(ExpressionStatementSyntax originalNode, ExpressionStatementSyntax formattedNode) { CompareResult result; @@ -3295,6 +3323,16 @@ private CompareResult CompareSlicePatternSyntax(SlicePatternSyntax originalNode, formattedStack.Push((formattedNode.Pattern, formattedNode)); return Equal; } + private CompareResult CompareSpreadElementSyntax(SpreadElementSyntax originalNode, SpreadElementSyntax formattedNode) + { + CompareResult result; + originalStack.Push((originalNode.Expression, originalNode)); + formattedStack.Push((formattedNode.Expression, formattedNode)); + if (originalNode.IsMissing != formattedNode.IsMissing) return NotEqual(originalNode, formattedNode); + result = this.Compare(originalNode.OperatorToken, formattedNode.OperatorToken, originalNode, formattedNode); + if (result.IsInvalid) return result; + return Equal; + } private CompareResult CompareStackAllocArrayCreationExpressionSyntax(StackAllocArrayCreationExpressionSyntax originalNode, StackAllocArrayCreationExpressionSyntax formattedNode) { CompareResult result; diff --git a/Src/CSharpier/SyntaxNodeJsonWriter.generated.cs b/Src/CSharpier/SyntaxNodeJsonWriter.generated.cs index 2a5af6316..5d4bae0e8 100644 --- a/Src/CSharpier/SyntaxNodeJsonWriter.generated.cs +++ b/Src/CSharpier/SyntaxNodeJsonWriter.generated.cs @@ -50,6 +50,7 @@ public static void WriteSyntaxNode(StringBuilder builder, SyntaxNode syntaxNode) if (syntaxNode is CheckedStatementSyntax) WriteCheckedStatementSyntax(builder, syntaxNode as CheckedStatementSyntax); if (syntaxNode is ClassDeclarationSyntax) WriteClassDeclarationSyntax(builder, syntaxNode as ClassDeclarationSyntax); if (syntaxNode is ClassOrStructConstraintSyntax) WriteClassOrStructConstraintSyntax(builder, syntaxNode as ClassOrStructConstraintSyntax); + if (syntaxNode is CollectionExpressionSyntax) WriteCollectionExpressionSyntax(builder, syntaxNode as CollectionExpressionSyntax); if (syntaxNode is CompilationUnitSyntax) WriteCompilationUnitSyntax(builder, syntaxNode as CompilationUnitSyntax); if (syntaxNode is ConditionalAccessExpressionSyntax) WriteConditionalAccessExpressionSyntax(builder, syntaxNode as ConditionalAccessExpressionSyntax); if (syntaxNode is ConditionalExpressionSyntax) WriteConditionalExpressionSyntax(builder, syntaxNode as ConditionalExpressionSyntax); @@ -91,6 +92,7 @@ public static void WriteSyntaxNode(StringBuilder builder, SyntaxNode syntaxNode) if (syntaxNode is EventFieldDeclarationSyntax) WriteEventFieldDeclarationSyntax(builder, syntaxNode as EventFieldDeclarationSyntax); if (syntaxNode is ExplicitInterfaceSpecifierSyntax) WriteExplicitInterfaceSpecifierSyntax(builder, syntaxNode as ExplicitInterfaceSpecifierSyntax); if (syntaxNode is ExpressionColonSyntax) WriteExpressionColonSyntax(builder, syntaxNode as ExpressionColonSyntax); + if (syntaxNode is ExpressionElementSyntax) WriteExpressionElementSyntax(builder, syntaxNode as ExpressionElementSyntax); if (syntaxNode is ExpressionStatementSyntax) WriteExpressionStatementSyntax(builder, syntaxNode as ExpressionStatementSyntax); if (syntaxNode is ExternAliasDirectiveSyntax) WriteExternAliasDirectiveSyntax(builder, syntaxNode as ExternAliasDirectiveSyntax); if (syntaxNode is FieldDeclarationSyntax) WriteFieldDeclarationSyntax(builder, syntaxNode as FieldDeclarationSyntax); @@ -201,6 +203,7 @@ public static void WriteSyntaxNode(StringBuilder builder, SyntaxNode syntaxNode) if (syntaxNode is SizeOfExpressionSyntax) WriteSizeOfExpressionSyntax(builder, syntaxNode as SizeOfExpressionSyntax); if (syntaxNode is SkippedTokensTriviaSyntax) WriteSkippedTokensTriviaSyntax(builder, syntaxNode as SkippedTokensTriviaSyntax); if (syntaxNode is SlicePatternSyntax) WriteSlicePatternSyntax(builder, syntaxNode as SlicePatternSyntax); + if (syntaxNode is SpreadElementSyntax) WriteSpreadElementSyntax(builder, syntaxNode as SpreadElementSyntax); if (syntaxNode is StackAllocArrayCreationExpressionSyntax) WriteStackAllocArrayCreationExpressionSyntax(builder, syntaxNode as StackAllocArrayCreationExpressionSyntax); if (syntaxNode is StructDeclarationSyntax) WriteStructDeclarationSyntax(builder, syntaxNode as StructDeclarationSyntax); if (syntaxNode is SubpatternSyntax) WriteSubpatternSyntax(builder, syntaxNode as SubpatternSyntax); @@ -1550,6 +1553,38 @@ public static void WriteClassOrStructConstraintSyntax(StringBuilder builder, Cla builder.Append(string.Join(",", properties.Where(o => o != null))); builder.Append("}"); } + public static void WriteCollectionExpressionSyntax(StringBuilder builder, CollectionExpressionSyntax syntaxNode) + { + builder.Append("{"); + var properties = new List(); + properties.Add($"\"nodeType\":\"{GetNodeType(syntaxNode.GetType())}\""); + properties.Add($"\"kind\":\"{syntaxNode.Kind().ToString()}\""); + if (syntaxNode.CloseBracketToken != default(SyntaxToken)) + { + var closeBracketTokenBuilder = new StringBuilder(); + WriteSyntaxToken(closeBracketTokenBuilder, syntaxNode.CloseBracketToken); + properties.Add($"\"closeBracketToken\":{closeBracketTokenBuilder.ToString()}"); + } + var elements = new List(); + foreach(var node in syntaxNode.Elements) + { + var innerBuilder = new StringBuilder(); + WriteSyntaxNode(innerBuilder, node); + elements.Add(innerBuilder.ToString()); + } + properties.Add($"\"elements\":[{string.Join(",", elements)}]"); + properties.Add(WriteBoolean("hasLeadingTrivia", syntaxNode.HasLeadingTrivia)); + properties.Add(WriteBoolean("hasTrailingTrivia", syntaxNode.HasTrailingTrivia)); + properties.Add(WriteBoolean("isMissing", syntaxNode.IsMissing)); + if (syntaxNode.OpenBracketToken != default(SyntaxToken)) + { + var openBracketTokenBuilder = new StringBuilder(); + WriteSyntaxToken(openBracketTokenBuilder, syntaxNode.OpenBracketToken); + properties.Add($"\"openBracketToken\":{openBracketTokenBuilder.ToString()}"); + } + builder.Append(string.Join(",", properties.Where(o => o != null))); + builder.Append("}"); + } public static void WriteCompilationUnitSyntax(StringBuilder builder, CompilationUnitSyntax syntaxNode) { builder.Append("{"); @@ -3074,6 +3109,24 @@ public static void WriteExpressionColonSyntax(StringBuilder builder, ExpressionC builder.Append(string.Join(",", properties.Where(o => o != null))); builder.Append("}"); } + public static void WriteExpressionElementSyntax(StringBuilder builder, ExpressionElementSyntax syntaxNode) + { + builder.Append("{"); + var properties = new List(); + properties.Add($"\"nodeType\":\"{GetNodeType(syntaxNode.GetType())}\""); + properties.Add($"\"kind\":\"{syntaxNode.Kind().ToString()}\""); + if (syntaxNode.Expression != default(ExpressionSyntax)) + { + var expressionBuilder = new StringBuilder(); + WriteSyntaxNode(expressionBuilder, syntaxNode.Expression); + properties.Add($"\"expression\":{expressionBuilder.ToString()}"); + } + properties.Add(WriteBoolean("hasLeadingTrivia", syntaxNode.HasLeadingTrivia)); + properties.Add(WriteBoolean("hasTrailingTrivia", syntaxNode.HasTrailingTrivia)); + properties.Add(WriteBoolean("isMissing", syntaxNode.IsMissing)); + builder.Append(string.Join(",", properties.Where(o => o != null))); + builder.Append("}"); + } public static void WriteExpressionStatementSyntax(StringBuilder builder, ExpressionStatementSyntax syntaxNode) { builder.Append("{"); @@ -7375,6 +7428,30 @@ public static void WriteSlicePatternSyntax(StringBuilder builder, SlicePatternSy builder.Append(string.Join(",", properties.Where(o => o != null))); builder.Append("}"); } + public static void WriteSpreadElementSyntax(StringBuilder builder, SpreadElementSyntax syntaxNode) + { + builder.Append("{"); + var properties = new List(); + properties.Add($"\"nodeType\":\"{GetNodeType(syntaxNode.GetType())}\""); + properties.Add($"\"kind\":\"{syntaxNode.Kind().ToString()}\""); + if (syntaxNode.Expression != default(ExpressionSyntax)) + { + var expressionBuilder = new StringBuilder(); + WriteSyntaxNode(expressionBuilder, syntaxNode.Expression); + properties.Add($"\"expression\":{expressionBuilder.ToString()}"); + } + properties.Add(WriteBoolean("hasLeadingTrivia", syntaxNode.HasLeadingTrivia)); + properties.Add(WriteBoolean("hasTrailingTrivia", syntaxNode.HasTrailingTrivia)); + properties.Add(WriteBoolean("isMissing", syntaxNode.IsMissing)); + if (syntaxNode.OperatorToken != default(SyntaxToken)) + { + var operatorTokenBuilder = new StringBuilder(); + WriteSyntaxToken(operatorTokenBuilder, syntaxNode.OperatorToken); + properties.Add($"\"operatorToken\":{operatorTokenBuilder.ToString()}"); + } + builder.Append(string.Join(",", properties.Where(o => o != null))); + builder.Append("}"); + } public static void WriteStackAllocArrayCreationExpressionSyntax(StringBuilder builder, StackAllocArrayCreationExpressionSyntax syntaxNode) { builder.Append("{"); diff --git a/Src/CSharpier/SyntaxPrinter/SyntaxNodePrinters/BaseTypeDeclaration.cs b/Src/CSharpier/SyntaxPrinter/SyntaxNodePrinters/BaseTypeDeclaration.cs index 95285d43d..74692d014 100644 --- a/Src/CSharpier/SyntaxPrinter/SyntaxNodePrinters/BaseTypeDeclaration.cs +++ b/Src/CSharpier/SyntaxPrinter/SyntaxNodePrinters/BaseTypeDeclaration.cs @@ -35,6 +35,7 @@ public static Doc Print(BaseTypeDeclarationSyntax node, FormattingContext contex else if (node is StructDeclarationSyntax structDeclarationSyntax) { keyword = structDeclarationSyntax.Keyword; + parameterList = structDeclarationSyntax.ParameterList; } else if (node is InterfaceDeclarationSyntax interfaceDeclarationSyntax) { diff --git a/Src/CSharpier/SyntaxPrinter/SyntaxNodePrinters/CollectionExpression.cs b/Src/CSharpier/SyntaxPrinter/SyntaxNodePrinters/CollectionExpression.cs new file mode 100644 index 000000000..57322b9fb --- /dev/null +++ b/Src/CSharpier/SyntaxPrinter/SyntaxNodePrinters/CollectionExpression.cs @@ -0,0 +1,38 @@ +namespace CSharpier.SyntaxPrinter.SyntaxNodePrinters; + +internal static class CollectionExpression +{ + public static Doc Print(CollectionExpressionSyntax node, FormattingContext context) + { + Doc separator = node.Parent + is AssignmentExpressionSyntax + or EqualsValueClauseSyntax { Parent: not PropertyDeclarationSyntax } + ? Doc.Line + : Doc.Null; + + var alwaysBreak = + node.Elements.FirstOrDefault() + is ExpressionElementSyntax { Expression: CollectionExpressionSyntax }; + + var result = Doc.Concat( + separator, + Token.Print(node.OpenBracketToken, context), + Doc.Indent( + alwaysBreak ? Doc.HardLine : Doc.Line, + SeparatedSyntaxList.Print( + node.Elements, + Node.Print, + alwaysBreak ? Doc.HardLine : Doc.Line, + context + ) + ), + node.Elements.Any() + ? alwaysBreak + ? Doc.HardLine + : Doc.Line + : Doc.Null, + Token.Print(node.CloseBracketToken, context) + ); + return Doc.Group(result); + } +} diff --git a/Src/CSharpier/SyntaxPrinter/SyntaxNodePrinters/InvocationExpression.cs b/Src/CSharpier/SyntaxPrinter/SyntaxNodePrinters/InvocationExpression.cs index 5af38ff2f..d92b86f1c 100644 --- a/Src/CSharpier/SyntaxPrinter/SyntaxNodePrinters/InvocationExpression.cs +++ b/Src/CSharpier/SyntaxPrinter/SyntaxNodePrinters/InvocationExpression.cs @@ -116,6 +116,16 @@ And we want to work with them from Left to Right ) ); } + else if (expression is ElementAccessExpressionSyntax elementAccessExpression) + { + FlattenAndPrintNodes(elementAccessExpression.Expression, printedNodes, context); + printedNodes.Add( + new PrintedNode( + elementAccessExpression, + Node.Print(elementAccessExpression.ArgumentList, context) + ) + ); + } else if (expression is MemberAccessExpressionSyntax memberAccessExpressionSyntax) { FlattenAndPrintNodes(memberAccessExpressionSyntax.Expression, printedNodes, context); @@ -169,8 +179,6 @@ expression is PostfixUnaryExpressionSyntax } } - // TODO maybe this should work more like prettier, where it makes groups in a way that they try to fill lines - // TODO also prettier doesn't seem to use fluid private static List> GroupPrintedNodesOnLines(List printedNodes) { // We want to group the printed nodes in the following manner @@ -223,25 +231,22 @@ List printedNodes // will be grouped as // [ // [Identifier, InvocationExpression], - // [MemberAccessExpression, MemberAccessExpression, InvocationExpression], + // [MemberAccessExpression] + // [MemberAccessExpression, InvocationExpression], // [MemberAccessExpression, InvocationExpression], // [MemberAccessExpression], // ] // so that we can print it as // a() - // .b.c() + // .b + // .c() // .d() // .e - // The first group is the first node followed by - // - as many InvocationExpression as possible - // < fn()()() >.something() - // - as many array accessors as possible - // < fn()[0][1][2] >.something() - // - then, as many MemberAccessExpression as possible but the last one - // < this.items >.something() - + // TODO #451 this whole thing could possibly just turn into a big loop + // based on the current node, and the next/previous node, decide when to create new groups. + // certain nodes need to stay in the current group, other nodes indicate that a new group needs to be created. var groups = new List>(); var currentGroup = new List { printedNodes[0] }; var index = 1; @@ -257,63 +262,47 @@ List printedNodes } } - if (printedNodes[0].Node is not InvocationExpressionSyntax) + if ( + printedNodes[0].Node is not (InvocationExpressionSyntax or PostfixUnaryExpressionSyntax) + && index < printedNodes.Count + && printedNodes[index].Node + is ElementAccessExpressionSyntax + or PostfixUnaryExpressionSyntax + ) { - for (; index + 1 < printedNodes.Count; ++index) - { - /* this handles the special case where we want ?.Property on the same line - someThing_______________________?.Property - .CallMethod__________________() - .CallMethod__________________(); - */ - if ( - printedNodes[index].Node is ConditionalAccessExpressionSyntax - && printedNodes[index + 1].Node - is MemberBindingExpressionSyntax { Parent: MemberAccessExpressionSyntax } - ) - { - currentGroup.Add(printedNodes[index]); - currentGroup.Add(printedNodes[index + 1]); - index++; - continue; - } - - if ( - ( - IsMemberish(printedNodes[index].Node) - && ( - IsMemberish(printedNodes[index + 1].Node) - || printedNodes[index + 1].Node is PostfixUnaryExpressionSyntax - ) - ) - || printedNodes[index].Node is PostfixUnaryExpressionSyntax - ) - { - currentGroup.Add(printedNodes[index]); - } - else - { - break; - } - } + currentGroup.Add(printedNodes[index]); + index++; } groups.Add(currentGroup); currentGroup = new List(); - var hasSeenInvocationExpression = false; + var hasSeenNodeThatRequiresBreak = false; for (; index < printedNodes.Count; index++) { - if (hasSeenInvocationExpression && IsMemberish(printedNodes[index].Node)) + if ( + hasSeenNodeThatRequiresBreak + && printedNodes[index].Node + is MemberAccessExpressionSyntax + or ConditionalAccessExpressionSyntax + ) { groups.Add(currentGroup); currentGroup = new List(); - hasSeenInvocationExpression = false; + hasSeenNodeThatRequiresBreak = false; } - if (printedNodes[index].Node is InvocationExpressionSyntax) + if ( + printedNodes[index].Node + is ( + InvocationExpressionSyntax + or MemberAccessExpressionSyntax + or ElementAccessExpressionSyntax + or MemberBindingExpressionSyntax + ) + ) { - hasSeenInvocationExpression = true; + hasSeenNodeThatRequiresBreak = true; } currentGroup.Add(printedNodes[index]); } @@ -326,11 +315,6 @@ printedNodes[index].Node is ConditionalAccessExpressionSyntax return groups; } - private static bool IsMemberish(CSharpSyntaxNode node) - { - return node is MemberAccessExpressionSyntax or ConditionalAccessExpressionSyntax; - } - private static Doc PrintIndentedGroup(ExpressionSyntax node, IList> groups) { if (groups.Count == 0) @@ -370,10 +354,7 @@ private static bool ShouldMergeFirstTwoGroups(List> groups) var firstNode = groups[0][0].Node; - if ( - firstNode is IdentifierNameSyntax identifierNameSyntax - && identifierNameSyntax.Identifier.Text.Length <= 4 - ) + if (firstNode is IdentifierNameSyntax { Identifier.Text.Length: <= 4 }) { return true; } diff --git a/global.json b/global.json index 065581b4a..0c4b7f5ec 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.304", + "version": "7.0.400", "rollForward": "latestFeature" } }