提交 fe1d203f 编写于 作者: M Martin Strecker

* Added support for VB (just one test added because most of the code is in a common base class).

* Added glyph to completion item
* Added type info test for InternalsVisibleToAttribute (SemanticModel) including test
* Added support for three out of four ways to strong name an assembly:
  *  By csproj property *AssemblyOriginatorKeyFile* (was already supported)
  *  By compiler option (was already supported)
  *  By *AssemblyKeyFileAttribute* and *AssemblyKeyNameAttribute* (new, requires compilation of every assembly). Test case added.
  *  Not supported: By Assembly Linker (IMO not possible)
* Added test for delayed signing
上级 3b91a09d
using Microsoft.CodeAnalysis.Completion;
// 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 Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Completion.Providers;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using System.Collections.Immutable;
using System.Threading.Tasks;
......@@ -13,33 +17,39 @@ public class InternalsVisibleToCompletionProviderTests : AbstractCSharpCompletio
{
private static readonly string s_keyPairFile = SigningTestHelpers.KeyPairFile;
private static readonly DesktopStrongNameProvider s_defaultProvider = new SigningTestHelpers.VirtualizedStrongNameProvider(ImmutableArray.Create<string>());
public InternalsVisibleToCompletionProviderTests(CSharpTestWorkspaceFixture workspaceFixture) : base(workspaceFixture)
{
// I needed to configure the workspace here, because CreateWorkspace was never called.
var ws = workspaceFixture.GetWorkspace();
var solution = ws.CurrentSolution;
var pi1 = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "ClassLibrary1", "ClassLibrary1", LanguageNames.CSharp,
var projectInfo1 = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "ClassLibrary1", "ClassLibrary1", LanguageNames.CSharp,
compilationOptions: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, cryptoKeyFile: s_keyPairFile, strongNameProvider: s_defaultProvider));
var pi2 = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "ClassLibrary2", "ClassLibrary2", LanguageNames.CSharp);
solution = solution.AddProject(pi1).AddProject(pi2);
var projectInfo2 = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "ClassLibrary2", "ClassLibrary2", LanguageNames.CSharp);
var projectInfo3 = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "ClassLibrary3", "ClassLibrary3", LanguageNames.CSharp,
compilationOptions: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, strongNameProvider: s_defaultProvider));
projectInfo3 = projectInfo3.WithMetadataReferences(new MetadataReference[] { MscorlibRef });
projectInfo3 = projectInfo3.WithDocuments(new DocumentInfo[] {
DocumentInfo.Create(DocumentId.CreateNewId(projectInfo3.Id), "AssemblyInfo.cs",
loader: TextLoader.From(TextAndVersion.Create(SourceText.From(
@"[assembly: System.Reflection.AssemblyKeyFile(""" + s_keyPairFile.Replace(@"\",@"\\") + @""")]"), VersionStamp.Default)))
});
var projectInfo4 = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "ClassLibrary4", "ClassLibrary4", LanguageNames.CSharp,
compilationOptions: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, cryptoKeyFile: s_keyPairFile, strongNameProvider: s_defaultProvider, delaySign: true));
solution = solution.AddProject(projectInfo1).AddProject(projectInfo2).AddProject(projectInfo3).AddProject(projectInfo4);
ws.ChangeSolution(solution);
}
protected override TestWorkspace CreateWorkspace(string fileContents)
{
// This would be the place to configure the workspace, but it is never called.
return base.CreateWorkspace(fileContents);
}
internal override CompletionProvider CreateCompletionProvider() => new InternalsVisibleToCompletionProvider();
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task CodeCompletionContainsOtherAssemblyOfSolution()
public async Task CodeCompletionContainsOtherAssembliesOfSolution()
{
var text = @"
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""$$"")]
";
await VerifyItemExistsAsync(text, "ClassLibrary1");
await VerifyItemExistsAsync(text, "ClassLibrary2");
await VerifyItemExistsAsync(text, "ClassLibrary3");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
......@@ -52,7 +62,7 @@ public async Task CodeCompletionIsEmptyAtClosingDoubleQuote()
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task CodeCompletionDoesNotContainsCurrentAssembly()
public async Task CodeCompletionDoesNotContainCurrentAssembly()
{
var text = @"
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""$$"")]
......@@ -83,5 +93,48 @@ public async Task CodeCompletionInsertsPublicKeyOnCommit()
";
await VerifyProviderCommitAsync(before, "ClassLibrary1", after, null, "");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task CodeCompletionContainsPublicKeyIfKeyIsSpecifiedByAttribute()
{
var before = @"
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""$$"")]
";
var after = @"
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""ClassLibrary3, PublicKey=00240000048000009400000006020000002400005253413100040000010001002b986f6b5ea5717d35c72d38561f413e267029efa9b5f107b9331d83df657381325b3a67b75812f63a9436ceccb49494de8f574f8e639d4d26c0fcf8b0e9a1a196b80b6f6ed053628d10d027e032df2ed1d60835e5f47d32c9ef6da10d0366a319573362c821b5f8fa5abc5bb22241de6f666a85d82d6ba8c3090d01636bd2bb"")]
";
await VerifyProviderCommitAsync(before, "ClassLibrary3", after, null, "");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task CodeCompletionContainsPublicKeyIfDelayedSigningIsEnabled()
{
var before = @"
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""$$"")]
";
var after = @"
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""ClassLibrary4, PublicKey=00240000048000009400000006020000002400005253413100040000010001002b986f6b5ea5717d35c72d38561f413e267029efa9b5f107b9331d83df657381325b3a67b75812f63a9436ceccb49494de8f574f8e639d4d26c0fcf8b0e9a1a196b80b6f6ed053628d10d027e032df2ed1d60835e5f47d32c9ef6da10d0366a319573362c821b5f8fa5abc5bb22241de6f666a85d82d6ba8c3090d01636bd2bb"")]
";
await VerifyProviderCommitAsync(before, "ClassLibrary4", after, null, "");
}
[Fact, Trait(Traits.Feature, Traits.Features.Completion)]
public async Task CodeCompletetionIsCanceledIfAttributeIsNotTheBCLAttribute()
{
var text = @"
[assembly: Test.InternalsVisibleTo(""$$"")]
namespace Test
{
[System.AttributeUsage(System.AttributeTargets.Assembly)]
public sealed class InternalsVisibleToAttribute: System.Attribute
{
public InternalsVisibleToAttribute(string ignore)
{
}
}
}";
await VerifyNoItemsExistAsync(text);
}
}
}
}
\ No newline at end of file
......@@ -221,6 +221,7 @@
<Compile Include="CodeActions\ConvertIfToSwitch\ConvertIfToSwitchTests.vb" />
<Compile Include="CodeActions\ConvertNumericLiteral\ConvertNumericLiteralTests.vb" />
<Compile Include="CodeActions\UseNamedArguments\UseNamedArgumentsTests.vb" />
<Compile Include="Completion\CompletionProviders\InternalsVisibleToCompletionProviderTests.vb" />
<Compile Include="Diagnostics\RemoveUnusedVariable\RemoveUnusedVariableTest.vb" />
<Compile Include="InitializeParameter\AddParameterCheckTests.vb" />
<Compile Include="Structure\CollectionInitializerStructureProviderTests.vb" />
......
' 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 System
Imports Microsoft.CodeAnalysis.Completion
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.VisualBasic.Completion.Providers
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.CompletionProviders
Public Class InternalsVisibleToCompletionProviderTests
Inherits AbstractVisualBasicCompletionProviderTests
Public Sub New(workspaceFixture As VisualBasicTestWorkspaceFixture)
MyBase.New(workspaceFixture)
Dim ws = workspaceFixture.GetWorkspace()
Dim solution = ws.CurrentSolution
Dim projectInfo1 = ProjectInfo.Create(ProjectId.CreateNewId(), VersionStamp.Create(), "ClassLibrary1", "ClassLibrary1", LanguageNames.CSharp)
solution = solution.AddProject(projectInfo1)
ws.ChangeSolution(solution)
End Sub
Friend Overrides Function CreateCompletionProvider() As CompletionProvider
Return New InternalsVisibleToCompletionProvider()
End Function
<Fact, Trait(Traits.Feature, Traits.Features.Completion)>
Public Async Function CodeCompletionContainsOtherAssembliesOfSolutionAsync() As Task
Dim text = "<Assembly:System.Runtime.CompilerServices.InternalsVisibleTo(""$$"")>"
Await VerifyItemExistsAsync(text, "ClassLibrary1")
End Function
End Class
End Namespace
\ No newline at end of file
using Microsoft.CodeAnalysis.Completion;
// 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 Microsoft.CodeAnalysis.Completion.Providers;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers
{
internal sealed class InternalsVisibleToCompletionProvider : CommonCompletionProvider
internal sealed class InternalsVisibleToCompletionProvider : AbstractInternalsVisibleToCompletionProvider
{
private const string ProjectIdKey = "ProjectId";
internal override bool IsInsertionTrigger(SourceText text, int insertedCharacterPosition, OptionSet options)
{
var ch = text[insertedCharacterPosition];
......@@ -25,121 +19,24 @@ internal override bool IsInsertionTrigger(SourceText text, int insertedCharacter
{
return true;
}
return base.IsInsertionTrigger(text, insertedCharacterPosition, options);
}
public override async Task ProvideCompletionsAsync(CompletionContext context)
{
var cancellationToken = context.CancellationToken;
var syntaxTree = await context.Document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
if (syntaxTree.IsEntirelyWithinStringLiteral(context.Position, cancellationToken))
{
var token = syntaxTree.FindTokenOnLeftOfPosition(context.Position, cancellationToken);
var attr = GetAttributeSyntaxOfToken(token);
if (attr == null)
{
return;
}
if (attr.Name.TryGetNameParts(out IList<string> nameParts) && nameParts.Count > 0)
{
var lastName = nameParts[nameParts.Count - 1];
if (lastName == "InternalsVisibleTo" || lastName == "InternalsVisibleToAttribute")
{
AddAssemblyCompletionItems(context, cancellationToken);
}
}
}
return false;
}
private static AttributeSyntax GetAttributeSyntaxOfToken(SyntaxToken token)
{
//Supported cases:
//[Attribute("|
//[Attribute(parameterName:"Text|")
//Also supported but excluded by syntaxTree.IsEntirelyWithinStringLiteral in ProvideCompletionsAsync
//[Attribute(""|
//[Attribute("Text"|)
var node = token.Parent;
if (node is LiteralExpressionSyntax && node.Kind() == SyntaxKind.StringLiteralExpression)
{
node = node.Parent;
if (node is AttributeArgumentSyntax)
{
node = node.Parent;
if (node is AttributeArgumentListSyntax)
{
return node.Parent as AttributeSyntax;
}
}
}
return default(AttributeSyntax);
}
protected override bool IsPositionEntirelyWithinStringLiteral(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken)
=> syntaxTree.IsEntirelyWithinStringLiteral(position, cancellationToken);
private static void AddAssemblyCompletionItems(CompletionContext context, CancellationToken cancellationToken)
protected override string GetAttributeNameOfAttributeSyntaxNode(SyntaxNode attributeSyntaxNode)
{
var currentProject = context.Document.Project;
foreach (var p in context.Document.Project.Solution.Projects)
if (attributeSyntaxNode is AttributeSyntax attributeSyntax)
{
if (p == currentProject)
if (attributeSyntax.Name.TryGetNameParts(out var nameParts) && nameParts.Count > 0)
{
continue;
}
var completionItem = CompletionItem.Create(displayText: p.AssemblyName,
properties: ImmutableDictionary.Create<string, string>().Add(ProjectIdKey, p.Id.Id.ToString()));
context.AddItem(completionItem);
}
}
public override async Task<CompletionChange> GetChangeAsync(Document document, CompletionItem item, char? commitKey = default(char?), CancellationToken cancellationToken = default(CancellationToken))
{
if (item.Properties.TryGetValue(ProjectIdKey, out var projectId))
{
var assemblyName = item.DisplayText;
var project = document.Project.Solution.GetProject(ProjectId.CreateFromSerialized(new System.Guid(projectId)));
var publicKey = await GetPublicKeyOfProjectAsync(project, cancellationToken).ConfigureAwait(false);
if (!string.IsNullOrEmpty(publicKey))
{
assemblyName += ", PublicKey=" + publicKey;
var lastName = nameParts[nameParts.Count - 1];
return lastName;
}
var tc = new TextChange(item.Span, assemblyName);
return CompletionChange.Create(tc);
}
Debug.Fail("Project can't be found by projectId.");
return await base.GetChangeAsync(document, item, commitKey, cancellationToken).ConfigureAwait(false);
}
private static async Task<string> GetPublicKeyOfProjectAsync(Project p, CancellationToken cancellationToken)
{
var compilationOptions = p.CompilationOptions;
if (compilationOptions == null ||
(string.IsNullOrEmpty(compilationOptions.CryptoKeyFile) && string.IsNullOrEmpty(compilationOptions.CryptoKeyContainer)))
{
return string.Empty;
}
var c = await p.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
if (c.Assembly?.Identity?.IsStrongName ?? false)
{
return GetPublicKeyAsHexString(c.Assembly.Identity.PublicKey);
}
return string.Empty;
}
private static string GetPublicKeyAsHexString(ImmutableArray<byte> publicKey)
{
var builder = SharedPools.Default<StringBuilder>().Allocate();
try
{
builder.Clear();
foreach (var b in publicKey)
{
builder.Append(b.ToString("x2"));
}
return builder.ToString();
}
finally
{
SharedPools.Default<StringBuilder>().ClearAndFree(builder);
}
}
}
}
// 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 Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Completion.Providers
{
internal abstract class AbstractInternalsVisibleToCompletionProvider : CommonCompletionProvider
{
private const string ProjectGuidKey = nameof(ProjectGuidKey);
protected abstract bool IsPositionEntirelyWithinStringLiteral(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken);
protected abstract string GetAttributeNameOfAttributeSyntaxNode(SyntaxNode attributeSyntaxNode);
public override async Task ProvideCompletionsAsync(CompletionContext context)
{
var cancellationToken = context.CancellationToken;
var syntaxTree = await context.Document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var syntaxFactsService = context.Document.GetLanguageService<ISyntaxFactsService>();
if (IsPositionEntirelyWithinStringLiteral(syntaxTree, context.Position, cancellationToken))
{
var token = syntaxTree.FindTokenOnLeftOfPosition(context.Position, cancellationToken);
var attributeSyntaxNode = GetAttributeSyntaxNodeOfToken(syntaxFactsService, token);
if (attributeSyntaxNode == null)
{
return;
}
var attributeName = GetAttributeNameOfAttributeSyntaxNode(attributeSyntaxNode);
if (attributeName == "InternalsVisibleTo" || attributeName == nameof(InternalsVisibleToAttribute))
{
if (await CheckTypeInfoOfAttributeAsync(context, attributeSyntaxNode).ConfigureAwait(false))
{
AddAssemblyCompletionItems(context, cancellationToken);
}
}
}
}
private static SyntaxNode GetAttributeSyntaxNodeOfToken(ISyntaxFactsService syntaxFactsService, SyntaxToken token)
{
//Supported cases:
//[Attribute("|
//[Attribute(parameterName:"Text|")
//Also supported but excluded by syntaxTree.IsEntirelyWithinStringLiteral in ProvideCompletionsAsync
//[Attribute(""|
//[Attribute("Text"|)
var node = token.Parent;
if (syntaxFactsService.IsStringLiteralExpression(node))
{
// LiteralExpressionSyntax -> AttributeArgumentSyntax -> AttributeArgumentListSyntax -> AttributeSyntax
var attributeSyntaxNodeCandidate = node.Parent?.Parent?.Parent;
if (attributeSyntaxNodeCandidate != null && syntaxFactsService.IsAttribute(attributeSyntaxNodeCandidate))
{
return attributeSyntaxNodeCandidate;
}
}
return null;
}
private static async Task<bool> CheckTypeInfoOfAttributeAsync(CompletionContext context, SyntaxNode attributeNode)
{
var semanticModel = await context.Document.GetSemanticModelForNodeAsync(attributeNode, context.CancellationToken).ConfigureAwait(false);
var typeInfo = semanticModel.GetTypeInfo(attributeNode);
var type = typeInfo.Type;
if (type == null)
{
return false;
}
//TODO there must be better ways to do the check type equality.
var typeName = type.ToDisplayString(new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces));
var assemblyName = type.ContainingAssembly.ToSignatureDisplayString();
var internalsVisibleToQualifiedName = typeof(InternalsVisibleToAttribute).AssemblyQualifiedName;
return typeName + ", " + assemblyName == internalsVisibleToQualifiedName;
}
private static void AddAssemblyCompletionItems(CompletionContext context, CancellationToken cancellationToken)
{
var currentProject = context.Document.Project;
foreach (var project in context.Document.Project.Solution.Projects)
{
if (project == currentProject)
{
continue;
}
var projectGuid = project.Id.Id.ToString();
var completionItem = CommonCompletionItem.Create(
displayText: project.AssemblyName,
rules: CompletionItemRules.Default,
glyph: project.GetGlyph(),
properties: ImmutableDictionary.Create<string, string>().Add(ProjectGuidKey, projectGuid));
context.AddItem(completionItem);
}
}
public override async Task<CompletionChange> GetChangeAsync(Document document, CompletionItem item, char? commitKey = default(char?), CancellationToken cancellationToken = default(CancellationToken))
{
if (item.Properties.TryGetValue(ProjectGuidKey, out var projectId))
{
var assemblyName = item.DisplayText;
var project = document.Project.Solution.GetProject(ProjectId.CreateFromSerialized(new System.Guid(projectId)));
var publicKey = await GetPublicKeyOfProjectAsync(project, cancellationToken).ConfigureAwait(false);
if (!string.IsNullOrEmpty(publicKey))
{
assemblyName += ", PublicKey=" + publicKey;
}
var textChange = new TextChange(item.Span, assemblyName);
return CompletionChange.Create(textChange);
}
Debug.Fail("Project can't be found by projectId.");
return await base.GetChangeAsync(document, item, commitKey, cancellationToken).ConfigureAwait(false);
}
private static async Task<string> GetPublicKeyOfProjectAsync(Project project, CancellationToken cancellationToken)
{
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
if (compilation.Assembly?.Identity?.IsStrongName ?? false)
{
return GetPublicKeyAsHexString(compilation.Assembly.Identity.PublicKey);
}
return string.Empty;
}
private static string GetPublicKeyAsHexString(ImmutableArray<byte> publicKey)
{
var pooledStrBuilder = PooledStringBuilder.GetInstance();
var builder = pooledStrBuilder.Builder;
foreach (var b in publicKey)
{
builder.Append(b.ToString("x2"));
}
return pooledStrBuilder.ToStringAndFree();
}
}
}
\ No newline at end of file
......@@ -114,6 +114,7 @@
<Compile Include="CodeFixes\RemoveUnusedVariable\AbstractRemoveUnusedVariableCodeFixProvider.cs" />
<Compile Include="CodeRefactorings\WorkspaceServices\ISymbolRenamedCodeActionOperationFactoryWorkspaceService.cs" />
<Compile Include="Completion\FileSystemCompletionHelper.cs" />
<Compile Include="Completion\Providers\AbstractInternalsVisibleToCompletionProvider.cs" />
<Compile Include="ConvertIfToSwitch\AbstractConvertIfToSwitchCodeRefactoringProvider.cs" />
<Compile Include="ConvertNumericLiteral\AbstractConvertNumericLiteralCodeRefactoringProvider.cs" />
<Compile Include="CodeRefactorings\UseNamedArguments\AbstractUseNamedArgumentsCodeRefactoringProvider.cs" />
......
......@@ -66,6 +66,7 @@
<Link>InternalUtilities\LambdaUtilities.vb</Link>
</Compile>
<Compile Include="AddPackage\VisualBasicAddSpecificPackageCodeFixProvider.vb" />
<Compile Include="Completion\CompletionProviders\InternalsVisibleToCompletionProvider.vb" />
<Compile Include="DocumentHighlighting\VisualBasicDocumentHighlightsService.vb" />
<Compile Include="InitializeParameter\InitializeParameterHelpers.vb" />
<Compile Include="InitializeParameter\VisualBasicAddParameterCheckCodeRefactoringProvider.vb" />
......
' 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 System
Imports System.Threading
Imports Microsoft.CodeAnalysis.Completion.Providers
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.Completion.Providers
Friend NotInheritable Class InternalsVisibleToCompletionProvider
Inherits AbstractInternalsVisibleToCompletionProvider
Friend Overrides Function IsInsertionTrigger(text As SourceText, insertedCharacterPosition As Integer, options As OptionSet) As Boolean
Dim ch = text(insertedCharacterPosition)
If ch = """"c Then
Return True
End If
Return False
End Function
Protected Overrides Function IsPositionEntirelyWithinStringLiteral(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean
Return syntaxTree.IsEntirelyWithinStringLiteral(position, cancellationToken)
End Function
Protected Overrides Function GetAttributeNameOfAttributeSyntaxNode(attributeSyntaxNode As SyntaxNode) As String
Dim attributeSyntax = TryCast(attributeSyntaxNode, AttributeSyntax)
If attributeSyntax Is Nothing Then
Return String.Empty
End If
Dim nameParts As IList(Of String) = Nothing
If attributeSyntax.Name.TryGetNameParts(nameParts) AndAlso nameParts.Count > 0 Then
Dim lastName = nameParts(nameParts.Count - 1)
Return lastName
End If
Return String.Empty
End Function
End Class
End Namespace
......@@ -38,7 +38,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion
New CrefCompletionProvider(),
New CompletionListTagCompletionProvider(),
New OverrideCompletionProvider(),
New XmlDocCommentCompletionProvider()
New XmlDocCommentCompletionProvider(),
New InternalsVisibleToCompletionProvider()
)
Private ReadOnly _workspace As Workspace
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册