提交 cdde5bd4 编写于 作者: C CyrusNajmabadi 提交者: GitHub

Merge pull request #19957 from CyrusNajmabadi/addUsingOOP4

Switch to using a string instead of a full diagnostic.
......@@ -174,11 +174,11 @@ protected override bool CanAddImport(SyntaxNode node, CancellationToken cancella
}
protected override bool CanAddImportForMethod(
Diagnostic diagnostic, ISyntaxFactsService syntaxFacts, SyntaxNode node, out SimpleNameSyntax nameNode)
string diagnosticId, ISyntaxFactsService syntaxFacts, SyntaxNode node, out SimpleNameSyntax nameNode)
{
nameNode = null;
switch (diagnostic.Id)
switch (diagnosticId)
{
case CS7036:
case CS0428:
......@@ -264,18 +264,18 @@ protected override bool CanAddImport(SyntaxNode node, CancellationToken cancella
return true;
}
protected override bool CanAddImportForDeconstruct(Diagnostic diagnostic, SyntaxNode node)
=> diagnostic.Id == CS8129;
protected override bool CanAddImportForDeconstruct(string diagnosticId, SyntaxNode node)
=> diagnosticId == CS8129;
protected override bool CanAddImportForNamespace(Diagnostic diagnostic, SyntaxNode node, out SimpleNameSyntax nameNode)
protected override bool CanAddImportForNamespace(string diagnosticId, SyntaxNode node, out SimpleNameSyntax nameNode)
{
nameNode = null;
return false;
}
protected override bool CanAddImportForQuery(Diagnostic diagnostic, SyntaxNode node)
protected override bool CanAddImportForQuery(string diagnosticId, SyntaxNode node)
{
if (diagnostic.Id != CS1935)
if (diagnosticId != CS1935)
{
return false;
}
......@@ -283,10 +283,10 @@ protected override bool CanAddImportForQuery(Diagnostic diagnostic, SyntaxNode n
return node.AncestorsAndSelf().Any(n => n is QueryExpressionSyntax && !(n.Parent is QueryContinuationSyntax));
}
protected override bool CanAddImportForType(Diagnostic diagnostic, SyntaxNode node, out SimpleNameSyntax nameNode)
protected override bool CanAddImportForType(string diagnosticId, SyntaxNode node, out SimpleNameSyntax nameNode)
{
nameNode = null;
switch (diagnostic.Id)
switch (diagnosticId)
{
case CS0103:
case CS0246:
......
......@@ -7,6 +7,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Host;
......@@ -40,11 +41,11 @@ internal abstract partial class AbstractAddImportCodeFixProvider<TSimpleNameSynt
}
protected abstract bool CanAddImport(SyntaxNode node, CancellationToken cancellationToken);
protected abstract bool CanAddImportForMethod(Diagnostic diagnostic, ISyntaxFactsService syntaxFacts, SyntaxNode node, out TSimpleNameSyntax nameNode);
protected abstract bool CanAddImportForNamespace(Diagnostic diagnostic, SyntaxNode node, out TSimpleNameSyntax nameNode);
protected abstract bool CanAddImportForDeconstruct(Diagnostic diagnostic, SyntaxNode node);
protected abstract bool CanAddImportForQuery(Diagnostic diagnostic, SyntaxNode node);
protected abstract bool CanAddImportForType(Diagnostic diagnostic, SyntaxNode node, out TSimpleNameSyntax nameNode);
protected abstract bool CanAddImportForMethod(string diagnosticId, ISyntaxFactsService syntaxFacts, SyntaxNode node, out TSimpleNameSyntax nameNode);
protected abstract bool CanAddImportForNamespace(string diagnosticId, SyntaxNode node, out TSimpleNameSyntax nameNode);
protected abstract bool CanAddImportForDeconstruct(string diagnosticId, SyntaxNode node);
protected abstract bool CanAddImportForQuery(string diagnosticId, SyntaxNode node);
protected abstract bool CanAddImportForType(string diagnosticId, SyntaxNode node, out TSimpleNameSyntax nameNode);
protected abstract ISet<INamespaceSymbol> GetImportNamespacesInScope(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken);
protected abstract ITypeSymbol GetDeconstructInfo(SemanticModel semanticModel, SyntaxNode node, CancellationToken cancellationToken);
......@@ -98,16 +99,17 @@ private async Task<int> HandleDiagnosticAsync(CodeFixContext context, Diagnostic
if (this.CanAddImport(node, cancellationToken))
{
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var allSymbolReferences = await FindResultsAsync(document, semanticModel, diagnostic, node, cancellationToken).ConfigureAwait(false);
var allSymbolReferences = await FindResultsAsync(document, semanticModel, diagnostic.Id, node, cancellationToken).ConfigureAwait(false);
// Nothing found at all. No need to proceed.
foreach (var reference in allSymbolReferences)
{
cancellationToken.ThrowIfCancellationRequested();
var codeAction = await reference.CreateCodeActionAsync(document, node, placeSystemNamespaceFirst, cancellationToken).ConfigureAwait(false);
if (codeAction != null)
var fixData = await reference.GetFixDataAsync(document, node, placeSystemNamespaceFirst, cancellationToken).ConfigureAwait(false);
if (fixData != null)
{
var codeAction = CreateCodeAction(document, fixData);
context.RegisterCodeFix(codeAction, diagnostic);
count++;
}
......@@ -120,8 +122,35 @@ private async Task<int> HandleDiagnosticAsync(CodeFixContext context, Diagnostic
return count;
}
private CodeAction CreateCodeAction(
Document document, AddImportFixData fixData)
{
switch (fixData.Kind)
{
case AddImportFixKind.ProjectSymbol:
return new ProjectSymbolReferenceCodeAction(document, fixData);
case AddImportFixKind.MetadataSymbol:
return new MetadataSymbolReferenceCodeAction(document, fixData);
case AddImportFixKind.PackageSymbol:
return new ParentInstallPackageCodeAction(document, fixData, GetPackageInstallerService(document));
case AddImportFixKind.ReferenceAssemblySymbol:
return new AssemblyReferenceCodeAction(document, fixData);
}
throw ExceptionUtilities.Unreachable;
}
private IPackageInstallerService GetPackageInstallerService(Document document)
{
var workspaceServices = document.Project.Solution.Workspace.Services;
return _packageInstallerService ?? workspaceServices.GetService<IPackageInstallerService>();
}
private async Task<ImmutableArray<Reference>> FindResultsAsync(
Document document, SemanticModel semanticModel, Diagnostic diagnostic, SyntaxNode node, CancellationToken cancellationToken)
Document document, SemanticModel semanticModel, string diagnosticId, SyntaxNode node, CancellationToken cancellationToken)
{
// Caches so we don't produce the same data multiple times while searching
// all over the solution.
......@@ -129,7 +158,7 @@ private async Task<int> HandleDiagnosticAsync(CodeFixContext context, Diagnostic
var projectToAssembly = new ConcurrentDictionary<Project, AsyncLazy<IAssemblySymbol>>(concurrencyLevel: 2, capacity: project.Solution.ProjectIds.Count);
var referenceToCompilation = new ConcurrentDictionary<PortableExecutableReference, Compilation>(concurrencyLevel: 2, capacity: project.Solution.Projects.Sum(p => p.MetadataReferences.Count));
var finder = new SymbolReferenceFinder(this, document, semanticModel, diagnostic, node, cancellationToken);
var finder = new SymbolReferenceFinder(this, document, semanticModel, diagnosticId, node, cancellationToken);
// Look for exact matches first:
var exactReferences = await FindResultsAsync(projectToAssembly, referenceToCompilation, project, finder, exact: true, cancellationToken: cancellationToken).ConfigureAwait(false);
......
// 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 Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Tags;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.AddImport
{
internal class AddImportFixData
{
public AddImportFixKind Kind { get; }
/// <summary>
/// Text changes to make to the document. Usually just the import to add. May also
/// include a change to the name node the feature was invoked on to fix the casing of it.
/// May be empty for fixes that don't need to add an import and only do something like
/// add a project/metadata reference.
/// </summary>
public ImmutableArray<TextChange> TextChanges { get; }
/// <summary>
/// String to display in the lightbulb menu.
/// </summary>
public string Title { get; private set; }
/// <summary>
/// Tags that control what glyph is displayed in the lightbulb menu.
/// </summary>
public ImmutableArray<string> Tags { get; private set; }
/// <summary>
/// The priority this item should have in the lightbulb list.
/// </summary>
public CodeActionPriority Priority { get; private set; }
#region When adding P2P refrences.
/// <summary>
/// The optional id for a <see cref="Project"/> we'd like to add a reference to.
/// </summary>
public ProjectId ProjectReferenceToAdd { get; private set; }
#endregion
#region When adding a metadata reference
/// <summary>
/// If we're adding <see cref="PortableExecutableReferenceFilePathToAdd"/> then this
/// is the id for the <see cref="Project"/> we can find that <see cref="PortableExecutableReference"/>
/// referenced from.
/// </summary>
public ProjectId PortableExecutableReferenceProjectId { get; private set; }
/// <summary>
/// If we want to add a <see cref="PortableExecutableReference"/> metadata reference, this
/// is the <see cref="PortableExecutableReference.FilePath"/> for it.
/// </summary>
public string PortableExecutableReferenceFilePathToAdd { get; private set; }
#endregion
#region When adding an assembly reference
public string AssemblyReferenceAssemblyName { get; private set; }
public string AssemblyReferenceFullyQualifiedTypeName { get; private set; }
#endregion
#region When adding a package reference
public string PackageSource { get; private set; }
public string PackageName { get; private set; }
public string PackageVersionOpt { get; private set; }
#endregion
private AddImportFixData(
AddImportFixKind kind,
ImmutableArray<TextChange> textChanges)
{
Kind = kind;
TextChanges = textChanges;
Tags = ImmutableArray<string>.Empty;
}
public static AddImportFixData CreateForProjectSymbol(ImmutableArray<TextChange> textChanges, string title, ImmutableArray<string> tags, CodeActionPriority priority, ProjectId projectReferenceToAdd)
{
return new AddImportFixData(AddImportFixKind.ProjectSymbol, textChanges)
{
Title = title,
Tags = tags,
Priority = priority,
ProjectReferenceToAdd = projectReferenceToAdd
};
}
public static AddImportFixData CreateForMetadataSymbol(ImmutableArray<TextChange> textChanges, string title, ImmutableArray<string> tags, CodeActionPriority priority, ProjectId portableExecutableReferenceProjectId, string portableExecutableReferenceFilePathToAdd)
{
return new AddImportFixData(AddImportFixKind.MetadataSymbol, textChanges)
{
Title = title,
Tags = tags,
Priority = priority,
PortableExecutableReferenceProjectId = portableExecutableReferenceProjectId,
PortableExecutableReferenceFilePathToAdd = portableExecutableReferenceFilePathToAdd
};
}
public static AddImportFixData CreateForReferenceAssemblySymbol(ImmutableArray<TextChange> textChanges, string title, string assemblyReferenceAssemblyName, string assemblyReferenceFullyQualifiedTypeName)
{
return new AddImportFixData(AddImportFixKind.ReferenceAssemblySymbol, textChanges)
{
Title = title,
Tags = WellKnownTagArrays.AddReference,
Priority = CodeActionPriority.Low,
AssemblyReferenceAssemblyName = assemblyReferenceAssemblyName,
AssemblyReferenceFullyQualifiedTypeName = assemblyReferenceFullyQualifiedTypeName
};
}
public static AddImportFixData CreateForPackageSymbol(ImmutableArray<TextChange> textChanges, string packageSource, string packageName, string packageVersionOpt)
{
return new AddImportFixData(AddImportFixKind.PackageSymbol, textChanges)
{
PackageSource = packageSource,
Priority = CodeActionPriority.Low,
PackageName = packageName,
PackageVersionOpt = packageVersionOpt,
};
}
}
}
\ 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.
namespace Microsoft.CodeAnalysis.AddImport
{
internal enum AddImportFixKind
{
ProjectSymbol,
MetadataSymbol,
PackageSymbol,
ReferenceAssemblySymbol,
}
}
\ No newline at end of file
......@@ -18,7 +18,9 @@ internal abstract partial class AbstractAddImportCodeFixProvider<TSimpleNameSynt
/// </summary>
private abstract class AddImportCodeAction : CodeAction
{
public sealed override string Title { get; }
protected readonly AddImportFixData FixData;
public override string Title { get; }
public sealed override ImmutableArray<string> Tags { get; }
internal sealed override CodeActionPriority Priority { get; }
......@@ -36,15 +38,15 @@ private abstract class AddImportCodeAction : CodeAction
protected AddImportCodeAction(
Document originalDocument,
ImmutableArray<TextChange> textChanges,
string title, ImmutableArray<string> tags,
CodeActionPriority priority)
AddImportFixData fixData)
{
OriginalDocument = originalDocument;
Title = title;
Tags = tags;
Priority = priority;
_textChanges = textChanges;
FixData = fixData;
Title = fixData.Title;
Tags = fixData.Tags;
Priority = fixData.Priority;
_textChanges = fixData.TextChanges;
}
protected async Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToken)
......
......@@ -2,13 +2,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Tags;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AddImport
......@@ -17,22 +14,14 @@ internal abstract partial class AbstractAddImportCodeFixProvider<TSimpleNameSynt
{
private class AssemblyReferenceCodeAction : AddImportCodeAction
{
private readonly string _assemblyName;
private readonly string _fullyQualifiedTypeName;
private readonly Lazy<string> _lazyResolvedPath;
public AssemblyReferenceCodeAction(
Document originalDocument,
ImmutableArray<TextChange> textChanges,
string title,
string assemblyName,
string fullyQualifiedTypeName)
: base(originalDocument, textChanges, title, WellKnownTagArrays.AddReference, CodeActionPriority.Low)
AddImportFixData fixData)
: base(originalDocument, fixData)
{
_assemblyName = assemblyName;
_fullyQualifiedTypeName = fullyQualifiedTypeName;
Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.ReferenceAssemblySymbol);
_lazyResolvedPath = new Lazy<string>(ResolvePath);
}
......@@ -41,7 +30,9 @@ private string ResolvePath()
var assemblyResolverService = OriginalDocument.Project.Solution.Workspace.Services.GetService<IFrameworkAssemblyPathResolver>();
var assemblyPath = assemblyResolverService?.ResolveAssemblyPath(
OriginalDocument.Project.Id, _assemblyName, _fullyQualifiedTypeName);
OriginalDocument.Project.Id,
FixData.AssemblyReferenceAssemblyName,
FixData.AssemblyReferenceFullyQualifiedTypeName);
return assemblyPath;
}
......
// 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.Threading;
......@@ -9,6 +8,7 @@
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AddImport
{
......@@ -16,6 +16,8 @@ internal abstract partial class AbstractAddImportCodeFixProvider<TSimpleNameSynt
{
private class InstallPackageAndAddImportCodeAction : AddImportCodeAction
{
public override string Title { get; }
/// <summary>
/// The operation that will actually install the nuget package.
/// </summary>
......@@ -23,12 +25,13 @@ private class InstallPackageAndAddImportCodeAction : AddImportCodeAction
public InstallPackageAndAddImportCodeAction(
Document originalDocument,
ImmutableArray<TextChange> textChanges,
AddImportFixData fixData,
string title,
CodeActionPriority priority,
InstallPackageDirectlyCodeActionOperation installOperation)
: base(originalDocument, textChanges, title, ImmutableArray<string>.Empty, priority)
: base(originalDocument, fixData)
{
Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.PackageSymbol);
Title = title;
_installOperation = installOperation;
}
......
// 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.Linq;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AddImport
......@@ -12,38 +9,18 @@ internal abstract partial class AbstractAddImportCodeFixProvider<TSimpleNameSynt
{
private class MetadataSymbolReferenceCodeAction : SymbolReferenceCodeAction
{
/// <summary>
/// If we're adding <see cref="_portableExecutableReferenceFilePathToAdd"/> then this
/// is the id for the <see cref="Project"/> we can find that <see cref="PortableExecutableReference"/>
/// referenced from.
/// </summary>
private readonly ProjectId _portableExecutableReferenceProjectId;
/// <summary>
/// If we want to add a <see cref="PortableExecutableReference"/> metadata reference, this
/// is the <see cref="PortableExecutableReference.FilePath"/> for it.
/// </summary>
private readonly string _portableExecutableReferenceFilePathToAdd;
public MetadataSymbolReferenceCodeAction(
Document originalDocument,
ImmutableArray<TextChange> textChanges,
string title, ImmutableArray<string> tags,
CodeActionPriority priority,
ProjectId portableExecutableReferenceProjectId,
string portableExecutableReferenceFilePathToAdd)
: base(originalDocument, textChanges, title, tags, priority)
public MetadataSymbolReferenceCodeAction(Document originalDocument, AddImportFixData fixData)
: base(originalDocument, fixData)
{
_portableExecutableReferenceProjectId = portableExecutableReferenceProjectId;
_portableExecutableReferenceFilePathToAdd = portableExecutableReferenceFilePathToAdd;
Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.MetadataSymbol);
}
protected override Project UpdateProject(Project project)
{
var projectWithReference = project.Solution.GetProject(_portableExecutableReferenceProjectId);
var projectWithReference = project.Solution.GetProject(FixData.PortableExecutableReferenceProjectId);
var reference = projectWithReference.MetadataReferences
.OfType<PortableExecutableReference>()
.First(pe => pe.FilePath == _portableExecutableReferenceFilePathToAdd);
.First(pe => pe.FilePath == FixData.PortableExecutableReferenceFilePathToAdd);
return project.AddMetadataReference(reference);
}
......
......@@ -2,13 +2,10 @@
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.AddPackage;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Tags;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AddImport
......@@ -35,57 +32,48 @@ private class ParentInstallPackageCodeAction : CodeAction.CodeActionWithNestedAc
/// </summary>
public ParentInstallPackageCodeAction(
Document document,
ImmutableArray<TextChange> textChanges,
IPackageInstallerService installerService,
string source,
string packageName,
string versionOpt)
: base(string.Format(FeaturesResources.Install_package_0, packageName),
CreateNestedActions(document, textChanges, installerService, source, packageName, versionOpt),
AddImportFixData fixData,
IPackageInstallerService installerService)
: base(string.Format(FeaturesResources.Install_package_0, fixData.PackageName),
CreateNestedActions(document, fixData, installerService),
isInlinable: false)
{
Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.PackageSymbol);
}
private static ImmutableArray<CodeAction> CreateNestedActions(
Document document,
ImmutableArray<TextChange> textChanges,
IPackageInstallerService installerService,
string source,
string packageName,
string versionOpt)
AddImportFixData fixData,
IPackageInstallerService installerService)
{
// Determine what versions of this package are already installed in some project
// in this solution. We'll offer to add those specific versions to this project,
// followed by an option to "Find and install latest version."
var installedVersions = installerService.GetInstalledVersions(packageName).NullToEmpty();
var installedVersions = installerService.GetInstalledVersions(fixData.PackageName).NullToEmpty();
var codeActions = ArrayBuilder<CodeAction>.GetInstance();
// First add the actions to install a specific version.
codeActions.AddRange(installedVersions.Select(
v => CreateCodeAction(
document, textChanges, installerService,
source, packageName, versionOpt: v, isLocal: true)));
document, fixData, installerService, versionOpt: v, isLocal: true)));
// Now add the action to install the specific version.
var preferredVersion = versionOpt;
var preferredVersion = fixData.PackageVersionOpt;
if (preferredVersion == null || !installedVersions.Contains(preferredVersion))
{
codeActions.Add(CreateCodeAction(
document, textChanges, installerService,
source, packageName, versionOpt, isLocal: false));
document, fixData, installerService, preferredVersion, isLocal: false));
}
// And finally the action to show the package manager dialog.
codeActions.Add(new InstallWithPackageManagerCodeAction(installerService, packageName));
codeActions.Add(new InstallWithPackageManagerCodeAction(installerService, fixData.PackageName));
return codeActions.ToImmutableAndFree();
}
private static CodeAction CreateCodeAction(
Document document,
ImmutableArray<TextChange> textChanges,
AddImportFixData fixData,
IPackageInstallerService installerService,
string source,
string packageName,
string versionOpt,
bool isLocal)
{
......@@ -96,12 +84,12 @@ private class ParentInstallPackageCodeAction : CodeAction.CodeActionWithNestedAc
: string.Format(FeaturesResources.Install_version_0, versionOpt);
var installOperation = new InstallPackageDirectlyCodeActionOperation(
installerService, document, source, packageName, versionOpt,
installerService, document, fixData.PackageSource, fixData.PackageName, versionOpt,
includePrerelease: false, isLocal: isLocal);
// Nuget hits should always come after other results.
return new InstallPackageAndAddImportCodeAction(
document, textChanges, title, CodeActionPriority.Low, installOperation);
document, fixData, title, installOperation);
}
}
}
......
// 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 Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.AddImport
{
......@@ -16,38 +14,30 @@ internal abstract partial class AbstractAddImportCodeFixProvider<TSimpleNameSynt
/// </summary>
private class ProjectSymbolReferenceCodeAction : SymbolReferenceCodeAction
{
/// <summary>
/// The optional id for a <see cref="Project"/> we'd like to add a reference to.
/// </summary>
private readonly ProjectId _projectReferenceToAdd;
public ProjectSymbolReferenceCodeAction(
Document originalDocument,
ImmutableArray<TextChange> textChanges,
string title, ImmutableArray<string> tags,
CodeActionPriority priority,
ProjectId projectReferenceToAdd)
: base(originalDocument, textChanges, title, tags, priority)
AddImportFixData fixData)
: base(originalDocument, fixData)
{
// We only want to add a project reference if the project the import references
// is different from the project we started from.
if (projectReferenceToAdd != originalDocument.Project.Id)
{
_projectReferenceToAdd = projectReferenceToAdd;
}
Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.ProjectSymbol);
}
private bool ShouldAddProjectReference()
=> FixData.ProjectReferenceToAdd != null && FixData.ProjectReferenceToAdd != OriginalDocument.Project.Id;
internal override bool PerformFinalApplicabilityCheck
=> _projectReferenceToAdd != null;
=> ShouldAddProjectReference();
internal override bool IsApplicable(Workspace workspace)
=> _projectReferenceToAdd != null && workspace.CanAddProjectReference(OriginalDocument.Project.Id, _projectReferenceToAdd);
=> ShouldAddProjectReference() &&
workspace.CanAddProjectReference(
OriginalDocument.Project.Id, FixData.ProjectReferenceToAdd);
protected override Project UpdateProject(Project project)
{
return _projectReferenceToAdd == null
? project
: project.AddProjectReference(new ProjectReference(_projectReferenceToAdd));
return ShouldAddProjectReference()
? project.AddProjectReference(new ProjectReference(FixData.ProjectReferenceToAdd))
: project;
}
}
}
......
// 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;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.AddImport
{
......@@ -20,10 +17,8 @@ private abstract class SymbolReferenceCodeAction : AddImportCodeAction
{
protected SymbolReferenceCodeAction(
Document originalDocument,
ImmutableArray<TextChange> textChanges,
string title, ImmutableArray<string> tags,
CodeActionPriority priority)
: base(originalDocument, textChanges, title, tags, priority)
AddImportFixData fixData)
: base(originalDocument, fixData)
{
}
......
......@@ -2,7 +2,6 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.SymbolSearch;
using Roslyn.Utilities;
......@@ -23,7 +22,7 @@ private partial class AssemblyReference : Reference
_referenceAssemblyWithType = referenceAssemblyWithType;
}
public override async Task<CodeAction> CreateCodeActionAsync(
public override async Task<AddImportFixData> GetFixDataAsync(
Document document, SyntaxNode node, bool placeSystemNamespaceFirst, CancellationToken cancellationToken)
{
var textChanges = await GetTextChangesAsync(
......@@ -33,8 +32,8 @@ private partial class AssemblyReference : Reference
var fullyQualifiedTypeName = string.Join(
".", _referenceAssemblyWithType.ContainingNamespaceNames.Concat(_referenceAssemblyWithType.TypeName));
return new AssemblyReferenceCodeAction(
document, textChanges, title, _referenceAssemblyWithType.AssemblyName, fullyQualifiedTypeName);
return AddImportFixData.CreateForReferenceAssemblySymbol(
textChanges, title, _referenceAssemblyWithType.AssemblyName, fullyQualifiedTypeName);
}
public override bool Equals(object obj)
......
......@@ -49,12 +49,12 @@ private partial class MetadataSymbolReference : SymbolReference
hasExistingImport);
}
protected override CodeAction CreateCodeAction(
protected override AddImportFixData GetFixData(
Document document, ImmutableArray<TextChange> textChanges, string description,
ImmutableArray<string> tags, CodeActionPriority priority)
{
return new MetadataSymbolReferenceCodeAction(
document, textChanges, description, tags, priority,
return AddImportFixData.CreateForMetadataSymbol(
textChanges, description, tags, priority,
_referenceProjectId, _reference.FilePath);
}
......
// 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;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Packaging;
using Roslyn.Utilities;
......@@ -33,14 +31,14 @@ private partial class PackageReference : Reference
_versionOpt = versionOpt;
}
public override async Task<CodeAction> CreateCodeActionAsync(
public override async Task<AddImportFixData> GetFixDataAsync(
Document document, SyntaxNode node, bool placeSystemNamespaceFirst, CancellationToken cancellationToken)
{
var textChanges = await GetTextChangesAsync(
document, node, placeSystemNamespaceFirst, cancellationToken).ConfigureAwait(false);
return new ParentInstallPackageCodeAction(
document, textChanges, _installerService, _source, _packageName, _versionOpt);
return AddImportFixData.CreateForPackageSymbol(
textChanges, _source, _packageName, _versionOpt);
}
public override bool Equals(object obj)
......
......@@ -67,12 +67,12 @@ protected override CodeActionPriority GetPriority(Document document)
return CodeActionPriority.Low;
}
protected override CodeAction CreateCodeAction(
protected override AddImportFixData GetFixData(
Document document, ImmutableArray<TextChange> textChanges, string description,
ImmutableArray<string> tags, CodeActionPriority priority)
{
return new ProjectSymbolReferenceCodeAction(
document, textChanges, description, tags, priority, _project.Id);
return AddImportFixData.CreateForProjectSymbol(
textChanges, description, tags, priority, _project.Id);
}
protected override (string description, bool hasExistingImport) GetDescription(
......
......@@ -117,7 +117,7 @@ public override int GetHashCode()
return (newContextNode, newDocument);
}
public abstract Task<CodeAction> CreateCodeActionAsync(
public abstract Task<AddImportFixData> GetFixDataAsync(
Document document, SyntaxNode node, bool placeSystemNamespaceFirst, CancellationToken cancellationToken);
protected async Task<ImmutableArray<TextChange>> GetTextChangesAsync(
......
......@@ -71,7 +71,7 @@ public override int GetHashCode()
return textChanges.ToImmutableArray();
}
public sealed override async Task<CodeAction> CreateCodeActionAsync(
public sealed override async Task<AddImportFixData> GetFixDataAsync(
Document document, SyntaxNode node,
bool placeSystemNamespaceFirst, CancellationToken cancellationToken)
{
......@@ -97,12 +97,12 @@ public override int GetHashCode()
var textChanges = await GetTextChangesAsync(
document, node, placeSystemNamespaceFirst, hasExistingImport, cancellationToken).ConfigureAwait(false);
return CreateCodeAction(
return GetFixData(
document, textChanges.ToImmutableArray(), description,
GetTags(document), GetPriority(document));
}
protected abstract CodeAction CreateCodeAction(
protected abstract AddImportFixData GetFixData(
Document document, ImmutableArray<TextChange> textChanges,
string description, ImmutableArray<string> tags, CodeActionPriority priority);
......
......@@ -20,7 +20,7 @@ private partial class SymbolReferenceFinder
{
private const string AttributeSuffix = nameof(Attribute);
private readonly Diagnostic _diagnostic;
private readonly string _diagnosticId;
private readonly Document _document;
private readonly SemanticModel _semanticModel;
......@@ -35,13 +35,13 @@ private partial class SymbolReferenceFinder
public SymbolReferenceFinder(
AbstractAddImportCodeFixProvider<TSimpleNameSyntax> owner,
Document document, SemanticModel semanticModel,
Diagnostic diagnostic, SyntaxNode node,
string diagnosticId, SyntaxNode node,
CancellationToken cancellationToken)
{
_owner = owner;
_document = document;
_semanticModel = semanticModel;
_diagnostic = diagnostic;
_diagnosticId = diagnosticId;
_node = node;
_containingType = semanticModel.GetEnclosingNamedType(node.SpanStart, cancellationToken);
......@@ -155,7 +155,7 @@ private ImmutableArray<SymbolReference> DeDupeAndSortReferences(ImmutableArray<S
private async Task<ImmutableArray<SymbolReference>> GetReferencesForMatchingTypesAsync(SearchScope searchScope)
{
searchScope.CancellationToken.ThrowIfCancellationRequested();
if (!_owner.CanAddImportForType(_diagnostic, _node, out var nameNode))
if (!_owner.CanAddImportForType(_diagnosticId, _node, out var nameNode))
{
return ImmutableArray<SymbolReference>.Empty;
}
......@@ -223,7 +223,7 @@ private async Task<ImmutableArray<SymbolReference>> GetReferencesForMatchingType
SearchScope searchScope)
{
searchScope.CancellationToken.ThrowIfCancellationRequested();
if (_owner.CanAddImportForNamespace(_diagnostic, _node, out var nameNode))
if (_owner.CanAddImportForNamespace(_diagnosticId, _node, out var nameNode))
{
_syntaxFacts.GetNameAndArityOfSimpleName(nameNode, out var name, out var arity);
......@@ -250,7 +250,7 @@ private async Task<ImmutableArray<SymbolReference>> GetReferencesForMatchingType
SearchScope searchScope)
{
searchScope.CancellationToken.ThrowIfCancellationRequested();
if (_owner.CanAddImportForMethod(_diagnostic, _syntaxFacts, _node, out var nameNode) &&
if (_owner.CanAddImportForMethod(_diagnosticId, _syntaxFacts, _node, out var nameNode) &&
nameNode != null)
{
// We have code like "Color.Black". "Color" bound to a 'Color Color' property, and
......@@ -310,7 +310,7 @@ private bool HasAccessibleStaticFieldOrProperty(INamedTypeSymbol namedType, stri
private async Task<ImmutableArray<SymbolReference>> GetReferencesForMatchingExtensionMethodsAsync(SearchScope searchScope)
{
searchScope.CancellationToken.ThrowIfCancellationRequested();
if (_owner.CanAddImportForMethod(_diagnostic, _syntaxFacts, _node, out var nameNode) &&
if (_owner.CanAddImportForMethod(_diagnosticId, _syntaxFacts, _node, out var nameNode) &&
nameNode != null)
{
searchScope.CancellationToken.ThrowIfCancellationRequested();
......@@ -368,7 +368,7 @@ private async Task<ImmutableArray<SymbolReference>> GetReferencesForMatchingExte
private async Task<ImmutableArray<SymbolReference>> GetReferencesForCollectionInitializerMethodsAsync(SearchScope searchScope)
{
searchScope.CancellationToken.ThrowIfCancellationRequested();
if (!_owner.CanAddImportForMethod(_diagnostic, _syntaxFacts, _node, out var nameNode))
if (!_owner.CanAddImportForMethod(_diagnosticId, _syntaxFacts, _node, out var nameNode))
{
return ImmutableArray<SymbolReference>.Empty;
}
......@@ -403,7 +403,7 @@ private async Task<ImmutableArray<SymbolReference>> GetReferencesForQueryPattern
{
searchScope.CancellationToken.ThrowIfCancellationRequested();
if (_owner.CanAddImportForQuery(_diagnostic, _node))
if (_owner.CanAddImportForQuery(_diagnosticId, _node))
{
var type = _owner.GetQueryClauseInfo(_semanticModel, _node, searchScope.CancellationToken);
if (type != null)
......@@ -426,7 +426,7 @@ private async Task<ImmutableArray<SymbolReference>> GetReferencesForDeconstructA
{
searchScope.CancellationToken.ThrowIfCancellationRequested();
if (_owner.CanAddImportForDeconstruct(_diagnostic, _node))
if (_owner.CanAddImportForDeconstruct(_diagnosticId, _node))
{
var type = _owner.GetDeconstructInfo(_semanticModel, _node, searchScope.CancellationToken);
if (type != null)
......
......@@ -23,7 +23,7 @@ private partial class SymbolReferenceFinder
return;
}
if (!_owner.CanAddImportForType(_diagnostic, _node, out var nameNode))
if (!_owner.CanAddImportForType(_diagnosticId, _node, out var nameNode))
{
return;
}
......@@ -63,7 +63,7 @@ private partial class SymbolReferenceFinder
var workspaceServices = _document.Project.Solution.Workspace.Services;
var symbolSearchService = _owner._symbolSearchService ?? workspaceServices.GetService<ISymbolSearchService>();
var installerService = _owner._packageInstallerService ?? workspaceServices.GetService<IPackageInstallerService>();
var installerService = _owner.GetPackageInstallerService(_document);
var language = _document.Project.Language;
......
......@@ -99,6 +99,8 @@
<Compile Include="..\..\..\Compilers\Shared\DesktopShim.cs">
<Link>Shared\Utilities\DesktopShim.cs</Link>
</Compile>
<Compile Include="AddImport\AddImportFixData.cs" />
<Compile Include="AddImport\AddImportFixKind.cs" />
<Compile Include="AddImport\CodeActions\AddImportCodeAction.cs" />
<Compile Include="AddImport\CodeActions\AssemblyReferenceCodeAction.cs" />
<Compile Include="AddImport\CodeActions\MetadataSymbolReferenceCodeAction.cs" />
......
......@@ -120,11 +120,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport
End Function
Protected Overrides Function CanAddImportForMethod(
diagnostic As Diagnostic,
diagnosticId As String,
syntaxFacts As ISyntaxFactsService,
node As SyntaxNode,
ByRef nameNode As SimpleNameSyntax) As Boolean
Select Case diagnostic.Id
Select Case diagnosticId
Case BC30456, BC30390, BC42309, BC30451
Exit Select
Case BC30512
......@@ -177,8 +177,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport
Return True
End Function
Protected Overrides Function CanAddImportForNamespace(diagnostic As Diagnostic, node As SyntaxNode, ByRef nameNode As SimpleNameSyntax) As Boolean
Select Case diagnostic.Id
Protected Overrides Function CanAddImportForNamespace(diagnosticId As String, node As SyntaxNode, ByRef nameNode As SimpleNameSyntax) As Boolean
Select Case diagnosticId
Case BC30002, BC30451
Exit Select
Case Else
......@@ -188,13 +188,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport
Return CanAddImportForTypeOrNamespaceCore(node, nameNode)
End Function
Protected Overrides Function CanAddImportForDeconstruct(diagnostic As Diagnostic, node As SyntaxNode) As Boolean
Protected Overrides Function CanAddImportForDeconstruct(diagnosticId As String, node As SyntaxNode) As Boolean
' Not supported yet.
Return False
End Function
Protected Overrides Function CanAddImportForQuery(diagnostic As Diagnostic, node As SyntaxNode) As Boolean
If diagnostic.Id <> BC36593 Then
Protected Overrides Function CanAddImportForQuery(diagnosticId As String, node As SyntaxNode) As Boolean
If diagnosticId <> BC36593 Then
Return False
End If
......@@ -208,8 +208,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.AddImport
End Function
Protected Overrides Function CanAddImportForType(
diagnostic As Diagnostic, node As SyntaxNode, ByRef nameNode As SimpleNameSyntax) As Boolean
Select Case diagnostic.Id
diagnosticId As String, node As SyntaxNode, ByRef nameNode As SimpleNameSyntax) As Boolean
Select Case diagnosticId
Case BC30002, BC30451, BC32042, BC32045, BC30389, BC31504, BC36610, BC30182
Exit Select
Case BC42309
......
......@@ -540,7 +540,7 @@ public IEnumerable<Project> GetProjectsWithInstalledPackage(Solution solution, s
{
var state = kvp.Value;
var versionSet = state.InstalledPackageToVersion[packageName];
if (versionSet.Contains(packageName))
if (versionSet.Contains(version))
{
var project = solution.GetProject(kvp.Key);
if (project != null)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册