Cleaned up support for OptimizationLevel.

This commit is contained in:
Andrey Shchekin 2017-05-14 22:07:11 +12:00
Родитель e652e24cc3
Коммит ed3bf9d83e
11 изменённых файлов: 87 добавлений и 65 удалений

Просмотреть файл

@ -5,9 +5,6 @@ using Microsoft.CodeAnalysis;
namespace MirrorSharp.Internal.Abstraction {
internal interface ILanguage {
[NotNull] string Name { get; }
[NotNull] ParseOptions DefaultParseOptions { get; }
[NotNull] CompilationOptions DefaultCompilationOptions { get; }
[NotNull] ILanguageSession CreateSession([NotNull] string text, ParseOptions parseOptions, CompilationOptions compilationOptions, [CanBeNull] IReadOnlyCollection<MetadataReference> assemblyReferences);
[NotNull] ILanguageSession CreateSession([NotNull] string text, OptimizationLevel? optimizationLevel, ParseOptions parseOptions, CompilationOptions compilationOptions, [CanBeNull] IReadOnlyCollection<MetadataReference> assemblyReferences);
}
}

Просмотреть файл

@ -69,7 +69,7 @@ namespace MirrorSharp.Internal.Handlers {
private void SetOptimize(WorkSession session, string value) {
var level = (OptimizationLevel)Enum.Parse(typeof(OptimizationLevel), value, true);
session.ChangeCompilationOptions(nameof(CompilationOptions.OptimizationLevel), o => o.WithOptimizationLevel(level));
session.ChangeOptimizationLevel(level);
}
private async Task SendOptionsEchoAsync(WorkSession session, ICommandResultSender sender, CancellationToken cancellationToken) {

Просмотреть файл

@ -15,6 +15,8 @@ using MirrorSharp.Internal.Reflection;
namespace MirrorSharp.Internal.Roslyn {
internal abstract class RoslynLanguageBase : ILanguage {
private readonly MefHostServices _hostServices;
private readonly ParseOptions _defaultParseOptions;
private readonly CompilationOptions _defaultCompilationOptions;
private readonly ImmutableArray<ISignatureHelpProviderWrapper> _defaultSignatureHelpProviders;
private readonly ImmutableDictionary<string, ImmutableArray<CodeFixProvider>> _defaultCodeFixProvidersIndexedByDiagnosticIds;
private readonly ImmutableArray<DiagnosticAnalyzer> _defaultAnalyzers;
@ -36,8 +38,8 @@ namespace MirrorSharp.Internal.Roslyn {
Assembly.Load(new AssemblyName(featuresAssemblyName)),
Assembly.Load(new AssemblyName(workspacesAssemblyName)),
});
DefaultParseOptions = defaultParseOptions;
DefaultCompilationOptions = defaultCompilationOptions;
_defaultParseOptions = defaultParseOptions;
_defaultCompilationOptions = defaultCompilationOptions;
_defaultAssemblyReferences = ImmutableList.Create<MetadataReference>(
MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location)
);
@ -53,14 +55,17 @@ namespace MirrorSharp.Internal.Roslyn {
}
public string Name { get; }
public ParseOptions DefaultParseOptions { get; }
public CompilationOptions DefaultCompilationOptions { get; }
public ILanguageSession CreateSession(string text, ParseOptions parseOptions, CompilationOptions compilationOptions, IReadOnlyCollection<MetadataReference> assemblyReferences) {
public ILanguageSession CreateSession(string text, OptimizationLevel? optimizationLevel, ParseOptions parseOptions, CompilationOptions compilationOptions, IReadOnlyCollection<MetadataReference> assemblyReferences) {
var projectId = ProjectId.CreateNewId();
compilationOptions = compilationOptions ?? _defaultCompilationOptions;
if (optimizationLevel != null)
compilationOptions = compilationOptions.WithOptimizationLevel(optimizationLevel.Value);
var projectInfo = ProjectInfo.Create(
projectId, VersionStamp.Create(), "_", "_", Name,
parseOptions: parseOptions,
parseOptions: parseOptions ?? _defaultParseOptions,
compilationOptions: compilationOptions,
metadataReferences: assemblyReferences ?? _defaultAssemblyReferences,
analyzerReferences: _defaultAnalyzerReferences

Просмотреть файл

@ -9,9 +9,9 @@ using MirrorSharp.Internal.Roslyn;
namespace MirrorSharp.Internal {
internal class WorkSession : IWorkSession {
[CanBeNull] private readonly IWorkSessionOptions _options;
[NotNull] private readonly IDictionary<string, Func<ParseOptions, ParseOptions>> _parseOptionsChanges = new Dictionary<string, Func<ParseOptions, ParseOptions>>();
[NotNull] private readonly IDictionary<string, Func<CompilationOptions, CompilationOptions>> _compilationOptionsChanges = new Dictionary<string, Func<CompilationOptions, CompilationOptions>>();
[NotNull] private ILanguage _language;
[CanBeNull] private OptimizationLevel? _optimizationLevel;
private ILanguageSession _languageSession;
private string _lastText = "";
@ -30,26 +30,10 @@ namespace MirrorSharp.Internal {
Reset();
}
public void ChangeParseOptions([NotNull] string key, [NotNull] Func<ParseOptions, ParseOptions> change) {
Argument.NotNull(nameof(key), key);
Argument.NotNull(nameof(change), change);
if (_parseOptionsChanges.TryGetValue(key, out var current) && current == change)
return;
_parseOptionsChanges[key] = change;
if (_languageSession is RoslynSession roslyn && change(roslyn.Project.ParseOptions) == roslyn.Project.ParseOptions)
return;
Reset();
}
public void ChangeCompilationOptions([NotNull] string key, [NotNull] Func<CompilationOptions, CompilationOptions> change) {
Argument.NotNull(nameof(key), key);
Argument.NotNull(nameof(change), change);
if (_compilationOptionsChanges.TryGetValue(key, out var current) && current == change)
return;
_compilationOptionsChanges[key] = change;
if (_languageSession is RoslynSession roslyn && change(roslyn.Project.CompilationOptions) == roslyn.Project.CompilationOptions)
public void ChangeOptimizationLevel([CanBeNull] OptimizationLevel? optimizationLevel) {
if (optimizationLevel == _optimizationLevel)
return;
_optimizationLevel = optimizationLevel;
Reset();
}
@ -62,19 +46,14 @@ namespace MirrorSharp.Internal {
}
private void Initialize() {
var parseOptions = _options?.GetDefaultParseOptionsByLanguageName?.Invoke(Language.Name) ?? Language.DefaultParseOptions;
foreach (var change in _parseOptionsChanges.Values) {
parseOptions = change(parseOptions);
}
var compilationOptions = _options?.GetDefaultCompilationOptionsByLanguageName?.Invoke(Language.Name) ?? Language.DefaultCompilationOptions;
foreach (var change in _compilationOptionsChanges.Values) {
compilationOptions = change(compilationOptions);
}
var parseOptions = _options?.GetDefaultParseOptionsByLanguageName?.Invoke(Language.Name);
var compilationOptions = _options?.GetDefaultCompilationOptionsByLanguageName?.Invoke(Language.Name);
var assemblyReferences = _options?.GetDefaultMetadataReferencesByLanguageName?.Invoke(Language.Name);
_languageSession = Language.CreateSession(_lastText, parseOptions, compilationOptions, assemblyReferences);
_languageSession = Language.CreateSession(_lastText, OptimizationLevel, parseOptions, compilationOptions, assemblyReferences);
}
public IWorkSessionOptions Options => _options;
public OptimizationLevel? OptimizationLevel => _optimizationLevel;
[NotNull] public ILanguage Language => _language;
[NotNull]
public ILanguageSession LanguageSession {

Просмотреть файл

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.FSharp.Compiler.AbstractIL.Internal;
@ -11,9 +10,7 @@ using MirrorSharp.Internal.Abstraction;
namespace MirrorSharp.FSharp {
public class FSharpLanguage : ILanguage {
public const string Name = "F#";
ParseOptions ILanguage.DefaultParseOptions => null;
CompilationOptions ILanguage.DefaultCompilationOptions => null;
private readonly ImmutableArray<string> _defaultAssemblyReferencePaths;
static FSharpLanguage() {
@ -22,18 +19,18 @@ namespace MirrorSharp.FSharp {
internal FSharpLanguage() {
var fsharpAssembly = typeof(FSharpOption<>).GetTypeInfo().Assembly;
_defaultAssemblyReferencePaths = ImmutableArray.Create<string>(
_defaultAssemblyReferencePaths = ImmutableArray.Create(
// note: this currently does not work on .NET Core, which is why this project isn't netstandard
typeof(object).GetTypeInfo().Assembly.Location,
new Uri(fsharpAssembly.EscapedCodeBase).LocalPath
);
}
ILanguageSession ILanguage.CreateSession(string text, ParseOptions parseOptions, CompilationOptions compilationOptions, IReadOnlyCollection<MetadataReference> assemblyReferences) {
ILanguageSession ILanguage.CreateSession(string text, OptimizationLevel? optimizationLevel, ParseOptions parseOptions, CompilationOptions compilationOptions, IReadOnlyCollection<MetadataReference> assemblyReferences) {
if (assemblyReferences != null)
throw new NotSupportedException();
return new FSharpSession(text, _defaultAssemblyReferencePaths);
return new FSharpSession(text, _defaultAssemblyReferencePaths, optimizationLevel);
}
string ILanguage.Name => Name;

Просмотреть файл

@ -18,20 +18,14 @@ namespace MirrorSharp.FSharp {
private readonly FSharpChecker _checker;
private readonly FSharpProjectOptions _projectOptions;
public FSharpSession(string text, ImmutableArray<string> assemblyReferencePaths) {
public FSharpSession(string text, ImmutableArray<string> assemblyReferencePaths, OptimizationLevel? optimizationLevel) {
_checker = FSharpChecker.Create(null, null, null, false);
_text = text;
var otherOptions = new List<string> { "--noframework" };
foreach (var path in assemblyReferencePaths) {
// ReSharper disable once HeapView.ObjectAllocation (Not worth fixing for now)
otherOptions.Add("-r:" + path);
}
_projectOptions = new FSharpProjectOptions(
"_",
projectFileNames: new[] { "_.fs" },
otherOptions: otherOptions.ToArray(),
otherOptions: ConvertToOptions(assemblyReferencePaths, optimizationLevel),
referencedProjects: Array.Empty<Tuple<string, FSharpProjectOptions>>(),
isIncompleteTypeCheckEnvironment: true,
useScriptResolutionRules: false,
@ -42,6 +36,23 @@ namespace MirrorSharp.FSharp {
);
}
private static string[] ConvertToOptions(ImmutableArray<string> assemblyReferencePaths, OptimizationLevel? optimizationLevel) {
var options = new List<string> {"--noframework"};
if (optimizationLevel == OptimizationLevel.Release) {
options.Add("--debug-");
options.Add("--optimize+");
}
else if (optimizationLevel == OptimizationLevel.Debug) {
options.Add("--debug+");
options.Add("--optimize-");
}
foreach (var path in assemblyReferencePaths) {
// ReSharper disable once HeapView.ObjectAllocation (Not worth fixing for now)
options.Add("-r:" + path);
}
return options.ToArray();
}
public async Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync(CancellationToken cancellationToken) {
var (parsed, check) = await FSharpAsync.StartAsTask(
_checker.ParseAndCheckFileInProject("_.fs", 0, _text, _projectOptions, null), null, cancellationToken

Просмотреть файл

@ -1,5 +1,6 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/Browsers/Browsers/@EntryValue">C27+,E12+,FF21+,IE11+,S9+</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=3C2A0FC7_002D4485_002D4654_002DB3B2_002D5717A2F2C97A_002Fd_003Abower_005Fcomponents/@EntryIndexedValue">ExplicitlyExcluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=70BCCC0E_002D6EEF_002D40D0_002D932A_002D87F9C42BD67B_002Fd_003Awwwroot_002Fd_003Abower_005Fcomponents/@EntryIndexedValue">ExplicitlyExcluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=D2EB1CDD_002D12B5_002D4FDC_002DA56C_002D8A327200E759_002Fd_003Abower_005Fcomponents/@EntryIndexedValue">ExplicitlyExcluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=FF13139E_002D69D3_002D472E_002DB4FE_002DAC2623AD67B9_002Fd_003Abower_005Fcomponents/@EntryIndexedValue">ExplicitlyExcluded</s:String>

Просмотреть файл

@ -1,5 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
@ -16,11 +19,19 @@ using Newtonsoft.Json;
namespace MirrorSharp.Testing {
public class MirrorSharpTestDriver {
private static readonly LanguageManager LanguageManager = new LanguageManager(new[] {
LanguageNames.CSharp,
LanguageNames.VisualBasic,
"F#"
});
private static readonly LanguageManager LanguageManager = CreateLanguageManager();
private static LanguageManager CreateLanguageManager() {
var languageNames = new List<string> {
LanguageNames.CSharp,
LanguageNames.VisualBasic
};
var basePath = Path.GetDirectoryName(new Uri(typeof(LanguageManager).GetTypeInfo().Assembly.CodeBase).LocalPath);
if (File.Exists(Path.Combine(basePath, "MirrorSharp.FSharp.dll")))
languageNames.Add("F#");
return new LanguageManager(languageNames);
}
private MirrorSharpTestDriver([CanBeNull] MirrorSharpOptions options = null, [CanBeNull] string languageName = LanguageNames.CSharp) {
var language = LanguageManager.GetLanguage(languageName);

Просмотреть файл

@ -1,12 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using MirrorSharp.Internal;
using Microsoft.CodeAnalysis;
using MirrorSharp.Testing;
using Xunit;
namespace MirrorSharp.Tests {
using static CommandIds;
public class FSharpTests {
[Fact]
public async void SlowUpdate_ProducesNoDiagnostics_IfCodeIsValid() {
@ -46,5 +44,20 @@ namespace MirrorSharp.Tests {
}).ToArray()
);
}
[Theory]
[InlineData(OptimizationLevel.Debug)]
[InlineData(OptimizationLevel.Release)]
public async void SetOptions_DoesNotProduceAnyDiagnosticIssues_WithEitherOptimizationLevel(OptimizationLevel level) {
var driver = MirrorSharpTestDriver.New();
await driver.SendSetOptionsAsync(new Dictionary<string, string> {
{ "language", "F#" },
{ "optimize", level.ToString() }
});
await driver.SendReplaceTextAsync("1 |> ignore");
var result = await driver.SendSlowUpdateAsync();
Assert.Empty(result.Diagnostics);
}
}
}

Просмотреть файл

@ -6,6 +6,14 @@
<RootNamespace>MirrorSharp.Tests</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;DEBUG;NET46;ROSLYN20</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE;RELEASE;NET46;ROSLYN20</DefineConstants>
</PropertyGroup>
<Import Project="..\Tests.Shared\MirrorSharp.Tests.Shared.projitems" Label="Shared" />
<ItemGroup>

Просмотреть файл

@ -34,7 +34,7 @@ namespace MirrorSharp.Tests {
[Fact]
public async void ExecuteAsync_PreservesSessionWorkspace_WhenUpdatingOptimizeToTheSameValue() {
var driver = MirrorSharpTestDriver.New().SetText("test");
driver.Session.ChangeCompilationOptions(nameof(CompilationOptions.OptimizationLevel), c => c.WithOptimizationLevel(OptimizationLevel.Release));
driver.Session.ChangeOptimizationLevel(OptimizationLevel.Release);
var workspace = driver.Session.Roslyn.Workspace;
await driver.SendAsync(SetOptions, "optimize=release");
Assert.Same(workspace, driver.Session.Roslyn.Workspace);