提交 1ddd3243 编写于 作者: C Charles Stoner

Merge pull request #4318 from cston/r

Refactor MetadataFileReferenceResolver classes
......@@ -81,7 +81,7 @@ public void Invariants()
TestProperty((old, value) => old.WithExtendedCustomDebugInformation(value), opt => opt.ExtendedCustomDebugInformation, false);
TestProperty((old, value) => old.WithXmlReferenceResolver(value), opt => opt.XmlReferenceResolver, new XmlFileResolver(null));
TestProperty((old, value) => old.WithMetadataReferenceResolver(value), opt => opt.MetadataReferenceResolver, new AssemblyReferenceResolver(new MetadataFileReferenceResolver(new string[0], null), new MetadataFileReferenceProvider()));
TestProperty((old, value) => old.WithMetadataReferenceResolver(value), opt => opt.MetadataReferenceResolver, new AssemblyReferenceResolver(MetadataFileReferenceResolver.Default, new MetadataFileReferenceProvider()));
TestProperty((old, value) => old.WithAssemblyIdentityComparer(value), opt => opt.AssemblyIdentityComparer, new DesktopAssemblyIdentityComparer(new AssemblyPortabilityPolicy()));
TestProperty((old, value) => old.WithStrongNameProvider(value), opt => opt.StrongNameProvider, new DesktopStrongNameProvider());
}
......@@ -347,7 +347,7 @@ private static CSharpCompilationOptions CreateCSharpCompilationOptions()
bool extendedCustomDebugInformation = true;
XmlReferenceResolver xmlReferenceResolver = new XmlFileResolver(null);
SourceReferenceResolver sourceReferenceResolver = new SourceFileResolver(ImmutableArray<string>.Empty, null);
MetadataReferenceResolver metadataReferenceResolver = new AssemblyReferenceResolver(new MetadataFileReferenceResolver(ImmutableArray<string>.Empty, null), MetadataFileReferenceProvider.Default);
MetadataReferenceResolver metadataReferenceResolver = new AssemblyReferenceResolver(MetadataFileReferenceResolver.Default, MetadataFileReferenceProvider.Default);
AssemblyIdentityComparer assemblyIdentityComparer = AssemblyIdentityComparer.Default; // Currently uses reference equality
StrongNameProvider strongNameProvider = new DesktopStrongNameProvider();
MetadataImportOptions metadataImportOptions = 0;
......
......@@ -1587,7 +1587,7 @@ public void ReferenceManagerReuse_WithMetadataReferenceResolver()
var c1 = CSharpCompilation.Create("c", options: TestOptions.ReleaseDll);
var c2 = c1.WithOptions(TestOptions.ReleaseDll.WithMetadataReferenceResolver(
new AssemblyReferenceResolver(new MetadataFileReferenceResolver(ImmutableArray.Create<string>(), null), MetadataFileReferenceProvider.Default)));
new AssemblyReferenceResolver(MetadataFileReferenceResolver.Default, MetadataFileReferenceProvider.Default)));
Assert.False(c1.ReferenceManagerEquals(c2));
......
......@@ -2621,10 +2621,12 @@ public void AddRemoveReferences()
private sealed class Resolver : TestMetadataReferenceResolver
{
private readonly RelativePathReferenceResolver _pathResolver;
private readonly string _data, _core, _system;
public Resolver(string data, string core, string system)
{
_pathResolver = RelativePathReferenceResolver.Default;
_data = data;
_core = core;
_system = system;
......@@ -2644,7 +2646,7 @@ public override string ResolveReference(string reference, string baseFileName)
return _system;
default:
return base.ResolveReference(reference, baseFileName);
return _pathResolver.ResolveReference(reference, baseFileName);
}
}
}
......
......@@ -163,7 +163,7 @@ public void ResolvePath_Order()
var f1 = dir1.CreateFile("f.dll").Path;
var f2 = dir2.CreateFile("f.dll").Path;
var resolver = new MetadataFileReferenceResolver(
var resolver = new RelativePathReferenceResolver(
ImmutableArray.Create(dir1.Path, dir2.Path),
baseDirectory: null);
......
......@@ -390,6 +390,7 @@
<Compile Include="FileSystem\PathKind.cs" />
<Compile Include="FileSystem\PathUtilities.cs" />
<Compile Include="FileSystem\FileUtilities.cs" />
<Compile Include="RelativePathReferenceResolver.cs" />
<Compile Include="PEWriter\Blob.cs" />
<Compile Include="PEWriter\BlobWriter.cs" />
<Compile Include="PEWriter\BlobWriterImpl.cs" />
......
......@@ -392,14 +392,10 @@ internal ImmutableArray<DiagnosticAnalyzer> ResolveAnalyzersFromArguments(string
private AnalyzerFileReference ResolveAnalyzerReference(CommandLineAnalyzerReference reference, IAnalyzerAssemblyLoader analyzerLoader)
{
string resolvedPath = FileUtilities.ResolveRelativePath(reference.FilePath, basePath: null, baseDirectory: BaseDirectory, searchPaths: ReferencePaths, fileExists: PortableShim.File.Exists);
if (PortableShim.File.Exists(resolvedPath))
if (resolvedPath != null)
{
resolvedPath = FileUtilities.TryNormalizeAbsolutePath(resolvedPath);
}
else
{
resolvedPath = null;
}
if (resolvedPath != null)
{
......
......@@ -5,7 +5,6 @@
using System.Diagnostics;
using System.Linq;
using Roslyn.Utilities;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.CodeAnalysis
{
......@@ -16,25 +15,44 @@ internal abstract partial class CommonCompiler
/// When scripts are included into a project we don't want #r's to reference other assemblies than those
/// specified explicitly in the project references.
/// </summary>
internal sealed class ExistingReferencesResolver : LoggingMetadataReferencesResolver
internal sealed class ExistingReferencesResolver : MetadataFileReferenceResolver
{
private readonly MetadataFileReferenceResolver _resolver;
private readonly ImmutableArray<PortableExecutableReference> _availableReferences;
private readonly AssemblyIdentityComparer _assemblyIdentityComparer;
public ExistingReferencesResolver(
MetadataFileReferenceResolver resolver,
ImmutableArray<PortableExecutableReference> availableReferences,
ImmutableArray<string> referencePaths,
string baseDirectory,
AssemblyIdentityComparer assemblyIdentityComparer,
TouchedFileLogger logger)
: base(referencePaths, baseDirectory, logger)
AssemblyIdentityComparer assemblyIdentityComparer)
{
Debug.Assert(!availableReferences.Any(r => r.Properties.Kind != MetadataImageKind.Assembly));
_resolver = resolver;
_availableReferences = availableReferences;
_assemblyIdentityComparer = assemblyIdentityComparer;
}
public override ImmutableArray<string> SearchPaths
{
get { return _resolver.SearchPaths; }
}
public override string BaseDirectory
{
get { return _resolver.BaseDirectory; }
}
internal override MetadataFileReferenceResolver WithSearchPaths(ImmutableArray<string> searchPaths)
{
return new ExistingReferencesResolver(_resolver.WithSearchPaths(searchPaths), _availableReferences, _assemblyIdentityComparer);
}
internal override MetadataFileReferenceResolver WithBaseDirectory(string baseDirectory)
{
return new ExistingReferencesResolver(_resolver.WithBaseDirectory(baseDirectory), _availableReferences, _assemblyIdentityComparer);
}
public override string ResolveReference(string reference, string baseFilePath)
{
if (PathUtilities.IsFilePath(reference))
......@@ -69,7 +87,7 @@ private string ResolveAssemblyName(string displayName)
/// </summary>
private string ResolveMetadataFile(string path, string basePath)
{
var fullPath = base.ResolveReference(path, basePath);
var fullPath = _resolver.ResolveReference(path, basePath);
foreach (var fileReference in _availableReferences)
{
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis
{
internal abstract partial class CommonCompiler
{
internal class LoggingMetadataReferencesResolver : MetadataFileReferenceResolver
internal sealed class LoggingMetadataReferencesResolver : MetadataFileReferenceResolver
{
protected readonly TouchedFileLogger logger;
private readonly MetadataFileReferenceResolver _resolver;
private readonly TouchedFileLogger _logger;
public LoggingMetadataReferencesResolver(ImmutableArray<string> searchPaths, string baseDirectory, TouchedFileLogger logger)
: base(searchPaths, baseDirectory)
public LoggingMetadataReferencesResolver(MetadataFileReferenceResolver resolver, TouchedFileLogger logger)
{
this.logger = logger;
Debug.Assert(logger != null);
_resolver = resolver;
_logger = logger;
}
protected override bool FileExists(string fullPath)
public override ImmutableArray<string> SearchPaths
{
if (logger != null && fullPath != null)
get { return _resolver.SearchPaths; }
}
public override string BaseDirectory
{
get { return _resolver.BaseDirectory; }
}
internal override MetadataFileReferenceResolver WithSearchPaths(ImmutableArray<string> searchPaths)
{
return new LoggingMetadataReferencesResolver(_resolver.WithSearchPaths(searchPaths), _logger);
}
internal override MetadataFileReferenceResolver WithBaseDirectory(string baseDirectory)
{
return new LoggingMetadataReferencesResolver(_resolver.WithBaseDirectory(baseDirectory), _logger);
}
public override string ResolveReference(string reference, string baseFilePath)
{
var path = _resolver.ResolveReference(reference, baseFilePath);
if (path != null)
{
logger.AddRead(fullPath);
_logger.AddRead(path);
}
return base.FileExists(fullPath);
return path;
}
}
}
......
......@@ -86,7 +86,7 @@ internal virtual MetadataFileReferenceProvider GetMetadataProvider()
internal virtual MetadataFileReferenceResolver GetExternalMetadataResolver(TouchedFileLogger touchedFiles)
{
return new LoggingMetadataReferencesResolver(Arguments.ReferencePaths, Arguments.BaseDirectory, touchedFiles);
return CreateLoggingMetadataResolver(touchedFiles);
}
/// <summary>
......@@ -111,16 +111,20 @@ internal virtual MetadataFileReferenceResolver GetExternalMetadataResolver(Touch
{
// when compiling into an assembly (csc/vbc) we only allow #r that match references given on command line:
referenceDirectiveResolver = new ExistingReferencesResolver(
CreateLoggingMetadataResolver(touchedFiles),
resolved.Where(r => r.Properties.Kind == MetadataImageKind.Assembly).OfType<PortableExecutableReference>().AsImmutable(),
Arguments.ReferencePaths,
Arguments.BaseDirectory,
assemblyIdentityComparer,
touchedFiles);
assemblyIdentityComparer);
}
return resolved;
}
private MetadataFileReferenceResolver CreateLoggingMetadataResolver(TouchedFileLogger logger)
{
MetadataFileReferenceResolver resolver = new RelativePathReferenceResolver(Arguments.ReferencePaths, Arguments.BaseDirectory);
return (logger == null) ? resolver : new LoggingMetadataReferencesResolver(resolver, logger);
}
/// <summary>
/// Reads content of a source file.
/// </summary>
......
......@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace Roslyn.Utilities
{
......@@ -34,7 +33,7 @@ internal static class FileUtilities
/// Method that tests existence of a file.
/// </param>
/// <returns>
/// The resolved path or null if the path can't be resolved.
/// The resolved path or null if the path can't be resolved or does not exist.
/// </returns>
internal static string ResolveRelativePath(
string path,
......@@ -47,6 +46,7 @@ internal static class FileUtilities
Debug.Assert(searchPaths != null);
Debug.Assert(fileExists != null);
string combinedPath;
var kind = PathUtilities.GetPathKind(path);
if (kind == PathKind.Relative)
{
......@@ -54,10 +54,9 @@ internal static class FileUtilities
baseDirectory = GetBaseDirectory(basePath, baseDirectory);
if (baseDirectory != null)
{
string combinedPath = PathUtilities.CombinePathsUnchecked(baseDirectory, path);
combinedPath = PathUtilities.CombinePathsUnchecked(baseDirectory, path);
Debug.Assert(PathUtilities.IsAbsolute(combinedPath));
if (fileExists == null || fileExists(combinedPath))
if (fileExists(combinedPath))
{
return combinedPath;
}
......@@ -66,10 +65,9 @@ internal static class FileUtilities
// try search paths:
foreach (var searchPath in searchPaths)
{
string combinedPath = PathUtilities.CombinePathsUnchecked(searchPath, path);
combinedPath = PathUtilities.CombinePathsUnchecked(searchPath, path);
Debug.Assert(PathUtilities.IsAbsolute(combinedPath));
if (fileExists == null || fileExists(combinedPath))
if (fileExists(combinedPath))
{
return combinedPath;
}
......@@ -78,7 +76,17 @@ internal static class FileUtilities
return null;
}
return ResolveRelativePath(kind, path, basePath, baseDirectory);
combinedPath = ResolveRelativePath(kind, path, basePath, baseDirectory);
if (combinedPath != null)
{
Debug.Assert(PathUtilities.IsAbsolute(combinedPath));
if (fileExists(combinedPath))
{
return combinedPath;
}
}
return null;
}
internal static string ResolveRelativePath(string path, string baseDirectory)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Roslyn.Utilities;
......@@ -13,43 +9,9 @@ namespace Microsoft.CodeAnalysis
/// <summary>
/// Resolves metadata references specified in source code (#r directives).
/// </summary>
internal class MetadataFileReferenceResolver
internal abstract class MetadataFileReferenceResolver
{
public static readonly MetadataFileReferenceResolver Default = new MetadataFileReferenceResolver(ImmutableArray<string>.Empty, baseDirectory: null);
private readonly ImmutableArray<string> _searchPaths;
private readonly string _baseDirectory;
/// <summary>
/// Initializes a new instance of the <see cref="MetadataFileReferenceResolver"/> class.
/// </summary>
/// <param name="searchPaths">An ordered set of fully qualified
/// paths which are searched when resolving assembly names.</param>
/// <param name="baseDirectory">Directory used when resolving relative paths.</param>
public MetadataFileReferenceResolver(ImmutableArray<string> searchPaths, string baseDirectory)
{
ValidateSearchPaths(searchPaths, "searchPaths");
if (baseDirectory != null && PathUtilities.GetPathKind(baseDirectory) != PathKind.Absolute)
{
throw ExceptionUtilities.Unreachable;
////throw new ArgumentException(CodeAnalysisResources.AbsolutePathExpected, "baseDirectory");
}
_searchPaths = searchPaths;
_baseDirectory = baseDirectory;
}
/// <summary>
/// Initializes a new instance of the <see cref="MetadataFileReferenceResolver"/> class.
/// </summary>
/// <param name="searchPaths">An ordered set of fully qualified
/// paths which are searched when resolving assembly names.</param>
/// <param name="baseDirectory">Directory used when resolving relative paths.</param>
public MetadataFileReferenceResolver(IEnumerable<string> searchPaths, string baseDirectory)
: this(searchPaths.AsImmutableOrNull(), baseDirectory)
{
}
internal static readonly RelativePathReferenceResolver Default = new RelativePathReferenceResolver(ImmutableArray<string>.Empty, baseDirectory: null);
internal static void ValidateSearchPaths(ImmutableArray<string> paths, string argName)
{
......@@ -59,7 +21,7 @@ internal static void ValidateSearchPaths(ImmutableArray<string> paths, string ar
////throw new ArgumentNullException(argName);
}
if (paths.Any(path => !PathUtilities.IsAbsolute(path)))
if (!paths.All(PathUtilities.IsAbsolute))
{
throw ExceptionUtilities.Unreachable;
////throw new ArgumentException(CodeAnalysisResources.AbsolutePathExpected, argName);
......@@ -72,9 +34,9 @@ internal static void ValidateSearchPaths(ImmutableArray<string> paths, string ar
/// <remarks>
/// All search paths are absolute.
/// </remarks>
public ImmutableArray<string> SearchPaths
public abstract ImmutableArray<string> SearchPaths
{
get { return _searchPaths; }
get;
}
/// <summary>
......@@ -89,11 +51,15 @@ public ImmutableArray<string> SearchPaths
///
/// Resolution of a relative path that needs the base directory fails if the base directory is null.
/// </remarks>
public string BaseDirectory
public abstract string BaseDirectory
{
get { return _baseDirectory; }
get;
}
internal abstract MetadataFileReferenceResolver WithSearchPaths(ImmutableArray<string> searchPaths);
internal abstract MetadataFileReferenceResolver WithBaseDirectory(string baseDirectory);
/// <summary>
/// Resolves a metadata reference that is a path or an assembly name.
/// </summary>
......@@ -105,52 +71,6 @@ public string BaseDirectory
/// <returns>
/// Normalized absolute path to the referenced file or null if it can't be resolved.
/// </returns>
public virtual string ResolveReference(string reference, string baseFilePath)
{
string resolvedPath = FileUtilities.ResolveRelativePath(reference, baseFilePath, _baseDirectory, _searchPaths, FileExists);
if (!FileExists(resolvedPath))
{
return null;
}
return FileUtilities.TryNormalizeAbsolutePath(resolvedPath);
}
internal string ResolveReferenceChecked(string reference, string baseFilePath)
{
string fullPath = ResolveReference(reference, baseFilePath);
if (fullPath != null && !PathUtilities.IsAbsolute(fullPath))
{
throw ExceptionUtilities.Unreachable;
//// throw new InvalidOperationException(string.Format(CodeAnalysisResources.PathReturnedByResolveMetadataFileMustBeAbsolute, GetType().FullName, fullPath));
}
return fullPath;
}
protected virtual bool FileExists(string fullPath)
{
Debug.Assert(fullPath == null || PathUtilities.IsAbsolute(fullPath));
return PortableShim.File.Exists(fullPath);
}
public override bool Equals(object obj)
{
// Explicitly check that we're not comparing against a derived type
if (obj == null || GetType() != obj.GetType())
{
return false;
}
var other = (MetadataFileReferenceResolver)obj;
return string.Equals(_baseDirectory, other._baseDirectory, StringComparison.Ordinal) &&
_searchPaths.SequenceEqual(other._searchPaths, StringComparer.Ordinal);
}
public override int GetHashCode()
{
return Hash.Combine(_baseDirectory != null ? StringComparer.Ordinal.GetHashCode(_baseDirectory) : 0,
Hash.CombineValues(_searchPaths, StringComparer.Ordinal));
}
public abstract string ResolveReference(string reference, string baseFilePath);
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
internal sealed class RelativePathReferenceResolver : MetadataFileReferenceResolver
{
private readonly ImmutableArray<string> _searchPaths;
private readonly string _baseDirectory;
private readonly Func<string, bool> _fileExists;
/// <summary>
/// Initializes a new instance of the <see cref="RelativePathReferenceResolver"/> class.
/// </summary>
/// <param name="searchPaths">An ordered set of fully qualified
/// paths which are searched when resolving assembly names.</param>
/// <param name="baseDirectory">Directory used when resolving relative paths.</param>
/// <param name="fileExists">Method that tests existence of a file.</param>
public RelativePathReferenceResolver(ImmutableArray<string> searchPaths, string baseDirectory, Func<string, bool> fileExists = null)
{
ValidateSearchPaths(searchPaths, "searchPaths");
if (baseDirectory != null && PathUtilities.GetPathKind(baseDirectory) != PathKind.Absolute)
{
throw ExceptionUtilities.Unreachable;
////throw new ArgumentException(CodeAnalysisResources.AbsolutePathExpected, "baseDirectory");
}
_searchPaths = searchPaths;
_baseDirectory = baseDirectory;
_fileExists = fileExists ?? FileExists;
}
public override ImmutableArray<string> SearchPaths
{
get { return _searchPaths; }
}
public override string BaseDirectory
{
get { return _baseDirectory; }
}
internal override MetadataFileReferenceResolver WithSearchPaths(ImmutableArray<string> searchPaths)
{
return new RelativePathReferenceResolver(searchPaths, _baseDirectory, _fileExists);
}
internal override MetadataFileReferenceResolver WithBaseDirectory(string baseDirectory)
{
return new RelativePathReferenceResolver(_searchPaths, baseDirectory, _fileExists);
}
public override string ResolveReference(string reference, string baseFilePath)
{
string resolvedPath = FileUtilities.ResolveRelativePath(reference, baseFilePath, _baseDirectory, _searchPaths, _fileExists);
if (resolvedPath == null)
{
return null;
}
return FileUtilities.TryNormalizeAbsolutePath(resolvedPath);
}
private static bool FileExists(string fullPath)
{
Debug.Assert(fullPath != null);
Debug.Assert(PathUtilities.IsAbsolute(fullPath));
return PortableShim.File.Exists(fullPath);
}
public override bool Equals(object obj)
{
var other = obj as RelativePathReferenceResolver;
return (other != null) &&
string.Equals(_baseDirectory, other._baseDirectory, StringComparison.Ordinal) &&
_searchPaths.SequenceEqual(other._searchPaths, StringComparer.Ordinal);
}
public override int GetHashCode()
{
return Hash.Combine(_baseDirectory != null ? StringComparer.Ordinal.GetHashCode(_baseDirectory) : 0,
Hash.CombineValues(_searchPaths, StringComparer.Ordinal));
}
}
}
......@@ -59,8 +59,7 @@ public override string NormalizePath(string path, string baseFilePath)
public override string ResolveReference(string path, string baseFilePath)
{
string resolvedPath = FileUtilities.ResolveRelativePath(path, baseFilePath, _baseDirectory, _searchPaths, FileExists);
if (!FileExists(resolvedPath))
if (resolvedPath == null)
{
return null;
}
......
......@@ -44,7 +44,7 @@ private static bool CheckCore(string baseDirectory, IEnumerable<CommandLineAnaly
foreach (var analyzerReference in analyzerReferences)
{
string resolvedPath = FileUtilities.ResolveRelativePath(analyzerReference.FilePath, basePath: null, baseDirectory: baseDirectory, searchPaths: SpecializedCollections.EmptyEnumerable<string>(), fileExists: File.Exists);
if (File.Exists(resolvedPath))
if (resolvedPath != null)
{
resolvedPath = FileUtilities.TryNormalizeAbsolutePath(resolvedPath);
if (resolvedPath != null)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Scripting
......@@ -14,7 +12,7 @@ namespace Microsoft.CodeAnalysis.Scripting
/// Extends MetadataFileReferenceResolver to enable resolution of assembly
/// simple names in the GAC.
/// </summary>
internal sealed class GacFileResolver : MetadataFileReferenceResolver
internal sealed class GacFileResolver
{
private readonly ImmutableArray<ProcessorArchitecture> _architectures;
private readonly CultureInfo _preferredCulture;
......@@ -23,27 +21,19 @@ internal sealed class GacFileResolver : MetadataFileReferenceResolver
/// A resolver that is configured to resolve against the GAC associated
/// with the bitness of the currently executing process.
/// </summary>
internal new static GacFileResolver Default = new GacFileResolver(
assemblySearchPaths: ImmutableArray<string>.Empty,
baseDirectory: null,
internal static GacFileResolver Default = new GacFileResolver(
architectures: GlobalAssemblyCache.CurrentArchitectures,
preferredCulture: null);
/// <summary>
/// Constructs an instance of a <see cref="GacFileResolver"/>
/// </summary>
/// <param name="assemblySearchPaths">An ordered set of fully qualified
/// paths which are searched when resolving assembly names.</param>
/// <param name="baseDirectory">Directory used when resolving relative paths.</param>
/// <param name="architectures">Supported architectures used to filter GAC assemblies.</param>
/// <param name="preferredCulture">A culture to use when choosing the best assembly from
/// among the set filtered by <paramref name="architectures"/></param>
public GacFileResolver(
IEnumerable<string> assemblySearchPaths,
string baseDirectory,
ImmutableArray<ProcessorArchitecture> architectures,
CultureInfo preferredCulture)
: base(assemblySearchPaths, baseDirectory)
{
_architectures = architectures;
_preferredCulture = preferredCulture;
......@@ -65,34 +55,29 @@ public CultureInfo PreferredCulture
get { return _preferredCulture; }
}
public override string ResolveReference(string reference, string baseFilePath)
public string ResolveReference(string reference)
{
if (PathUtilities.IsFilePath(reference))
{
return base.ResolveReference(reference, baseFilePath);
return null;
}
string path;
GlobalAssemblyCache.ResolvePartialName(reference, out path, _architectures, this.PreferredCulture);
return FileExists(path) ? path : null;
return (path != null && PortableShim.File.Exists(path)) ? path : null;
}
public override bool Equals(object obj)
{
if (!base.Equals(obj))
{
return false;
}
var other = (GacFileResolver)obj;
return _architectures.SequenceEqual(other._architectures) &&
var other = obj as GacFileResolver;
return (other != null) &&
_architectures.SequenceEqual(other._architectures) &&
_preferredCulture == other._preferredCulture;
}
public override int GetHashCode()
{
return Hash.Combine(base.GetHashCode(),
Hash.Combine(_preferredCulture, Hash.CombineValues(_architectures)));
return Hash.Combine(_preferredCulture, Hash.CombineValues(_architectures));
}
}
}
......@@ -1439,7 +1439,7 @@ End Class
Dim c1 = VisualBasicCompilation.Create("c", options:=TestOptions.ReleaseDll)
Dim c2 = c1.WithOptions(TestOptions.ReleaseDll.WithMetadataReferenceResolver(
New AssemblyReferenceResolver(New MetadataFileReferenceResolver(ImmutableArray.Create(Of String)(), Nothing), MetadataFileReferenceProvider.Default)))
New AssemblyReferenceResolver(MetadataFileReferenceResolver.Default, MetadataFileReferenceProvider.Default)))
Assert.False(c1.ReferenceManagerEquals(c2))
Dim c3 = c1.WithOptions(TestOptions.ReleaseDll.WithMetadataReferenceResolver(c1.Options.MetadataReferenceResolver))
......
......@@ -78,7 +78,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests
TestProperty(Function(old, value) old.WithXmlReferenceResolver(value), Function(opt) opt.XmlReferenceResolver, New XmlFileResolver(Nothing))
TestProperty(Function(old, value) old.WithSourceReferenceResolver(value), Function(opt) opt.SourceReferenceResolver, New SourceFileResolver(ImmutableArray(Of String).Empty, Nothing))
TestProperty(Function(old, value) old.WithMetadataReferenceResolver(value), Function(opt) opt.MetadataReferenceResolver, New AssemblyReferenceResolver(New MetadataFileReferenceResolver({}, Nothing), New MetadataFileReferenceProvider()))
TestProperty(Function(old, value) old.WithMetadataReferenceResolver(value), Function(opt) opt.MetadataReferenceResolver, New AssemblyReferenceResolver(MetadataFileReferenceResolver.Default, New MetadataFileReferenceProvider()))
TestProperty(Function(old, value) old.WithAssemblyIdentityComparer(value), Function(opt) opt.AssemblyIdentityComparer, New DesktopAssemblyIdentityComparer(New AssemblyPortabilityPolicy()))
TestProperty(Function(old, value) old.WithStrongNameProvider(value), Function(opt) opt.StrongNameProvider, New DesktopStrongNameProvider())
End Sub
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
......@@ -712,7 +713,7 @@ public void TestWithReferenceDirective()
Expression",
parseOptions: GetScriptOptions(),
compilationOptions: TestOptions.ReleaseDll.WithMetadataReferenceResolver(new AssemblyReferenceResolver(new MetadataFileReferenceResolver(Array.Empty<string>(), null), MetadataFileReferenceProvider.Default)),
compilationOptions: TestOptions.ReleaseDll.WithMetadataReferenceResolver(new AssemblyReferenceResolver(MetadataFileReferenceResolver.Default, MetadataFileReferenceProvider.Default)),
compareTokens: false);
}
......
......@@ -13,10 +13,12 @@
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion.FileSystem;
using Microsoft.CodeAnalysis.Editor.Implementation.Interactive;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Interactive;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
......@@ -24,10 +26,10 @@
using Microsoft.VisualStudio.Utilities;
using Microsoft.VisualStudio.InteractiveWindow;
using Microsoft.VisualStudio.InteractiveWindow.Commands;
using Microsoft.CodeAnalysis.Scripting;
using Roslyn.Utilities;
using DesktopMetadataReferenceResolver = WORKSPACES::Microsoft.CodeAnalysis.Scripting.DesktopMetadataReferenceResolver;
using GacFileResolver = WORKSPACES::Microsoft.CodeAnalysis.Scripting.GacFileResolver;
using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion.FileSystem;
using NuGetPackageResolver = WORKSPACES::Microsoft.CodeAnalysis.Scripting.NuGetPackageResolver;
namespace Microsoft.CodeAnalysis.Editor.Interactive
{
......@@ -45,7 +47,7 @@ public abstract class InteractiveEvaluator : IInteractiveEvaluator, ICurrentWork
private readonly InteractiveWorkspace _workspace;
private IInteractiveWindow _currentWindow;
private ImmutableHashSet<MetadataReference> _references;
private GacFileResolver _metadataReferenceResolver;
private MetadataFileReferenceResolver _metadataReferenceResolver;
private ImmutableArray<string> _sourceSearchPaths;
private ProjectId _previousSubmissionProjectId;
......@@ -201,12 +203,7 @@ private void ProcessStarting(InteractiveHostOptions options)
referencePaths = rspArguments.ReferencePaths;
// the base directory for references specified in the .rsp file is the .rsp file directory:
var rspMetadataReferenceResolver = new GacFileResolver(
referencePaths,
baseDirectory: rspArguments.BaseDirectory,
architectures: GacFileResolver.Default.Architectures, // TODO (tomat)
preferredCulture: System.Globalization.CultureInfo.CurrentCulture); // TODO (tomat)
var rspMetadataReferenceResolver = CreateFileResolver(referencePaths, rspArguments.BaseDirectory);
var metadataProvider = metadataService.GetProvider();
// ignore unresolved references, they will be reported in the interactive window:
......@@ -234,12 +231,7 @@ private void ProcessStarting(InteractiveHostOptions options)
}
// reset search paths, working directory:
_metadataReferenceResolver = new GacFileResolver(
referencePaths,
baseDirectory: _initialWorkingDirectory,
architectures: GacFileResolver.Default.Architectures, // TODO (tomat)
preferredCulture: System.Globalization.CultureInfo.CurrentCulture); // TODO (tomat)
_metadataReferenceResolver = CreateFileResolver(referencePaths, _initialWorkingDirectory);
_sourceSearchPaths = InteractiveHost.Service.DefaultSourceSearchPaths;
// create the first submission project in the workspace after reset:
......@@ -254,6 +246,16 @@ private Dispatcher Dispatcher
get { return ((FrameworkElement)GetInteractiveWindow().TextView).Dispatcher; }
}
private static MetadataFileReferenceResolver CreateFileResolver(ImmutableArray<string> referencePaths, string baseDirectory)
{
return new DesktopMetadataReferenceResolver(
new RelativePathReferenceResolver(referencePaths, baseDirectory),
NuGetPackageResolver.Instance,
new GacFileResolver(
architectures: GacFileResolver.Default.Architectures, // TODO (tomat)
preferredCulture: System.Globalization.CultureInfo.CurrentCulture)); // TODO (tomat)
}
#endregion
#region Workspace
......@@ -563,11 +565,9 @@ public void UpdateLocalPaths(string[] newReferenceSearchPaths, string[] newSourc
var changed = false;
if (newReferenceSearchPaths != null || newBaseDirectory != null)
{
_metadataReferenceResolver = new GacFileResolver(
_metadataReferenceResolver = CreateFileResolver(
(newReferenceSearchPaths == null) ? _metadataReferenceResolver.SearchPaths : newReferenceSearchPaths.AsImmutable(),
baseDirectory: newBaseDirectory ?? _metadataReferenceResolver.BaseDirectory,
architectures: GacFileResolver.Default.Architectures, // TODO (tomat)
preferredCulture: System.Globalization.CultureInfo.CurrentCulture); // TODO (tomat)
newBaseDirectory ?? _metadataReferenceResolver.BaseDirectory);
changed = true;
}
......
......@@ -69,6 +69,16 @@ internal TaskResult(ScriptOptions options, ScriptState<object> state)
this.Options = options;
this.State = state;
}
internal TaskResult With(ScriptOptions options)
{
return new TaskResult(options, State);
}
internal TaskResult With(ScriptState<object> state)
{
return new TaskResult(Options, state);
}
}
private static readonly ImmutableArray<string> s_systemNoShadowCopyDirectories = ImmutableArray.Create(
......@@ -299,7 +309,6 @@ private static string GenerateUniqueChannelLocalName()
{
var result = await ReportUnhandledExceptionIfAny(lastTask).ConfigureAwait(false);
var options = result.Options;
var state = result.State;
try
{
Directory.SetCurrentDirectory(baseDirectory);
......@@ -316,7 +325,7 @@ private static string GenerateUniqueChannelLocalName()
{
operation.Completed(null);
}
return new TaskResult(options, state);
return result.With(options);
}
/// <summary>
......@@ -365,7 +374,6 @@ private async Task<TaskResult> AddReferenceAsync(Task<TaskResult> lastTask, Remo
var result = await ReportUnhandledExceptionIfAny(lastTask).ConfigureAwait(false);
var success = false;
var options = result.Options;
var state = result.State;
try
{
string fullPath = ResolveReferencePath(options, reference, baseFilePath: null);
......@@ -386,7 +394,7 @@ private async Task<TaskResult> AddReferenceAsync(Task<TaskResult> lastTask, Remo
{
operation.Completed(success);
}
return new TaskResult(options, state);
return result.With(options);
}
/// <summary>
......@@ -505,7 +513,7 @@ private TaskResult CompleteExecution(TaskResult result, RemoteAsyncOperation<Rem
options = options.WithBaseDirectory(currentDirectory);
operation.Completed(new RemoteExecutionResult(success, newSourcePaths, newReferencePaths, newWorkingDirectory, resolvedPath));
return new TaskResult(options, result.State);
return result.With(options);
}
private static async Task<TaskResult> ReportUnhandledExceptionIfAny(Task<TaskResult> lastTask)
......@@ -574,7 +582,8 @@ public void SetTestObjectFormattingOptions()
// The base directory for relative paths is the directory that contains the .rsp file.
// Note that .rsp files included by this .rsp file will share the base directory (Dev10 behavior of csc/vbc).
var args = parser.Parse(new[] { "@" + initializationFileOpt }, Path.GetDirectoryName(initializationFileOpt), RuntimeEnvironment.GetRuntimeDirectory(), null /* TODO: pass a valid value*/);
var rspDirectory = Path.GetDirectoryName(initializationFileOpt);
var args = parser.Parse(new[] { "@" + initializationFileOpt }, rspDirectory, RuntimeEnvironment.GetRuntimeDirectory(), null /* TODO: pass a valid value*/);
foreach (var error in args.Errors)
{
......@@ -586,6 +595,10 @@ public void SetTestObjectFormattingOptions()
{
// TODO (tomat): other arguments
// TODO (tomat): parse options
var referencePaths = args.ReferencePaths;
result = result.With(result.Options.AddSearchPaths(referencePaths));
_hostObject.ReferencePaths.Clear();
_hostObject.ReferencePaths.AddRange(referencePaths);
// TODO (tomat): consolidate with other reference resolving
foreach (CommandLineReference cmdLineReference in args.MetadataReferences)
......@@ -596,10 +609,9 @@ public void SetTestObjectFormattingOptions()
var options = result.Options;
string fullPath = ResolveReferencePath(options, cmdLineReference.Reference, baseFilePath: null);
LoadReference(fullPath, suppressWarnings: true, addReference: true, options: ref options);
result = new TaskResult(options, result.State);
result = result.With(options);
}
var rspDirectory = Path.GetDirectoryName(initializationFileOpt);
foreach (CommandLineSourceFile file in args.SourceFiles)
{
// execute all files as scripts (matches csi/vbi semantics)
......@@ -703,14 +715,13 @@ public SerializableAssemblyLoadResult LoadReferenceThrowing(string reference, bo
{
var result = ReportUnhandledExceptionIfAny(_lastTask).Result;
var options = result.Options;
var state = result.State;
var fullPath = ResolveReferencePath(options, reference, baseFilePath: null);
if (fullPath == null)
{
throw new FileNotFoundException(message: null, fileName: reference);
}
var loadResult = LoadFromPathThrowing(fullPath, addReference, ref options);
_lastTask = Task.FromResult(new TaskResult(options, state));
_lastTask = Task.FromResult(result.With(options));
return loadResult;
}
}
......@@ -874,12 +885,11 @@ private async Task<ExecuteResult> ExecuteOnUIThread(TaskResult result, Script<ob
{
try
{
var options = result.Options;
var state = result.State;
var globals = state ?? (object)_hostObject;
state = script.RunAsync(globals, CancellationToken.None);
var value = await state.ReturnValue.ConfigureAwait(false);
return new ExecuteResult(new TaskResult(options, state), value, null, true);
return new ExecuteResult(result.With(state), value, null, true);
}
catch (Exception e)
{
......
......@@ -45,7 +45,7 @@ public InteractiveHostTests()
remoteService.SetTestObjectFormattingOptions();
// assert and remove logo:
var output = ReadOutputToEnd().Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
var output = SplitLines(ReadOutputToEnd());
var errorOutput = ReadErrorOutputToEnd();
Assert.Equal("", errorOutput);
......@@ -153,13 +153,8 @@ private class CompiledFile
public ImmutableArray<byte> Image;
}
private CompiledFile CompileLibrary(TempDirectory dir, string fileName, string assemblyName, string source, params MetadataReference[] references)
private static CompiledFile CompileLibrary(TempDirectory dir, string fileName, string assemblyName, string source, params MetadataReference[] references)
{
const string Prefix = "RoslynTestFile_";
fileName = Prefix + fileName;
assemblyName = Prefix + assemblyName;
var file = dir.CreateFile(fileName);
var compilation = CreateCompilation(
new[] { source },
......@@ -742,7 +737,7 @@ public void AddReference_MultipleReferencesWithSameWeakIdentity()
//// var task = Host.InitializeContextAsync(rspFile.Path, isRestarting: false, killProcess: true);
//// task.Wait();
//// var output = ReadOutputToEnd().Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
//// var output = SplitLines(ReadOutputToEnd());
//// var errorOutput = ReadErrorOutputToEnd();
//// Assert.Equal(4, output.Length);
......@@ -755,7 +750,7 @@ public void AddReference_MultipleReferencesWithSameWeakIdentity()
//// Host.InitializeContextAsync(rspFile.Path).Wait();
//// output = ReadOutputToEnd().Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
//// output = SplitLines(ReadOutputToEnd());
//// errorOutput = ReadErrorOutputToEnd();
//// Assert.True(2 == output.Length, "Output is: '" + string.Join("<NewLine>", output) + "'. Expecting 2 lines.");
......@@ -793,7 +788,7 @@ public void AddReference_MultipleReferencesWithSameWeakIdentity()
//// var errorOutput = ReadErrorOutputToEnd();
//// Assert.Equal("", errorOutput);
//// var output = ReadOutputToEnd().Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
//// var output = SplitLines(ReadOutputToEnd());
//// Assert.Equal(4, output.Length);
//// Assert.Equal("Microsoft (R) Roslyn C# Compiler version " + FileVersionInfo.GetVersionInfo(Host.GetType().Assembly.Location).FileVersion, output[0]);
//// Assert.Equal("Loading context from '" + Path.GetFileName(rspFile.Path) + "'.", output[1]);
......@@ -801,6 +796,25 @@ public void AddReference_MultipleReferencesWithSameWeakIdentity()
//// Assert.Equal("13", output[3]);
//// }
[Fact]
public void ReferencePaths()
{
var directory = Temp.CreateDirectory();
var assemblyName = GetUniqueName();
CompileLibrary(directory, assemblyName + ".dll", assemblyName, @"public class C { }");
var rspFile = Temp.CreateFile();
rspFile.WriteAllText("/rp:" + directory.Path);
var task = Host.ResetAsync(InteractiveHostOptions.Default.WithInitializationFile(rspFile.Path));
task.Wait();
Execute(
$@"#r ""{assemblyName}.dll""
typeof(C).Assembly.GetName()");
var output = SplitLines(ReadOutputToEnd());
Assert.Equal(2, output.Length);
Assert.Equal("Loading context from '" + Path.GetFileName(rspFile.Path) + "'.", output[0]);
Assert.Equal($"[{assemblyName}, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]", output[1]);
}
[Fact]
public void ReferenceDirectives()
{
......@@ -972,5 +986,10 @@ public void SubmissionResult_PrintingVoid()
}
#endregion
private static ImmutableArray<string> SplitLines(string text)
{
return ImmutableArray.Create(text.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries));
}
}
}
......@@ -7,11 +7,9 @@
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.CodeAnalysis.Scripting;
using Roslyn.Utilities;
using Microsoft.VisualStudio.Shell.Interop;
namespace CSharpInteractive
{
......@@ -41,7 +39,10 @@ internal static int Main(string[] args)
internal override MetadataFileReferenceResolver GetExternalMetadataResolver(TouchedFileLogger touchedFiles)
{
// We don't log touched files atm.
return new GacFileResolver(Arguments.ReferencePaths, Arguments.BaseDirectory, GacFileResolver.Default.Architectures, CultureInfo.CurrentCulture);
return new DesktopMetadataReferenceResolver(
new RelativePathReferenceResolver(Arguments.ReferencePaths, Arguments.BaseDirectory),
null,
new GacFileResolver(GacFileResolver.Default.Architectures, CultureInfo.CurrentCulture));
}
public override void PrintLogo(TextWriter consoleOutput)
......
......@@ -5,9 +5,9 @@ Imports System.IO
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Scripting
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.VisualStudio.Shell.Interop
Imports Microsoft.CodeAnalysis.Scripting
Friend NotInheritable Class Vbi
Inherits VisualBasicCompiler
......@@ -30,7 +30,10 @@ Friend NotInheritable Class Vbi
Friend Overrides Function GetExternalMetadataResolver(touchedFiles As TouchedFileLogger) As MetadataFileReferenceResolver
' We don't log touched files atm.
Return New GacFileResolver(Arguments.ReferencePaths, Arguments.BaseDirectory, GacFileResolver.Default.Architectures, CultureInfo.CurrentCulture)
Return New DesktopMetadataReferenceResolver(
New RelativePathReferenceResolver(Arguments.ReferencePaths, Arguments.BaseDirectory),
Nothing,
New GacFileResolver(GacFileResolver.Default.Architectures, CultureInfo.CurrentCulture))
End Function
Public Overrides Sub PrintLogo(consoleOutput As TextWriter)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Scripting
{
internal sealed class DesktopMetadataReferenceResolver : MetadataFileReferenceResolver
{
private readonly MetadataFileReferenceResolver _pathResolver;
private readonly NuGetPackageResolver _packageResolver;
private readonly GacFileResolver _gacFileResolver;
internal DesktopMetadataReferenceResolver(
MetadataFileReferenceResolver pathResolver,
NuGetPackageResolver packageResolver,
GacFileResolver gacFileResolver)
{
_pathResolver = pathResolver;
_packageResolver = packageResolver;
_gacFileResolver = gacFileResolver;
}
public override ImmutableArray<string> SearchPaths
{
get { return _pathResolver.SearchPaths; }
}
public override string BaseDirectory
{
get { return _pathResolver.BaseDirectory; }
}
internal override MetadataFileReferenceResolver WithSearchPaths(ImmutableArray<string> searchPaths)
{
return new DesktopMetadataReferenceResolver(_pathResolver.WithSearchPaths(searchPaths), _packageResolver, _gacFileResolver);
}
internal override MetadataFileReferenceResolver WithBaseDirectory(string baseDirectory)
{
return new DesktopMetadataReferenceResolver(_pathResolver.WithBaseDirectory(baseDirectory), _packageResolver, _gacFileResolver);
}
public override string ResolveReference(string reference, string baseFilePath)
{
if (PathUtilities.IsFilePath(reference))
{
return _pathResolver.ResolveReference(reference, baseFilePath);
}
if (_packageResolver != null)
{
string path = _packageResolver.ResolveNuGetPackage(reference);
if (path != null && PortableShim.File.Exists(path))
{
return path;
}
}
if (_gacFileResolver != null)
{
return _gacFileResolver.ResolveReference(reference);
}
return null;
}
public override bool Equals(object obj)
{
var other = obj as DesktopMetadataReferenceResolver;
return (other != null) &&
object.Equals(_pathResolver, other._pathResolver) &&
object.Equals(_packageResolver, other._packageResolver) &&
object.Equals(_gacFileResolver, other._gacFileResolver);
}
public override int GetHashCode()
{
int result = _pathResolver.GetHashCode();
if (_packageResolver != null)
{
result = Hash.Combine(result, _packageResolver.GetHashCode());
}
if (_gacFileResolver != null)
{
result = Hash.Combine(result, _gacFileResolver.GetHashCode());
}
return result;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Scripting
{
internal sealed class NuGetPackageResolver
{
internal static readonly NuGetPackageResolver Instance = new NuGetPackageResolver();
private NuGetPackageResolver()
{
}
internal string ResolveNuGetPackage(string reference)
{
if (PathUtilities.IsFilePath(reference))
{
return null;
}
var assemblyName = GetPackageAssemblyName(reference);
if (assemblyName == null)
{
return null;
}
// Expecting {package}{version}\lib\{arch}\{package}.dll.
var resolvedPath = PathUtilities.CombineAbsoluteAndRelativePaths(reference, "lib");
if (!PortableShim.Directory.Exists(resolvedPath))
{
return null;
}
// We're not validating the architecture currently
// so fail if there's not exactly one architecture.
resolvedPath = PortableShim.Directory.EnumerateDirectories(resolvedPath, "*", PortableShim.SearchOption.TopDirectoryOnly).SingleOrDefault();
if (resolvedPath == null)
{
return null;
}
return PathUtilities.CombineAbsoluteAndRelativePaths(resolvedPath, assemblyName);
}
private static string GetPackageAssemblyName(string reference)
{
// Assembly name is <id/> in .nuspec file.
// For now, simply strip off any version #, etc.
var name = PathUtilities.GetFileName(reference);
int offset = 0;
while ((offset = name.IndexOf('.', offset)) >= 0)
{
if ((offset < name.Length - 1) && char.IsDigit(name[offset + 1]))
{
return name.Substring(0, offset) + ".dll";
}
offset += 1;
}
return null;
}
}
}
......@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Scripting
/// <summary>
/// Options for creating and running scripts.
/// </summary>
public class ScriptOptions
public sealed class ScriptOptions
{
private readonly ImmutableArray<MetadataReference> _references;
private readonly ImmutableArray<string> _namespaces;
......@@ -23,7 +23,12 @@ public class ScriptOptions
public ScriptOptions()
: this(ImmutableArray<MetadataReference>.Empty,
ImmutableArray<string>.Empty,
new AssemblyReferenceResolver(GacFileResolver.Default, MetadataFileReferenceProvider.Default),
new AssemblyReferenceResolver(
new DesktopMetadataReferenceResolver(
MetadataFileReferenceResolver.Default,
null,
GacFileResolver.Default),
MetadataFileReferenceProvider.Default),
isInteractive: true)
{
}
......@@ -342,25 +347,10 @@ public ScriptOptions WithSearchPaths(IEnumerable<string> searchPaths)
else
{
// TODO:
var gacResolver = _referenceResolver.PathResolver as GacFileResolver;
if (gacResolver != null)
{
return With(resolver: new AssemblyReferenceResolver(
new GacFileResolver(
searchPaths,
gacResolver.BaseDirectory,
gacResolver.Architectures,
gacResolver.PreferredCulture),
_referenceResolver.Provider));
}
else
{
return With(resolver: new AssemblyReferenceResolver(
new MetadataFileReferenceResolver(
searchPaths,
_referenceResolver.PathResolver.BaseDirectory),
_referenceResolver.Provider));
}
var resolver = new AssemblyReferenceResolver(
_referenceResolver.PathResolver.WithSearchPaths(searchPaths.AsImmutableOrEmpty()),
_referenceResolver.Provider);
return With(resolver: resolver);
}
}
......@@ -407,25 +397,10 @@ public ScriptOptions WithBaseDirectory(string baseDirectory)
else
{
// TODO:
var gacResolver = _referenceResolver.PathResolver as GacFileResolver;
if (gacResolver != null)
{
return With(resolver: new AssemblyReferenceResolver(
new GacFileResolver(
_referenceResolver.PathResolver.SearchPaths,
baseDirectory,
gacResolver.Architectures,
gacResolver.PreferredCulture),
_referenceResolver.Provider));
}
else
{
return With(resolver: new AssemblyReferenceResolver(
new MetadataFileReferenceResolver(
_referenceResolver.PathResolver.SearchPaths,
baseDirectory),
_referenceResolver.Provider));
}
var resolver = new AssemblyReferenceResolver(
_referenceResolver.PathResolver.WithBaseDirectory(baseDirectory),
_referenceResolver.Provider);
return With(resolver: resolver);
}
}
......@@ -434,7 +409,7 @@ public ScriptOptions WithBaseDirectory(string baseDirectory)
/// </summary>
internal ScriptOptions WithReferenceResolver(MetadataFileReferenceResolver resolver)
{
if (resolver == _referenceResolver.PathResolver)
if (resolver.Equals(_referenceResolver.PathResolver))
{
return this;
}
......@@ -447,7 +422,7 @@ internal ScriptOptions WithReferenceResolver(MetadataFileReferenceResolver resol
/// </summary>
internal ScriptOptions WithReferenceProvider(MetadataFileReferenceProvider provider)
{
if (provider == _referenceResolver.Provider)
if (provider.Equals(_referenceResolver.Provider))
{
return this;
}
......
......@@ -147,9 +147,11 @@
<Link>GlobalAssemblyCache.cs</Link>
</Compile>
<Compile Include="AssemblyLoadResult.cs" />
<Compile Include="DesktopMetadataReferenceResolver.cs" />
<Compile Include="InteractiveAssemblyLoader.cs" />
<Compile Include="MetadataShadowCopy.cs" />
<Compile Include="MetadataShadowCopyProvider.cs" />
<Compile Include="NuGetPackageResolver.cs" />
<Compile Include="ScriptCompilerUtil.cs" />
<Compile Include="ShadowCopy.cs" />
<Compile Include="ObjectFormatter.cs" />
......@@ -203,4 +205,4 @@
<Import Project="..\..\..\build\Targets\VSL.Imports.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
......@@ -40,14 +40,6 @@ public ScriptEngine Engine
get { return _engine; }
}
internal MetadataFileReferenceResolver MetadataReferenceResolver
{
get
{
return _options.AssemblyResolver.PathResolver;
}
}
internal Type HostObjectType
{
get { return _globalsType; }
......
......@@ -14,10 +14,29 @@ namespace Roslyn.Test.Utilities
/// </summary>
internal abstract class TestMetadataReferenceResolver : MetadataFileReferenceResolver
{
public TestMetadataReferenceResolver()
: base(searchPaths: ImmutableArray.Create<string>(),
baseDirectory: null)
public override string ResolveReference(string reference, string baseFilePath)
{
return null;
}
public override ImmutableArray<string> SearchPaths
{
get { return ImmutableArray<string>.Empty; }
}
public override string BaseDirectory
{
get { return null; }
}
internal override MetadataFileReferenceResolver WithSearchPaths(ImmutableArray<string> searchPaths)
{
throw new NotImplementedException();
}
internal override MetadataFileReferenceResolver WithBaseDirectory(string baseDirectory)
{
throw new NotImplementedException();
}
}
......@@ -52,22 +71,48 @@ public override string ResolveReference(string reference, string baseFilePath)
}
}
internal class VirtualizedFileReferenceResolver : MetadataFileReferenceResolver
internal sealed class VirtualizedFileReferenceResolver : MetadataFileReferenceResolver
{
private readonly RelativePathReferenceResolver _resolver;
private readonly HashSet<string> _existingFullPaths;
public VirtualizedFileReferenceResolver(
IEnumerable<string> existingFullPaths = null,
string baseDirectory = null,
ImmutableArray<string> searchPaths = default(ImmutableArray<string>))
: base(searchPaths.NullToEmpty(), baseDirectory)
{
_resolver = new RelativePathReferenceResolver(searchPaths.NullToEmpty(), baseDirectory, FileExists);
_existingFullPaths = new HashSet<string>(existingFullPaths, StringComparer.OrdinalIgnoreCase);
}
protected override bool FileExists(string fullPath)
public override ImmutableArray<string> SearchPaths
{
get { return _resolver.SearchPaths; }
}
public override string BaseDirectory
{
get { return _resolver.BaseDirectory; }
}
internal override MetadataFileReferenceResolver WithSearchPaths(ImmutableArray<string> searchPaths)
{
throw new NotImplementedException();
}
internal override MetadataFileReferenceResolver WithBaseDirectory(string baseDirectory)
{
throw new NotImplementedException();
}
public override string ResolveReference(string reference, string baseFilePath)
{
return _resolver.ResolveReference(reference, baseFilePath);
}
private bool FileExists(string fullPath)
{
return fullPath != null && _existingFullPaths != null && _existingFullPaths.Contains(FileUtilities.NormalizeAbsolutePath(fullPath));
return _existingFullPaths.Contains(FileUtilities.NormalizeAbsolutePath(fullPath));
}
}
}
......@@ -183,7 +183,7 @@ protected override CSharpCompilationOptions CreateCompilationOptions()
if (this.Workspace != null)
{
referenceResolver = new AssemblyReferenceResolver(
new MetadataFileReferenceResolver(referenceSearchPaths, projectDirectory),
new RelativePathReferenceResolver(referenceSearchPaths, projectDirectory),
this.Workspace.CurrentSolution.Services.MetadataService.GetProvider());
}
else
......
......@@ -1267,7 +1267,7 @@ private static MetadataFileReferenceResolver CreateMetadataReferenceResolver(str
assemblySearchPaths = ImmutableArray.Create(outputDirectory);
}
return new MetadataFileReferenceResolver(assemblySearchPaths, baseDirectory: projectDirectory);
return new RelativePathReferenceResolver(assemblySearchPaths, baseDirectory: projectDirectory);
}
private bool TryGetOutputPathFromBuildManager(out string binOutputPath)
......
......@@ -34,7 +34,7 @@ public static ProjectInfo CreateProjectInfo(string projectName, string language,
var commandLineArguments = commandLineParser.Parse(commandLineArgs, projectDirectory, isInteractive: false, sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());
// TODO (tomat): to match csc.exe/vbc.exe we should use CommonCommandLineCompiler.ExistingReferencesResolver to deal with #r's
var referenceResolver = new MetadataFileReferenceResolver(commandLineArguments.ReferencePaths, commandLineArguments.BaseDirectory);
var referenceResolver = new RelativePathReferenceResolver(commandLineArguments.ReferencePaths, commandLineArguments.BaseDirectory);
var referenceProvider = tmpWorkspace.Services.GetRequiredService<IMetadataService>().GetProvider();
var analyzerLoader = tmpWorkspace.Services.GetRequiredService<IAnalyzerService>().GetLoader();
var xmlFileResolver = new XmlFileResolver(commandLineArguments.BaseDirectory);
......
......@@ -361,7 +361,7 @@ private async Task<ProjectId> LoadProjectAsync(string projectFilePath, IProjectF
isInteractive: false,
sdkDirectory: RuntimeEnvironment.GetRuntimeDirectory());
var resolver = new MetadataFileReferenceResolver(commandLineArgs.ReferencePaths, commandLineArgs.BaseDirectory);
var resolver = new RelativePathReferenceResolver(commandLineArgs.ReferencePaths, commandLineArgs.BaseDirectory);
var metadataReferences = commandLineArgs.ResolveMetadataReferences(new AssemblyReferenceResolver(resolver, metadataService.GetProvider()));
var analyzerLoader = analyzerService.GetLoader();
......@@ -449,7 +449,7 @@ private async Task<ProjectId> LoadProjectAsync(string projectFilePath, IProjectF
.WithSourceReferenceResolver(new SourceFileResolver(ImmutableArray<string>.Empty, projectDirectory))
.WithMetadataReferenceResolver(
new AssemblyReferenceResolver(
new MetadataFileReferenceResolver(ImmutableArray<string>.Empty, projectDirectory),
new RelativePathReferenceResolver(ImmutableArray<string>.Empty, projectDirectory),
MetadataFileReferenceProvider.Default))
.WithStrongNameProvider(new DesktopStrongNameProvider(ImmutableArray.Create(projectDirectory, outputFilePath)))
.WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default);
......
......@@ -86,6 +86,12 @@
<Compile Include="..\..\..\Compilers\Helpers\SimpleAnalyzerAssemblyLoader.cs">
<Link>InternalUtilities\SimpleAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\..\Scripting\Core\DesktopMetadataReferenceResolver.cs">
<Link>InternalUtilities\DesktopMetadataReferenceResolver.cs</Link>
</Compile>
<Compile Include="..\..\..\Scripting\Core\NuGetPackageResolver.cs">
<Link>InternalUtilities\NuGetPackageResolver.cs</Link>
</Compile>
<Compile Include="Options\ExportOptionAttribute.cs" />
<Compile Include="InternalUtilities\FilePathUtilities.cs" />
<Compile Include="Log\EtwLogger.cs" />
......
......@@ -248,6 +248,9 @@
<Compile Include="..\..\..\Compilers\Core\Portable\MetadataFileReferenceResolver.cs">
<Link>InternalUtilities\MetadataFileReferenceResolver.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\RelativePathReferenceResolver.cs">
<Link>InternalUtilities\RelativePathReferenceResolver.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\ReflectionUtilities.cs">
<Link>InternalUtilities\ReflectionUtilities.cs</Link>
</Compile>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册