Skip to content

Commit

Permalink
Merge pull request OmniSharp#1210 from filipw/bugfix/1199
Browse files Browse the repository at this point in the history
Initialize CSX file watcher also when no CSX files are available at startup
  • Loading branch information
DustinCampbell authored Jun 5, 2018
2 parents 5129ba5 + 7f0a2ee commit ce1e1c7
Show file tree
Hide file tree
Showing 10 changed files with 298 additions and 175 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ All changes to the project will be documented in this file.

## [1.32.0] - _Not Yet Released_
* Added new `/codestructure` endpoint which serves a replacement for the `/currentfilemembersastree` endpoint. The new endpoint has a cleaner design, properly supports all C# types and members, and supports more information, such as accessibility, static vs. instance, etc. (PR: [#1211](https://github.com/OmniSharp/omnisharp-roslyn/pull/1211))
* Fixed a bug where language services for newly created CSX files were not provided if no CSX files existed at the moment OmniSharp was started ([#1199](https://github.com/OmniSharp/omnisharp-roslyn/issues/1199), PR: [#1210](https://github.com/OmniSharp/omnisharp-roslyn/pull/1210))
* The legacy project.json support is now disabled by default, allowing OmniSharp to start up a bit faster for common scenarios. If you wish to enable project.json support, add the following setting to your `omnisharp.json` file. (PR: [#1194](https://github.com/OmniSharp/omnisharp-roslyn/pull/1194))

```JSON
Expand Down
25 changes: 25 additions & 0 deletions src/OmniSharp.Script/ScriptContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Collections.Generic;
using Dotnet.Script.DependencyModel.Compilation;
using Microsoft.CodeAnalysis;

namespace OmniSharp.Script
{
public class ScriptContext
{
public ScriptContext(ScriptProjectProvider scriptProjectProvider, HashSet<MetadataReference> metadataReferences, HashSet<string> assemblyReferences, CompilationDependency[] compilationDependencies)
{
ScriptProjectProvider = scriptProjectProvider;
MetadataReferences = metadataReferences;
AssemblyReferences = assemblyReferences;
CompilationDependencies = compilationDependencies;
}

public ScriptProjectProvider ScriptProjectProvider { get; }

public HashSet<MetadataReference> MetadataReferences { get; }

public HashSet<string> AssemblyReferences { get; }

public CompilationDependency[] CompilationDependencies { get; }
}
}
4 changes: 2 additions & 2 deletions src/OmniSharp.Script/ScriptContextModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public ScriptContextModel(string csxPath, ProjectInfo project, HashSet<string> i
{
Path = csxPath;
ImplicitAssemblyReferences = implicitAssemblyReferences;
CommonUsings = ScriptHelper.DefaultNamespaces;
CommonUsings = ScriptProjectProvider.DefaultNamespaces;
GlobalsType = project.HostObjectType;
}

Expand All @@ -22,4 +22,4 @@ public ScriptContextModel(string csxPath, ProjectInfo project, HashSet<string> i

public IEnumerable<string> CommonUsings { get; }
}
}
}
175 changes: 175 additions & 0 deletions src/OmniSharp.Script/ScriptContextProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Reflection;
using Dotnet.Script.DependencyModel.Compilation;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
using OmniSharp.Roslyn.Utilities;
using OmniSharp.Services;
using LogLevel = Dotnet.Script.DependencyModel.Logging.LogLevel;

namespace OmniSharp.Script
{
[Export, Shared]
public class ScriptContextProvider
{
private readonly ILoggerFactory _loggerFactory;
private readonly CompilationDependencyResolver _compilationDependencyResolver;
private readonly IOmniSharpEnvironment _env;
private readonly MetadataFileReferenceCache _metadataFileReferenceCache;
private readonly ILogger _logger;

[ImportingConstructor]
public ScriptContextProvider(ILoggerFactory loggerFactory, IOmniSharpEnvironment env, MetadataFileReferenceCache metadataFileReferenceCache)
{
_loggerFactory = loggerFactory;
_env = env;
_metadataFileReferenceCache = metadataFileReferenceCache;
_logger = loggerFactory.CreateLogger<ScriptContextProvider>();
_compilationDependencyResolver = new CompilationDependencyResolver(type =>
{
// Prefix with "OmniSharp" so that we make it through the log filter.
var categoryName = $"OmniSharp.Script.{type.FullName}";
var dependencyResolverLogger = loggerFactory.CreateLogger(categoryName);
return ((level, message) =>
{
if (level == LogLevel.Debug)
{
dependencyResolverLogger.LogDebug(message);
}
if (level == LogLevel.Info)
{
dependencyResolverLogger.LogInformation(message);
}
});
});
}

public ScriptContext CreateScriptContext(ScriptOptions scriptOptions)
{
var currentDomainAssemblies = AppDomain.CurrentDomain.GetAssemblies();

// explicitly inherit scripting library references to all global script object (CommandLineScriptGlobals) to be recognized
var inheritedCompileLibraries = currentDomainAssemblies.Where(x =>
x.FullName.StartsWith("microsoft.codeanalysis", StringComparison.OrdinalIgnoreCase)).ToList();

// explicitly include System.ValueTuple
inheritedCompileLibraries.AddRange(currentDomainAssemblies.Where(x =>
x.FullName.StartsWith("system.valuetuple", StringComparison.OrdinalIgnoreCase)));

CompilationDependency[] compilationDependencies = null;
try
{
_logger.LogInformation($"Searching for compilation dependencies with the fallback framework of '{scriptOptions.DefaultTargetFramework}'.");
compilationDependencies = _compilationDependencyResolver.GetDependencies(_env.TargetDirectory, scriptOptions.IsNugetEnabled(), scriptOptions.DefaultTargetFramework).ToArray();
}
catch (Exception e)
{
_logger.LogError("Failed to resolve compilation dependencies", e);
compilationDependencies = Array.Empty<CompilationDependency>();
}

var metadataReferences = new HashSet<MetadataReference>(MetadataReferenceEqualityComparer.Instance);
var assemblyReferences = new HashSet<string>();

var isDesktopClr = true;
// if we have no compilation dependencies
// we will assume desktop framework
// and add default CLR references
// same applies for having a context that is not a .NET Core app
if (!compilationDependencies.Any())
{
_logger.LogInformation("Unable to find dependency context for CSX files. Will default to non-context usage (Desktop CLR scripts).");
AddDefaultClrMetadataReferences(metadataReferences, assemblyReferences);
}
else
{
isDesktopClr = false;
HashSet<string> loadedFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

foreach (var compilationAssembly in compilationDependencies.SelectMany(cd => cd.AssemblyPaths).Distinct())
{
if (loadedFiles.Add(Path.GetFileName(compilationAssembly)))
{
_logger.LogDebug("Discovered script compilation assembly reference: " + compilationAssembly);
AddMetadataReference(metadataReferences, assemblyReferences, compilationAssembly);
}
}
}

// inject all inherited assemblies
foreach (var inheritedCompileLib in inheritedCompileLibraries)
{
_logger.LogDebug("Adding implicit reference: " + inheritedCompileLib);
AddMetadataReference(metadataReferences, assemblyReferences, inheritedCompileLib.Location);
}

var scriptProjectProvider = new ScriptProjectProvider(scriptOptions, _env, _loggerFactory, isDesktopClr);

return new ScriptContext(scriptProjectProvider, metadataReferences, assemblyReferences, compilationDependencies);
}

private void AddDefaultClrMetadataReferences(HashSet<MetadataReference> commonReferences, HashSet<string> assemblyReferences)
{
var assemblies = new[]
{
typeof(object).GetTypeInfo().Assembly,
typeof(Enumerable).GetTypeInfo().Assembly,
typeof(Stack<>).GetTypeInfo().Assembly,
typeof(Lazy<,>).GetTypeInfo().Assembly,
FromName("System.Runtime"),
FromName("mscorlib")
};

var references = assemblies
.Where(a => a != null)
.Select(a => a.Location)
.Distinct()
.Select(l =>
{
assemblyReferences.Add(l);
return _metadataFileReferenceCache.GetMetadataReference(l);
});

foreach (var reference in references)
{
commonReferences.Add(reference);
}

Assembly FromName(string assemblyName)
{
try
{
return Assembly.Load(new AssemblyName(assemblyName));
}
catch
{
return null;
}
}
}

private void AddMetadataReference(ISet<MetadataReference> referenceCollection, HashSet<string> assemblyReferences, string fileReference)
{
if (!File.Exists(fileReference))
{
_logger.LogWarning($"Couldn't add reference to '{fileReference}' because the file was not found.");
return;
}

var metadataReference = _metadataFileReferenceCache.GetMetadataReference(fileReference);
if (metadataReference == null)
{
_logger.LogWarning($"Couldn't add reference to '{fileReference}' because the loaded metadata reference was null.");
return;
}

referenceCollection.Add(metadataReference);
assemblyReferences.Add(fileReference);
_logger.LogDebug($"Added reference to '{fileReference}'");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

namespace OmniSharp.Script
{
public class ScriptHelper
public class ScriptProjectProvider
{
private const string BinderFlagsType = "Microsoft.CodeAnalysis.CSharp.BinderFlags";
private const string TopLevelBinderFlagsProperty = "TopLevelBinderFlags";
Expand Down Expand Up @@ -49,7 +49,7 @@ public class ScriptHelper
private readonly ILogger _logger;
private readonly bool _isDesktopClr;

public ScriptHelper(ScriptOptions scriptOptions, IOmniSharpEnvironment env, ILoggerFactory loggerFactory, bool isDesktopClr)
public ScriptProjectProvider(ScriptOptions scriptOptions, IOmniSharpEnvironment env, ILoggerFactory loggerFactory, bool isDesktopClr)
{
_scriptOptions = scriptOptions ?? throw new ArgumentNullException(nameof(scriptOptions));
_env = env ?? throw new ArgumentNullException(nameof(env));
Expand Down
Loading

0 comments on commit ce1e1c7

Please sign in to comment.