提交 83b2a898 编写于 作者: C CyrusNajmabadi

Push logic into abstract class so we can share it with VB.

上级 3d4aa052
...@@ -1020,6 +1020,71 @@ public void AddFirstMissingCloseBrace(SyntaxNode root, SyntaxNode contextNode, o ...@@ -1020,6 +1020,71 @@ public void AddFirstMissingCloseBrace(SyntaxNode root, SyntaxNode contextNode, o
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public SyntaxNode GetObjectCreationInitializer(SyntaxNode objectCreationExpression)
{
throw new NotImplementedException();
}
public bool IsSimpleAssignmentStatement(SyntaxNode statement)
{
throw new NotImplementedException();
}
public void GetPartsOfAssignmentStatement(SyntaxNode statement, out SyntaxNode left, out SyntaxNode right)
{
throw new NotImplementedException();
}
public SyntaxNode GetNameOfMemberAccessExpression(SyntaxNode memberAccessExpression)
{
throw new NotImplementedException();
}
public SyntaxToken GetOperatorTokenOfMemberAccessExpression(SyntaxNode memberAccessExpression)
{
throw new NotImplementedException();
}
public bool IsSimpleMemberAccessExpression(SyntaxNode node)
{
throw new NotImplementedException();
}
public SyntaxToken GetIdentifierOfSimpleName(SyntaxNode node)
{
throw new NotImplementedException();
}
public SyntaxToken GetIdentifierOfVariableDeclarator(SyntaxNode node)
{
throw new NotImplementedException();
}
public bool IsIdentifierName(SyntaxNode node)
{
throw new NotImplementedException();
}
public bool IsLocalDeclarationStatement(SyntaxNode node)
{
throw new NotImplementedException();
}
public bool IsDeclaratorOfLocalDeclarationStatement(SyntaxNode declator, SyntaxNode localDeclarationStatement)
{
throw new NotImplementedException();
}
public bool AreEquivalent(SyntaxToken token1, SyntaxToken token2)
{
throw new NotImplementedException();
}
public bool AreEquivalent(SyntaxNode node1, SyntaxNode node2)
{
throw new NotImplementedException();
}
} }
} }
} }
......
...@@ -660,7 +660,7 @@ End Class]]></a>.Value.NormalizeLineEndings() ...@@ -660,7 +660,7 @@ End Class]]></a>.Value.NormalizeLineEndings()
Throw New NotImplementedException() Throw New NotImplementedException()
End Function End Function
Public Function IsMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsMemberAccessExpression Public Function IsMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsSimpleMemberAccessExpression
Throw New NotImplementedException() Throw New NotImplementedException()
End Function End Function
...@@ -895,6 +895,54 @@ End Class]]></a>.Value.NormalizeLineEndings() ...@@ -895,6 +895,54 @@ End Class]]></a>.Value.NormalizeLineEndings()
Public Sub AddFirstMissingCloseBrace(root As SyntaxNode, contextNode As SyntaxNode, ByRef newRoot As SyntaxNode, ByRef newContextNode As SyntaxNode) Implements ISyntaxFactsService.AddFirstMissingCloseBrace Public Sub AddFirstMissingCloseBrace(root As SyntaxNode, contextNode As SyntaxNode, ByRef newRoot As SyntaxNode, ByRef newContextNode As SyntaxNode) Implements ISyntaxFactsService.AddFirstMissingCloseBrace
Throw New NotImplementedException() Throw New NotImplementedException()
End Sub End Sub
Public Function GetObjectCreationInitializer(objectCreationExpression As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetObjectCreationInitializer
Throw New NotImplementedException()
End Function
Public Function IsSimpleAssignmentStatement(statement As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsSimpleAssignmentStatement
Throw New NotImplementedException()
End Function
Public Sub GetPartsOfAssignmentStatement(statement As SyntaxNode, ByRef left As SyntaxNode, ByRef right As SyntaxNode) Implements ISyntaxFactsService.GetPartsOfAssignmentStatement
Throw New NotImplementedException()
End Sub
Public Function GetNameOfMemberAccessExpression(memberAccessExpression As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetNameOfMemberAccessExpression
Throw New NotImplementedException()
End Function
Public Function GetOperatorTokenOfMemberAccessExpression(memberAccessExpression As SyntaxNode) As SyntaxToken Implements ISyntaxFactsService.GetOperatorTokenOfMemberAccessExpression
Throw New NotImplementedException()
End Function
Public Function GetIdentifierOfSimpleName(node As SyntaxNode) As SyntaxToken Implements ISyntaxFactsService.GetIdentifierOfSimpleName
Throw New NotImplementedException()
End Function
Public Function GetIdentifierOfVariableDeclarator(node As SyntaxNode) As SyntaxToken Implements ISyntaxFactsService.GetIdentifierOfVariableDeclarator
Throw New NotImplementedException()
End Function
Public Function IsIdentifierName(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsIdentifierName
Throw New NotImplementedException()
End Function
Public Function IsLocalDeclarationStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsLocalDeclarationStatement
Throw New NotImplementedException()
End Function
Public Function IsDeclaratorOfLocalDeclarationStatement(declator As SyntaxNode, localDeclarationStatement As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsDeclaratorOfLocalDeclarationStatement
Throw New NotImplementedException()
End Function
Public Function AreEquivalent(token1 As SyntaxToken, token2 As SyntaxToken) As Boolean Implements ISyntaxFactsService.AreEquivalent
Throw New NotImplementedException()
End Function
Public Function AreEquivalent(node1 As SyntaxNode, node2 As SyntaxNode) As Boolean Implements ISyntaxFactsService.AreEquivalent
Throw New NotImplementedException()
End Function
End Class End Class
End Class End Class
End Namespace End Namespace
...@@ -13,72 +13,24 @@ ...@@ -13,72 +13,24 @@
using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.UseObjectInitializer;
using Roslyn.Utilities; using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.UseObjectInitializer namespace Microsoft.CodeAnalysis.CSharp.UseObjectInitializer
{ {
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.UseObjectInitializer), Shared] [ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.UseObjectInitializer), Shared]
internal class CSharpUseObjectInitializerCodeFixProvider : CodeFixProvider internal class CSharpUseObjectInitializerCodeFixProvider :
AbstractUseObjectInitializerCodeFixProvider<
ExpressionSyntax,
StatementSyntax,
ObjectCreationExpressionSyntax,
MemberAccessExpressionSyntax,
VariableDeclaratorSyntax>
{ {
public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; protected override SyntaxTrivia GetNewLine()
public override ImmutableArray<string> FixableDiagnosticIds
=> ImmutableArray.Create(IDEDiagnosticIds.UseObjectInitializerDiagnosticId);
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
context.RegisterCodeFix(
new MyCodeAction(c => FixAsync(context.Document, context.Diagnostics.First(), c)),
context.Diagnostics);
return SpecializedTasks.EmptyTask;
}
private async Task<Document> FixAsync(
Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var objectCreation = (ObjectCreationExpressionSyntax)root.FindNode(diagnostic.AdditionalLocations[0].SourceSpan);
var matches = new Analyzer(objectCreation).Analyze();
var editor = new SyntaxEditor(root, document.Project.Solution.Workspace);
editor.ReplaceNode(objectCreation, GetNewObjectCreation(objectCreation, matches));
foreach(var match in matches)
{
editor.RemoveNode(match.ExpressionStatement);
}
var newRoot = editor.GetChangedRoot();
return document.WithSyntaxRoot(newRoot);
}
private ObjectCreationExpressionSyntax GetNewObjectCreation(
ObjectCreationExpressionSyntax objectCreation,
List<Match> matches)
{
var initializer = SyntaxFactory.InitializerExpression(
SyntaxKind.ObjectInitializerExpression,
SyntaxFactory.SeparatedList(
matches.Select(CreateAssignmentExpression)));
return objectCreation.WithInitializer(initializer)
.WithAdditionalAnnotations(Formatter.Annotation);
}
private ExpressionSyntax CreateAssignmentExpression(Match match)
{
return SyntaxFactory.AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
match.MemberAccessExpression.Name,
match.Initializer).WithLeadingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed);
}
private class MyCodeAction : CodeAction.DocumentChangeAction
{ {
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument) return SyntaxFactory.ElasticCarriageReturnLineFeed;
: base(FeaturesResources.Object_initialization_can_be_simplified, createChangedDocument)
{
}
} }
} }
} }
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.UseObjectInitializer;
namespace Microsoft.CodeAnalysis.CSharp.UseObjectInitializer namespace Microsoft.CodeAnalysis.CSharp.UseObjectInitializer
{ {
[DiagnosticAnalyzer(LanguageNames.CSharp)] [DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class CSharpUseObjectInitializerDiagnosticAnalyzer : DiagnosticAnalyzer, IBuiltInAnalyzer internal class CSharpUseObjectInitializerDiagnosticAnalyzer :
AbstractUseObjectInitializerDiagnosticAnalyzer<
SyntaxKind,
ExpressionSyntax,
StatementSyntax,
ObjectCreationExpressionSyntax,
MemberAccessExpressionSyntax,
VariableDeclaratorSyntax>
{ {
private static readonly string Id = IDEDiagnosticIds.UseObjectInitializerDiagnosticId; protected override SyntaxKind GetObjectCreationSyntaxKind() => SyntaxKind.ObjectCreationExpression;
private static readonly DiagnosticDescriptor s_descriptor = protected override ISyntaxFactsService GetSyntaxFactsService() => CSharpSyntaxFactsService.Instance;
CreateDescriptor(Id, DiagnosticSeverity.Hidden);
private static readonly DiagnosticDescriptor s_unnecessaryWithSuggestionDescriptor =
CreateDescriptor(Id, DiagnosticSeverity.Hidden, DiagnosticCustomTags.Unnecessary);
private static readonly DiagnosticDescriptor s_unnecessaryWithoutSuggestionDescriptor =
CreateDescriptor(Id + "WithoutSuggestion",
DiagnosticSeverity.Hidden, DiagnosticCustomTags.Unnecessary);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
=> ImmutableArray.Create(s_descriptor, s_unnecessaryWithoutSuggestionDescriptor, s_unnecessaryWithSuggestionDescriptor);
public bool OpenFileOnly(Workspace workspace) => false;
private static DiagnosticDescriptor CreateDescriptor(string id, DiagnosticSeverity severity, params string[] customTags)
=> new DiagnosticDescriptor(
id,
FeaturesResources.Object_initialization_can_be_simplified,
FeaturesResources.Object_initialization_can_be_simplified,
DiagnosticCategory.Style,
severity,
isEnabledByDefault: true,
customTags: customTags);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ObjectCreationExpression);
}
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var optionSet = context.Options.GetOptionSet();
var option = optionSet.GetOption(CodeStyleOptions.PreferObjectInitializer, LanguageNames.CSharp);
if (!option.Value)
{
// not point in analyzing if the option is off.
return;
}
var objectCreationExpression = (ObjectCreationExpressionSyntax)context.Node;
var matches = new Analyzer(objectCreationExpression).Analyze();
if (matches == null)
{
return;
}
var locations = ImmutableArray.Create(objectCreationExpression.GetLocation());
var severity = option.Notification.Value;
context.ReportDiagnostic(Diagnostic.Create(
CreateDescriptor(Id, severity),
objectCreationExpression.GetLocation(),
additionalLocations: locations));
var syntaxTree = objectCreationExpression.SyntaxTree;
foreach (var match in matches)
{
var location1 = Location.Create(syntaxTree, TextSpan.FromBounds(
match.MemberAccessExpression.SpanStart, match.MemberAccessExpression.OperatorToken.Span.End));
context.ReportDiagnostic(Diagnostic.Create(
s_unnecessaryWithSuggestionDescriptor, location1, additionalLocations: locations));
context.ReportDiagnostic(Diagnostic.Create(
s_unnecessaryWithoutSuggestionDescriptor,
match.ExpressionStatement.SemicolonToken.GetLocation(),
additionalLocations: locations));
}
}
public DiagnosticAnalyzerCategory GetAnalyzerCategory()
{
return DiagnosticAnalyzerCategory.SemanticDocumentAnalysis;
}
}
internal struct Match
{
public readonly ExpressionStatementSyntax ExpressionStatement;
public readonly MemberAccessExpressionSyntax MemberAccessExpression;
public readonly ExpressionSyntax Initializer;
public Match(ExpressionStatementSyntax expressionStatement, MemberAccessExpressionSyntax memberAccessExpression, ExpressionSyntax initializer)
{
ExpressionStatement = expressionStatement;
MemberAccessExpression = memberAccessExpression;
Initializer = initializer;
}
}
internal struct Analyzer
{
private readonly ObjectCreationExpressionSyntax _objectCreationExpression;
private StatementSyntax _containingStatement;
private SyntaxNodeOrToken _valuePattern;
public Analyzer(ObjectCreationExpressionSyntax objectCreationExpression) : this()
{
_objectCreationExpression = objectCreationExpression;
}
internal List<Match> Analyze()
{
if (_objectCreationExpression.Initializer != null)
{
// Don't bother if this already has an initializer.
return null;
}
if (!TryInitializeVariableDeclarationCase() &&
!TryInitializeAssignmentCase())
{
return null;
}
var containingBlock = _containingStatement.Parent as BlockSyntax;
if (containingBlock == null)
{
return null;
}
List<Match> matches = null;
HashSet<string> seenNames = null;
var statementIndex = containingBlock.Statements.IndexOf(_containingStatement);
for (var i = statementIndex + 1; i < containingBlock.Statements.Count; i++)
{
var expressionStatement = containingBlock.Statements[i] as ExpressionStatementSyntax;
if (expressionStatement == null)
{
break;
}
var assignExpression = expressionStatement.Expression as AssignmentExpressionSyntax;
if (assignExpression?.Kind() != SyntaxKind.SimpleAssignmentExpression)
{
break;
}
var leftMemberAccess = assignExpression.Left as MemberAccessExpressionSyntax;
if (leftMemberAccess?.Kind() != SyntaxKind.SimpleMemberAccessExpression)
{
break;
}
var expression = leftMemberAccess.Expression;
if (!ValuePatternMatches(expression))
{
break;
}
// found a match!
seenNames = seenNames ?? new HashSet<string>();
matches = matches ?? new List<Match>();
// If we see an assignment to the same property/field, we can't convert it
// to an initializer.
if (!seenNames.Add(leftMemberAccess.Name.Identifier.ValueText))
{
break;
}
matches.Add(new Match(expressionStatement, leftMemberAccess, assignExpression.Right));
}
return matches;
}
private bool ValuePatternMatches(ExpressionSyntax expression)
{
if (_valuePattern.IsToken)
{
return expression.IsKind(SyntaxKind.IdentifierName) &&
SyntaxFactory.AreEquivalent(
_valuePattern.AsToken(),
((IdentifierNameSyntax)expression).Identifier);
}
else
{
return SyntaxFactory.AreEquivalent(
_valuePattern.AsNode(),
expression);
}
}
private bool TryInitializeAssignmentCase()
{
if (!IsRightSideOfAssignment())
{
return false;
}
_containingStatement = _objectCreationExpression.FirstAncestorOrSelf<StatementSyntax>();
_valuePattern = ((AssignmentExpressionSyntax)_objectCreationExpression.Parent).Left;
return true;
}
private bool IsRightSideOfAssignment()
{
return _objectCreationExpression.IsParentKind(SyntaxKind.SimpleAssignmentExpression) &&
((AssignmentExpressionSyntax)_objectCreationExpression.Parent).Right == _objectCreationExpression &&
_objectCreationExpression.Parent.IsParentKind(SyntaxKind.ExpressionStatement);
}
private bool TryInitializeVariableDeclarationCase()
{
if (!IsVariableDeclarationInitializer())
{
return false;
}
_containingStatement = _objectCreationExpression.FirstAncestorOrSelf<StatementSyntax>();
_valuePattern = ((VariableDeclaratorSyntax)_objectCreationExpression.Parent.Parent).Identifier;
return true;
}
private bool IsVariableDeclarationInitializer()
{
return
_objectCreationExpression.IsParentKind(SyntaxKind.EqualsValueClause) &&
_objectCreationExpression.Parent.IsParentKind(SyntaxKind.VariableDeclarator) &&
_objectCreationExpression.Parent.Parent.IsParentKind(SyntaxKind.VariableDeclaration) &&
_objectCreationExpression.Parent.Parent.Parent.IsParentKind(SyntaxKind.LocalDeclarationStatement);
}
} }
}
} \ No newline at end of file
...@@ -653,6 +653,7 @@ ...@@ -653,6 +653,7 @@
<Compile Include="UseAutoProperty\AbstractUseAutoPropertyCodeFixProvider.cs" /> <Compile Include="UseAutoProperty\AbstractUseAutoPropertyCodeFixProvider.cs" />
<Compile Include="UseAutoProperty\AbstractUseAutoPropertyAnalyzer.cs" /> <Compile Include="UseAutoProperty\AbstractUseAutoPropertyAnalyzer.cs" />
<Compile Include="UseObjectInitializer\AbstractUseObjectInitializerDiagnosticAnalyzer.cs" /> <Compile Include="UseObjectInitializer\AbstractUseObjectInitializerDiagnosticAnalyzer.cs" />
<Compile Include="UseObjectInitializer\AbstractUseObjectInitializerCodeFixProvider.cs" />
<Compile Include="Workspace\BackgroundCompiler.cs" /> <Compile Include="Workspace\BackgroundCompiler.cs" />
<Compile Include="Workspace\BackgroundParser.cs" /> <Compile Include="Workspace\BackgroundParser.cs" />
</ItemGroup> </ItemGroup>
......
...@@ -90,7 +90,7 @@ protected AbstractGenerateMemberService() ...@@ -90,7 +90,7 @@ protected AbstractGenerateMemberService()
var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>(); var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>();
var semanticModel = document.SemanticModel; var semanticModel = document.SemanticModel;
var isMemberAccessExpression = syntaxFacts.IsMemberAccessExpression(simpleNameOrMemberAccessExpression); var isMemberAccessExpression = syntaxFacts.IsSimpleMemberAccessExpression(simpleNameOrMemberAccessExpression);
if (isMemberAccessExpression || if (isMemberAccessExpression ||
syntaxFacts.IsConditionalMemberAccessExpression(simpleNameOrMemberAccessExpression)) syntaxFacts.IsConditionalMemberAccessExpression(simpleNameOrMemberAccessExpression))
{ {
......
// 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.UseObjectInitializer
{
internal abstract class AbstractUseObjectInitializerCodeFixProvider<
TExpressionSyntax,
TStatementSyntax,
TObjectCreationExpressionSyntax,
TMemberAccessExpressionSyntax,
TVariableDeclarator>
: CodeFixProvider
where TExpressionSyntax : SyntaxNode
where TObjectCreationExpressionSyntax : TExpressionSyntax
where TMemberAccessExpressionSyntax : TExpressionSyntax
where TStatementSyntax : SyntaxNode
where TVariableDeclarator : SyntaxNode
{
public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
public override ImmutableArray<string> FixableDiagnosticIds
=> ImmutableArray.Create(IDEDiagnosticIds.UseObjectInitializerDiagnosticId);
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
context.RegisterCodeFix(
new MyCodeAction(c => FixAsync(context.Document, context.Diagnostics.First(), c)),
context.Diagnostics);
return SpecializedTasks.EmptyTask;
}
private async Task<Document> FixAsync(
Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var objectCreation = (TObjectCreationExpressionSyntax)root.FindNode(diagnostic.AdditionalLocations[0].SourceSpan);
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var analyzer = new Analyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TVariableDeclarator>(
syntaxFacts, objectCreation);
var matches = analyzer.Analyze();
var editor = new SyntaxEditor(root, document.Project.Solution.Workspace);
editor.ReplaceNode(objectCreation, GetNewObjectCreation(
syntaxFacts, editor.Generator, objectCreation, matches));
foreach (var match in matches)
{
editor.RemoveNode(match.Statement);
}
var newRoot = editor.GetChangedRoot();
return document.WithSyntaxRoot(newRoot);
}
private TObjectCreationExpressionSyntax GetNewObjectCreation(
ISyntaxFactsService syntaxFacts,
SyntaxGenerator genarator,
TObjectCreationExpressionSyntax objectCreation,
List<Match<TStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax>> matches)
{
var initializer = genarator.ObjectMemberInitializer(
matches.Select(m => CreateNamedFieldInitializer(syntaxFacts, genarator, m)));
return (TObjectCreationExpressionSyntax)genarator.WithObjectCreationInitializer(objectCreation, initializer)
.WithAdditionalAnnotations(Formatter.Annotation);
}
private SyntaxNode CreateNamedFieldInitializer(
ISyntaxFactsService syntaxFacts,
SyntaxGenerator generator,
Match<TStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax> match)
{
return generator.NamedFieldInitializer(
syntaxFacts.GetNameOfMemberAccessExpression(match.MemberAccessExpression),
match.Initializer).WithLeadingTrivia(GetNewLine());
}
protected abstract SyntaxTrivia GetNewLine();
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument)
: base(FeaturesResources.Object_initialization_can_be_simplified, createChangedDocument)
{
}
}
}
}
//// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // 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; using System.Collections.Generic;
//using System.Collections.Generic; using System.Collections.Immutable;
//using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeStyle;
//using System.Linq; using Microsoft.CodeAnalysis.Diagnostics;
//using System.Text; using Microsoft.CodeAnalysis.LanguageServices;
//using System.Threading.Tasks; using Microsoft.CodeAnalysis.Text;
//using Microsoft.CodeAnalysis.Diagnostics;
namespace Microsoft.CodeAnalysis.UseObjectInitializer
//namespace Microsoft.CodeAnalysis.UseObjectInitializer {
//{ internal abstract class AbstractUseObjectInitializerDiagnosticAnalyzer<
// internal abstract class AbstractUseObjectInitializerDiagnosticAnalyzer< TSyntaxKind,
// TObjectCreationExpression, TExpressionSyntax,
// TEqualsValueClause, TStatementSyntax,
// TVariableDeclarator, TObjectCreationExpressionSyntax,
// TAssignmentExpression, TMemberAccessExpressionSyntax,
// TSyntaxKind> TVariableDeclarator>
// : DiagnosticAnalyzer : DiagnosticAnalyzer, IBuiltInAnalyzer
// where TObjectCreationExpression : SyntaxNode where TSyntaxKind : struct
// where TEqualsValueClause : SyntaxNode where TExpressionSyntax : SyntaxNode
// where TVariableDeclarator : SyntaxNode where TObjectCreationExpressionSyntax : TExpressionSyntax
// where TAssignmentExpression : SyntaxNode where TMemberAccessExpressionSyntax : TExpressionSyntax
// where TSyntaxKind : struct where TStatementSyntax : SyntaxNode
// { where TVariableDeclarator : SyntaxNode
// public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics {
// { private static readonly string Id = IDEDiagnosticIds.UseObjectInitializerDiagnosticId;
// get
// { private static readonly DiagnosticDescriptor s_descriptor =
// throw new NotImplementedException(); CreateDescriptor(Id, DiagnosticSeverity.Hidden);
// }
// } private static readonly DiagnosticDescriptor s_unnecessaryWithSuggestionDescriptor =
CreateDescriptor(Id, DiagnosticSeverity.Hidden, DiagnosticCustomTags.Unnecessary);
// public override void Initialize(AnalysisContext context)
// { private static readonly DiagnosticDescriptor s_unnecessaryWithoutSuggestionDescriptor =
// context.RegisterSyntaxNodeAction<TSyntaxKind>( CreateDescriptor(Id + "WithoutSuggestion",
// AnalyzeNode, DiagnosticSeverity.Hidden, DiagnosticCustomTags.Unnecessary);
// ImmutableArray.Create(GetObjectCreationSyntaxKind()));
// } public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
=> ImmutableArray.Create(s_descriptor, s_unnecessaryWithoutSuggestionDescriptor, s_unnecessaryWithSuggestionDescriptor);
// protected abstract TSyntaxKind GetObjectCreationSyntaxKind();
public bool OpenFileOnly(Workspace workspace) => false;
// private void AnalyzeNode(SyntaxNodeAnalysisContext obj)
// { private static DiagnosticDescriptor CreateDescriptor(string id, DiagnosticSeverity severity, params string[] customTags)
// var objectCreationNode = (TObjectCreationExpression)obj.Node; => new DiagnosticDescriptor(
// if (objectCreationNode.Parent is TEqualsValueClause && id,
// objectCreationNode.Parent.Parent is TVariableDeclarator) FeaturesResources.Object_initialization_can_be_simplified,
// { FeaturesResources.Object_initialization_can_be_simplified,
// AnalyzeInVariableDeclarator(objectCreationNode); DiagnosticCategory.Style,
// return; severity,
// } isEnabledByDefault: true,
customTags: customTags);
// if( objectCreationNode.Parent is TAssignmentExpression &&)
// } public override void Initialize(AnalysisContext context)
// } {
//} context.RegisterSyntaxNodeAction(AnalyzeNode, GetObjectCreationSyntaxKind());
}
protected abstract TSyntaxKind GetObjectCreationSyntaxKind();
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var optionSet = context.Options.GetOptionSet();
var option = optionSet.GetOption(CodeStyleOptions.PreferObjectInitializer, LanguageNames.CSharp);
if (!option.Value)
{
// not point in analyzing if the option is off.
return;
}
var objectCreationExpression = (TObjectCreationExpressionSyntax)context.Node;
var syntaxFacts = GetSyntaxFactsService();
var analyzer = new Analyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TVariableDeclarator>(
syntaxFacts,
objectCreationExpression);
var matches = analyzer.Analyze();
if (matches == null)
{
return;
}
var locations = ImmutableArray.Create(objectCreationExpression.GetLocation());
var severity = option.Notification.Value;
context.ReportDiagnostic(Diagnostic.Create(
CreateDescriptor(Id, severity),
objectCreationExpression.GetLocation(),
additionalLocations: locations));
var syntaxTree = objectCreationExpression.SyntaxTree;
foreach (var match in matches)
{
var location1 = Location.Create(syntaxTree, TextSpan.FromBounds(
match.MemberAccessExpression.SpanStart,
syntaxFacts.GetOperatorTokenOfMemberAccessExpression(match.MemberAccessExpression).Span.End));
context.ReportDiagnostic(Diagnostic.Create(
s_unnecessaryWithSuggestionDescriptor, location1, additionalLocations: locations));
if (match.Statement.Span.End > match.Initializer.FullSpan.End)
{
context.ReportDiagnostic(Diagnostic.Create(
s_unnecessaryWithoutSuggestionDescriptor,
Location.Create(syntaxTree, TextSpan.FromBounds(
match.Initializer.FullSpan.End,
match.Statement.Span.End)),
additionalLocations: locations));
}
}
}
protected abstract ISyntaxFactsService GetSyntaxFactsService();
public DiagnosticAnalyzerCategory GetAnalyzerCategory()
{
return DiagnosticAnalyzerCategory.SemanticDocumentAnalysis;
}
}
internal struct Match<TStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax>
where TExpressionSyntax : SyntaxNode
where TMemberAccessExpressionSyntax : TExpressionSyntax
where TStatementSyntax : SyntaxNode
{
public readonly TStatementSyntax Statement;
public readonly TMemberAccessExpressionSyntax MemberAccessExpression;
public readonly TExpressionSyntax Initializer;
public Match(
TStatementSyntax statement,
TMemberAccessExpressionSyntax memberAccessExpression,
TExpressionSyntax initializer)
{
Statement = statement;
MemberAccessExpression = memberAccessExpression;
Initializer = initializer;
}
}
internal struct Analyzer<
TExpressionSyntax,
TStatementSyntax,
TObjectCreationExpressionSyntax,
TMemberAccessExpressionSyntax,
TVariableDeclaratorSyntax>
where TExpressionSyntax : SyntaxNode
where TStatementSyntax : SyntaxNode
where TObjectCreationExpressionSyntax : TExpressionSyntax
where TMemberAccessExpressionSyntax : TExpressionSyntax
where TVariableDeclaratorSyntax : SyntaxNode
{
private readonly ISyntaxFactsService _syntaxFacts;
private readonly TObjectCreationExpressionSyntax _objectCreationExpression;
private TStatementSyntax _containingStatement;
private SyntaxNodeOrToken _valuePattern;
public Analyzer(
ISyntaxFactsService syntaxFacts,
TObjectCreationExpressionSyntax objectCreationExpression) : this()
{
_syntaxFacts = syntaxFacts;
_objectCreationExpression = objectCreationExpression;
}
internal List<Match<TStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax>> Analyze()
{
if (_syntaxFacts.GetObjectCreationInitializer(_objectCreationExpression) != null)
{
// Don't bother if this already has an initializer.
return null;
}
_containingStatement = _objectCreationExpression.FirstAncestorOrSelf<TStatementSyntax>();
if (_containingStatement == null)
{
return null;
}
if (!TryInitializeVariableDeclarationCase() &&
!TryInitializeAssignmentCase())
{
return null;
}
var containingBlock = _containingStatement.Parent;
var foundStatement = false;
List<Match<TStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax>> matches = null;
HashSet<string> seenNames = null;
foreach (var child in containingBlock.ChildNodesAndTokens())
{
if (!foundStatement)
{
if (child == _containingStatement)
{
foundStatement = true;
}
continue;
}
if (child.IsToken)
{
break;
}
var statement = child.AsNode() as TStatementSyntax;
if (statement == null)
{
break;
}
if (!_syntaxFacts.IsSimpleAssignmentStatement(statement))
{
break;
}
SyntaxNode left, right;
_syntaxFacts.GetPartsOfAssignmentStatement(statement, out left, out right);
var rightExpression = right as TExpressionSyntax;
var leftMemberAccess = left as TMemberAccessExpressionSyntax;
if (!_syntaxFacts.IsSimpleMemberAccessExpression(leftMemberAccess))
{
break;
}
var expression = (TExpressionSyntax)_syntaxFacts.GetExpressionOfMemberAccessExpression(leftMemberAccess);
if (!ValuePatternMatches(expression))
{
break;
}
// found a match!
seenNames = seenNames ?? new HashSet<string>();
matches = matches ?? new List<Match<TStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax>>();
// If we see an assignment to the same property/field, we can't convert it
// to an initializer.
var name = _syntaxFacts.GetNameOfMemberAccessExpression(leftMemberAccess);
var identifier = _syntaxFacts.GetIdentifierOfSimpleName(name);
if (!seenNames.Add(identifier.ValueText))
{
break;
}
matches.Add(new Match<TStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax>(
statement, leftMemberAccess, rightExpression));
}
return matches;
}
private bool ValuePatternMatches(TExpressionSyntax expression)
{
if (_valuePattern.IsToken)
{
return _syntaxFacts.IsIdentifierName(expression) &&
_syntaxFacts.AreEquivalent(
_valuePattern.AsToken(),
_syntaxFacts.GetIdentifierOfSimpleName(expression));
}
else
{
return _syntaxFacts.AreEquivalent(
_valuePattern.AsNode(), expression);
}
}
private bool TryInitializeAssignmentCase()
{
if (!_syntaxFacts.IsSimpleAssignmentStatement(_containingStatement))
{
return false;
}
SyntaxNode left, right;
_syntaxFacts.GetPartsOfAssignmentStatement(_containingStatement, out left, out right);
if (right != _objectCreationExpression)
{
return false;
}
_valuePattern = left;
return true;
}
private bool TryInitializeVariableDeclarationCase()
{
if (!_syntaxFacts.IsLocalDeclarationStatement(_containingStatement))
{
return false;
}
var containingDeclarator = _objectCreationExpression.FirstAncestorOrSelf<TVariableDeclaratorSyntax>();
if (containingDeclarator == null)
{
return false;
}
if (!_syntaxFacts.IsDeclaratorOfLocalDeclarationStatement(containingDeclarator, _containingStatement))
{
return false;
}
_valuePattern = _syntaxFacts.GetIdentifierOfVariableDeclarator(containingDeclarator);
return true;
}
}
}
\ No newline at end of file
...@@ -192,7 +192,7 @@ public async Task<List<CompilationErrorDetails>> GetCompilationErrorDetails(Docu ...@@ -192,7 +192,7 @@ public async Task<List<CompilationErrorDetails>> GetCompilationErrorDetails(Docu
} }
} }
if (syntaxFacts.IsMemberAccessExpression(node.Parent)) if (syntaxFacts.IsSimpleMemberAccessExpression(node.Parent))
{ {
var expression = node.Parent; var expression = node.Parent;
......
...@@ -4099,6 +4099,27 @@ internal override SyntaxNode NamedAnonymousObjectMemberDeclarator(SyntaxNode ide ...@@ -4099,6 +4099,27 @@ internal override SyntaxNode NamedAnonymousObjectMemberDeclarator(SyntaxNode ide
(ExpressionSyntax)expression); (ExpressionSyntax)expression);
} }
internal override SyntaxNode ObjectMemberInitializer(IEnumerable<SyntaxNode> fieldInitializers)
{
return SyntaxFactory.InitializerExpression(
SyntaxKind.ObjectInitializerExpression,
SyntaxFactory.SeparatedList(fieldInitializers.Cast<ExpressionSyntax>()));
}
internal override SyntaxNode NamedFieldInitializer(SyntaxNode name, SyntaxNode value)
{
return SyntaxFactory.AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
(ExpressionSyntax)name,
(ExpressionSyntax)value);
}
internal override SyntaxNode WithObjectCreationInitializer(SyntaxNode objectCreationExpression, SyntaxNode initializer)
{
return ((ObjectCreationExpressionSyntax)objectCreationExpression)
.WithInitializer((InitializerExpressionSyntax)initializer);
}
#endregion #endregion
} }
} }
...@@ -533,7 +533,7 @@ public bool IsBindableToken(SyntaxToken token) ...@@ -533,7 +533,7 @@ public bool IsBindableToken(SyntaxToken token)
return false; return false;
} }
public bool IsMemberAccessExpression(SyntaxNode node) public bool IsSimpleMemberAccessExpression(SyntaxNode node)
{ {
return node is MemberAccessExpressionSyntax && return node is MemberAccessExpressionSyntax &&
((MemberAccessExpressionSyntax)node).Kind() == SyntaxKind.SimpleMemberAccessExpression; ((MemberAccessExpressionSyntax)node).Kind() == SyntaxKind.SimpleMemberAccessExpression;
...@@ -1775,6 +1775,70 @@ public bool IsDeclaration(SyntaxNode node) ...@@ -1775,6 +1775,70 @@ public bool IsDeclaration(SyntaxNode node)
newContextNode = newRoot.GetAnnotatedNodes(s_annotation).Single(); newContextNode = newRoot.GetAnnotatedNodes(s_annotation).Single();
} }
public SyntaxNode GetObjectCreationInitializer(SyntaxNode objectCreationExpression)
{
return ((ObjectCreationExpressionSyntax)objectCreationExpression).Initializer;
}
public bool IsSimpleAssignmentStatement(SyntaxNode statement)
{
return statement.IsKind(SyntaxKind.ExpressionStatement) &&
((ExpressionStatementSyntax)statement).Expression.IsKind(SyntaxKind.SimpleAssignmentExpression);
}
public void GetPartsOfAssignmentStatement(SyntaxNode statement, out SyntaxNode left, out SyntaxNode right)
{
var assignment = (AssignmentExpressionSyntax)((ExpressionStatementSyntax)statement).Expression;
left = assignment.Left;
right = assignment.Right;
}
public SyntaxNode GetNameOfMemberAccessExpression(SyntaxNode memberAccessExpression)
{
return ((MemberAccessExpressionSyntax)memberAccessExpression).Name;
}
public SyntaxToken GetOperatorTokenOfMemberAccessExpression(SyntaxNode memberAccessExpression)
{
return ((MemberAccessExpressionSyntax)memberAccessExpression).OperatorToken;
}
public SyntaxToken GetIdentifierOfSimpleName(SyntaxNode node)
{
return ((SimpleNameSyntax)node).Identifier;
}
public SyntaxToken GetIdentifierOfVariableDeclarator(SyntaxNode node)
{
return ((VariableDeclaratorSyntax)node).Identifier;
}
public bool IsIdentifierName(SyntaxNode node)
{
return node.IsKind(SyntaxKind.IdentifierName);
}
public bool IsLocalDeclarationStatement(SyntaxNode node)
{
return node.IsKind(SyntaxKind.LocalDeclarationStatement);
}
public bool IsDeclaratorOfLocalDeclarationStatement(SyntaxNode declarator, SyntaxNode localDeclarationStatement)
{
return ((LocalDeclarationStatementSyntax)localDeclarationStatement).Declaration.Variables.Contains(
(VariableDeclaratorSyntax)declarator);
}
public bool AreEquivalent(SyntaxToken token1, SyntaxToken token2)
{
return SyntaxFactory.AreEquivalent(token1, token2);
}
public bool AreEquivalent(SyntaxNode node1, SyntaxNode node2)
{
return SyntaxFactory.AreEquivalent(node1, node2);
}
private class AddFirstMissingCloseBaceRewriter: CSharpSyntaxRewriter private class AddFirstMissingCloseBaceRewriter: CSharpSyntaxRewriter
{ {
private readonly SyntaxNode _contextNode; private readonly SyntaxNode _contextNode;
......
...@@ -118,6 +118,10 @@ public SyntaxNode FieldDeclaration(IFieldSymbol field, SyntaxNode initializer) ...@@ -118,6 +118,10 @@ public SyntaxNode FieldDeclaration(IFieldSymbol field, SyntaxNode initializer)
initializer); initializer);
} }
internal abstract SyntaxNode ObjectMemberInitializer(IEnumerable<SyntaxNode> fieldInitializers);
internal abstract SyntaxNode NamedFieldInitializer(SyntaxNode name, SyntaxNode value);
internal abstract SyntaxNode WithObjectCreationInitializer(SyntaxNode objectCreationExpression, SyntaxNode initializer);
/// <summary> /// <summary>
/// Creates a method declaration. /// Creates a method declaration.
/// </summary> /// </summary>
......
...@@ -49,11 +49,16 @@ internal interface ISyntaxFactsService : ILanguageService ...@@ -49,11 +49,16 @@ internal interface ISyntaxFactsService : ILanguageService
bool IsObjectCreationExpressionType(SyntaxNode node); bool IsObjectCreationExpressionType(SyntaxNode node);
bool IsObjectCreationExpression(SyntaxNode node); bool IsObjectCreationExpression(SyntaxNode node);
SyntaxNode GetObjectCreationInitializer(SyntaxNode objectCreationExpression);
bool IsInvocationExpression(SyntaxNode node); bool IsInvocationExpression(SyntaxNode node);
// Left side of = assignment. // Left side of = assignment.
bool IsLeftSideOfAssignment(SyntaxNode node); bool IsLeftSideOfAssignment(SyntaxNode node);
bool IsSimpleAssignmentStatement(SyntaxNode statement);
void GetPartsOfAssignmentStatement(SyntaxNode statement, out SyntaxNode left, out SyntaxNode right);
// Left side of any assignment (for example *= or += ) // Left side of any assignment (for example *= or += )
bool IsLeftSideOfAnyAssignment(SyntaxNode node); bool IsLeftSideOfAnyAssignment(SyntaxNode node);
SyntaxNode GetRightHandSideOfAssignment(SyntaxNode node); SyntaxNode GetRightHandSideOfAssignment(SyntaxNode node);
...@@ -66,26 +71,36 @@ internal interface ISyntaxFactsService : ILanguageService ...@@ -66,26 +71,36 @@ internal interface ISyntaxFactsService : ILanguageService
SyntaxNode GetRightSideOfDot(SyntaxNode node); SyntaxNode GetRightSideOfDot(SyntaxNode node);
bool IsRightSideOfQualifiedName(SyntaxNode node); bool IsRightSideOfQualifiedName(SyntaxNode node);
bool IsMemberAccessExpressionName(SyntaxNode node); bool IsMemberAccessExpressionName(SyntaxNode node);
SyntaxNode GetNameOfMemberAccessExpression(SyntaxNode memberAccessExpression);
SyntaxNode GetExpressionOfMemberAccessExpression(SyntaxNode memberAccessExpression);
SyntaxToken GetOperatorTokenOfMemberAccessExpression(SyntaxNode memberAccessExpression);
bool IsMemberAccessExpression(SyntaxNode node); bool IsSimpleMemberAccessExpression(SyntaxNode node);
bool IsPointerMemberAccessExpression(SyntaxNode node); bool IsPointerMemberAccessExpression(SyntaxNode node);
bool IsNamedParameter(SyntaxNode node); bool IsNamedParameter(SyntaxNode node);
bool IsSkippedTokensTrivia(SyntaxNode node); bool IsSkippedTokensTrivia(SyntaxNode node);
SyntaxNode GetExpressionOfMemberAccessExpression(SyntaxNode node);
SyntaxNode GetExpressionOfConditionalMemberAccessExpression(SyntaxNode node); SyntaxNode GetExpressionOfConditionalMemberAccessExpression(SyntaxNode node);
SyntaxNode GetExpressionOfArgument(SyntaxNode node); SyntaxNode GetExpressionOfArgument(SyntaxNode node);
SyntaxNode GetExpressionOfInterpolation(SyntaxNode node); SyntaxNode GetExpressionOfInterpolation(SyntaxNode node);
bool IsConditionalMemberAccessExpression(SyntaxNode node); bool IsConditionalMemberAccessExpression(SyntaxNode node);
SyntaxNode GetNameOfAttribute(SyntaxNode node); SyntaxNode GetNameOfAttribute(SyntaxNode node);
SyntaxToken GetIdentifierOfGenericName(SyntaxNode node); SyntaxToken GetIdentifierOfGenericName(SyntaxNode node);
SyntaxToken GetIdentifierOfSimpleName(SyntaxNode node);
SyntaxToken GetIdentifierOfVariableDeclarator(SyntaxNode node);
RefKind GetRefKindOfArgument(SyntaxNode node); RefKind GetRefKindOfArgument(SyntaxNode node);
void GetNameAndArityOfSimpleName(SyntaxNode node, out string name, out int arity); void GetNameAndArityOfSimpleName(SyntaxNode node, out string name, out int arity);
SyntaxList<SyntaxNode> GetContentsOfInterpolatedString(SyntaxNode interpolatedString); SyntaxList<SyntaxNode> GetContentsOfInterpolatedString(SyntaxNode interpolatedString);
SeparatedSyntaxList<SyntaxNode> GetArgumentsForInvocationExpression(SyntaxNode invocationExpression); SeparatedSyntaxList<SyntaxNode> GetArgumentsForInvocationExpression(SyntaxNode invocationExpression);
bool IsUsingDirectiveName(SyntaxNode node); bool IsUsingDirectiveName(SyntaxNode node);
bool IsIdentifierName(SyntaxNode node);
bool IsGenericName(SyntaxNode node); bool IsGenericName(SyntaxNode node);
bool IsAttribute(SyntaxNode node); bool IsAttribute(SyntaxNode node);
...@@ -100,6 +115,9 @@ internal interface ISyntaxFactsService : ILanguageService ...@@ -100,6 +115,9 @@ internal interface ISyntaxFactsService : ILanguageService
bool IsLockStatement(SyntaxNode node); bool IsLockStatement(SyntaxNode node);
bool IsUsingStatement(SyntaxNode node); bool IsUsingStatement(SyntaxNode node);
bool IsLocalDeclarationStatement(SyntaxNode node);
bool IsDeclaratorOfLocalDeclarationStatement(SyntaxNode declator, SyntaxNode localDeclarationStatement);
bool IsThisConstructorInitializer(SyntaxToken token); bool IsThisConstructorInitializer(SyntaxToken token);
bool IsBaseConstructorInitializer(SyntaxToken token); bool IsBaseConstructorInitializer(SyntaxToken token);
bool IsQueryExpression(SyntaxNode node); bool IsQueryExpression(SyntaxNode node);
...@@ -135,6 +153,9 @@ internal interface ISyntaxFactsService : ILanguageService ...@@ -135,6 +153,9 @@ internal interface ISyntaxFactsService : ILanguageService
bool IsTopLevelNodeWithMembers(SyntaxNode node); bool IsTopLevelNodeWithMembers(SyntaxNode node);
bool HasIncompleteParentMember(SyntaxNode node); bool HasIncompleteParentMember(SyntaxNode node);
bool AreEquivalent(SyntaxToken token1, SyntaxToken token2);
bool AreEquivalent(SyntaxNode node1, SyntaxNode node2);
bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo declaredSymbolInfo); bool TryGetDeclaredSymbolInfo(SyntaxNode node, out DeclaredSymbolInfo declaredSymbolInfo);
string GetDisplayName(SyntaxNode node, DisplayNameOptions options, string rootNamespace = null); string GetDisplayName(SyntaxNode node, DisplayNameOptions options, string rootNamespace = null);
...@@ -151,11 +172,9 @@ internal interface ISyntaxFactsService : ILanguageService ...@@ -151,11 +172,9 @@ internal interface ISyntaxFactsService : ILanguageService
SyntaxNode ConvertToSingleLine(SyntaxNode node, bool useElasticTrivia = false); SyntaxNode ConvertToSingleLine(SyntaxNode node, bool useElasticTrivia = false);
SyntaxToken ToIdentifierToken(string name); SyntaxToken ToIdentifierToken(string name);
List<SyntaxNode> GetMethodLevelMembers(SyntaxNode root); List<SyntaxNode> GetMethodLevelMembers(SyntaxNode root);
bool ContainsInMemberBody(SyntaxNode node, TextSpan span); bool ContainsInMemberBody(SyntaxNode node, TextSpan span);
int GetMethodLevelMemberId(SyntaxNode root, SyntaxNode node); int GetMethodLevelMemberId(SyntaxNode root, SyntaxNode node);
SyntaxNode GetMethodLevelMember(SyntaxNode root, int memberId); SyntaxNode GetMethodLevelMember(SyntaxNode root, int memberId);
TextSpan GetInactiveRegionSpanAroundPosition(SyntaxTree tree, int position, CancellationToken cancellationToken); TextSpan GetInactiveRegionSpanAroundPosition(SyntaxTree tree, int position, CancellationToken cancellationToken);
...@@ -177,7 +196,6 @@ internal interface ISyntaxFactsService : ILanguageService ...@@ -177,7 +196,6 @@ internal interface ISyntaxFactsService : ILanguageService
SyntaxNode GetBindableParent(SyntaxToken token); SyntaxNode GetBindableParent(SyntaxToken token);
IEnumerable<SyntaxNode> GetConstructors(SyntaxNode root, CancellationToken cancellationToken); IEnumerable<SyntaxNode> GetConstructors(SyntaxNode root, CancellationToken cancellationToken);
bool TryGetCorrespondingOpenBrace(SyntaxToken token, out SyntaxToken openBrace); bool TryGetCorrespondingOpenBrace(SyntaxToken token, out SyntaxToken openBrace);
/// <summary> /// <summary>
......
...@@ -17,7 +17,7 @@ public static bool IsWord(this ISyntaxFactsService syntaxFacts, SyntaxToken toke ...@@ -17,7 +17,7 @@ public static bool IsWord(this ISyntaxFactsService syntaxFacts, SyntaxToken toke
public static bool IsAnyMemberAccessExpression( public static bool IsAnyMemberAccessExpression(
this ISyntaxFactsService syntaxFacts, SyntaxNode node) this ISyntaxFactsService syntaxFacts, SyntaxNode node)
{ {
return syntaxFacts.IsMemberAccessExpression(node) || syntaxFacts.IsPointerMemberAccessExpression(node); return syntaxFacts.IsSimpleMemberAccessExpression(node) || syntaxFacts.IsPointerMemberAccessExpression(node);
} }
} }
} }
...@@ -3874,6 +3874,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration ...@@ -3874,6 +3874,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
DirectCast(expression, ExpressionSyntax)) DirectCast(expression, ExpressionSyntax))
End Function End Function
Friend Overrides Function ObjectMemberInitializer(fieldInitializers As IEnumerable(Of SyntaxNode)) As SyntaxNode
Return SyntaxFactory.ObjectMemberInitializer(
fieldInitializers.Cast(Of FieldInitializerSyntax).ToArray())
End Function
Friend Overrides Function NamedFieldInitializer(name As SyntaxNode, value As SyntaxNode) As SyntaxNode
Return SyntaxFactory.NamedFieldInitializer(
DirectCast(name, IdentifierNameSyntax),
DirectCast(value, ExpressionSyntax))
End Function
Friend Overrides Function WithObjectCreationInitializer(objectCreationExpression As SyntaxNode, initializer As SyntaxNode) As SyntaxNode
Return DirectCast(objectCreationExpression, ObjectCreationExpressionSyntax).
WithInitializer(DirectCast(initializer, ObjectCreationInitializerSyntax))
End Function
#End Region #End Region
End Class End Class
......
...@@ -436,7 +436,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ...@@ -436,7 +436,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Me.IsOperator(token) Me.IsOperator(token)
End Function End Function
Public Function IsMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsMemberAccessExpression Public Function IsSimpleMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsSimpleMemberAccessExpression
Return TypeOf node Is MemberAccessExpressionSyntax AndAlso Return TypeOf node Is MemberAccessExpressionSyntax AndAlso
DirectCast(node, MemberAccessExpressionSyntax).Kind = SyntaxKind.SimpleMemberAccessExpression DirectCast(node, MemberAccessExpressionSyntax).Kind = SyntaxKind.SimpleMemberAccessExpression
End Function End Function
...@@ -1463,5 +1463,56 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ...@@ -1463,5 +1463,56 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
newRoot = root newRoot = root
newContextNode = contextNode newContextNode = contextNode
End Sub End Sub
Public Function GetObjectCreationInitializer(objectCreationExpression As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetObjectCreationInitializer
Return DirectCast(objectCreationExpression, ObjectCreationExpressionSyntax).Initializer
End Function
Public Function IsSimpleAssignmentStatement(statement As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsSimpleAssignmentStatement
Return statement.IsKind(SyntaxKind.SimpleAssignmentStatement)
End Function
Public Sub GetPartsOfAssignmentStatement(statement As SyntaxNode, ByRef left As SyntaxNode, ByRef right As SyntaxNode) Implements ISyntaxFactsService.GetPartsOfAssignmentStatement
Dim assignment = DirectCast(statement, AssignmentStatementSyntax)
left = assignment.Left
right = assignment.Right
End Sub
Public Function GetNameOfMemberAccessExpression(memberAccessExpression As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetNameOfMemberAccessExpression
Return DirectCast(memberAccessExpression, MemberAccessExpressionSyntax).Name
End Function
Public Function GetOperatorTokenOfMemberAccessExpression(memberAccessExpression As SyntaxNode) As SyntaxToken Implements ISyntaxFactsService.GetOperatorTokenOfMemberAccessExpression
Return DirectCast(memberAccessExpression, MemberAccessExpressionSyntax).OperatorToken
End Function
Public Function GetIdentifierOfSimpleName(node As SyntaxNode) As SyntaxToken Implements ISyntaxFactsService.GetIdentifierOfSimpleName
Return DirectCast(node, SimpleNameSyntax).Identifier
End Function
Public Function GetIdentifierOfVariableDeclarator(node As SyntaxNode) As SyntaxToken Implements ISyntaxFactsService.GetIdentifierOfVariableDeclarator
Return DirectCast(node, VariableDeclaratorSyntax).Names.Last().Identifier
End Function
Public Function IsIdentifierName(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsIdentifierName
Return node.IsKind(SyntaxKind.IdentifierName)
End Function
Public Function IsLocalDeclarationStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsLocalDeclarationStatement
Return node.IsKind(SyntaxKind.LocalDeclarationStatement)
End Function
Public Function IsDeclaratorOfLocalDeclarationStatement(declarator As SyntaxNode, localDeclarationStatement As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsDeclaratorOfLocalDeclarationStatement
Return DirectCast(localDeclarationStatement, LocalDeclarationStatementSyntax).Declarators.
Contains(DirectCast(declarator, VariableDeclaratorSyntax))
End Function
Public Function AreEquivalent(token1 As SyntaxToken, token2 As SyntaxToken) As Boolean Implements ISyntaxFactsService.AreEquivalent
Return SyntaxFactory.AreEquivalent(token1, token2)
End Function
Public Function AreEquivalent(node1 As SyntaxNode, node2 As SyntaxNode) As Boolean Implements ISyntaxFactsService.AreEquivalent
Return SyntaxFactory.AreEquivalent(node1, node2)
End Function
End Class End Class
End Namespace End Namespace
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册