Skip to content

Commit

Permalink
Merge pull request #2389 from sharwell/csharp7-spacing
Browse files Browse the repository at this point in the history
Update spacing rules for C# 7
  • Loading branch information
sharwell authored Jun 11, 2017
2 parents 26858c3 + 187bcc8 commit 3f098f5
Show file tree
Hide file tree
Showing 43 changed files with 2,692 additions and 87 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
{
using System.Threading;
using System.Threading.Tasks;
using StyleCop.Analyzers.Test.SpacingRules;
using TestHelper;
using Xunit;

public class SA1000CSharp7UnitTests : SA1000UnitTests
{
[Fact]
public async Task TestOutVariableDeclarationAsync()
{
string statementWithoutSpace = @"int.TryParse(""0"", out@Int32 x);";

string statementWithSpace = @"int.TryParse(""0"", out @Int32 x);";

await this.TestKeywordStatementAsync(statementWithSpace, EmptyDiagnosticResults, statementWithSpace).ConfigureAwait(false);

DiagnosticResult expected = this.CSharpDiagnostic().WithArguments("out", string.Empty, "followed").WithLocation(12, 31);

await this.TestKeywordStatementAsync(statementWithoutSpace, expected, statementWithSpace).ConfigureAwait(false);
}

[Fact]
public async Task TestVarKeywordTupleTypeAsync()
{
string statementWithoutSpace = @"var(a, b) = (2, 3);";

string statementWithSpace = @"var (a, b) = (2, 3);";

await this.TestKeywordStatementAsync(statementWithSpace, EmptyDiagnosticResults, statementWithSpace).ConfigureAwait(false);

DiagnosticResult expected = this.CSharpDiagnostic().WithArguments("var", string.Empty, "followed").WithLocation(12, 13);

await this.TestKeywordStatementAsync(statementWithoutSpace, expected, statementWithSpace).ConfigureAwait(false);
}

[Fact]
public async Task TestRefExpressionAndTypeAsync()
{
string statementWithoutSpace = @"
int a = 0;
ref@Int32 b = ref@Call(ref@a);
ref@Int32 Call(ref@Int32 p)
=> ref@p;
";

string statementWithSpace = @"
int a = 0;
ref @Int32 b = ref @Call(ref @a);
ref @Int32 Call(ref @Int32 p)
=> ref @p;
";

await this.TestKeywordStatementAsync(statementWithSpace, EmptyDiagnosticResults, statementWithSpace).ConfigureAwait(false);

DiagnosticResult[] expected =
{
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(14, 1),
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(14, 15),
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(14, 24),
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(16, 1),
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(16, 16),
this.CSharpDiagnostic().WithArguments("ref", string.Empty, "followed").WithLocation(17, 8),
};

await this.TestKeywordStatementAsync(statementWithoutSpace, expected, statementWithSpace).ConfigureAwait(false);
}

/// <summary>
/// Verifies that spacing for tuple expressions is handled properly.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
/// <seealso cref="SA1008CSharp7UnitTests.TestTupleExpressionsAsync"/>
[Fact]
public async Task TestReturnTupleExpressionsAsync()
{
var testCode = @"using System.Collections.Generic;
namespace TestNamespace
{
public class TestClass
{
public void TestMethod()
{
// Returns (leading spaces after keyword checked in SA1000, not SA1008)
(int, int) LocalFunction1() { return( 1, 2); }
(int, int) LocalFunction2() { return(1, 2); }
(int, int) LocalFunction3() { return ( 1, 2); }
}
}
}
";

var fixedCode = @"using System.Collections.Generic;
namespace TestNamespace
{
public class TestClass
{
public void TestMethod()
{
// Returns (leading spaces after keyword checked in SA1000, not SA1008)
(int, int) LocalFunction1() { return ( 1, 2); }
(int, int) LocalFunction2() { return (1, 2); }
(int, int) LocalFunction3() { return ( 1, 2); }
}
}
}
";

DiagnosticResult[] expectedDiagnostics =
{
// Returns
this.CSharpDiagnostic().WithArguments("return", string.Empty, "followed").WithLocation(10, 43),
this.CSharpDiagnostic().WithArguments("return", string.Empty, "followed").WithLocation(11, 43),
};

await this.VerifyCSharpDiagnosticAsync(testCode, expectedDiagnostics, CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpFixAsync(testCode, fixedCode).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
{
using System.Threading;
using System.Threading.Tasks;
using StyleCop.Analyzers.Test.SpacingRules;
using TestHelper;
using Xunit;

public class SA1001CSharp7UnitTests : SA1001UnitTests
{
/// <summary>
/// Verifies spacing around a <c>]</c> character in tuple types and expressions.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
/// <seealso cref="SA1009CSharp7UnitTests.TestBracketsInTupleTypesNotFollowedBySpaceAsync"/>
/// <seealso cref="SA1011CSharp7UnitTests.TestBracketsInTupleTypesNotFollowedBySpaceAsync"/>
[Fact]
public async Task TestBracketsInTupleTypesNotFollowedBySpaceAsync()
{
const string testCode = @"using System;
public class Foo
{
public (int[] , int[] ) TestMethod((int[] , int[] ) a)
{
(int[] , int[] ) ints = (new int[][] { new[] { 3 } }[0] , new int[][] { new[] { 3 } }[0] );
return ints;
}
}";
const string fixedCode = @"using System;
public class Foo
{
public (int[], int[] ) TestMethod((int[], int[] ) a)
{
(int[], int[] ) ints = (new int[][] { new[] { 3 } }[0], new int[][] { new[] { 3 } }[0] );
return ints;
}
}";

DiagnosticResult[] expected =
{
this.CSharpDiagnostic().WithLocation(5, 19).WithArguments(" not", "preceded"),
this.CSharpDiagnostic().WithLocation(5, 47).WithArguments(" not", "preceded"),
this.CSharpDiagnostic().WithLocation(7, 16).WithArguments(" not", "preceded"),
this.CSharpDiagnostic().WithLocation(7, 65).WithArguments(" not", "preceded"),
};

await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
}

/// <summary>
/// Verifies spacing around a <c>}</c> character in tuple expressions.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
/// <seealso cref="SA1009CSharp7UnitTests.TestSpacingAroundClosingBraceInTupleExpressionsAsync"/>
/// <seealso cref="SA1013CSharp7UnitTests.TestSpacingAroundClosingBraceInTupleExpressionsAsync"/>
[Fact]
public async Task TestSpacingAroundClosingBraceInTupleExpressionsAsync()
{
const string testCode = @"using System;
public class Foo
{
public void TestMethod()
{
var values = (new[] { 3} , new[] { 3} );
}
}";
const string fixedCode = @"using System;
public class Foo
{
public void TestMethod()
{
var values = (new[] { 3}, new[] { 3} );
}
}";

DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(7, 34).WithArguments(" not", "preceded");

await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
}

/// <summary>
/// Verifies spacing around a <c>&gt;</c> character in tuple types.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
/// <seealso cref="SA1009CSharp7UnitTests.TestClosingGenericBracketsInTupleTypesNotFollowedBySpaceAsync"/>
/// <seealso cref="SA1015CSharp7UnitTests.TestClosingGenericBracketsInTupleTypesNotPrecededBySpaceAsync"/>
[Fact]
public async Task TestClosingGenericBracketsInTupleTypesNotFollowedBySpaceAsync()
{
const string testCode = @"using System;
public class Foo
{
public void TestMethod()
{
(Func<int > , Func<int > ) value = (null, null);
}
}";
const string fixedCode = @"using System;
public class Foo
{
public void TestMethod()
{
(Func<int >, Func<int > ) value = (null, null);
}
}";

DiagnosticResult expected = this.CSharpDiagnostic().WithLocation(7, 21).WithArguments(" not", "preceded");

await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpDiagnosticAsync(fixedCode, EmptyDiagnosticResults, CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpFixAsync(testCode, fixedCode, cancellationToken: CancellationToken.None).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
{
using Test.SpacingRules;

public class SA1002CSharp7UnitTests : SA1002UnitTests
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
{
using System.Threading;
using System.Threading.Tasks;
using Test.SpacingRules;
using TestHelper;
using Xunit;

using static StyleCop.Analyzers.SpacingRules.SA1003SymbolsMustBeSpacedCorrectly;

public class SA1003CSharp7UnitTests : SA1003UnitTests
{
/// <summary>
/// Verifies that the additional expression-bodied members supported in C# 7 trigger diagnostics as expected.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns>
[Fact]
public async Task TestCSharp7ExpressionBodiedMembersAsync()
{
var testCode = @"using System;
namespace N1
{
public class C1
{
private int x;
private EventHandler e;
public C1()=>x = 1; // Constructors
~C1()=>x = 0; // Finalizers
public event EventHandler E { add=>e += value; remove=>e -= value; } // Event accessors
public int Answer { get=>42; set=>x = 2; } // Property accessors
public int this[int index] { get=>42; set=>x = value; } // Indexer accessors
public void Method()
{
int LocalFunction()=>42; // Local functions
}
}
}
";
var fixedTestCode = @"using System;
namespace N1
{
public class C1
{
private int x;
private EventHandler e;
public C1() => x = 1; // Constructors
~C1() => x = 0; // Finalizers
public event EventHandler E { add => e += value; remove => e -= value; } // Event accessors
public int Answer { get => 42; set => x = 2; } // Property accessors
public int this[int index] { get => 42; set => x = value; } // Indexer accessors
public void Method()
{
int LocalFunction() => 42; // Local functions
}
}
}
";
DiagnosticResult[] expected =
{
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(9, 20).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(9, 20).WithArguments("=>"),

this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(10, 14).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(10, 14).WithArguments("=>"),

this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(11, 42).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(11, 42).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(11, 62).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(11, 62).WithArguments("=>"),

this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(12, 32).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(12, 32).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(12, 41).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(12, 41).WithArguments("=>"),

this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(13, 41).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(13, 41).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(13, 50).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(13, 50).WithArguments("=>"),

this.CSharpDiagnostic(DescriptorPrecededByWhitespace).WithLocation(16, 32).WithArguments("=>"),
this.CSharpDiagnostic(DescriptorFollowedByWhitespace).WithLocation(16, 32).WithArguments("=>"),
};

await this.VerifyCSharpDiagnosticAsync(testCode, expected, CancellationToken.None).ConfigureAwait(false);
await this.VerifyCSharpFixAsync(testCode, fixedTestCode).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
{
using Test.SpacingRules;

public class SA1004CSharp7UnitTests : SA1004UnitTests
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

namespace StyleCop.Analyzers.Test.CSharp7.SpacingRules
{
using Test.SpacingRules;

public class SA1005CSharp7UnitTests : SA1005UnitTests
{
}
}
Loading

0 comments on commit 3f098f5

Please sign in to comment.