提交 6cbfec92 编写于 作者: T Tomas Matousek

Merge remote-tracking branch 'upstream/master'

......@@ -833,15 +833,23 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return True
' After an open parenthesis (() or before a closing parenthesis ()).
' After an open curly brace ({) or before a closing curly brace (}).
' After an open embedded expression (<%=) or before the close of an embedded expression (%>) within an XML literal.
Case SyntaxKind.OpenParenToken,
SyntaxKind.OpenBraceToken,
SyntaxKind.LessThanPercentEqualsToken,
SyntaxKind.PercentGreaterThanToken
Return True
' After an open curly brace ({) or before a closing curly brace (})
' However, a line-continuation character is required following the open curly brace of a string interpolation.
Case SyntaxKind.OpenBraceToken
If parentKind = SyntaxKind.Interpolation Then
Return False
End If
Return True
' After a member qualifier character (.) and before the member name.
' However, you must include a line-continuation character (_) following a member qualifier character when you are using the With statement or
' supplying values in the initialization list for a type.
......@@ -892,12 +900,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' Order By, Select, Skip, Skip While, Take, Take While, Where, In, Into, On, Ascending, and Descending).
' After the From keyword in a collection initializer.
Case SyntaxKind.AggregateKeyword,
SyntaxKind.ByKeyword,
SyntaxKind.EqualsKeyword,
SyntaxKind.FromKeyword,
SyntaxKind.IntoKeyword,
SyntaxKind.JoinKeyword,
SyntaxKind.WhereKeyword
SyntaxKind.ByKeyword,
SyntaxKind.EqualsKeyword,
SyntaxKind.FromKeyword,
SyntaxKind.IntoKeyword,
SyntaxKind.JoinKeyword,
SyntaxKind.WhereKeyword
Return True
......@@ -932,27 +940,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' Keywords that may appear outside of query clauses
Case SyntaxKind.OnKeyword,
SyntaxKind.LetKeyword,
SyntaxKind.SelectKeyword,
SyntaxKind.WhileKeyword
SyntaxKind.LetKeyword,
SyntaxKind.SelectKeyword,
SyntaxKind.WhileKeyword
Return TypeOf token.Parent Is QueryClauseSyntax
' XML Literals
Case SyntaxKind.BeginCDataToken,
SyntaxKind.DoubleQuoteToken,
SyntaxKind.LessThanExclamationMinusMinusToken,
SyntaxKind.LessThanQuestionToken,
SyntaxKind.XmlKeyword,
SyntaxKind.XmlNameToken,
SyntaxKind.XmlTextLiteralToken
SyntaxKind.DoubleQuoteToken,
SyntaxKind.LessThanExclamationMinusMinusToken,
SyntaxKind.LessThanQuestionToken,
SyntaxKind.XmlKeyword,
SyntaxKind.XmlNameToken,
SyntaxKind.XmlTextLiteralToken
Return True
Case SyntaxKind.EndCDataToken,
SyntaxKind.MinusMinusGreaterThanToken,
SyntaxKind.QuestionGreaterThanToken,
SyntaxKind.SlashGreaterThanToken
SyntaxKind.MinusMinusGreaterThanToken,
SyntaxKind.QuestionGreaterThanToken,
SyntaxKind.SlashGreaterThanToken
' An implicit line continuation is allowed only if the token is not the end of
' the xml literal. Walk up the parent chain and see if there is a parent node
......@@ -1042,13 +1050,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return parentKind = SyntaxKind.AttributeList
' After an open parenthesis (() or before a closing parenthesis ()).
' After an open curly brace ({) or before a closing curly brace (}).
' After an open embedded expression (<%=) or before the close of an embedded expression (%>) within an XML literal.
Case SyntaxKind.CloseParenToken,
SyntaxKind.CloseBraceToken,
SyntaxKind.PercentGreaterThanToken
Return True
Return True
' After an open curly brace ({) or before a closing curly brace (})
' However, a line-continuation character is required before the closing curly brace of a string interpolation.
Case SyntaxKind.CloseBraceToken
If parentKind = SyntaxKind.Interpolation Then
Return False
End If
Return True
' Before and after query operators (Aggregate, Distinct, From, Group By, Group Join, Join, Let,
' Order By, Select, Skip, Skip While, Take, Take While, Where, In, Into, On, Ascending, and Descending).
......
......@@ -142,7 +142,8 @@ private static bool TokenShouldNotFormatOnReturn(SyntaxToken token)
private static bool TokenShouldNotFormatOnTypeChar(SyntaxToken token)
{
return token.IsKind(SyntaxKind.CloseParenToken) && !token.Parent.IsKind(SyntaxKind.UsingStatement);
return (token.IsKind(SyntaxKind.CloseParenToken) && !token.Parent.IsKind(SyntaxKind.UsingStatement)) ||
(token.IsKind(SyntaxKind.ColonToken) && !(token.Parent.IsKind(SyntaxKind.LabeledStatement) || token.Parent.IsKind(SyntaxKind.CaseSwitchLabel) || token.Parent.IsKind(SyntaxKind.DefaultSwitchLabel)));
}
public async Task<IList<TextChange>> GetFormattingChangesAsync(Document document, char typedChar, int caretPosition, CancellationToken cancellationToken)
......@@ -165,7 +166,9 @@ public async Task<IList<TextChange>> GetFormattingChangesAsync(Document document
return null;
}
// Check to see if the token is ')' and also the parent is a using statement. If not, bail
// Check to see if any of the below. If not, bail.
// case 1: The token is ')' and the parent is an using statement.
// case 2: The token is ':' and the parent is either labelled statement or case switch or default switch
if (TokenShouldNotFormatOnTypeChar(token))
{
return null;
......
......@@ -834,6 +834,227 @@ static void Main(string[] args)
static void Main(string[] args)
{
}
}";
AssertFormatAfterTypeChar(code, expected);
}
[WorkItem(464)]
[WorkItem(908729)]
[Fact, Trait(Traits.Feature, Traits.Features.Formatting)]
public void ColonInSwitchCase()
{
var code = @"class Program
{
static void Main(string[] args)
{
int f = 0;
switch(f)
{
case 1 :$$ break;
}
}
}";
var expected = @"class Program
{
static void Main(string[] args)
{
int f = 0;
switch(f)
{
case 1: break;
}
}
}";
AssertFormatAfterTypeChar(code, expected);
}
[WorkItem(464)]
[WorkItem(908729)]
[Fact, Trait(Traits.Feature, Traits.Features.Formatting)]
public void ColonInDefaultSwitchCase()
{
var code = @"class Program
{
static void Main(string[] args)
{
int f = 0;
switch(f)
{
case 1: break;
default :$$ break;
}
}
}";
var expected = @"class Program
{
static void Main(string[] args)
{
int f = 0;
switch(f)
{
case 1: break;
default: break;
}
}
}";
AssertFormatAfterTypeChar(code, expected);
}
[WorkItem(464)]
[WorkItem(908729)]
[Fact, Trait(Traits.Feature, Traits.Features.Formatting)]
public void ColonInLabeledStatement()
{
var code = @"class Program
{
static void Main(string[] args)
{
label1 :$$ int s = 0;
}
}";
var expected = @"class Program
{
static void Main(string[] args)
{
label1: int s = 0;
}
}";
AssertFormatAfterTypeChar(code, expected);
}
[WorkItem(464)]
[WorkItem(908729)]
[Fact, Trait(Traits.Feature, Traits.Features.Formatting)]
public void DoNotFormatColonInTargetAttribute()
{
var code = @"using System;
[method :$$ C]
class C : Attribute
{
}";
var expected = @"using System;
[method : C]
class C : Attribute
{
}";
AssertFormatAfterTypeChar(code, expected);
}
[WorkItem(464)]
[WorkItem(908729)]
[Fact, Trait(Traits.Feature, Traits.Features.Formatting)]
public void DoNotFormatColonInBaseList()
{
var code = @"class C :$$ Attribute
{
}";
var expected = @"class C : Attribute
{
}";
AssertFormatAfterTypeChar(code, expected);
}
[WorkItem(464)]
[WorkItem(908729)]
[Fact, Trait(Traits.Feature, Traits.Features.Formatting)]
public void DoNotFormatColonInThisConstructor()
{
var code = @"class Foo
{
Foo(int s) :$$ this()
{
}
Foo()
{
}
}";
var expected = @"class Foo
{
Foo(int s) : this()
{
}
Foo()
{
}
}";
AssertFormatAfterTypeChar(code, expected);
}
[WorkItem(464)]
[WorkItem(908729)]
[Fact, Trait(Traits.Feature, Traits.Features.Formatting)]
public void DoNotFormatColonInConditionalOperator()
{
var code = @"class Program
{
static void Main(string[] args)
{
var vari = foo() ? true :$$ false;
}
}";
var expected = @"class Program
{
static void Main(string[] args)
{
var vari = foo() ? true : false;
}
}";
AssertFormatAfterTypeChar(code, expected);
}
[WorkItem(464)]
[WorkItem(908729)]
[Fact, Trait(Traits.Feature, Traits.Features.Formatting)]
public void DoNotFormatColonInArgument()
{
var code = @"class Program
{
static void Main(string[] args)
{
Main(args :$$ args);
}
}";
var expected = @"class Program
{
static void Main(string[] args)
{
Main(args : args);
}
}";
AssertFormatAfterTypeChar(code, expected);
}
[WorkItem(464)]
[WorkItem(908729)]
[Fact, Trait(Traits.Feature, Traits.Features.Formatting)]
public void DoNotFormatColonInTyepPararmeter()
{
var code = @"class Program<T>
{
class C1<U>
where T :$$ U
{
}
}";
var expected = @"class Program<T>
{
class C1<U>
where T : U
{
}
}";
AssertFormatAfterTypeChar(code, expected);
......
......@@ -39,13 +39,13 @@
.ver 1:0:0:0
}
.module Microsoft.VisualStudio.Debugger.Engine.dll
// MVID: {C3F504FB-22AF-4D5E-8F9E-94471D35BDB3}
// MVID: {6C44C082-16C7-4FDA-BDD9-290D72D500E8}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x02830000
// Image base: 0x01010000
// =============== CLASS MEMBERS DECLARATION ===================
......@@ -38,13 +38,13 @@
.ver 14:0:0:0
}
.module Microsoft.VisualStudio.Debugger.Metadata.dll
// MVID: {A849A496-7C3A-4A0C-9391-02EE53F11055}
// MVID: {79F62A13-7C48-401B-9FC6-02D7CDCE84B8}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00910000
// Image base: 0x00370000
// =============== CLASS MEMBERS DECLARATION ===================
......
......@@ -138,7 +138,7 @@ public TextChunk(string text)
private readonly bool _invalidPattern;
private readonly Segment _fullPatternSegment;
private readonly Segment[] _dotSeparatedSegements;
private readonly Segment[] _dotSeparatedSegments;
private readonly Dictionary<string, List<TextSpan>> _stringToWordSpans = new Dictionary<string, List<TextSpan>>();
private readonly Func<string, List<TextSpan>> _breakIntoWordSpans = StringBreaker.BreakIntoWordParts;
......@@ -165,13 +165,13 @@ public PatternMatcher(string pattern, CultureInfo culture, bool verbatimIdentifi
_compareInfo = culture.CompareInfo;
_fullPatternSegment = new Segment(pattern, verbatimIdentifierPrefixIsWordCharacter);
_dotSeparatedSegements = pattern.Split(DotCharacterArray, StringSplitOptions.RemoveEmptyEntries)
_dotSeparatedSegments = pattern.Split(DotCharacterArray, StringSplitOptions.RemoveEmptyEntries)
.Select(text => new Segment(text.Trim(), verbatimIdentifierPrefixIsWordCharacter))
.ToArray();
_invalidPattern = _dotSeparatedSegements.Length == 0 || _dotSeparatedSegements.Any(s => s.IsInvalid);
_invalidPattern = _dotSeparatedSegments.Length == 0 || _dotSeparatedSegments.Any(s => s.IsInvalid);
}
public bool IsDottedPattern => _dotSeparatedSegements.Length > 1;
public bool IsDottedPattern => _dotSeparatedSegments.Length > 1;
private bool SkipMatch(string candidate)
{
......@@ -202,7 +202,7 @@ public IEnumerable<PatternMatch> GetMatchesForLastSegmentOfPattern(string candid
return null;
}
return MatchSegment(candidate, _dotSeparatedSegements.Last());
return MatchSegment(candidate, _dotSeparatedSegments.Last());
}
/// <summary>
......@@ -227,7 +227,7 @@ public IEnumerable<PatternMatch> GetMatches(string candidate, string dottedConta
// First, check that the last part of the dot separated pattern matches the name of the
// candidate. If not, then there's no point in proceeding and doing the more
// expensive work.
var candidateMatch = MatchSegment(candidate, _dotSeparatedSegements.Last());
var candidateMatch = MatchSegment(candidate, _dotSeparatedSegments.Last());
if (candidateMatch == null)
{
return null;
......@@ -238,7 +238,7 @@ public IEnumerable<PatternMatch> GetMatches(string candidate, string dottedConta
// -1 because the last part was checked against the name, and only the rest
// of the parts are checked against the container.
if (_dotSeparatedSegements.Length - 1 > containerParts.Length)
if (_dotSeparatedSegments.Length - 1 > containerParts.Length)
{
// There weren't enough container parts to match against the pattern parts.
// So this definitely doesn't match.
......@@ -249,11 +249,11 @@ public IEnumerable<PatternMatch> GetMatches(string candidate, string dottedConta
// the dotted parts match up correctly.
var totalMatch = candidateMatch.ToList();
for (int i = _dotSeparatedSegements.Length - 2, j = containerParts.Length - 1;
for (int i = _dotSeparatedSegments.Length - 2, j = containerParts.Length - 1;
i >= 0;
i--, j--)
{
var segment = _dotSeparatedSegements[i];
var segment = _dotSeparatedSegments[i];
var containerName = containerParts[j];
var containerMatch = MatchSegment(containerName, segment);
if (containerMatch == null)
......@@ -403,8 +403,7 @@ private static bool ContainsUpperCaseLetter(string pattern)
// (Pattern: fogbar, Candidate: quuxfogbarFogBar).
if (chunk.Text.Length < candidate.Length)
{
var firstInstance = _compareInfo.IndexOf(candidate, chunk.Text, CompareOptions.IgnoreCase);
if (firstInstance != -1 && char.IsUpper(candidate[firstInstance]))
if (index != -1 && char.IsUpper(candidate[index]))
{
return new PatternMatch(PatternMatchKind.Substring, punctuationStripped, isCaseSensitive: false);
}
......
......@@ -1307,6 +1307,75 @@ End Module
Verify(code, expected);
}
[Fact]
[WorkItem(710, "#710")]
[Trait(Traits.Feature, Traits.Features.RemoveUnnecessaryLineContinuation)]
public void DontRemoveLineContinuationInStringInterpolation1()
{
var code = @"[|
Module Program
Dim x = $""{ _
1}""
End Module
|]";
var expected = @"
Module Program
Dim x = $""{ _
1}""
End Module
";
Verify(code, expected);
}
[Fact]
[WorkItem(710, "#710")]
[Trait(Traits.Feature, Traits.Features.RemoveUnnecessaryLineContinuation)]
public void DontRemoveLineContinuationInStringInterpolation2()
{
var code = @"[|
Module Program
Dim x = $""{1 _
}""
End Module
|]";
var expected = @"
Module Program
Dim x = $""{1 _
}""
End Module
";
Verify(code, expected);
}
[Fact]
[WorkItem(710, "#710")]
[Trait(Traits.Feature, Traits.Features.RemoveUnnecessaryLineContinuation)]
public void DontRemoveLineContinuationInStringInterpolation3()
{
var code = @"[|
Module Program
Dim x = $""{ _
1 _
}""
End Module
|]";
var expected = @"
Module Program
Dim x = $""{ _
1 _
}""
End Module
";
Verify(code, expected);
}
private string CreateMethod(string body)
{
return @"Imports System
......
......@@ -106,7 +106,7 @@ Namespace Microsoft.CodeAnalysis.CodeCleanup.Providers
End If
' check context
If token1.IsLastTokenOfStatement() Then
If token1.IsLastTokenOfStatement() AndAlso Not token1.IsMissing Then
' check trivia
If Not GetTrailingTrivia(token1).Any(SyntaxKind.LineContinuationTrivia) AndAlso
Not GetLeadingTrivia(token2).Any(SyntaxKind.LineContinuationTrivia) Then
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册