提交 2365f288 编写于 作者: S Shyam N

Make defaultValue a required parameter

for ExtensionManager.PerformFunction*()

Fixes internal TFS bug 1166482.

In cases where a fix provider throws an unhandled exception, ExtensionManager.PerformFunction*() was correctly handling the exception by displaying an 'info bar' alerting the user about the crash. However, because the defaultValue parameter for ExtensionManager.PerformFunction*() was optional, in some cases, we would end up returning default(ImmutableArray<T>) as opposed to ImmutableArray<T>.Empty to the VS platform's light bulb  engine. The difference is significant in this case since ImmutableArray<T> is a struct and since it is returned as an IEnumerable<T>. The platform code checks whether the returned IEnumerable<T> is 'null' (which it won't be) and then calls '.Any()' on it and this results in an InvalidOperationException from ImmutableArray<T>...

In addition to supplying the correct defaultValue of ImmutableArray<T>.Empty to avoid the above crash, I am also making defaultValue a required parameter (so that future consumers of ExtensionManager.PerformFunction*() don't run into this problem).
上级 f07c32aa
......@@ -122,7 +122,7 @@ public string DisplayText
// Underscores will become an accelerator in the VS smart tag. So we double all
// underscores so they actually get represented as an underscore in the UI.
var extensionManager = this.Workspace.Services.GetService<IExtensionManager>();
var text = extensionManager.PerformFunction(Provider, () => CodeAction.Title, string.Empty);
var text = extensionManager.PerformFunction(Provider, () => CodeAction.Title, defaultValue: string.Empty);
return text.Replace("_", "__");
}
}
......@@ -153,7 +153,7 @@ public virtual bool HasPreview
// 'null' / empty collection from within GetPreviewAsync().
return true;
}
}
}
public virtual async Task<object> GetPreviewAsync(CancellationToken cancellationToken)
......@@ -184,7 +184,7 @@ public virtual async Task<object> GetPreviewAsync(CancellationToken cancellation
}
// GetPreviewPane() below needs to run on UI thread. We use ConfigureAwait(true) to stay on the UI thread.
}).ConfigureAwait(true);
}, defaultValue: null).ConfigureAwait(true);
var previewPaneService = Workspace.Services.GetService<IPreviewPaneService>();
if (previewPaneService == null)
......@@ -216,7 +216,7 @@ public virtual bool HasActionSets
{
return false;
}
}
}
public virtual Task<IEnumerable<SuggestedActionSet>> GetActionSetsAsync(CancellationToken cancellationToken)
{
......
......@@ -50,8 +50,8 @@ public async override Task<IEnumerable<SuggestedActionSet>> GetActionSetsAsync(C
// Light bulb will always invoke this property on the UI thread.
AssertIsForeground();
if (_actionSets == null)
{
if (_actionSets == null)
{
var extensionManager = this.Workspace.Services.GetService<IExtensionManager>();
_actionSets = await extensionManager.PerformFunctionAsync(Provider, async () =>
......@@ -75,12 +75,12 @@ public async override Task<IEnumerable<SuggestedActionSet>> GetActionSetsAsync(C
return builder.ToImmutable();
// We use ConfigureAwait(true) to stay on the UI thread.
}).ConfigureAwait(true);
}
return _actionSets;
}, defaultValue: ImmutableArray<SuggestedActionSet>.Empty).ConfigureAwait(true);
}
return _actionSets;
}
private async Task<SuggestedActionSet> GetPreviewChangesSuggestedActionSetAsync(CancellationToken cancellationToken)
{
var previewResult = await GetPreviewResultAsync(cancellationToken).ConfigureAwait(true);
......
......@@ -220,6 +220,7 @@ public async Task<IEnumerable<CodeFixCollection>> GetFixesAsync(Document documen
await task.ConfigureAwait(false);
return fixes;
};
await AppendFixesOrSuppressionsAsync(document, span, diagnostics, result, fixer,
hasFix, getFixes, cancellationToken).ConfigureAwait(false);
}
......@@ -261,8 +262,10 @@ public async Task<IEnumerable<CodeFixCollection>> GetFixesAsync(Document documen
// this can happen for suppression case where all diagnostics can't be suppressed
return result;
}
var extensionManager = document.Project.Solution.Workspace.Services.GetService<IExtensionManager>();
var fixes = await extensionManager.PerformFunctionAsync(fixer, () => getFixes(diagnostics)).ConfigureAwait(false);
var fixes = await extensionManager.PerformFunctionAsync(fixer, () => getFixes(diagnostics), defaultValue: SpecializedCollections.EmptyEnumerable<CodeFix>()).ConfigureAwait(false);
if (fixes != null && fixes.Any())
{
FixAllCodeActionContext fixAllContext = null;
......@@ -270,7 +273,8 @@ public async Task<IEnumerable<CodeFixCollection>> GetFixesAsync(Document documen
if (codeFixProvider != null)
{
// If the codeFixProvider supports fix all occurrences, then get the corresponding FixAllProviderInfo and fix all context.
var fixAllProviderInfo = extensionManager.PerformFunction(codeFixProvider, () => ImmutableInterlocked.GetOrAdd(ref _fixAllProviderMap, codeFixProvider, FixAllProviderInfo.Create));
var fixAllProviderInfo = extensionManager.PerformFunction(codeFixProvider, () => ImmutableInterlocked.GetOrAdd(ref _fixAllProviderMap, codeFixProvider, FixAllProviderInfo.Create), defaultValue: null);
if (fixAllProviderInfo != null)
{
fixAllContext = new FixAllCodeActionContext(document, fixAllProviderInfo, codeFixProvider, diagnostics, this.GetDocumentDiagnosticsAsync, this.GetProjectDiagnosticsAsync, cancellationToken);
......@@ -409,7 +413,7 @@ private ImmutableArray<DiagnosticId> GetFixableDiagnosticIds(CodeFixProvider fix
return extensionManager.PerformFunction(
fixer,
() => ImmutableInterlocked.GetOrAdd(ref _fixerToFixableIdsMap, fixer, f => f.FixableDiagnosticIds),
ImmutableArray<DiagnosticId>.Empty);
defaultValue: ImmutableArray<DiagnosticId>.Empty);
}
try
......
......@@ -36,7 +36,7 @@ public static void PerformAction(this IExtensionManager extensionManager, object
this IExtensionManager extensionManager,
object extension,
Func<T> function,
T defaultValue = default(T))
T defaultValue)
{
try
{
......@@ -84,7 +84,7 @@ public static void PerformAction(this IExtensionManager extensionManager, object
this IExtensionManager extensionManager,
object extension,
Func<Task<T>> function,
T defaultValue = default(T))
T defaultValue)
{
try
{
......@@ -115,7 +115,7 @@ public static void PerformAction(this IExtensionManager extensionManager, object
t1 =>
{
var query = from e in extensions
let types = extensionManager.PerformFunction(e, () => nodeTypeGetter(e))
let types = extensionManager.PerformFunction(e, () => nodeTypeGetter(e), defaultValue: SpecializedCollections.EmptyEnumerable<Type>())
where types != null
where !types.Any() || types.Any(t2 => t1 == t2 || t1.GetTypeInfo().IsSubclassOf(t2))
select e;
......@@ -134,7 +134,7 @@ public static void PerformAction(this IExtensionManager extensionManager, object
k =>
{
var query = from e in extensions
let kinds = extensionManager.PerformFunction(e, () => tokenKindGetter(e))
let kinds = extensionManager.PerformFunction(e, () => tokenKindGetter(e), defaultValue: SpecializedCollections.EmptyEnumerable<int>())
where kinds != null
where !kinds.Any() || kinds.Contains(k)
select e;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册