提交 1dd8ba21 编写于 作者: C CyrusNajmabadi

Don't offer p2p references if the underlying project system says they would not be allowed.

上级 3b872310
......@@ -283,6 +283,9 @@
<Compile Include="Implementation\Classification\SemanticClassificationBufferTaggerProvider.cs" />
<Compile Include="Implementation\Classification\SemanticClassificationBufferTaggerProvider.Tagger.cs" />
<Compile Include="Implementation\Classification\SemanticClassificationUtilities.cs" />
<Compile Include="Implementation\CodeFixes\CodeFixService.cs" />
<Compile Include="Implementation\CodeFixes\CodeFixService.ProjectCodeFixProvider.cs" />
<Compile Include="Implementation\CodeFixes\ICodeFixService.cs" />
<Compile Include="Implementation\GoToImplementation\AbstractGoToImplementationService.cs" />
<Compile Include="Implementation\GoToImplementation\IGoToImplementationService.cs" />
<Compile Include="Implementation\Intellisense\Completion\OptionSetExtensions.cs" />
......
......@@ -22,11 +22,12 @@
namespace Microsoft.CodeAnalysis.CodeFixes
{
using Editor.Shared.Utilities;
using DiagnosticId = String;
using LanguageKind = String;
[Export(typeof(ICodeFixService)), Shared]
internal partial class CodeFixService : ICodeFixService
internal partial class CodeFixService : ForegroundThreadAffinitizedObject, ICodeFixService
{
private readonly IDiagnosticAnalyzerService _diagnosticService;
......@@ -52,6 +53,7 @@ internal partial class CodeFixService : ICodeFixService
[ImportMany]IEnumerable<Lazy<IErrorLoggerService>> loggers,
[ImportMany]IEnumerable<Lazy<CodeFixProvider, CodeChangeProviderMetadata>> fixers,
[ImportMany]IEnumerable<Lazy<ISuppressionFixProvider, CodeChangeProviderMetadata>> suppressionProviders)
: base(assertIsForeground: false)
{
_errorLoggers = loggers;
_diagnosticService = service;
......@@ -407,12 +409,28 @@ private async Task<bool> ContainsAnyFix(Document document, DiagnosticData diagno
foreach (var fixer in allFixers)
{
await extensionManager.PerformActionAsync(fixer, () => fixer.RegisterCodeFixesAsync(context) ?? SpecializedTasks.EmptyTask).ConfigureAwait(false);
if (!fixes.Any())
foreach (var fix in fixes)
{
continue;
}
if (!fix.Action.PerformFinalApplicabilityCheck)
{
return true;
}
return true;
// Have to see if this fix is still applicable. Jump to the foreground thread
// to make that check.
var applicable = await Task.Factory.StartNew(() =>
{
this.AssertIsForeground();
return fix.Action.IsApplicable(document.Project.Solution.Workspace);
},
cancellationToken, TaskCreationOptions.None, this.ForegroundTaskScheduler).ConfigureAwait(false);
this.AssertIsBackground();
if (applicable)
{
return true;
}
}
}
return false;
......
......@@ -51,6 +51,11 @@ public override int GetHashCode()
public abstract Glyph? GetGlyph(Document document);
public abstract Solution UpdateSolution(Document newDocument);
internal virtual Func<Workspace, bool> GetIsApplicableCheck(Project contextProject)
{
return null;
}
}
private class ProjectSymbolReference : SymbolReference
......@@ -86,6 +91,17 @@ public override Solution UpdateSolution(Document newDocument)
return newProject.Solution;
}
internal override Func<Workspace, bool> GetIsApplicableCheck(Project contextProject)
{
if (contextProject.Id == _project.Id)
{
// no need to do applicability check for a reference in our own project.
return null;
}
return workspace => workspace.CanAddProjectReference(contextProject.Id, _project.Id);
}
}
private class MetadataSymbolReference : SymbolReference
......
......@@ -108,7 +108,8 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
if (description != null)
{
var action = new MyCodeAction(description, reference.GetGlyph(document),
c => this.AddImportAndReferenceAsync(node, reference, document, placeSystemNamespaceFirst, c));
c => this.AddImportAndReferenceAsync(node, reference, document, placeSystemNamespaceFirst, c),
reference.GetIsApplicableCheck(document.Project));
context.RegisterCodeFix(action, diagnostic);
}
}
......@@ -391,14 +392,27 @@ private static bool NotNull(SymbolReference reference)
private class MyCodeAction : CodeAction.SolutionChangeAction
{
private readonly Glyph? _glyph;
private readonly Func<Workspace, bool> _isApplicable;
public MyCodeAction(string title, Glyph? glyph, Func<CancellationToken, Task<Solution>> createChangedSolution) :
public MyCodeAction(
string title,
Glyph? glyph,
Func<CancellationToken, Task<Solution>> createChangedSolution,
Func<Workspace, bool> isApplicable = null) :
base(title, createChangedSolution, equivalenceKey: title)
{
_glyph = glyph;
_isApplicable = isApplicable;
}
internal override int? Glyph => _glyph.HasValue ? (int)_glyph.Value : (int?)null;
internal override bool PerformFinalApplicabilityCheck => _isApplicable != null;
internal override bool IsApplicable(Workspace workspace)
{
return _isApplicable == null ? true : _isApplicable(workspace);
}
}
private struct SearchResult<T> where T : ISymbol
......
......@@ -105,13 +105,10 @@
<Compile Include="CodeFixes\FixAllOccurrences\FixAllCodeActionContext.DiagnosticProvider.cs" />
<Compile Include="CodeFixes\FixAllOccurrences\FixAllProviderInfo.cs" />
<Compile Include="CodeFixes\FixAllOccurrences\FixAllCodeActionContext.cs" />
<Compile Include="CodeFixes\CodeFixService.cs" />
<Compile Include="CodeFixes\CodeFixService.ProjectCodeFixProvider.cs" />
<Compile Include="CodeFixes\FirstDiagnosticResult.cs" />
<Compile Include="CodeFixes\FixAllOccurrences\IFixMultipleOccurrencesService.cs" />
<Compile Include="CodeFixes\FullyQualify\AbstractFullyQualifyCodeFixProvider.cs" />
<Compile Include="CodeFixes\GenerateMember\AbstractGenerateMemberCodeFixProvider.cs" />
<Compile Include="CodeFixes\ICodeFixService.cs" />
<Compile Include="CodeFixes\ICodeFixProviderFactory.cs" />
<Compile Include="CodeFixes\FixAllOccurrences\IFixAllGetFixesService.cs" />
<Compile Include="CodeFixes\Iterator\AbstractIteratorCodeFixProvider.cs" />
......
......@@ -1047,6 +1047,66 @@ internal void OnAdditionalDocumentTextUpdatedOnDisk(DocumentId documentId)
return this.ServiceProvider.GetService(typeof(TService)) as TInterface;
}
internal override bool CanAddProjectReference(ProjectId referencingProject, ProjectId referencedProject)
{
_foregroundObject.AssertIsForeground();
IVsHierarchy referencingHierarchy;
IVsHierarchy referencedHierarchy;
if (!TryGetHierarchy(referencingProject, out referencingHierarchy) ||
!TryGetHierarchy(referencedProject, out referencedHierarchy))
{
return false;
}
var referencingProjectFlavor3 = referencingHierarchy as IVsProjectFlavorReferences3;
var referencedProjectFlavor3 = referencedHierarchy as IVsProjectFlavorReferences3;
if (referencingProjectFlavor3 != null && referencedProjectFlavor3 != null)
{
const int ContextFlags = (int)__VSQUERYFLAVORREFERENCESCONTEXT.VSQUERYFLAVORREFERENCESCONTEXT_RefreshReference;
uint canAddProjectReference;
uint canBeReferenced;
string unused;
if (ErrorHandler.Failed(referencingProjectFlavor3.QueryAddProjectReferenceEx(referencedHierarchy, ContextFlags, out canAddProjectReference, out unused)) ||
ErrorHandler.Failed(referencedProjectFlavor3.QueryCanBeReferencedEx(referencingHierarchy, ContextFlags, out canBeReferenced, out unused)))
{
// Something went wrong even trying to see if the reference would be allowed.
// Assume it won't be allowed.
return false;
}
if (canAddProjectReference == (uint)__VSREFERENCEQUERYRESULT.REFERENCE_DENY ||
canBeReferenced == (uint)__VSREFERENCEQUERYRESULT.REFERENCE_DENY)
{
// If either of them deny then add a project reference is not allowed.
return false;
}
if (canAddProjectReference == (int)__VSREFERENCEQUERYRESULT.REFERENCE_ALLOW ||
canBeReferenced == (int)__VSREFERENCEQUERYRESULT.REFERENCE_ALLOW)
{
// At least one allows this, and neither deny. So this is allowed.
return true;
}
// Both are unknown if they should allow this. Fall through and use the regular
// matrix check.
}
// Normal matrix check for projects that don't implement IVsProjectFlavorReferences3.
var referenceManager = GetVsService<SVsReferenceManager, IVsReferenceManager>();
if (referenceManager == null)
{
return false;
}
var result = referenceManager.QueryCanReferenceProject(referencingHierarchy, referencedHierarchy);
return result == (uint)__VSREFERENCEQUERYRESULT.REFERENCE_ALLOW ||
result == (uint)__VSREFERENCEQUERYRESULT.REFERENCE_UNKNOWN;
}
/// <summary>
/// A trivial implementation of <see cref="IVisualStudioWorkspaceHost" /> that just
/// forwards the calls down to the underlying Workspace.
......
......@@ -255,6 +255,8 @@ protected virtual async Task<Document> PostProcessChangesAsync(Document document
return document;
}
internal virtual bool PerformFinalApplicabilityCheck => false;
/// <summary>
/// Called by the CodeActions on the UI thread to determine if the CodeAction is still
/// applicable and should be presented to the user. CodeActions can override this if they
......
......@@ -878,6 +878,15 @@ public virtual bool CanApplyChange(ApplyChangesKind feature)
return false;
}
/// <summary>
/// Returns <code>true</code> if a reference to referencedProject can be added to
/// referencingProject. <code>false</code> otherwise.
/// </summary>
internal virtual bool CanAddProjectReference(ProjectId referencingProject, ProjectId referencedProject)
{
return false;
}
/// <summary>
/// Apply changes made to a solution back to the workspace.
///
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册