提交 10bfd2f9 编写于 作者: C CyrusNajmabadi

Don't generate a variable if it would conflict wit

h another local in scope.
上级 5e433c83
......@@ -18,9 +18,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.Introd
public class IntroduceVariableTests : AbstractCSharpCodeActionTest
{
protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace)
{
return new IntroduceVariableCodeRefactoringProvider();
}
=> new IntroduceVariableCodeRefactoringProvider();
private readonly CodeStyleOption<bool> onWithInfo = new CodeStyleOption<bool>(true, NotificationOption.Suggestion);
......@@ -3872,8 +3870,8 @@ public async Task ElementOfTuple()
var i = (1, [|""hello""|]).ToString();
}";
var expected =
@"class C
var expected =
@"class C
{
private const string {|Rename:V|} = ""hello"";
var i = (1, V).ToString();
......@@ -4019,5 +4017,40 @@ void Foo()
withScriptOption: true)
);
}
[WorkItem(11777, "https://github.com/dotnet/roslyn/issues/11777")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsIntroduceVariable)]
public async Task TestGenerateLocalConflictingName1()
{
await TestAsync(
@"class Program
{
class MySpan { public int Start { get; } public int End { get; } }
void Method(MySpan span)
{
int pos = span.Start;
while (pos < [|span.End|])
{
int spanEnd = span.End;
int end = pos;
}
}
}",
@"
class Program
{
class MySpan { public int Start { get; } public int End { get; } }
void Method(MySpan span)
{
int pos = span.Start;
int {|Rename:end1|} = span.End;
while (pos < end1)
{
int spanEnd = span.End;
int end = pos;
}
}
}");
}
}
}
\ No newline at end of file
......@@ -7089,4 +7089,4 @@ void Method()
withScriptOption: true);
}
}
}
}
\ No newline at end of file
......@@ -28,7 +28,10 @@ internal partial class CSharpIntroduceVariableService
bool isConstant,
CancellationToken cancellationToken)
{
var newLocalNameToken = GenerateUniqueLocalName(document, expression, isConstant, cancellationToken);
var containerToGenerateInto = GetContainerToGenerateInto(document, expression, cancellationToken);
var newLocalNameToken = GenerateUniqueLocalName(
document, expression, isConstant, containerToGenerateInto, cancellationToken);
var newLocalName = SyntaxFactory.IdentifierName(newLocalNameToken);
var modifiers = isConstant
......@@ -46,6 +49,29 @@ internal partial class CSharpIntroduceVariableService
null,
SyntaxFactory.EqualsValueClause(expression.WithoutTrailingTrivia().WithoutLeadingTrivia())))));
switch (containerToGenerateInto)
{
case BlockSyntax block:
return await IntroduceLocalDeclarationIntoBlockAsync(
document, block, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken).ConfigureAwait(false);
case ArrowExpressionClauseSyntax arrowExpression:
return RewriteExpressionBodiedMemberAndIntroduceLocalDeclaration(
document, arrowExpression, expression, newLocalName,
declarationStatement, allOccurrences, cancellationToken);
case LambdaExpressionSyntax lambda:
return IntroduceLocalDeclarationIntoLambda(
document, lambda, expression, newLocalName, declarationStatement,
allOccurrences, cancellationToken);
}
throw new InvalidOperationException();
}
private SyntaxNode GetContainerToGenerateInto(
SemanticDocument document, ExpressionSyntax expression, CancellationToken cancellationToken)
{
var anonymousMethodParameters = GetAnonymousMethodParameters(document, expression, cancellationToken);
var lambdas = anonymousMethodParameters.SelectMany(p => p.ContainingSymbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax(cancellationToken)).AsEnumerable())
.Where(n => n is ParenthesizedLambdaExpressionSyntax || n is SimpleLambdaExpressionSyntax)
......@@ -55,27 +81,24 @@ internal partial class CSharpIntroduceVariableService
if (parentLambda != null)
{
return IntroduceLocalDeclarationIntoLambda(
document, expression, newLocalName, declarationStatement, parentLambda, allOccurrences, cancellationToken);
return parentLambda;
}
else if (IsInExpressionBodiedMember(expression))
{
return RewriteExpressionBodiedMemberAndIntroduceLocalDeclaration(
document, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken);
return expression.GetAncestorOrThis<ArrowExpressionClauseSyntax>();
}
else
{
return await IntroduceLocalDeclarationIntoBlockAsync(
document, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken).ConfigureAwait(false);
return expression.GetAncestorsOrThis<BlockSyntax>().LastOrDefault();
}
}
private Document IntroduceLocalDeclarationIntoLambda(
SemanticDocument document,
SyntaxNode oldLambda,
ExpressionSyntax expression,
IdentifierNameSyntax newLocalName,
LocalDeclarationStatementSyntax declarationStatement,
SyntaxNode oldLambda,
bool allOccurrences,
CancellationToken cancellationToken)
{
......@@ -190,13 +213,14 @@ private bool CanUseVar(ITypeSymbol typeSymbol)
private Document RewriteExpressionBodiedMemberAndIntroduceLocalDeclaration(
SemanticDocument document,
ArrowExpressionClauseSyntax arrowExpression,
ExpressionSyntax expression,
NameSyntax newLocalName,
LocalDeclarationStatementSyntax declarationStatement,
bool allOccurrences,
CancellationToken cancellationToken)
{
var oldBody = expression.GetAncestorOrThis<ArrowExpressionClauseSyntax>();
var oldBody = arrowExpression;
var oldParentingNode = oldBody.Parent;
var leadingTrivia = oldBody.GetLeadingTrivia()
.AddRange(oldBody.ArrowToken.TrailingTrivia);
......@@ -267,6 +291,7 @@ private bool CanUseVar(ITypeSymbol typeSymbol)
private async Task<Document> IntroduceLocalDeclarationIntoBlockAsync(
SemanticDocument document,
BlockSyntax block,
ExpressionSyntax expression,
NameSyntax newLocalName,
LocalDeclarationStatementSyntax declarationStatement,
......@@ -275,7 +300,7 @@ private bool CanUseVar(ITypeSymbol typeSymbol)
{
declarationStatement = declarationStatement.WithAdditionalAnnotations(Formatter.Annotation);
var oldOutermostBlock = expression.GetAncestorsOrThis<BlockSyntax>().LastOrDefault();
var oldOutermostBlock = block;
var matches = FindMatches(document, expression, document, oldOutermostBlock, allOccurrences, cancellationToken);
Debug.Assert(matches.Contains(expression));
......
......@@ -24,14 +24,17 @@ private static bool IsAnyQueryClause(SyntaxNode node)
protected override Task<Document> IntroduceQueryLocalAsync(
SemanticDocument document, ExpressionSyntax expression, bool allOccurrences, CancellationToken cancellationToken)
{
var newLocalNameToken = GenerateUniqueLocalName(document, expression, isConstant: false, cancellationToken: cancellationToken);
var oldOutermostQuery = expression.GetAncestorsOrThis<QueryExpressionSyntax>().LastOrDefault();
var newLocalNameToken = GenerateUniqueLocalName(
document, expression, isConstant: false,
container: oldOutermostQuery, cancellationToken: cancellationToken);
var newLocalName = SyntaxFactory.IdentifierName(newLocalNameToken);
var letClause = SyntaxFactory.LetClause(
newLocalNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()),
expression).WithAdditionalAnnotations(Formatter.Annotation);
newLocalNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()),
expression).WithAdditionalAnnotations(Formatter.Annotation);
var oldOutermostQuery = expression.GetAncestorsOrThis<QueryExpressionSyntax>().LastOrDefault();
var matches = FindMatches(document, expression, document, oldOutermostQuery, allOccurrences, cancellationToken);
var innermostClauses = new HashSet<SyntaxNode>(
matches.Select(expr => expr.GetAncestorsOrThis<SyntaxNode>().First(IsAnyQueryClause)));
......
......@@ -20,9 +20,6 @@ internal abstract class AbstractIntroduceVariableCodeAction : CodeAction
private readonly TExpressionSyntax _expression;
private readonly SemanticDocument _document;
private readonly TService _service;
private readonly string _title;
private static readonly Regex s_newlinePattern = new Regex(@"[\r\n]+");
internal AbstractIntroduceVariableCodeAction(
TService service,
......@@ -40,13 +37,10 @@ internal abstract class AbstractIntroduceVariableCodeAction : CodeAction
_isConstant = isConstant;
_isLocal = isLocal;
_isQueryLocal = isQueryLocal;
_title = CreateDisplayText(expression);
Title = CreateDisplayText(expression);
}
public override string Title
{
get { return _title; }
}
public override string Title { get; }
protected override async Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
{
......@@ -79,10 +73,7 @@ private async Task<Document> IntroduceFieldAsync(CancellationToken cancellationT
private string CreateDisplayText(TExpressionSyntax expression)
{
var singleLineExpression = _document.Project.LanguageServices.GetService<ISyntaxFactsService>().ConvertToSingleLine(expression);
var nodeString = singleLineExpression.ToFullString().Trim();
// prevent the display string from spanning multiple lines
nodeString = s_newlinePattern.Replace(nodeString, " ");
var nodeString = singleLineExpression.ToString();
// prevent the display string from being too long
const int MaxLength = 40;
......
......@@ -216,19 +216,55 @@ private CodeAction CreateAction(State state, bool allOccurrences, bool isConstan
SemanticDocument document,
TExpressionSyntax expression,
bool isConstant,
SyntaxNode container,
CancellationToken cancellationToken)
{
var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>();
var semanticFacts = document.Project.LanguageServices.GetService<ISemanticFactsService>();
var syntaxFacts = document.Document.GetLanguageService<ISyntaxFactsService>();
var semanticFacts = document.Document.GetLanguageService<ISemanticFactsService>();
var semanticModel = document.SemanticModel;
var existingSymbols = GetExistingSymbols(semanticModel, container, cancellationToken);
var baseName = semanticFacts.GenerateNameForExpression(semanticModel, expression, capitalize: isConstant);
var reservedNames = semanticModel.LookupSymbols(expression.SpanStart).Select(s => s.Name);
var reservedNames = semanticModel.LookupSymbols(expression.SpanStart)
.Select(s => s.Name)
.Concat(existingSymbols.Select(s => s.Name));
return syntaxFacts.ToIdentifierToken(
NameGenerator.EnsureUniqueness(baseName, reservedNames, syntaxFacts.IsCaseSensitive));
}
private static HashSet<ISymbol> GetExistingSymbols(
SemanticModel semanticModel, SyntaxNode container, CancellationToken cancellationToken)
{
var symbols = new HashSet<ISymbol>();
if (container != null)
{
GetExistingSymbols(semanticModel, container, symbols, cancellationToken);
}
return symbols;
}
private static void GetExistingSymbols(
SemanticModel semanticModel, SyntaxNode node,
HashSet<ISymbol> symbols, CancellationToken cancellationToken)
{
var symbol = semanticModel.GetDeclaredSymbol(node, cancellationToken);
if (symbol != null)
{
symbols.Add(symbol);
}
foreach (var child in node.ChildNodesAndTokens())
{
if (child.IsNode)
{
GetExistingSymbols(semanticModel, child.AsNode(), symbols, cancellationToken);
}
}
}
protected ISet<TExpressionSyntax> FindMatches(
SemanticDocument originalDocument,
TExpressionSyntax expressionInOriginal,
......
......@@ -10,23 +10,26 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable
Friend Partial Class VisualBasicIntroduceVariableService
Protected Overrides Async Function IntroduceFieldAsync(document As SemanticDocument,
expression As ExpressionSyntax,
allOccurrences As Boolean,
isConstant As Boolean,
cancellationToken As CancellationToken) As Task(Of Tuple(Of Document, SyntaxNode, Integer))
Protected Overrides Async Function IntroduceFieldAsync(
document As SemanticDocument,
expression As ExpressionSyntax,
allOccurrences As Boolean,
isConstant As Boolean,
cancellationToken As CancellationToken) As Task(Of Tuple(Of Document, SyntaxNode, Integer))
Dim oldTypeDeclaration = expression.GetAncestorOrThis(Of TypeBlockSyntax)()
Dim oldType = If(oldTypeDeclaration IsNot Nothing,
document.SemanticModel.GetDeclaredSymbol(oldTypeDeclaration.BlockStatement, cancellationToken),
Nothing)
Dim newNameToken = GenerateUniqueLocalName(document, expression, isConstant, cancellationToken)
Dim newNameToken = GenerateUniqueLocalName(
document, expression, isConstant, container:=Nothing,
cancellationToken:=cancellationToken)
Dim newQualifiedName = SyntaxFactory.SimpleMemberAccessExpression(
expression:=SyntaxFactory.ParseName(oldType.ToNameDisplayString()),
operatorToken:=SyntaxFactory.Token(SyntaxKind.DotToken),
name:=SyntaxFactory.IdentifierName(newNameToken)).WithAdditionalAnnotations(Simplifier.Annotation)
expression:=SyntaxFactory.ParseName(oldType.ToNameDisplayString()),
operatorToken:=SyntaxFactory.Token(SyntaxKind.DotToken),
name:=SyntaxFactory.IdentifierName(newNameToken)).WithAdditionalAnnotations(Simplifier.Annotation)
If oldType IsNot Nothing Then
Return Await IntroduceFieldIntoTypeAsync(
......@@ -43,6 +46,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable
Dim newRoot = newCompilationUnit.WithMembers(
newCompilationUnit.Members.Insert(insertionIndex, newFieldDeclaration))
Return Tuple.Create(document.Document.WithSyntaxRoot(newRoot), destination, insertionIndex)
End If
End Function
......
......@@ -17,7 +17,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable
isConstant As Boolean,
cancellationToken As CancellationToken) As Task(Of Document)
Dim newLocalNameToken = CType(GenerateUniqueLocalName(document, expression, isConstant, cancellationToken), SyntaxToken)
Dim container = GetContainerToGenerateInfo(document, expression, cancellationToken)
Dim newLocalNameToken = GenerateUniqueLocalName(
document, expression, isConstant, container, cancellationToken)
Dim newLocalName = SyntaxFactory.IdentifierName(newLocalNameToken)
Dim modifier = If(isConstant, SyntaxFactory.Token(SyntaxKind.ConstKeyword), SyntaxFactory.Token(SyntaxKind.DimKeyword))
......@@ -37,6 +39,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable
declarationStatement = declarationStatement.WithAppendedTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed)
End If
If TypeOf container Is SingleLineLambdaExpressionSyntax Then
Return IntroduceLocalDeclarationIntoLambda(
document, DirectCast(container, SingleLineLambdaExpressionSyntax),
expression, newLocalName, declarationStatement, allOccurrences, cancellationToken)
Else
Return Await IntroduceLocalDeclarationIntoBlockAsync(
document, container, expression, newLocalName,
declarationStatement, allOccurrences, cancellationToken).ConfigureAwait(False)
End If
End Function
Private Function GetContainerToGenerateInfo(
document As SemanticDocument,
expression As ExpressionSyntax,
cancellationToken As CancellationToken) As SyntaxNode
Dim anonymousMethodParameters = GetAnonymousMethodParameters(document, expression, cancellationToken)
Dim lambdas = anonymousMethodParameters.SelectMany(Function(p) p.ContainingSymbol.DeclaringSyntaxReferences).
Select(Function(r) r.GetSyntax()).
......@@ -45,23 +63,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable
ToSet()
Dim parentLambda = GetParentLambda(expression, lambdas)
If parentLambda IsNot Nothing Then
Return IntroduceLocalDeclarationIntoLambda(
document, expression, newLocalName, declarationStatement, parentLambda, allOccurrences, cancellationToken)
Else
Return Await IntroduceLocalDeclarationIntoBlockAsync(
document, expression, newLocalName, declarationStatement, allOccurrences, cancellationToken).ConfigureAwait(False)
Return parentLambda
End If
Return expression.GetContainingExecutableBlocks().LastOrDefault()
End Function
Private Function IntroduceLocalDeclarationIntoLambda(document As SemanticDocument,
expression As ExpressionSyntax,
newLocalName As IdentifierNameSyntax,
declarationStatement As StatementSyntax,
oldLambda As SingleLineLambdaExpressionSyntax,
allOccurrences As Boolean,
cancellationToken As CancellationToken) As Document
Private Function IntroduceLocalDeclarationIntoLambda(
document As SemanticDocument,
oldLambda As SingleLineLambdaExpressionSyntax,
expression As ExpressionSyntax,
newLocalName As IdentifierNameSyntax,
declarationStatement As StatementSyntax,
allOccurrences As Boolean,
cancellationToken As CancellationToken) As Document
Dim oldBody = DirectCast(oldLambda.Body, ExpressionSyntax)
Dim rewrittenBody = Rewrite(
......@@ -118,6 +135,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable
Private Async Function IntroduceLocalDeclarationIntoBlockAsync(
document As SemanticDocument,
container As SyntaxNode,
expression As ExpressionSyntax,
newLocalName As NameSyntax,
localDeclaration As LocalDeclarationStatementSyntax,
......@@ -127,7 +145,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable
Dim localAnnotation = New SyntaxAnnotation()
localDeclaration = localDeclaration.WithAdditionalAnnotations(Formatter.Annotation, localAnnotation)
Dim oldOutermostBlock = expression.GetContainingExecutableBlocks().LastOrDefault()
Dim oldOutermostBlock = container
If oldOutermostBlock.IsSingleLineExecutableBlock() Then
oldOutermostBlock = oldOutermostBlock.Parent
End If
......
......@@ -8,12 +8,17 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable
Friend Partial Class VisualBasicIntroduceVariableService
Protected Overrides Function IntroduceQueryLocalAsync(document As SemanticDocument,
expression As ExpressionSyntax,
allOccurrences As Boolean,
cancellationToken As CancellationToken) As Task(Of Document)
Protected Overrides Function IntroduceQueryLocalAsync(
document As SemanticDocument,
expression As ExpressionSyntax,
allOccurrences As Boolean,
cancellationToken As CancellationToken) As Task(Of Document)
Dim newLocalNameToken = GenerateUniqueLocalName(document, expression, isConstant:=False, cancellationToken:=cancellationToken)
Dim oldOutermostQuery = expression.GetAncestorsOrThis(Of QueryExpressionSyntax)().LastOrDefault()
Dim newLocalNameToken = GenerateUniqueLocalName(
document, expression, isConstant:=False,
container:=oldOutermostQuery, cancellationToken:=cancellationToken)
Dim newLocalName = SyntaxFactory.IdentifierName(newLocalNameToken)
Dim letClause = SyntaxFactory.LetClause(
......@@ -22,7 +27,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.IntroduceVariable
SyntaxFactory.ModifiedIdentifier(newLocalNameToken.WithAdditionalAnnotations(RenameAnnotation.Create()))),
expression)).WithAdditionalAnnotations(Formatter.Annotation)
Dim oldOutermostQuery = expression.GetAncestorsOrThis(Of QueryExpressionSyntax)().LastOrDefault()
Dim matches = FindMatches(document, expression, document, oldOutermostQuery, allOccurrences, cancellationToken)
Dim innermostClauses = New HashSet(Of QueryClauseSyntax)(
matches.Select(Function(expr) expr.GetAncestor(Of QueryClauseSyntax)()))
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
......@@ -12,12 +13,14 @@ internal partial class SyntaxNodeExtensions
{
internal class SingleLineRewriter : CSharpSyntaxRewriter
{
private bool useElasticTrivia;
private static readonly Regex s_newlinePattern = new Regex(@"[\r\n]+");
private readonly bool _useElasticTrivia;
private bool _lastTokenEndedInWhitespace;
public SingleLineRewriter(bool useElasticTrivia)
{
this.useElasticTrivia = useElasticTrivia;
this._useElasticTrivia = useElasticTrivia;
}
public override SyntaxToken VisitToken(SyntaxToken token)
......@@ -28,7 +31,7 @@ public override SyntaxToken VisitToken(SyntaxToken token)
}
else if (token.LeadingTrivia.Count > 0)
{
if (useElasticTrivia)
if (_useElasticTrivia)
{
token = token.WithLeadingTrivia(SyntaxFactory.ElasticSpace);
}
......@@ -40,7 +43,7 @@ public override SyntaxToken VisitToken(SyntaxToken token)
if (token.TrailingTrivia.Count > 0)
{
if (useElasticTrivia)
if (_useElasticTrivia)
{
token = token.WithTrailingTrivia(SyntaxFactory.ElasticSpace);
}
......@@ -48,6 +51,7 @@ public override SyntaxToken VisitToken(SyntaxToken token)
{
token = token.WithTrailingTrivia(SyntaxFactory.Space);
}
_lastTokenEndedInWhitespace = true;
}
else
......@@ -55,6 +59,20 @@ public override SyntaxToken VisitToken(SyntaxToken token)
_lastTokenEndedInWhitespace = false;
}
if (token.Kind() == SyntaxKind.StringLiteralToken ||
token.Kind() == SyntaxKind.InterpolatedStringTextToken)
{
if (s_newlinePattern.IsMatch(token.Text))
{
var newText = s_newlinePattern.Replace(token.Text, " ");
token = SyntaxFactory.Token(
token.LeadingTrivia,
token.Kind(),
newText, newText,
token.TrailingTrivia);
}
}
return token;
}
}
......
......@@ -714,9 +714,7 @@ public bool IsElementAccessExpression(SyntaxNode node)
}
public SyntaxNode ConvertToSingleLine(SyntaxNode node, bool useElasticTrivia = false)
{
return node.ConvertToSingleLine(useElasticTrivia);
}
=> node.ConvertToSingleLine(useElasticTrivia);
public SyntaxToken ToIdentifierToken(string name)
{
......
......@@ -12,29 +12,31 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions
Friend Class SingleLineRewriter
Inherits VisualBasicSyntaxRewriter
Private useElasticTrivia As Boolean
Private ReadOnly _useElasticTrivia As Boolean
Private _lastTokenEndedInWhitespace As Boolean
Public Sub New(Optional useElasticTrivia As Boolean = False)
Me.useElasticTrivia = useElasticTrivia
_useElasticTrivia = useElasticTrivia
End Sub
Public Overrides Function VisitToken(token As SyntaxToken) As SyntaxToken
If _lastTokenEndedInWhitespace Then
token = token.WithLeadingTrivia(Enumerable.Empty(Of SyntaxTrivia)())
ElseIf token.LeadingTrivia.Count > 0 Then
If useElasticTrivia Then
If _useElasticTrivia Then
token = token.WithLeadingTrivia(SyntaxFactory.ElasticSpace)
Else
token = token.WithLeadingTrivia(SyntaxFactory.Space)
End If
End If
If token.TrailingTrivia.Count > 0 Then
If useElasticTrivia Then
If _useElasticTrivia Then
token = token.WithTrailingTrivia(SyntaxFactory.ElasticSpace)
Else
token = token.WithTrailingTrivia(SyntaxFactory.Space)
End If
_lastTokenEndedInWhitespace = True
Else
_lastTokenEndedInWhitespace = False
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册