提交 5fbc5770 编写于 作者: J Jonathon Marolf 提交者: GitHub

Merge pull request #15669 from jmarolf/bugfix/catch-all-editorconfig-exceptions

handle exceptions that may occur while fetching editorconfig settings
......@@ -63,6 +63,8 @@
<Compile Include="IntelliSense\Completion\Presentation\Roslyn15CompletionSet.cs" />
<Compile Include="IntelliSense\Completion\Presentation\VisualStudio15CompletionSetFactory.cs" />
<Compile Include="IntelliSense\Completion\Presentation\VisualStudio15CompletionSet.cs" />
<Compile Include="Options\EditorConfigDocumentOptionsProvider.DocumentOptions.cs" />
<Compile Include="Options\EditorConfigDocumentOptionsProvider.EmptyCodingConventionContext.cs" />
<Compile Include="Structure\BlockContextProvider.cs" />
<Compile Include="Structure\VisualStudio15StructureTaggerProvider.cs" />
<Compile Include="Options\EditorConfigDocumentOptionsProviderFactory.cs" />
......
using System;
using System.Linq;
using Microsoft.CodeAnalysis.Options;
using Microsoft.VisualStudio.CodingConventions;
namespace Microsoft.CodeAnalysis.Editor.Options
{
internal sealed partial class EditorConfigDocumentOptionsProvider : IDocumentOptionsProvider
{
private class DocumentOptions : IDocumentOptions
{
private ICodingConventionsSnapshot _codingConventionSnapshot;
public DocumentOptions(ICodingConventionsSnapshot codingConventionSnapshot)
{
_codingConventionSnapshot = codingConventionSnapshot;
}
public bool TryGetDocumentOption(Document document, OptionKey option, out object value)
{
var editorConfigPersistence = option.Option.StorageLocations.OfType<EditorConfigStorageLocation>().SingleOrDefault();
if (editorConfigPersistence == null)
{
value = null;
return false;
}
if (_codingConventionSnapshot.TryGetConventionValue(editorConfigPersistence.KeyName, out value))
{
try
{
value = editorConfigPersistence.ParseValue(value.ToString(), option.Option.Type);
return true;
}
catch (Exception)
{
// TODO: report this somewhere?
return false;
}
}
else
{
return false;
}
}
}
}
}
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.CodingConventions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Options
{
internal sealed partial class EditorConfigDocumentOptionsProvider
{
private class EmptyCodingConventionContext : ICodingConventionContext
{
public static ICodingConventionContext Instance { get; } = new EmptyCodingConventionContext();
public ICodingConventionsSnapshot CurrentConventions { get; } = EmptyCodingConventionsSnapshot.Instance;
#pragma warning disable CS0067
public event CodingConventionsChangedAsyncEventHandler CodingConventionsChangedAsync;
#pragma warning restore CS0067
public void Dispose() { }
public Task WriteConventionValueAsync(string conventionName, string conventionValue, CancellationToken cancellationToken)
=> Task.CompletedTask;
private class EmptyCodingConventionsSnapshot : ICodingConventionsSnapshot
{
public static EmptyCodingConventionsSnapshot Instance { get; } = new EmptyCodingConventionsSnapshot();
public IReadOnlyDictionary<string, object> AllRawConventions { get; } =
(IReadOnlyDictionary<string, object>)SpecializedCollections.EmptyDictionary<string, object>();
public IUniversalCodingConventions UniversalConventions { get; } = EmptyUniversalCodingConventions.Instance;
public int Version => 0;
public bool TryGetConventionValue<T>(string conventionName, out T conventionValue)
{
conventionValue = default(T);
return false;
}
private class EmptyUniversalCodingConventions : IUniversalCodingConventions
{
public static EmptyUniversalCodingConventions Instance { get; } = new EmptyUniversalCodingConventions();
public bool TryGetAllowTrailingWhitespace(out bool allowTrailingWhitespace)
{
allowTrailingWhitespace = false;
return false;
}
public bool TryGetEncoding(out Encoding encoding)
{
encoding = null;
return false;
}
public bool TryGetIndentSize(out int indentSize)
{
indentSize = default(int);
return false;
}
public bool TryGetIndentStyle(out IndentStyle indentStyle)
{
indentStyle = default(IndentStyle);
return false;
}
public bool TryGetLineEnding(out string lineEnding)
{
lineEnding = null;
return false;
}
public bool TryGetRequireFinalNewline(out bool requireFinalNewline)
{
requireFinalNewline = false;
return false;
}
public bool TryGetTabWidth(out int tabWidth)
{
tabWidth = default(int);
return false;
}
}
}
}
}
}
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.VisualStudio.CodingConventions;
using System;
namespace Microsoft.CodeAnalysis.Editor.Options
{
// NOTE: this type depends on Dev15 assemblies, which is why the type is in EditorFeatures.Next. But, that library
// is rehostable and once we move .editorconfig support fully through the system, it should be moved to Workspaces
// or perhaps even lower.
internal sealed class EditorConfigDocumentOptionsProvider : IDocumentOptionsProvider
internal sealed partial class EditorConfigDocumentOptionsProvider : IDocumentOptionsProvider
{
private readonly object _gate = new object();
......@@ -36,9 +35,7 @@ private void Workspace_DocumentClosed(object sender, DocumentEventArgs e)
{
lock (_gate)
{
Task<ICodingConventionContext> contextTask;
if (_openDocumentContexts.TryGetValue(e.Document.Id, out contextTask))
if (_openDocumentContexts.TryGetValue(e.Document.Id, out var contextTask))
{
_openDocumentContexts.Remove(e.Document.Id);
......@@ -56,7 +53,7 @@ private void Workspace_DocumentOpened(object sender, DocumentEventArgs e)
{
lock (_gate)
{
_openDocumentContexts.Add(e.Document.Id, Task.Run(() => _codingConventionsManager.GetConventionContextAsync(e.Document.FilePath, CancellationToken.None)));
_openDocumentContexts.Add(e.Document.Id, Task.Run(() => GetConventionContextAsync(e.Document.FilePath, CancellationToken.None)));
}
}
......@@ -104,7 +101,7 @@ public async Task<IDocumentOptions> GetOptionsForDocumentAsync(Document document
// We don't have anything cached, so we'll just get it now lazily and not hold onto it. The workspace layer will ensure
// that we maintain snapshot rules for the document options. We'll also run it on the thread pool
// as in some builds the ICodingConventionsManager captures the thread pool.
var conventionsAsync = Task.Run(() => _codingConventionsManager.GetConventionContextAsync(path, cancellationToken));
var conventionsAsync = Task.Run(() => GetConventionContextAsync(path, cancellationToken));
using (var context = await conventionsAsync.ConfigureAwait(false))
{
......@@ -113,43 +110,11 @@ public async Task<IDocumentOptions> GetOptionsForDocumentAsync(Document document
}
}
private class DocumentOptions : IDocumentOptions
private Task<ICodingConventionContext> GetConventionContextAsync(string path, CancellationToken cancellationToken)
{
private ICodingConventionsSnapshot _codingConventionSnapshot;
public DocumentOptions(ICodingConventionsSnapshot codingConventionSnapshot)
{
_codingConventionSnapshot = codingConventionSnapshot;
}
public bool TryGetDocumentOption(Document document, OptionKey option, out object value)
{
var editorConfigPersistence = option.Option.StorageLocations.OfType<EditorConfigStorageLocation>().SingleOrDefault();
if (editorConfigPersistence == null)
{
value = null;
return false;
}
if (_codingConventionSnapshot.TryGetConventionValue(editorConfigPersistence.KeyName, out value))
{
try
{
value = editorConfigPersistence.ParseValue(value.ToString(), option.Option.Type);
return true;
}
catch (Exception)
{
// TODO: report this somewhere?
return false;
}
}
else
{
return false;
}
}
return IOUtilities.PerformIOAsync(
() => _codingConventionsManager.GetConventionContextAsync(path, cancellationToken),
defaultValue: EmptyCodingConventionContext.Instance);
}
}
}
......@@ -3,6 +3,7 @@
using System;
using System.IO;
using System.Security;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Shared.Utilities
{
......@@ -30,6 +31,19 @@ public static T PerformIO<T>(Func<T> function, T defaultValue = default(T))
return defaultValue;
}
public static async Task<T> PerformIOAsync<T>(Func<Task<T>> function, T defaultValue = default(T))
{
try
{
return await function().ConfigureAwait(false);
}
catch (Exception e) when (IsNormalIOException(e))
{
}
return defaultValue;
}
public static bool IsNormalIOException(Exception e)
{
return e is IOException ||
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册