提交 c6012415 编写于 作者: A Andy Gocke

Add analyzer loading support for CoreCLR

Adds a new type, CoreClrAnalyzerAssemblyLoader, that is responsible
for finding and loading analyzer assemblies on CoreCLR. This is used
in the CscCore and VbcCore CoreCLR-targeting projects.
上级 dd396a80
......@@ -67,8 +67,11 @@
<Compile Include="..\..\Helpers\ConsoleUtil.cs">
<Link>ConsoleUtil.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\NoOpAnalyzerAssemblyLoader.cs">
<Link>ConsoleUtil.cs</Link>
<Compile Include="..\..\Helpers\CoreClrAnalyzerAssemblyLoader.cs">
<Link>CoreClrAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\AnalyzerAssemblyLoadUtils.cs">
<Link>AnalyzerAssemblyLoadUtils.cs</Link>
</Compile>
<Compile Include="Csc.cs" />
<Compile Include="Program.cs" />
......
......@@ -3,6 +3,7 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
namespace Microsoft.CodeAnalysis.CSharp.CommandLine
{
......@@ -12,6 +13,6 @@ public static int Main(string[] args)
=> Csc.Run(args: args,
clientDirectory: AppContext.BaseDirectory,
sdkDirectory: null,
analyzerLoader: new NoOpAnalyzerAssemblyLoader());
analyzerLoader: CoreClrAnalyzerAssemblyLoader.CreateAndSetDefault());
}
}
......@@ -23,8 +23,9 @@
"System.Runtime.Extensions": "4.0.11-beta-23321",
"System.Runtime.Handles": "4.0.1-beta-23321",
"System.Runtime.InteropServices": "4.0.21-beta-23321",
"System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-23311",
"System.Runtime.Loader": "4.0.0-beta-23321",
"System.Runtime.Serialization.Json": "4.0.1-beta-23321",
"System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-23311",
"System.Text.Encoding": "4.0.11-beta-23321",
"System.Text.Encoding.Extensions": "4.0.11-beta-23321",
"System.Threading": "4.0.11-beta-23321",
......
......@@ -478,6 +478,19 @@
"lib/DNXCore50/System.Runtime.InteropServices.dll": {}
}
},
"System.Runtime.Loader/4.0.0-beta-23321": {
"dependencies": {
"System.IO": "[4.0.0, )",
"System.Reflection": "[4.0.0, )",
"System.Runtime": "[4.0.0, )"
},
"compile": {
"ref/dotnet/System.Runtime.Loader.dll": {}
},
"runtime": {
"lib/DNXCore50/System.Runtime.Loader.dll": {}
}
},
"System.Runtime.Serialization.Json/4.0.1-beta-23321": {
"dependencies": {
"System.Private.DataContractSerialization": "[4.0.1-beta-23321, )"
......@@ -1391,6 +1404,19 @@
"lib/DNXCore50/System.Runtime.InteropServices.dll": {}
}
},
"System.Runtime.Loader/4.0.0-beta-23321": {
"dependencies": {
"System.IO": "[4.0.0, )",
"System.Reflection": "[4.0.0, )",
"System.Runtime": "[4.0.0, )"
},
"compile": {
"ref/dotnet/System.Runtime.Loader.dll": {}
},
"runtime": {
"lib/DNXCore50/System.Runtime.Loader.dll": {}
}
},
"System.Runtime.Serialization.Json/4.0.1-beta-23321": {
"dependencies": {
"System.Private.DataContractSerialization": "[4.0.1-beta-23321, )"
......@@ -2466,6 +2492,19 @@
"lib/DNXCore50/System.Runtime.InteropServices.dll": {}
}
},
"System.Runtime.Loader/4.0.0-beta-23321": {
"dependencies": {
"System.IO": "[4.0.0, )",
"System.Reflection": "[4.0.0, )",
"System.Runtime": "[4.0.0, )"
},
"compile": {
"ref/dotnet/System.Runtime.Loader.dll": {}
},
"runtime": {
"lib/DNXCore50/System.Runtime.Loader.dll": {}
}
},
"System.Runtime.Serialization.Json/4.0.1-beta-23321": {
"dependencies": {
"System.Private.DataContractSerialization": "[4.0.1-beta-23321, )"
......@@ -4581,6 +4620,18 @@
"System.Runtime.InteropServices.nuspec"
]
},
"System.Runtime.Loader/4.0.0-beta-23321": {
"sha512": "xyfQB/CKuzy/kaiMWtNgX16mMTsgt2ktdmG7COIXBFAkHUARSeBAjMOWkGdNWPzOWINYumqamA8JxGsQlPhuPQ==",
"type": "Package",
"files": [
"[Content_Types].xml",
"_rels/.rels",
"lib/DNXCore50/System.Runtime.Loader.dll",
"package/services/metadata/core-properties/55d60ad8f5d24e06bf703dd426e1ec45.psmdcp",
"ref/dotnet/System.Runtime.Loader.dll",
"System.Runtime.Loader.nuspec"
]
},
"System.Runtime.Serialization.Json/4.0.1-beta-23321": {
"sha512": "TWQRwFnriFMykVgsCyowKFI5eLWoceMtoIrrx9Wd2ZL+XAnsdiYe8OUVeL9Q0kLVs3Ew12sPiXtY2wvVDAYR3w==",
"type": "Package",
......@@ -5138,6 +5189,7 @@
"System.Runtime.Extensions >= 4.0.11-beta-23321",
"System.Runtime.Handles >= 4.0.1-beta-23321",
"System.Runtime.InteropServices >= 4.0.21-beta-23321",
"System.Runtime.Loader >= 4.0.0-beta-23321",
"System.Runtime.Serialization.Json >= 4.0.1-beta-23321",
"System.Security.Cryptography.Hashing.Algorithms >= 4.0.0-beta-23311",
"System.Text.Encoding >= 4.0.11-beta-23321",
......
......@@ -53,6 +53,9 @@
<Compile Include="..\..\Helpers\AbstractAnalyzerAssemblyLoader.cs">
<Link>AbstractAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\AnalyzerAssemblyLoadUtils.cs">
<Link>AnalyzerAssemblyLoadUtils.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\ConsoleUtil.cs">
<Link>ConsoleUtil.cs</Link>
</Compile>
......@@ -77,4 +80,4 @@
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
</ImportGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -51,6 +51,9 @@
<Compile Include="..\..\Helpers\AbstractAnalyzerAssemblyLoader.cs">
<Link>AbstractAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\AnalyzerAssemblyLoadUtils.cs">
<Link>AnalyzerAssemblyLoadUtils.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\ShadowCopyAnalyzerAssemblyLoader.cs">
<Link>ShadowCopyAnalyzerAssemblyLoader.cs</Link>
</Compile>
......
......@@ -11,6 +11,8 @@
using System.Reflection.PortableExecutable;
using Roslyn.Utilities;
using static Microsoft.CodeAnalysis.AnalyzerAssemblyLoadUtils;
namespace Microsoft.CodeAnalysis
{
internal abstract class AbstractAnalyzerAssemblyLoader : IAnalyzerAssemblyLoader
......@@ -148,41 +150,5 @@ private bool FileMatchesAssemblyName(string path, string assemblySimpleName)
{
return Path.GetFileNameWithoutExtension(path).Equals(assemblySimpleName, StringComparison.OrdinalIgnoreCase);
}
private static AssemblyIdentity TryGetAssemblyIdentity(string filePath)
{
try
{
if (!File.Exists(filePath))
{
return null;
}
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete))
using (var peReader = new PEReader(stream))
{
var metadataReader = peReader.GetMetadataReader();
AssemblyDefinition assemblyDefinition = metadataReader.GetAssemblyDefinition();
string name = metadataReader.GetString(assemblyDefinition.Name);
Version version = assemblyDefinition.Version;
StringHandle cultureHandle = assemblyDefinition.Culture;
string cultureName = (!cultureHandle.IsNil) ? metadataReader.GetString(cultureHandle) : null;
AssemblyFlags flags = assemblyDefinition.Flags;
bool hasPublicKey = (flags & AssemblyFlags.PublicKey) != 0;
BlobHandle publicKeyHandle = assemblyDefinition.PublicKey;
ImmutableArray<byte> publicKeyOrToken = !publicKeyHandle.IsNil
? metadataReader.GetBlobBytes(publicKeyHandle).AsImmutableOrNull()
: default(ImmutableArray<byte>);
return new AssemblyIdentity(name, version, cultureName, publicKeyOrToken, hasPublicKey);
}
}
catch { }
return 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;
using System.Collections.Immutable;
using System.IO;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
namespace Microsoft.CodeAnalysis
{
internal static class AnalyzerAssemblyLoadUtils
{
public static AssemblyIdentity TryGetAssemblyIdentity(string filePath)
{
try
{
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete))
using (var peReader = new PEReader(stream))
{
var metadataReader = peReader.GetMetadataReader();
AssemblyDefinition assemblyDefinition = metadataReader.GetAssemblyDefinition();
string name = metadataReader.GetString(assemblyDefinition.Name);
Version version = assemblyDefinition.Version;
StringHandle cultureHandle = assemblyDefinition.Culture;
string cultureName = (!cultureHandle.IsNil) ? metadataReader.GetString(cultureHandle) : null;
AssemblyFlags flags = assemblyDefinition.Flags;
bool hasPublicKey = (flags & AssemblyFlags.PublicKey) != 0;
BlobHandle publicKeyHandle = assemblyDefinition.PublicKey;
ImmutableArray<byte> publicKeyOrToken = !publicKeyHandle.IsNil
? metadataReader.GetBlobBytes(publicKeyHandle).AsImmutableOrNull()
: default(ImmutableArray<byte>);
return new AssemblyIdentity(name, version, cultureName, publicKeyOrToken, hasPublicKey);
}
}
catch { }
return 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;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Roslyn.Utilities;
using static Microsoft.CodeAnalysis.AnalyzerAssemblyLoadUtils;
namespace Microsoft.CodeAnalysis
{
/// Core CLR compatible wrapper for loading analyzers.
internal sealed class CoreClrAnalyzerAssemblyLoader : AssemblyLoadContext, IAnalyzerAssemblyLoader
{
private readonly Dictionary<string, Assembly> _pathsToAssemblies = new Dictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<string, Assembly> _namesToAssemblies = new Dictionary<string, Assembly>();
private readonly List<string> _dependencyPaths = new List<string>();
private readonly object _guard = new object();
/// <summary>
/// Creates a new instance of <see cref="CoreClrAnalyzerAssemblyLoader" />,
/// sets that instance to be the default <see cref="AssemblyLoadContext" />,
/// and returns that instance. Throws if the Default is already set or the
/// binding model is already locked.
/// </summary>
public static CoreClrAnalyzerAssemblyLoader CreateAndSetDefault()
{
var assemblyLoader = new CoreClrAnalyzerAssemblyLoader();
InitializeDefaultContext(assemblyLoader);
return assemblyLoader;
}
public void AddDependencyLocation(string fullPath)
{
if (fullPath == null)
{
throw new ArgumentNullException(nameof(fullPath));
}
lock (_guard)
{
_dependencyPaths.Add(fullPath);
}
}
public Assembly LoadFromPath(string fullPath)
{
if (fullPath == null)
{
throw new ArgumentNullException(nameof(fullPath));
}
Debug.Assert(PathUtilities.IsAbsolute(fullPath));
lock (_guard)
{
Assembly assembly;
if (_pathsToAssemblies.TryGetValue(fullPath, out assembly))
{
return assembly;
}
return LoadAndCache(fullPath);
}
}
private static readonly string[] s_extensions = new string[] { ".dll", ".exe" };
/// <summary>
/// Searches and loads from the base directory of the current
/// app context
/// </summary>
private Assembly AppContextLoad(AssemblyName assemblyName)
{
var baseDir = AppContext.BaseDirectory;
foreach (var extension in s_extensions)
{
var path = Path.Combine(baseDir, assemblyName.Name + extension);
if (File.Exists(path))
{
lock (_guard)
{
return LoadAndCache(path);
}
}
}
return null;
}
protected override Assembly Load(AssemblyName assemblyName)
{
lock (_guard)
{
// Try and grab assembly using standard load
Assembly assembly = AppContextLoad(assemblyName);
if (assembly != null)
{
return assembly;
}
string fullName = assemblyName.FullName;
if (_namesToAssemblies.TryGetValue(fullName, out assembly))
{
return assembly;
}
AssemblyIdentity requestedIdentity;
if (!AssemblyIdentity.TryParseDisplayName(fullName, out requestedIdentity))
{
return null;
}
foreach (var candidatePath in _dependencyPaths)
{
if (IsAssemblyAlreadyLoaded(candidatePath) ||
!FileMatchesAssemblyName(candidatePath, requestedIdentity.Name))
{
continue;
}
var candidateIdentity = TryGetAssemblyIdentity(candidatePath);
if (requestedIdentity.Equals(candidateIdentity))
{
return LoadAndCache(candidatePath);
}
}
return null;
}
}
/// <remarks>
/// Assumes we have a lock on _guard
/// </remarks>
private Assembly LoadAndCache(string fullPath)
{
var assembly = LoadFromAssemblyPath(fullPath);
var name = assembly.FullName;
_pathsToAssemblies[fullPath] = assembly;
_namesToAssemblies[name] = assembly;
return assembly;
}
private bool IsAssemblyAlreadyLoaded(string path)
{
return _pathsToAssemblies.ContainsKey(path);
}
private bool FileMatchesAssemblyName(string path, string assemblySimpleName)
{
return Path.GetFileNameWithoutExtension(path).Equals(assemblySimpleName, StringComparison.OrdinalIgnoreCase);
}
}
}
// 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.Reflection;
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// Workaround for assembly loading in core clr -- this loader does nothing.
/// </summary>
internal sealed class NoOpAnalyzerAssemblyLoader : IAnalyzerAssemblyLoader
{
public Assembly LoadFromPath(string fullPath) => null;
public void AddDependencyLocation(string fullPath) { }
}
}
......@@ -12,6 +12,6 @@ public static int Main(string[] args)
=> Vbc.Run(args: args,
clientDirectory: AppContext.BaseDirectory,
sdkDirectory: @"C:\Windows\Microsoft.NET\Framework\v4.0.30319",
analyzerLoader: new NoOpAnalyzerAssemblyLoader());
analyzerLoader: CoreClrAnalyzerAssemblyLoader.CreateAndSetDefault());
}
}
......@@ -67,8 +67,11 @@
<Compile Include="..\..\Helpers\ConsoleUtil.cs">
<Link>ConsoleUtil.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\NoOpAnalyzerAssemblyLoader.cs">
<Link>ConsoleUtil.cs</Link>
<Compile Include="..\..\Helpers\CoreClrAnalyzerAssemblyLoader.cs">
<Link>CoreClrAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\AnalyzerAssemblyLoadUtils.cs">
<Link>AnalyzerAssemblyLoadUtils.cs</Link>
</Compile>
<Compile Include="Vbc.cs" />
<Compile Include="Program.cs" />
......
......@@ -23,8 +23,9 @@
"System.Runtime.Extensions": "4.0.11-beta-23321",
"System.Runtime.Handles": "4.0.1-beta-23321",
"System.Runtime.InteropServices": "4.0.21-beta-23321",
"System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-23311",
"System.Runtime.Loader": "4.0.0-beta-23321",
"System.Runtime.Serialization.Json": "4.0.1-beta-23321",
"System.Security.Cryptography.Hashing.Algorithms": "4.0.0-beta-23311",
"System.Text.Encoding": "4.0.11-beta-23321",
"System.Text.Encoding.Extensions": "4.0.11-beta-23321",
"System.Threading": "4.0.11-beta-23321",
......
......@@ -478,6 +478,19 @@
"lib/DNXCore50/System.Runtime.InteropServices.dll": {}
}
},
"System.Runtime.Loader/4.0.0-beta-23321": {
"dependencies": {
"System.IO": "[4.0.0, )",
"System.Reflection": "[4.0.0, )",
"System.Runtime": "[4.0.0, )"
},
"compile": {
"ref/dotnet/System.Runtime.Loader.dll": {}
},
"runtime": {
"lib/DNXCore50/System.Runtime.Loader.dll": {}
}
},
"System.Runtime.Serialization.Json/4.0.1-beta-23321": {
"dependencies": {
"System.Private.DataContractSerialization": "[4.0.1-beta-23321, )"
......@@ -1391,6 +1404,19 @@
"lib/DNXCore50/System.Runtime.InteropServices.dll": {}
}
},
"System.Runtime.Loader/4.0.0-beta-23321": {
"dependencies": {
"System.IO": "[4.0.0, )",
"System.Reflection": "[4.0.0, )",
"System.Runtime": "[4.0.0, )"
},
"compile": {
"ref/dotnet/System.Runtime.Loader.dll": {}
},
"runtime": {
"lib/DNXCore50/System.Runtime.Loader.dll": {}
}
},
"System.Runtime.Serialization.Json/4.0.1-beta-23321": {
"dependencies": {
"System.Private.DataContractSerialization": "[4.0.1-beta-23321, )"
......@@ -2466,6 +2492,19 @@
"lib/DNXCore50/System.Runtime.InteropServices.dll": {}
}
},
"System.Runtime.Loader/4.0.0-beta-23321": {
"dependencies": {
"System.IO": "[4.0.0, )",
"System.Reflection": "[4.0.0, )",
"System.Runtime": "[4.0.0, )"
},
"compile": {
"ref/dotnet/System.Runtime.Loader.dll": {}
},
"runtime": {
"lib/DNXCore50/System.Runtime.Loader.dll": {}
}
},
"System.Runtime.Serialization.Json/4.0.1-beta-23321": {
"dependencies": {
"System.Private.DataContractSerialization": "[4.0.1-beta-23321, )"
......@@ -4581,6 +4620,18 @@
"System.Runtime.InteropServices.nuspec"
]
},
"System.Runtime.Loader/4.0.0-beta-23321": {
"sha512": "xyfQB/CKuzy/kaiMWtNgX16mMTsgt2ktdmG7COIXBFAkHUARSeBAjMOWkGdNWPzOWINYumqamA8JxGsQlPhuPQ==",
"type": "Package",
"files": [
"[Content_Types].xml",
"_rels/.rels",
"lib/DNXCore50/System.Runtime.Loader.dll",
"package/services/metadata/core-properties/55d60ad8f5d24e06bf703dd426e1ec45.psmdcp",
"ref/dotnet/System.Runtime.Loader.dll",
"System.Runtime.Loader.nuspec"
]
},
"System.Runtime.Serialization.Json/4.0.1-beta-23321": {
"sha512": "TWQRwFnriFMykVgsCyowKFI5eLWoceMtoIrrx9Wd2ZL+XAnsdiYe8OUVeL9Q0kLVs3Ew12sPiXtY2wvVDAYR3w==",
"type": "Package",
......@@ -5138,6 +5189,7 @@
"System.Runtime.Extensions >= 4.0.11-beta-23321",
"System.Runtime.Handles >= 4.0.1-beta-23321",
"System.Runtime.InteropServices >= 4.0.21-beta-23321",
"System.Runtime.Loader >= 4.0.0-beta-23321",
"System.Runtime.Serialization.Json >= 4.0.1-beta-23321",
"System.Security.Cryptography.Hashing.Algorithms >= 4.0.0-beta-23311",
"System.Text.Encoding >= 4.0.11-beta-23321",
......
......@@ -72,6 +72,9 @@
<Compile Include="..\..\Helpers\AbstractAnalyzerAssemblyLoader.cs">
<Link>AbstractAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\AnalyzerAssemblyLoadUtils.cs">
<Link>AnalyzerAssemblyLoadUtils.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\ConsoleUtil.cs">
<Link>ConsoleUtil.cs</Link>
</Compile>
......
......@@ -89,6 +89,9 @@
<Compile Include="..\..\..\Compilers\Helpers\AbstractAnalyzerAssemblyLoader.cs">
<Link>AbstractAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Helpers\AnalyzerAssemblyLoadUtils.cs">
<Link>AnalyzerAssemblyLoadUtils.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Helpers\SimpleAnalyzerAssemblyLoader.cs">
<Link>SimpleAnalyzerAssemblyLoader.cs</Link>
</Compile>
......@@ -163,4 +166,4 @@
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
<Import Project="..\..\..\..\build\Targets\Roslyn.Toolsets.Xunit.targets" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
......@@ -58,6 +58,9 @@
<Compile Include="..\..\..\Compilers\Helpers\AbstractAnalyzerAssemblyLoader.cs">
<Link>InternalUtilities\AbstractAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Helpers\AnalyzerAssemblyLoadUtils.cs">
<Link>AnalyzerAssemblyLoadUtils.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Helpers\GlobalAssemblyCacheHelpers\FusionAssemblyIdentity.cs">
<Link>InternalUtilities\FusionAssemblyIdentity.cs</Link>
</Compile>
......@@ -167,4 +170,4 @@
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
</ImportGroup>
</Project>
\ No newline at end of file
</Project>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册