Skip to content

Commit

Permalink
Cleaned up support for OptimizationLevel.
Browse files Browse the repository at this point in the history
  • Loading branch information
ashmind committed May 14, 2017
1 parent e652e24 commit ed3bf9d
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 65 deletions.
5 changes: 1 addition & 4 deletions Common/Internal/Abstraction/ILanguage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
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);
}
}
2 changes: 1 addition & 1 deletion Common/Internal/Handlers/SetOptionsHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private void SetLanguage(WorkSession session, string value) {

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) {
Expand Down
17 changes: 11 additions & 6 deletions Common/Internal/Roslyn/RoslynLanguageBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
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;
Expand All @@ -36,8 +38,8 @@ [NotNull] CompilationOptions defaultCompilationOptions
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)
);
Expand All @@ -53,14 +55,17 @@ [NotNull] CompilationOptions defaultCompilationOptions
}

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
Expand Down
37 changes: 8 additions & 29 deletions Common/Internal/WorkSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
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 = "";

Expand All @@ -30,26 +30,10 @@ public void ChangeLanguage([NotNull] ILanguage language) {
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();
}

Expand All @@ -62,19 +46,14 @@ private void Reset() {
}

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 {
Expand Down
11 changes: 4 additions & 7 deletions FSharp/FSharpLanguage.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -11,9 +10,7 @@
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() {
Expand All @@ -22,18 +19,18 @@ static FSharpLanguage() {

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;
Expand Down
27 changes: 19 additions & 8 deletions FSharp/FSharpSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,14 @@ internal class FSharpSession : ILanguageSession {
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,
Expand All @@ -42,6 +36,23 @@ public FSharpSession(string text, ImmutableArray<string> assemblyReferencePaths)
);
}

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
Expand Down
1 change: 1 addition & 0 deletions MirrorSharp.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -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>
Expand Down
23 changes: 17 additions & 6 deletions Testing/MirrorSharpTestDriver.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -16,11 +19,19 @@

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);
Expand Down
19 changes: 16 additions & 3 deletions Tests.Roslyn2.Net46/FSharpTests.cs
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -46,5 +44,20 @@ public async void SlowUpdate_ProducesExpectedDiagnostics_IfCodeHasErrors() {
}).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);
}
}
}
8 changes: 8 additions & 0 deletions Tests.Roslyn2.Net46/Tests.Roslyn2.Net46.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
2 changes: 1 addition & 1 deletion Tests.Shared/SetOptionsHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public async void ExecuteAsync_UpdatesSessionCompilationOptimizationsLevel(strin
[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);
Expand Down

0 comments on commit ed3bf9d

Please sign in to comment.