未验证 提交 0dd9b972 编写于 作者: S Sam Harwell 提交者: GitHub

Merge pull request #24022 from MaStr11/AmbiguousTypeCodefixProvider

Ambiguous type codefix provider (using alias)
// 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.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.AliasAmbiguousType;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.AliasAmbiguousType
{
public class AliasAmbiguousTypeTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (null, new CSharpAliasAmbiguousTypeCodeFixProvider());
protected override ImmutableArray<CodeAction> MassageActions(ImmutableArray<CodeAction> actions)
=> FlattenActions(actions);
private string GetAmbiguousDefinition(string typeDefinion)
=> $@"
namespace N1
{{
{ typeDefinion }
}}
namespace N2
{{
{ typeDefinion }
}}";
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousClassObjectCreationUsingsInNamespace()
{
var classDef = GetAmbiguousDefinition("public class Ambiguous { }");
var initialMarkup = classDef + @"
namespace Test
{
using N1;
using N2;
class C
{
void M()
{
var a = new [|Ambiguous|]();
}
}
}";
var expectedMarkup0 = classDef + @"
namespace Test
{
using N1;
using N2;
using Ambiguous = N1.Ambiguous;
class C
{
void M()
{
var a = new Ambiguous();
}
}
}";
var expectedMarkup1 = classDef + @"
namespace Test
{
using N1;
using N2;
using Ambiguous = N2.Ambiguous;
class C
{
void M()
{
var a = new Ambiguous();
}
}
}";
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup0, index: 0);
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup1, index: 1);
await TestSmartTagTextAsync(initialMarkup, "using Ambiguous = N1.Ambiguous;", index: 0);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousClassObjectCreationUsingsInCompilationUnit()
{
var classDef = GetAmbiguousDefinition("public class Ambiguous { }");
await TestInRegularAndScriptAsync(@"
using N1;
using N2;
" + classDef + @"
namespace Test
{
class C
{
void M()
{
var a = new [|Ambiguous|]();
}
}
}", @"
using N1;
using N2;
using Ambiguous = N1.Ambiguous;
" + classDef + @"
namespace Test
{
class C
{
void M()
{
var a = new Ambiguous();
}
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousClassObjectCreationGenericsDontOfferDiagnostic()
{
var genericAmbiguousClassDefinition = GetAmbiguousDefinition("public class Ambiguous<T> { }");
await TestMissingAsync(@"
using N1;
using N2;
" + genericAmbiguousClassDefinition + @"
namespace Test
{
class C
{
void M()
{
var a = new [|Ambiguous<int>|]();
}
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousAttribute()
{
var classDef = GetAmbiguousDefinition("public class AmbiguousAttribute: System.Attribute { }");
await TestInRegularAndScriptAsync(@"
using N1;
using N2;
" + classDef + @"
namespace Test
{
[[|Ambiguous|]]
class C
{
}
}", @"
using N1;
using N2;
using AmbiguousAttribute = N1.AmbiguousAttribute;
" + classDef + @"
namespace Test
{
[Ambiguous]
class C
{
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestNamespaceAndTypenameIdenticalOffersNoDiagnostics()
{
// This gives CS0433: The type 'Ambiguous' exists in both 'Assembly1' and 'Assembly2'
// Couldn't get a CS0104 in this situation. Keep the test anyway if someone finds a way to force CS0104 here
// or CS0433 is added as a supported diagnostic for this fix.
await TestMissingAsync(@"
<Workspace>
<Project Language=""C#"" AssemblyName=""Assembly1"" CommonReferences=""true"">
<Document FilePath=""File1.cs"">
namespace N
{
public class Ambiguous { }
}
</Document>
</Project>
<Project Language=""C#"" AssemblyName=""Assembly2"" CommonReferences=""true"">
<Document FilePath=""File2.cs"">
namespace N
{
public class Ambiguous { }
}
</Document>
</Project>
<Project Language=""C#"" AssemblyName=""Test"" CommonReferences=""true"">
<ProjectReference Alias=""A1"">Assembly1</ProjectReference>
<ProjectReference Alias=""A2"">Assembly2</ProjectReference>
<Document FilePath=""File3.cs"">
extern alias A1;
extern alias A2;
using A1::N;
using A2::N;
namespace N1
{
public class C
{
void M()
{
var a = new [|Ambiguous|]();
}
}
}
</Document>
</Project>
</Workspace>
");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousAliasNoDiagnostics()
{
await TestMissingAsync(@"
extern alias alias;
using alias=alias;
class myClass : [|alias|]::Uri
{
}
");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousNestedClass()
{
var initialMarkup = @"
using static Static<string>;
using static Static<int>;
public static class Static<T>
{
public class Nested
{
public void M() { }
}
}
class D
{
static void Main(string[] args)
{
var c = new [|Nested|]();
c.M();
}
}";
var expectedMarkup0 = @"
using static Static<string>;
using static Static<int>;
using Nested = Static<string>.Nested;
public static class Static<T>
{
public class Nested
{
public void M() { }
}
}
class D
{
static void Main(string[] args)
{
var c = new Nested();
c.M();
}
}";
var expectedMarkup1 = @"
using static Static<string>;
using static Static<int>;
using Nested = Static<int>.Nested;
public static class Static<T>
{
public class Nested
{
public void M() { }
}
}
class D
{
static void Main(string[] args)
{
var c = new Nested();
c.M();
}
}";
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup0, index: 0);
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup1, index: 1);
await TestSmartTagTextAsync(initialMarkup, "using Nested = Static<string>.Nested;", index: 0);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousClassDiagnosedAtBaseList()
{
var classDef = GetAmbiguousDefinition(@"public class AmbiguousClass { }");
var initialMarkup = @"
using N1;
using N2;
" + classDef + @"
namespace NTest
{
public class Test : [|AmbiguousClass|] { }
}
";
var expectedMarkup = @"
using N1;
using N2;
using AmbiguousClass = N1.AmbiguousClass;
" + classDef + @"
namespace NTest
{
public class Test : AmbiguousClass { }
}
";
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousClassDiagnosedAtTypeConstraint()
{
var classDef = GetAmbiguousDefinition(@"public class AmbiguousClass { }");
var initialMarkup = @"
using N1;
using N2;
" + classDef + @"
namespace NTest
{
public class Test<T> where T : [|AmbiguousClass|] { }
}
";
var expectedMarkup = @"
using N1;
using N2;
using AmbiguousClass = N1.AmbiguousClass;
" + classDef + @"
namespace NTest
{
public class Test<T> where T : AmbiguousClass { }
}
";
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousEnumDiagnosedAtFieldDeclaration()
{
var enumDef = GetAmbiguousDefinition(@"public enum AmbiguousEnum { }");
var initialMarkup = @"
using N1;
using N2;
" + enumDef + @"
namespace NTest
{
public class Test
{
private [|AmbiguousEnum|] _AmbiguousEnum;
}
}
";
var expectedMarkup = @"
using N1;
using N2;
using AmbiguousEnum = N1.AmbiguousEnum;
" + enumDef + @"
namespace NTest
{
public class Test
{
private AmbiguousEnum _AmbiguousEnum;
}
}
";
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousStructDiagnosedAtPropertyDeclaration()
{
var strcutDef = GetAmbiguousDefinition(@"public struct AmbiguousStruct { }");
var initialMarkup = @"
using N1;
using N2;
" + strcutDef + @"
namespace NTest
{
public class Test
{
public [|AmbiguousStruct|] AmbiguousStruct { get; }
}
}
";
var expectedMarkup = @"
using N1;
using N2;
using AmbiguousStruct = N1.AmbiguousStruct;
" + strcutDef + @"
namespace NTest
{
public class Test
{
public AmbiguousStruct AmbiguousStruct { get; }
}
}
";
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousClassDiagnosedAtTypeArgument()
{
var classDef = GetAmbiguousDefinition(@"public class AmbiguousClass { }");
var initialMarkup = @"
using N1;
using N2;
" + classDef + @"
namespace NTest
{
public class Test
{
public void M()
{
var list = new System.Collections.Generic.List<[|AmbiguousClass|]> { new AmbiguousClass() };
}
}
}
";
var expectedMarkup = @"
using N1;
using N2;
using AmbiguousClass = N1.AmbiguousClass;
" + classDef + @"
namespace NTest
{
public class Test
{
public void M()
{
var list = new System.Collections.Generic.List<AmbiguousClass> { new AmbiguousClass() };
}
}
}
";
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousClassDiagnosedAtIdentifierOfIncompleteExpression()
{
var classDef = GetAmbiguousDefinition(@"public class AmbiguousClass { }");
var initialMarkup = @"
using N1;
using N2;
" + classDef + @"
namespace NTest
{
public class Test
{
public void M()
{
[|AmbiguousClass|]
}
}
}
";
var expectedMarkup = @"
using N1;
using N2;
using AmbiguousClass = N1.AmbiguousClass;
" + classDef + @"
namespace NTest
{
public class Test
{
public void M()
{
AmbiguousClass
}
}
}
";
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousClassDiagnosedAtMethodParameter()
{
var classDef = GetAmbiguousDefinition(@"public class AmbiguousClass { }");
var initialMarkup = @"
using N1;
using N2;
" + classDef + @"
namespace NTest
{
public class Test
{
public void M([|AmbiguousClass|] a)
{
}
}
}
";
var expectedMarkup = @"
using N1;
using N2;
using AmbiguousClass = N1.AmbiguousClass;
" + classDef + @"
namespace NTest
{
public class Test
{
public void M(AmbiguousClass a)
{
}
}
}
";
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)]
public async Task TestAmbiguousClassDiagnosedAtFromClauseTypeIdentifier()
{
var classDef = GetAmbiguousDefinition(@"public class AmbiguousClass { }");
var initialMarkup = @"
using N1;
using N2;
using System.Linq;
" + classDef + @"
namespace NTest
{
public class Test
{
public void M()
{
var qry = from [|AmbiguousClass|] a in new object[] { }
select a;
}
}
}
";
var expectedMarkup = @"
using N1;
using N2;
using System.Linq;
using AmbiguousClass = N1.AmbiguousClass;
" + classDef + @"
namespace NTest
{
public class Test
{
public void M()
{
var qry = from AmbiguousClass a in new object[] { }
select a;
}
}
}
";
await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup);
}
}
}
......@@ -41,6 +41,7 @@ public static class Features
public const string CodeActionsAddOverload = "CodeActions.AddOverloads";
public const string CodeActionsAddParameter = "CodeActions.AddParameter";
public const string CodeActionsAddParenthesesAroundConditionalExpressionInInterpolatedString = "CodeActions.AddParenthesesAroundConditionalExpressionInInterpolatedString";
public const string CodeActionsAliasAmbiguousType = "CodeActions.AliasAmbiguousType";
public const string CodeActionsChangeToAsync = "CodeActions.ChangeToAsync";
public const string CodeActionsChangeToIEnumerable = "CodeActions.ChangeToIEnumerable";
public const string CodeActionsChangeToYield = "CodeActions.ChangeToYield";
......
' 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.Collections.Immutable
Imports Microsoft.CodeAnalysis.CodeActions
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.VisualBasic.AliasAmbiguousType
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.AliasAmbiguousType
Public Class AliasAmbiguousTypeTests
Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest
Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider)
Return (Nothing, New VisualBasicAliasAmbiguousTypeCodeFixProvider())
End Function
Protected Overrides Function MassageActions(actions As ImmutableArray(Of CodeAction)) As ImmutableArray(Of CodeAction)
Return FlattenActions(actions)
End Function
Private Function GetAmbiguousDefinition(ByVal typeDefinion As String) As String
Return $"
Namespace N1
{typeDefinion}
End Namespace
Namespace N2
{typeDefinion}
End Namespace"
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)>
Public Async Function TestAmbiguousClassObjectCreationGlobalImports() As Task
Dim classDef = GetAmbiguousDefinition("
Public Class Ambiguous
End Class")
Dim initialMarkup = "
Imports N1
Imports N2
" & classDef & "
Namespace N3
Class C
Private Sub M()
Dim a = New [|Ambiguous|]()
End Sub
End Class
End Namespace"
Dim expectedMarkupTemplate = "
Imports N1
Imports N2
{0}
" & classDef & "
Namespace N3
Class C
Private Sub M()
Dim a = New Ambiguous()
End Sub
End Class
End Namespace"
Await TestInRegularAndScriptAsync(initialMarkup, String.Format(expectedMarkupTemplate, "Imports Ambiguous = N1.Ambiguous"), index:=0)
Await TestInRegularAndScriptAsync(initialMarkup, String.Format(expectedMarkupTemplate, "Imports Ambiguous = N2.Ambiguous"), index:=1)
Await TestSmartTagTextAsync(initialMarkup, "Imports Ambiguous = N1.Ambiguous", index:=0)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)>
Public Async Function TestAmbiguousAttribute() As Task
Dim classDef = GetAmbiguousDefinition("
Class AAttribute
Inherits System.Attribute
End Class
")
Dim initialMarkup = "
Imports N1
Imports N2
" & classDef & "
<[|A|]()>
Class C
End Class"
Dim expectedMarkupTemplate = "
Imports N1
Imports N2
Imports AAttribute = N1.AAttribute
" & classDef & "
<[|A|]()>
Class C
End Class"
Await TestInRegularAndScriptAsync(initialMarkup, expectedMarkupTemplate)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)>
Public Async Function TestAmbiguousBug4817() As Task
Dim initialMarkup = "
Imports A
Imports B
Class A
Shared Sub Goo()
End Sub
End Class
Class B
Inherits A
Overloads Shared Sub Goo(x As Integer)
End Sub
End Class
Module C
Sub Main()
[|Goo|]()
End Sub
End Module
"
Await TestMissingAsync(initialMarkup)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)>
Public Async Function TestAmbiguousClassInModule() As Task
Dim initialMarkup = "
Imports N1, N2
Namespace N1
Module K
Class Goo
End Class
End Module
End Namespace
Namespace N2
Module L
Class Goo
End Class
End Module
End Namespace
Class A
Public d As [|Goo|]
End Class
"
Dim expectedMarkup = "
Imports N1, N2
Imports Goo = N1.Goo
Namespace N1
Module K
Class Goo
End Class
End Module
End Namespace
Namespace N2
Module L
Class Goo
End Class
End Module
End Namespace
Class A
Public d As Goo
End Class
"
Await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup)
End Function
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAliasAmbiguousType)>
Public Async Function TestAmbiguousInterfaceNameReferencedInSmallCaps() As Task
Dim initialMarkup = "
Imports N1, N2
Namespace N1
Interface I1
End Interface
End Namespace
Namespace N2
Interface I1
End Interface
End Namespace
Public Class Cls2
Implements [|i1|]
End Class
"
Dim expectedMarkup = "
Imports N1, N2
Imports I1 = N1.I1
Namespace N1
Interface I1
End Interface
End Namespace
Namespace N2
Interface I1
End Interface
End Namespace
Public Class Cls2
Implements i1
End Class
"
Await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup)
End Function
End Class
End Namespace
// 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.Collections.Immutable;
using System.Composition;
using Microsoft.CodeAnalysis.AliasAmbiguousType;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CSharp.AliasAmbiguousType
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.AliasAmbiguousType), Shared]
[ExtensionOrder(After = PredefinedCodeFixProviderNames.FullyQualify)]
internal class CSharpAliasAmbiguousTypeCodeFixProvider : AbstractAliasAmbiguousTypeCodeFixProvider
{
/// <summary>
/// 'reference' is an ambiguous reference between 'identifier' and 'identifier'
/// </summary>
private const string CS0104 = nameof(CS0104);
public override ImmutableArray<string> FixableDiagnosticIds
=> ImmutableArray.Create(CS0104);
protected override string GetTextPreviewOfChange(string alias, ITypeSymbol typeSymbol)
=> $"using { alias } = { typeSymbol.ToNameDisplayString() };";
}
}
// 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.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.AddImports;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using static Microsoft.CodeAnalysis.CodeActions.CodeAction;
namespace Microsoft.CodeAnalysis.AliasAmbiguousType
{
internal abstract class AbstractAliasAmbiguousTypeCodeFixProvider : CodeFixProvider
{
protected abstract string GetTextPreviewOfChange(string aliasName, ITypeSymbol typeSymbol);
public override FixAllProvider GetFixAllProvider() => null;
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var cancellationToken = context.CancellationToken;
var document = context.Document;
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
// Innermost: We are looking for an IdentifierName. IdentifierName is sometimes at the same span as its parent (e.g. SimpleBaseTypeSyntax).
var diagnosticNode = root.FindNode(context.Span, getInnermostNodeForTie: true);
if (!syntaxFacts.IsIdentifierName(diagnosticNode))
{
return;
}
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var symbolInfo = semanticModel.GetSymbolInfo(diagnosticNode, cancellationToken);
if (SymbolCandidatesContainsSupportedSymbols(symbolInfo))
{
var addImportService = document.GetLanguageService<IAddImportsService>();
var syntaxGenerator = document.GetLanguageService<SyntaxGenerator>();
var compilation = semanticModel.Compilation;
var optionSet = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var placeSystemNamespaceFirst = optionSet.GetOption(GenerationOptions.PlaceSystemNamespaceFirst, document.Project.Language);
var codeActionsBuilder = ImmutableArray.CreateBuilder<CodeAction>(symbolInfo.CandidateSymbols.Length);
foreach (var symbol in symbolInfo.CandidateSymbols.Cast<ITypeSymbol>())
{
var typeName = symbol.Name;
var codeActionPreviewText = GetTextPreviewOfChange(typeName, symbol);
codeActionsBuilder.Add(new MyCodeAction(codeActionPreviewText, c =>
{
var aliasDirective = syntaxGenerator.AliasImportDeclaration(typeName, symbol);
var newRoot = addImportService.AddImport(compilation, root, diagnosticNode, aliasDirective, placeSystemNamespaceFirst);
return Task.FromResult(document.WithSyntaxRoot(newRoot));
}));
}
var groupingTitle = string.Format(FeaturesResources.Alias_ambiguous_type_0, diagnosticNode.ToString());
var groupingCodeAction = new CodeActionWithNestedActions(groupingTitle, codeActionsBuilder.ToImmutable(), isInlinable: true);
context.RegisterCodeFix(groupingCodeAction, context.Diagnostics.First());
}
}
private static bool SymbolCandidatesContainsSupportedSymbols(SymbolInfo symbolInfo)
=> symbolInfo.CandidateReason == CandidateReason.Ambiguous &&
// Arity: Aliases can only name closed constructed types. (See also proposal https://github.com/dotnet/csharplang/issues/1239)
// Aliasing as a closed constructed type is possible but would require to remove the type arguments from the diagnosed node.
// It is unlikely that the user wants that and so generic types are not supported.
symbolInfo.CandidateSymbols.All(symbol => symbol.IsKind(SymbolKind.NamedType) &&
symbol.GetArity() == 0);
private class MyCodeAction : DocumentChangeAction
{
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument) :
base(title, createChangedDocument, equivalenceKey: title)
{
}
}
}
}
......@@ -9,6 +9,7 @@ internal static class PredefinedCodeFixProviderNames
public const string AddAsync = nameof(AddAsync);
public const string AddParameter = nameof(AddParameter);
public const string AddParenthesesAroundConditionalExpressionInInterpolatedString = nameof(AddParenthesesAroundConditionalExpressionInInterpolatedString);
public const string AliasAmbiguousType = nameof(AliasAmbiguousType);
public const string ApplyNamingStyle = nameof(ApplyNamingStyle);
public const string AddBraces = nameof(AddBraces);
public const string ChangeReturnType = nameof(ChangeReturnType);
......
......@@ -427,7 +427,18 @@ internal class FeaturesResources {
return ResourceManager.GetString("Adding_an_imported_method_will_prevent_the_debug_session_from_continuing", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Alias ambiguous type &apos;{0}&apos;.
/// </summary>
internal static string Alias_ambiguous_type_0
{
get
{
return ResourceManager.GetString("Alias_ambiguous_type_0", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to All lowercase.
/// </summary>
......
......@@ -1334,4 +1334,7 @@ This version used in: {2}</value>
<data name="indexer_" xml:space="preserve">
<value>indexer</value>
</data>
</root>
<data name="Alias_ambiguous_type_0" xml:space="preserve">
<value>Alias ambiguous type '{0}'</value>
</data>
</root>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ Tato verze se používá zde: {2}.</target>
<target state="translated">indexer</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ Diese Version wird verwendet in: {2}</target>
<target state="translated">Indexer</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ Esta versión se utiliza en: {2}</target>
<target state="translated">indizador</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ Version utilisée dans : {2}</target>
<target state="translated">indexeur</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ Questa versione è usata {2}</target>
<target state="translated">indicizzatore</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ This version used in: {2}</source>
<target state="translated">インデクサー</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ This version used in: {2}</source>
<target state="translated">인덱서</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ Ta wersja jest używana wersja: {2}</target>
<target state="translated">indeksator</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ Essa versão é usada no: {2}</target>
<target state="translated">indexador</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ This version used in: {2}</source>
<target state="translated">индексатор</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ Bu sürüm şurada kullanılır: {2}</target>
<target state="translated">dizin oluşturucu</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ This version used in: {2}</source>
<target state="translated">索引器</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1985,6 +1985,11 @@ This version used in: {2}</source>
<target state="translated">索引子</target>
<note />
</trans-unit>
<trans-unit id="Alias_ambiguous_type_0">
<source>Alias ambiguous type '{0}'</source>
<target state="new">Alias ambiguous type '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
' 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.Collections.Immutable
Imports System.Composition
Imports Microsoft.CodeAnalysis.AliasAmbiguousType
Imports Microsoft.CodeAnalysis.CodeFixes
Namespace Microsoft.CodeAnalysis.VisualBasic.AliasAmbiguousType
<ExportCodeFixProvider(LanguageNames.VisualBasic, Name:=PredefinedCodeFixProviderNames.AliasAmbiguousType), [Shared]>
<ExtensionOrder(After:=PredefinedCodeFixProviderNames.FullyQualify)>
Friend Class VisualBasicAliasAmbiguousTypeCodeFixProvider
Inherits AbstractAliasAmbiguousTypeCodeFixProvider
'BC30561: '<name1>' is ambiguous, imported from the namespaces or types '<name2>'
Private Const BC30561 As String = NameOf(BC30561)
Public Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(BC30561)
Protected Overrides Function GetTextPreviewOfChange(aliasName As String, typeSymbol As ITypeSymbol) As String
Return $"Imports { aliasName } = { typeSymbol.ToNameDisplayString() }"
End Function
End Class
End Namespace
......@@ -82,6 +82,9 @@ public override SyntaxNode NamespaceImportDeclaration(SyntaxNode name)
return SyntaxFactory.UsingDirective((NameSyntax)name);
}
public override SyntaxNode AliasImportDeclaration(string aliasIdentifierName, SyntaxNode name)
=> SyntaxFactory.UsingDirective(SyntaxFactory.NameEquals(aliasIdentifierName), (NameSyntax)name);
public override SyntaxNode NamespaceDeclaration(SyntaxNode name, IEnumerable<SyntaxNode> declarations)
{
return SyntaxFactory.NamespaceDeclaration(
......@@ -3186,9 +3189,9 @@ private static SyntaxNode WithBaseList(SyntaxNode declaration, BaseListSyntax ba
}
}
#endregion
#endregion
#region Remove, Replace, Insert
#region Remove, Replace, Insert
public override SyntaxNode ReplaceNode(SyntaxNode root, SyntaxNode declaration, SyntaxNode newDeclaration)
{
......@@ -3525,9 +3528,9 @@ private static SyntaxNode ShiftTrivia(SyntaxNode root, SyntaxNode node)
internal override bool IsRegularOrDocComment(SyntaxTrivia trivia)
=> trivia.IsRegularOrDocComment();
#endregion
#endregion
#region Statements and Expressions
#region Statements and Expressions
public override SyntaxNode AddEventHandler(SyntaxNode @event, SyntaxNode handler)
{
......@@ -3962,6 +3965,9 @@ public override SyntaxNode QualifiedName(SyntaxNode left, SyntaxNode right)
return SyntaxFactory.QualifiedName((NameSyntax)left, (SimpleNameSyntax)right).WithAdditionalAnnotations(Simplifier.Annotation);
}
public override SyntaxNode NameExpression(INamespaceOrTypeSymbol namespaceOrTypeSymbol)
=> namespaceOrTypeSymbol.GenerateNameSyntax();
public override SyntaxNode TypeExpression(ITypeSymbol typeSymbol)
{
return typeSymbol.GenerateTypeSyntax();
......@@ -4214,6 +4220,6 @@ internal override SyntaxNode RefExpression(SyntaxNode expression)
public override SyntaxNode TupleExpression(IEnumerable<SyntaxNode> arguments)
=> SyntaxFactory.TupleExpression(SyntaxFactory.SeparatedList(arguments.Select(AsArgument)));
#endregion
#endregion
}
}
......@@ -787,6 +787,21 @@ public SyntaxNode NamespaceImportDeclaration(string name)
return NamespaceImportDeclaration(DottedName(name));
}
/// <summary>
/// Creates an alias import declaration.
/// </summary>
/// <param name="aliasIdentifierName">The name of the alias.</param>
/// <param name="symbol">The namespace or type to be aliased.</param>
public SyntaxNode AliasImportDeclaration(string aliasIdentifierName, INamespaceOrTypeSymbol symbol)
=> AliasImportDeclaration(aliasIdentifierName, NameExpression(symbol));
/// <summary>
/// Creates an alias import declaration.
/// </summary>
/// <param name="aliasIdentifierName">The name of the alias.</param>
/// <param name="name">The namespace or type to be aliased.</param>
public abstract SyntaxNode AliasImportDeclaration(string aliasIdentifierName, SyntaxNode name);
/// <summary>
/// Creates an attribute.
/// </summary>
......@@ -1689,6 +1704,13 @@ public SyntaxNode DottedName(string dottedName)
private static readonly char[] s_dotSeparator = new char[] { '.' };
/// <summary>
/// Creates a name that denotes a type or namespace.
/// </summary>
/// <param name="namespaceOrTypeSymbol">The symbol to create a name for.</param>
/// <returns></returns>
public abstract SyntaxNode NameExpression(INamespaceOrTypeSymbol namespaceOrTypeSymbol);
/// <summary>
/// Creates an expression that denotes a type.
/// </summary>
......
Microsoft.CodeAnalysis.Editing.SyntaxGenerator.AliasImportDeclaration(string aliasIdentifierName, Microsoft.CodeAnalysis.INamespaceOrTypeSymbol symbol) -> Microsoft.CodeAnalysis.SyntaxNode
abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.AliasImportDeclaration(string aliasIdentifierName, Microsoft.CodeAnalysis.SyntaxNode name) -> Microsoft.CodeAnalysis.SyntaxNode
abstract Microsoft.CodeAnalysis.Editing.SyntaxGenerator.NameExpression(Microsoft.CodeAnalysis.INamespaceOrTypeSymbol namespaceOrTypeSymbol) -> Microsoft.CodeAnalysis.SyntaxNode
const Microsoft.CodeAnalysis.Classification.ClassificationTypeNames.EnumMemberName = "enum member name" -> string
const Microsoft.CodeAnalysis.Classification.ClassificationTypeNames.FieldName = "field name" -> string
const Microsoft.CodeAnalysis.Classification.ClassificationTypeNames.ConstantName = "constant name" -> string
......@@ -6,4 +9,4 @@ const Microsoft.CodeAnalysis.Classification.ClassificationTypeNames.ParameterNam
const Microsoft.CodeAnalysis.Classification.ClassificationTypeNames.MethodName = "method name" -> string
const Microsoft.CodeAnalysis.Classification.ClassificationTypeNames.ExtensionMethodName = "extension method name" -> string
const Microsoft.CodeAnalysis.Classification.ClassificationTypeNames.PropertyName = "property name" -> string
const Microsoft.CodeAnalysis.Classification.ClassificationTypeNames.EventName = "event name" -> string
\ No newline at end of file
const Microsoft.CodeAnalysis.Classification.ClassificationTypeNames.EventName = "event name" -> string
......@@ -341,6 +341,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Throw New NotSupportedException("ThrowExpressions are not supported in Visual Basic")
End Function
Public Overrides Function NameExpression(namespaceOrTypeSymbol As INamespaceOrTypeSymbol) As SyntaxNode
Return namespaceOrTypeSymbol.GenerateTypeSyntax()
End Function
Public Overrides Function TypeExpression(typeSymbol As ITypeSymbol) As SyntaxNode
Return typeSymbol.GenerateTypeSyntax()
End Function
......@@ -1500,6 +1504,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Return SyntaxFactory.ImportsStatement(SyntaxFactory.SingletonSeparatedList(Of ImportsClauseSyntax)(SyntaxFactory.SimpleImportsClause(DirectCast(name, NameSyntax))))
End Function
Public Overrides Function AliasImportDeclaration(aliasIdentifierName As String, name As SyntaxNode) As SyntaxNode
If TypeOf name Is NameSyntax Then
Return SyntaxFactory.ImportsStatement(SyntaxFactory.SeparatedList(Of ImportsClauseSyntax).Add(
SyntaxFactory.SimpleImportsClause(
SyntaxFactory.ImportAliasClause(aliasIdentifierName),
CType(name, NameSyntax))))
End If
Throw New ArgumentException("name is not a NameSyntax.", NameOf(name))
End Function
Public Overrides Function NamespaceDeclaration(name As SyntaxNode, nestedDeclarations As IEnumerable(Of SyntaxNode)) As SyntaxNode
Dim imps As IEnumerable(Of StatementSyntax) = AsImports(nestedDeclarations)
Dim members As IEnumerable(Of StatementSyntax) = AsNamespaceMembers(nestedDeclarations)
......@@ -2893,7 +2908,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Case SyntaxKind.ProtectedKeyword
If accessibility = Accessibility.Friend Then
accessibility = Accessibility.ProtectedOrFriend
ElseIf accessibility = Accessibility.Private
ElseIf accessibility = Accessibility.Private Then
accessibility = Accessibility.ProtectedAndFriend
Else
accessibility = Accessibility.Protected
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册