提交 23bd2a20 编写于 作者: C CyrusNajmabadi

Provide VB impl of the IAddImportsService.

上级 94b3a01f
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.AddImport; using Microsoft.CodeAnalysis.AddImports;
using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeFixes.AddImport; using Microsoft.CodeAnalysis.CodeFixes.AddImport;
...@@ -430,24 +430,6 @@ protected override string GetDescription(IReadOnlyList<string> nameParts) ...@@ -430,24 +430,6 @@ protected override string GetDescription(IReadOnlyList<string> nameParts)
return null; return null;
} }
private bool HasExistingUsingDirective(
CompilationUnitSyntax root,
NamespaceDeclarationSyntax namespaceToAddTo,
UsingDirectiveSyntax usingDirective)
{
var usings = namespaceToAddTo?.Usings ?? root.Usings;
foreach (var existingUsing in usings)
{
if (SyntaxFactory.AreEquivalent(usingDirective, existingUsing))
{
return true;
}
}
return false;
}
protected override async Task<Document> AddImportAsync( protected override async Task<Document> AddImportAsync(
SyntaxNode contextNode, SyntaxNode contextNode,
INamespaceOrTypeSymbol namespaceOrTypeSymbol, INamespaceOrTypeSymbol namespaceOrTypeSymbol,
...@@ -487,7 +469,7 @@ protected override string GetDescription(IReadOnlyList<string> nameParts) ...@@ -487,7 +469,7 @@ protected override string GetDescription(IReadOnlyList<string> nameParts)
newImports.Add(usingDirective); newImports.Add(usingDirective);
} }
var addImportService = document.GetLanguageService<IAddImportService>(); var addImportService = document.GetLanguageService<IAddImportsService>();
var newRoot = addImportService.AddImports(root, contextNode, newImports, placeSystemNamespaceFirst); var newRoot = addImportService.AddImports(root, contextNode, newImports, placeSystemNamespaceFirst);
return (CompilationUnitSyntax)newRoot; return (CompilationUnitSyntax)newRoot;
} }
...@@ -505,19 +487,12 @@ protected override string GetDescription(IReadOnlyList<string> nameParts) ...@@ -505,19 +487,12 @@ protected override string GetDescription(IReadOnlyList<string> nameParts)
// Suppress diagnostics on the import we create. Because we only get here when we are // Suppress diagnostics on the import we create. Because we only get here when we are
// adding a nuget package, it is certainly the case that in the preview this will not // adding a nuget package, it is certainly the case that in the preview this will not
// bind properly. It will look silly to show such an error, so we just suppress things. // bind properly. It will look silly to show such an error, so we just suppress things.
var simpleUsingDirective = SyntaxFactory.UsingDirective( var usingDirective = SyntaxFactory.UsingDirective(
CreateNameSyntax(namespaceParts, namespaceParts.Count - 1)).WithAdditionalAnnotations( CreateNameSyntax(namespaceParts, namespaceParts.Count - 1)).WithAdditionalAnnotations(
SuppressDiagnosticsAnnotation.Create()); SuppressDiagnosticsAnnotation.Create());
// If we have an existing using with this name then don't bother adding this new using. var service = document.GetLanguageService<IAddImportsService>();
if (root.Usings.Any(u => u.IsEquivalentTo(simpleUsingDirective, topLevel: false))) var newRoot = service.AddImport(root, contextNode, usingDirective, placeSystemNamespaceFirst);
{
return Task.FromResult(document);
}
var newRoot = root.AddUsingDirective(
simpleUsingDirective, contextNode, placeSystemNamespaceFirst,
Formatter.Annotation);
return Task.FromResult(document.WithSyntaxRoot(newRoot)); return Task.FromResult(document.WithSyntaxRoot(newRoot));
} }
...@@ -559,7 +534,7 @@ private NameSyntax CreateNameSyntax(IReadOnlyList<string> namespaceParts, int in ...@@ -559,7 +534,7 @@ private NameSyntax CreateNameSyntax(IReadOnlyList<string> namespaceParts, int in
CompilationUnitSyntax root, CompilationUnitSyntax root,
SyntaxNode contextNode) SyntaxNode contextNode)
{ {
var addImportService = document.GetLanguageService<IAddImportService>(); var addImportService = document.GetLanguageService<IAddImportsService>();
var nameSyntax = namespaceOrTypeSymbol.GenerateNameSyntax(); var nameSyntax = namespaceOrTypeSymbol.GenerateNameSyntax();
...@@ -602,7 +577,7 @@ private NameSyntax CreateNameSyntax(IReadOnlyList<string> namespaceParts, int in ...@@ -602,7 +577,7 @@ private NameSyntax CreateNameSyntax(IReadOnlyList<string> namespaceParts, int in
var usingDirective = SyntaxFactory.UsingDirective(nameSyntax) var usingDirective = SyntaxFactory.UsingDirective(nameSyntax)
.WithAdditionalAnnotations(Formatter.Annotation); .WithAdditionalAnnotations(Formatter.Annotation);
if (HasExistingUsingDirective(root, namespaceToAddTo, usingDirective)) if (addImportService.HasExistingImport(root, contextNode, usingDirective))
{ {
return null; return null;
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
Imports System.Collections.Immutable Imports System.Collections.Immutable
Imports System.Composition Imports System.Composition
Imports System.Threading Imports System.Threading
Imports Microsoft.CodeAnalysis.AddImports
Imports Microsoft.CodeAnalysis.CaseCorrection Imports Microsoft.CodeAnalysis.CaseCorrection
Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeActions
Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.CodeFixes
...@@ -249,12 +250,37 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport ...@@ -249,12 +250,37 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport
Protected Overrides Function TryGetDescription( Protected Overrides Function TryGetDescription(
document As Document, document As Document,
namespaceSymbol As INamespaceOrTypeSymbol, symbol As INamespaceOrTypeSymbol,
semanticModel As SemanticModel, semanticModel As SemanticModel,
root As SyntaxNode, root As SyntaxNode,
checkForExistingImport As Boolean, checkForExistingImport As Boolean,
cancellationToken As CancellationToken) As String cancellationToken As CancellationToken) As String
Return $"Imports {namespaceSymbol.ToDisplayString()}"
Dim importsStatement = GetImportsStatement(symbol)
Dim addImportService = document.GetLanguageService(Of IAddImportsService)
If addImportService.HasExistingImport(root, root, importsStatement) Then
Return Nothing
End If
Return $"Imports {symbol.ToDisplayString()}"
End Function
Private Function GetImportsStatement(symbol As INamespaceOrTypeSymbol) As ImportsStatementSyntax
Dim nameSyntax = DirectCast(symbol.GenerateTypeSyntax(addGlobal:=False), NameSyntax)
Return GetImportsStatement(nameSyntax)
End Function
Private Function GetImportsStatement(nameSyntax As NameSyntax) As ImportsStatementSyntax
nameSyntax = nameSyntax.WithAdditionalAnnotations(Simplifier.Annotation)
Dim memberImportsClause = SyntaxFactory.SimpleImportsClause(nameSyntax)
Dim newImport = SyntaxFactory.ImportsStatement(
importsClauses:=SyntaxFactory.SingletonSeparatedList(Of ImportsClauseSyntax)(memberImportsClause))
newImport = newImport.WithAdditionalAnnotations(CaseCorrector.Annotation, Formatter.Annotation)
Return newImport
End Function End Function
Protected Overrides Function GetImportNamespacesInScope(semanticModel As SemanticModel, node As SyntaxNode, cancellationToken As CancellationToken) As ISet(Of INamespaceSymbol) Protected Overrides Function GetImportNamespacesInScope(semanticModel As SemanticModel, node As SyntaxNode, cancellationToken As CancellationToken) As ISet(Of INamespaceSymbol)
...@@ -314,56 +340,49 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport ...@@ -314,56 +340,49 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport
Return symbol IsNot Nothing AndAlso symbol.Locations.Length > 0 Return symbol IsNot Nothing AndAlso symbol.Locations.Length > 0
End Function End Function
Protected Overloads Overrides Function AddImportAsync( Protected Overloads Overrides Async Function AddImportAsync(
contextNode As SyntaxNode, contextNode As SyntaxNode,
symbol As INamespaceOrTypeSymbol, symbol As INamespaceOrTypeSymbol,
document As Document, document As Document,
placeSystemNamespaceFirst As Boolean, placeSystemNamespaceFirst As Boolean,
cancellationToken As CancellationToken) As Task(Of Document) cancellationToken As CancellationToken) As Task(Of Document)
Dim nameSyntax = DirectCast(symbol.GenerateTypeSyntax(addGlobal:=False), NameSyntax) Dim importsStatement = GetImportsStatement(symbol)
Return AddImportsAsync( Return Await AddImportAsync(
contextNode, document, placeSystemNamespaceFirst, nameSyntax, contextNode, document, placeSystemNamespaceFirst,
additionalAnnotation:=Nothing, cancellationToken:=cancellationToken) importsStatement, cancellationToken).ConfigureAwait(False)
End Function End Function
Private Shared Async Function AddImportsAsync( Private Overloads Shared Async Function AddImportAsync(
contextNode As SyntaxNode, contextNode As SyntaxNode, document As Document, placeSystemNamespaceFirst As Boolean,
document As Document, importsStatement As ImportsStatementSyntax, cancellationToken As CancellationToken) As Task(Of Document)
placeSystemNamespaceFirst As Boolean, Dim importService = document.GetLanguageService(Of IAddImportsService)
nameSyntax As NameSyntax,
additionalAnnotation As SyntaxAnnotation,
cancellationToken As CancellationToken) As Task(Of Document)
Dim root = DirectCast(Await contextNode.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(False), CompilationUnitSyntax)
Dim memberImportsClause = Dim root = Await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(False)
SyntaxFactory.SimpleImportsClause(name:=nameSyntax.WithAdditionalAnnotations(Simplifier.Annotation)) Dim newRoot = importService.AddImport(root, contextNode, importsStatement, placeSystemNamespaceFirst)
Dim newImport = SyntaxFactory.ImportsStatement( Dim newDocument = document.WithSyntaxRoot(newRoot)
importsClauses:=SyntaxFactory.SingletonSeparatedList(Of ImportsClauseSyntax)(memberImportsClause))
If additionalAnnotation IsNot Nothing Then Return newDocument
newImport = newImport.WithAdditionalAnnotations(additionalAnnotation)
End If
' Don't add the import if an eqiuvalent one is already there.
If root.Imports.Any(Function(i) i.IsEquivalentTo(newImport, topLevel:=False)) Then
Return document
End If
Dim syntaxTree = contextNode.SyntaxTree
Return document.WithSyntaxRoot(
root.AddImportsStatement(newImport, placeSystemNamespaceFirst, CaseCorrector.Annotation, Formatter.Annotation))
End Function End Function
Protected Overrides Function AddImportAsync(contextNode As SyntaxNode, nameSpaceParts As IReadOnlyList(Of String), document As Document, specialCaseSystem As Boolean, cancellationToken As CancellationToken) As Task(Of Document) Protected Overrides Function AddImportAsync(
contextNode As SyntaxNode,
nameSpaceParts As IReadOnlyList(Of String),
Document As Document,
placeSystemNamespaceFirst As Boolean,
cancellationToken As CancellationToken) As Task(Of Document)
Dim nameSyntax = CreateNameSyntax(nameSpaceParts, nameSpaceParts.Count - 1) Dim nameSyntax = CreateNameSyntax(nameSpaceParts, nameSpaceParts.Count - 1)
Dim importsStatement = GetImportsStatement(nameSyntax)
' Suppress diagnostics on the import we create. Because we only get here when we are ' Suppress diagnostics on the import we create. Because we only get here when we are
' adding a nuget package, it is certainly the case that in the preview this will not ' adding a nuget package, it is certainly the case that in the preview this will not
' bind properly. It will look silly to show such an error, so we just suppress things. ' bind properly. It will look silly to show such an error, so we just suppress things.
Return AddImportsAsync(contextNode, document, specialCaseSystem, nameSyntax, importsStatement = importsStatement.WithAdditionalAnnotations(SuppressDiagnosticsAnnotation.Create())
SuppressDiagnosticsAnnotation.Create(), cancellationToken)
Return AddImportAsync(
contextNode, Document, placeSystemNamespaceFirst,
importsStatement, cancellationToken)
End Function End Function
Private Function CreateNameSyntax(nameSpaceParts As IReadOnlyList(Of String), index As Integer) As NameSyntax Private Function CreateNameSyntax(nameSpaceParts As IReadOnlyList(Of String), index As Integer) As NameSyntax
......
...@@ -110,7 +110,7 @@ public override int GetExpansionFunction(IXMLDOMNode xmlFunctionNode, string bst ...@@ -110,7 +110,7 @@ public override int GetExpansionFunction(IXMLDOMNode xmlFunctionNode, string bst
return document; return document;
} }
var addImportService = document.GetLanguageService<IAddImportService>(); var addImportService = document.GetLanguageService<IAddImportsService>();
var newRoot = addImportService.AddImports(root, contextLocation, newUsingDirectives, placeSystemNamespaceFirst); var newRoot = addImportService.AddImports(root, contextLocation, newUsingDirectives, placeSystemNamespaceFirst);
var newDocument = document.WithSyntaxRoot(newRoot); var newDocument = document.WithSyntaxRoot(newRoot);
......
// 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 System.Composition; using System.Composition;
using System.Linq; using Microsoft.CodeAnalysis.AddImports;
using Microsoft.CodeAnalysis.AddImport;
using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.AddImport namespace Microsoft.CodeAnalysis.CSharp.AddImports
{ {
[ExportLanguageService(typeof(IAddImportService), LanguageNames.CSharp), Shared] [ExportLanguageService(typeof(IAddImportsService), LanguageNames.CSharp), Shared]
internal class CSharpAddImportService : IAddImportService internal class CSharpAddImportsService : AbstractAddImportsService<
CompilationUnitSyntax, NamespaceDeclarationSyntax, UsingDirectiveSyntax, ExternAliasDirectiveSyntax>
{ {
private static readonly Func<UsingDirectiveSyntax, bool> s_isUsing = u => u.Alias == null; protected override SyntaxNode GetAlias(UsingDirectiveSyntax usingOrAlias)
private static readonly Func<UsingDirectiveSyntax, bool> s_isAlias = u => u.Alias != null; => usingOrAlias.Alias;
private static readonly Func<SyntaxNode, bool> s_hasAliases = n => GetUsingsAndAliases(n).Any(s_isAlias); protected override SyntaxNode Rewrite(
private static readonly Func<SyntaxNode, bool> s_hasUsings = n => GetUsingsAndAliases(n).Any(s_isUsing); ExternAliasDirectiveSyntax[] externAliases,
private static readonly Func<SyntaxNode, bool> s_hasExterns = n => GetExterns(n).Any(); UsingDirectiveSyntax[] usingDirectives,
UsingDirectiveSyntax[] aliasDirectives,
private static readonly Func<SyntaxNode, bool> s_hasAnyImports = n => GetUsingsAndAliases(n).Any() || GetExterns(n).Any(); SyntaxNode externContainer,
SyntaxNode usingContainer,
public SyntaxNode GetImportContainer(SyntaxNode root, SyntaxNode contextLocation, SyntaxNode import) SyntaxNode aliasContainer,
{ bool placeSystemNamespaceFirst,
contextLocation = contextLocation ?? root; SyntaxNode root)
GetContainers(root, contextLocation,
out var externContainer, out var usingContainer, out var aliasContainer);
switch (import)
{
case ExternAliasDirectiveSyntax e: return externContainer;
case UsingDirectiveSyntax u: return s_isAlias(u) ? aliasContainer : usingContainer;
}
throw new InvalidOperationException();
}
public SyntaxNode AddImports(
SyntaxNode root,
SyntaxNode contextLocation,
IEnumerable<SyntaxNode> newImports,
bool placeSystemNamespaceFirst)
{ {
contextLocation = contextLocation ?? root;
GetContainers(root, contextLocation,
out var externContainer, out var usingContainer, out var aliasContainer);
var externAliases = newImports.OfType<ExternAliasDirectiveSyntax>().ToArray();
var usingDirectives = newImports.OfType<UsingDirectiveSyntax>().Where(u => u.Alias == null).ToArray();
var aliasDirectives = newImports.OfType<UsingDirectiveSyntax>().Where(u => u.Alias != null).ToArray();
var rewriter = new Rewriter( var rewriter = new Rewriter(
externAliases, usingDirectives, aliasDirectives, externAliases, usingDirectives, aliasDirectives,
externContainer, usingContainer, aliasContainer, externContainer, usingContainer, aliasContainer,
placeSystemNamespaceFirst); placeSystemNamespaceFirst);
var newRoot = rewriter.Visit(root);
var newRoot = rewriter.Visit(root);
return newRoot; return newRoot;
} }
private static void GetContainers(SyntaxNode root, SyntaxNode contextLocation, out SyntaxNode externContainer, out SyntaxNode usingContainer, out SyntaxNode aliasContainer) protected override SyntaxList<UsingDirectiveSyntax> GetUsingsAndAliases(SyntaxNode node)
{
var applicableContainer = GetFirstApplicableContainer(contextLocation);
var contextSpine = applicableContainer.GetAncestorsOrThis<SyntaxNode>().ToImmutableArray();
// The node we'll add to if we can't find a specific namespace with imports of
// the type we're trying to add. This will be the closest namespace with any
// imports in it, or the root if there are no such namespaces.
var fallbackNode = contextSpine.FirstOrDefault(s_hasAnyImports) ?? root;
// The specific container to add each type of import to. We look for a container
// that already has an import of the same type as the node we want to add to.
// If we can find one, we add to that container. If not, we call back to the
// innermost node with any imports.
externContainer = contextSpine.FirstOrDefault(s_hasExterns) ?? fallbackNode;
usingContainer = contextSpine.FirstOrDefault(s_hasUsings) ?? fallbackNode;
aliasContainer = contextSpine.FirstOrDefault(s_hasAliases) ?? fallbackNode;
}
private static SyntaxList<UsingDirectiveSyntax> GetUsingsAndAliases(SyntaxNode node)
{ {
switch (node) switch (node)
{ {
...@@ -93,7 +44,7 @@ private static SyntaxList<UsingDirectiveSyntax> GetUsingsAndAliases(SyntaxNode n ...@@ -93,7 +44,7 @@ private static SyntaxList<UsingDirectiveSyntax> GetUsingsAndAliases(SyntaxNode n
} }
} }
private static SyntaxList<ExternAliasDirectiveSyntax> GetExterns(SyntaxNode node) protected override SyntaxList<ExternAliasDirectiveSyntax> GetExterns(SyntaxNode node)
{ {
switch (node) switch (node)
{ {
...@@ -103,18 +54,6 @@ private static SyntaxList<ExternAliasDirectiveSyntax> GetExterns(SyntaxNode node ...@@ -103,18 +54,6 @@ private static SyntaxList<ExternAliasDirectiveSyntax> GetExterns(SyntaxNode node
} }
} }
private static SyntaxNode GetFirstApplicableContainer(SyntaxNode contextNode)
{
var usingDirective = contextNode.GetAncestor<UsingDirectiveSyntax>();
if (usingDirective != null)
{
contextNode = usingDirective.Parent;
}
return contextNode.GetAncestor<NamespaceDeclarationSyntax>() ??
(SyntaxNode)contextNode.GetAncestor<CompilationUnitSyntax>();
}
private class Rewriter : CSharpSyntaxRewriter private class Rewriter : CSharpSyntaxRewriter
{ {
private readonly bool _placeSystemNamespaceFirst; private readonly bool _placeSystemNamespaceFirst;
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
<InternalsVisibleToTest Include="Roslyn.Services.Test.Utilities2" /> <InternalsVisibleToTest Include="Roslyn.Services.Test.Utilities2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="AddImport\CSharpAddImportService.cs" /> <Compile Include="AddImports\CSharpAddImportsService.cs" />
<Compile Include="CaseCorrection\CSharpCaseCorrectionService.cs" /> <Compile Include="CaseCorrection\CSharpCaseCorrectionService.cs" />
<Compile Include="Classification\ClassificationHelpers.cs" /> <Compile Include="Classification\ClassificationHelpers.cs" />
<Compile Include="Classification\Classifiers\AbstractSyntaxClassifier.cs" /> <Compile Include="Classification\Classifiers\AbstractSyntaxClassifier.cs" />
......
// 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 Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.AddImports
{
internal abstract class AbstractAddImportsService<TCompilationUnitSyntax, TNamespaceDeclarationSyntax, TUsingOrAliasSyntax, TExternSyntax>
: IAddImportsService
where TCompilationUnitSyntax : SyntaxNode
where TNamespaceDeclarationSyntax : SyntaxNode
where TUsingOrAliasSyntax : SyntaxNode
where TExternSyntax : SyntaxNode
{
protected AbstractAddImportsService()
{
}
protected abstract SyntaxNode GetAlias(TUsingOrAliasSyntax usingOrAlias);
private bool IsUsing(TUsingOrAliasSyntax usingOrAlias) => GetAlias(usingOrAlias) == null;
private bool IsAlias(TUsingOrAliasSyntax usingOrAlias) => GetAlias(usingOrAlias) != null;
private bool HasAliases(SyntaxNode node) => GetUsingsAndAliases(node).Any(IsAlias);
private bool HasUsings(SyntaxNode node) => GetUsingsAndAliases(node).Any(IsUsing);
private bool HasExterns(SyntaxNode node) => GetExterns(node).Any();
private bool HasAnyImports(SyntaxNode node) => GetUsingsAndAliases(node).Any() || GetExterns(node).Any();
public bool HasExistingImport(SyntaxNode root, SyntaxNode contextLocation, SyntaxNode import)
{
contextLocation = contextLocation ?? root;
var applicableContainer = GetFirstApplicableContainer(contextLocation);
var containers = applicableContainer.GetAncestorsOrThis<SyntaxNode>().ToArray();
foreach (var node in containers)
{
if (GetUsingsAndAliases(node).Any(u => u.IsEquivalentTo(import, topLevel: false)))
{
return true;
}
if (GetExterns(node).Any(u => u.IsEquivalentTo(import, topLevel: false)))
{
return true;
}
}
return false;
}
public SyntaxNode GetImportContainer(SyntaxNode root, SyntaxNode contextLocation, SyntaxNode import)
{
contextLocation = contextLocation ?? root;
GetContainers(root, contextLocation,
out var externContainer, out var usingContainer, out var aliasContainer);
switch (import)
{
case TExternSyntax e: return externContainer;
case TUsingOrAliasSyntax u: return IsAlias(u) ? aliasContainer : usingContainer;
}
throw new InvalidOperationException();
}
public SyntaxNode AddImports(
SyntaxNode root,
SyntaxNode contextLocation,
IEnumerable<SyntaxNode> newImports,
bool placeSystemNamespaceFirst)
{
contextLocation = contextLocation ?? root;
GetContainers(root, contextLocation,
out var externContainer, out var usingContainer, out var aliasContainer);
var filteredImports = newImports.Where(i => !HasExistingImport(root, contextLocation, i)).ToArray();
var externAliases = filteredImports.OfType<TExternSyntax>().ToArray();
var usingDirectives = filteredImports.OfType<TUsingOrAliasSyntax>().Where(IsUsing).ToArray();
var aliasDirectives = filteredImports.OfType<TUsingOrAliasSyntax>().Where(IsAlias).ToArray();
var newRoot = Rewrite(
externAliases, usingDirectives, aliasDirectives,
externContainer, usingContainer, aliasContainer,
placeSystemNamespaceFirst, root);
return newRoot;
}
protected abstract SyntaxNode Rewrite(
TExternSyntax[] externAliases, TUsingOrAliasSyntax[] usingDirectives, TUsingOrAliasSyntax[] aliasDirectives,
SyntaxNode externContainer, SyntaxNode usingContainer, SyntaxNode aliasContainer,
bool placeSystemNamespaceFirst, SyntaxNode root);
private void GetContainers(SyntaxNode root, SyntaxNode contextLocation, out SyntaxNode externContainer, out SyntaxNode usingContainer, out SyntaxNode aliasContainer)
{
var applicableContainer = GetFirstApplicableContainer(contextLocation);
var contextSpine = applicableContainer.GetAncestorsOrThis<SyntaxNode>().ToImmutableArray();
// The node we'll add to if we can't find a specific namespace with imports of
// the type we're trying to add. This will be the closest namespace with any
// imports in it, or the root if there are no such namespaces.
var fallbackNode = contextSpine.FirstOrDefault(HasAnyImports) ?? root;
// The specific container to add each type of import to. We look for a container
// that already has an import of the same type as the node we want to add to.
// If we can find one, we add to that container. If not, we call back to the
// innermost node with any imports.
externContainer = contextSpine.FirstOrDefault(HasExterns) ?? fallbackNode;
usingContainer = contextSpine.FirstOrDefault(HasUsings) ?? fallbackNode;
aliasContainer = contextSpine.FirstOrDefault(HasAliases) ?? fallbackNode;
}
protected abstract SyntaxList<TUsingOrAliasSyntax> GetUsingsAndAliases(SyntaxNode node);
protected abstract SyntaxList<TExternSyntax> GetExterns(SyntaxNode node);
private static SyntaxNode GetFirstApplicableContainer(SyntaxNode contextNode)
{
var usingDirective = contextNode.GetAncestor<TUsingOrAliasSyntax>();
if (usingDirective != null)
{
contextNode = usingDirective.Parent;
}
return contextNode.GetAncestor<TNamespaceDeclarationSyntax>() ??
(SyntaxNode)contextNode.GetAncestor<TCompilationUnitSyntax>();
}
}
}
\ No newline at end of file
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host;
using Roslyn.Utilities; using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AddImport namespace Microsoft.CodeAnalysis.AddImports
{ {
internal interface IAddImportService : ILanguageService internal interface IAddImportsService : ILanguageService
{ {
SyntaxNode AddImports( SyntaxNode AddImports(
SyntaxNode root, SyntaxNode contextLocation, SyntaxNode root, SyntaxNode contextLocation,
...@@ -17,12 +17,14 @@ internal interface IAddImportService : ILanguageService ...@@ -17,12 +17,14 @@ internal interface IAddImportService : ILanguageService
/// that <paramref name="import"/> should be added to. /// that <paramref name="import"/> should be added to.
/// </summary> /// </summary>
SyntaxNode GetImportContainer(SyntaxNode root, SyntaxNode contextLocation, SyntaxNode import); SyntaxNode GetImportContainer(SyntaxNode root, SyntaxNode contextLocation, SyntaxNode import);
bool HasExistingImport(SyntaxNode root, SyntaxNode contextLocation, SyntaxNode import);
} }
internal static class IAddImportServiceExtensions internal static class IAddImportServiceExtensions
{ {
public static SyntaxNode AddImport( public static SyntaxNode AddImport(
this IAddImportService service, SyntaxNode root, SyntaxNode contextLocation, this IAddImportsService service, SyntaxNode root, SyntaxNode contextLocation,
SyntaxNode newImport, bool placeSystemNamespaceFirst) SyntaxNode newImport, bool placeSystemNamespaceFirst)
{ {
return service.AddImports(root, contextLocation, return service.AddImports(root, contextLocation,
......
...@@ -294,7 +294,8 @@ ...@@ -294,7 +294,8 @@
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\UnicodeCharacterUtilities.cs"> <Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\UnicodeCharacterUtilities.cs">
<Link>InternalUtilities\UnicodeCharacterUtilities.cs</Link> <Link>InternalUtilities\UnicodeCharacterUtilities.cs</Link>
</Compile> </Compile>
<Compile Include="AddImport\IAddImportService.cs" /> <Compile Include="AddImports\AbstractAddImportsService.cs" />
<Compile Include="AddImports\IAddImportsService.cs" />
<Compile Include="CaseCorrection\AbstractCaseCorrectionService.cs" /> <Compile Include="CaseCorrection\AbstractCaseCorrectionService.cs" />
<Compile Include="CaseCorrection\CaseCorrector.cs" /> <Compile Include="CaseCorrection\CaseCorrector.cs" />
<Compile Include="CaseCorrection\ICaseCorrectionService.cs" /> <Compile Include="CaseCorrection\ICaseCorrectionService.cs" />
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.AddImports
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.AddImports
Friend Class VisualBasicAddImportsService
Inherits AbstractAddImportsService(Of
CompilationUnitSyntax,
NamespaceBlockSyntax,
ImportsStatementSyntax,
ImportsStatementSyntax)
Protected Overrides Function GetAlias(usingOrAlias As ImportsStatementSyntax) As SyntaxNode
Return usingOrAlias.ImportsClauses.OfType(Of SimpleImportsClauseSyntax).
FirstOrDefault()?.Alias
End Function
Protected Overrides Function GetExterns(node As SyntaxNode) As SyntaxList(Of ImportsStatementSyntax)
Return Nothing
End Function
Protected Overrides Function GetUsingsAndAliases(node As SyntaxNode) As SyntaxList(Of ImportsStatementSyntax)
If node.Kind() = SyntaxKind.CompilationUnit Then
Return DirectCast(node, CompilationUnitSyntax).Imports
End If
Return Nothing
End Function
Protected Overrides Function Rewrite(
externAliases() As ImportsStatementSyntax,
usingDirectives() As ImportsStatementSyntax,
aliasDirectives() As ImportsStatementSyntax,
externContainer As SyntaxNode,
usingContainer As SyntaxNode,
aliasContainer As SyntaxNode,
placeSystemNamespaceFirst As Boolean,
root As SyntaxNode) As SyntaxNode
Dim compilationUnit = DirectCast(root, CompilationUnitSyntax)
Return compilationUnit.AddImportsStatements(
usingDirectives.Concat(aliasDirectives).ToList(),
placeSystemNamespaceFirst)
End Function
End Class
End Namespace
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
<InternalsVisibleToTest Include="Roslyn.Services.Test.Utilities2" /> <InternalsVisibleToTest Include="Roslyn.Services.Test.Utilities2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="AddImports\VisualBasicAddImportsService.vb" />
<Compile Include="CaseCorrection\VisualBasicCaseCorrectionService.Rewriter.vb" /> <Compile Include="CaseCorrection\VisualBasicCaseCorrectionService.Rewriter.vb" />
<Compile Include="CaseCorrection\VisualBasicCaseCorrectionService.vb" /> <Compile Include="CaseCorrection\VisualBasicCaseCorrectionService.vb" />
<Compile Include="CaseCorrection\VisualBasicCaseCorrectionServiceFactory.vb" /> <Compile Include="CaseCorrection\VisualBasicCaseCorrectionServiceFactory.vb" />
...@@ -271,4 +272,4 @@ ...@@ -271,4 +272,4 @@
<PublicAPI Include="PublicAPI.Unshipped.txt" /> <PublicAPI Include="PublicAPI.Unshipped.txt" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\..\..\build\Targets\Imports.targets" /> <Import Project="..\..\..\..\build\Targets\Imports.targets" />
</Project> </Project>
\ No newline at end of file
...@@ -4,8 +4,6 @@ Imports System.Runtime.CompilerServices ...@@ -4,8 +4,6 @@ Imports System.Runtime.CompilerServices
Imports System.Threading Imports System.Threading
Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.VisualBasic.Utilities Imports Microsoft.CodeAnalysis.VisualBasic.Utilities
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册