提交 58ca057b 编写于 作者: T Tom Meschter

Push loaders out to the hosts

Move the analyzer assembly loaders out of `CodeAnalysis.Desktop` and
into the individual host projects (csc. csi, vbc, vbi, etc.). This
solves two issues:

1. The loader types can now be made internal.
2. `CodeAnalysis.Desktop` no longer has a dependency on the loader
implementation, and the loaders can be swapped or modified on a per-host
basis as needed.
上级 d032573b
......@@ -68,6 +68,10 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\packages\System.Collections.Immutable.1.1.34-rc\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="System.Reflection.Metadata, Version=1.0.19.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\packages\System.Reflection.Metadata.1.0.19-rc\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Core\MSBuildTask\BuildClient.cs">
......@@ -82,9 +86,15 @@
<Compile Include="..\..\Core\VBCSCompiler\CompilerServerLogger.cs">
<Link>CompilerServerLogger.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\AbstractAnalyzerAssemblyLoader.cs">
<Link>AbstractAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\ConsoleUtil.cs">
<Link>ConsoleUtil.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\SimpleAnalyzerAssemblyLoader.cs">
<Link>SimpleAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="Csc.cs" />
<Compile Include="Program.cs" />
</ItemGroup>
......@@ -105,4 +115,4 @@
<Import Project="..\..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
......@@ -49,7 +49,6 @@
<CodeAnalysisRuleSet>..\CodeAnalysisRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Compile Include="AbstractAnalyzerAssemblyLoader.cs" />
<Compile Include="AdditionalTextFile.cs" />
<Compile Include="AnalyzerLoadFailureEventArgs.cs" />
<Compile Include="AssemblyReferenceResolver.cs" />
......@@ -95,8 +94,6 @@
<Compile Include="MetadataFileReferenceResolver.cs" />
<Compile Include="PathKind.cs" />
<Compile Include="PathUtilities.cs" />
<Compile Include="ShadowCopyAnalyzerAssemblyLoader.cs" />
<Compile Include="SimpleAnalyzerAssemblyLoader.cs" />
<Compile Include="SourceFileResolver.cs" />
<Compile Include="SqmServiceProvider.cs" />
<Compile Include="XmlFileResolver.cs" />
......
Microsoft.CodeAnalysis.AbstractAnalyzerAssemblyLoader
Microsoft.CodeAnalysis.AbstractAnalyzerAssemblyLoader.AddDependencyLocation(string fullPath) -> void
Microsoft.CodeAnalysis.AbstractAnalyzerAssemblyLoader.LoadFromPath(string fullPath) -> System.Reflection.Assembly
Microsoft.CodeAnalysis.CommandLineAnalyzerReference
Microsoft.CodeAnalysis.CommandLineAnalyzerReference.CommandLineAnalyzerReference(string path) -> void
Microsoft.CodeAnalysis.CommandLineAnalyzerReference.Equals(Microsoft.CodeAnalysis.CommandLineAnalyzerReference other) -> bool
......@@ -78,9 +75,6 @@ Microsoft.CodeAnalysis.RuleSetInclude.Action.get -> Microsoft.CodeAnalysis.Repor
Microsoft.CodeAnalysis.RuleSetInclude.IncludePath.get -> string
Microsoft.CodeAnalysis.RuleSetInclude.LoadRuleSet(Microsoft.CodeAnalysis.RuleSet parent) -> Microsoft.CodeAnalysis.RuleSet
Microsoft.CodeAnalysis.RuleSetInclude.RuleSetInclude(string includePath, Microsoft.CodeAnalysis.ReportDiagnostic action) -> void
Microsoft.CodeAnalysis.ShadowCopyAnalyzerAssemblyLoader
Microsoft.CodeAnalysis.ShadowCopyAnalyzerAssemblyLoader.ShadowCopyAnalyzerAssemblyLoader(string baseDirectory = null) -> void
Microsoft.CodeAnalysis.SimpleAnalyzerAssemblyLoader
Microsoft.CodeAnalysis.SourceFileResolver
Microsoft.CodeAnalysis.SourceFileResolver.BaseDirectory.get -> string
Microsoft.CodeAnalysis.SourceFileResolver.SearchPaths.get -> System.Collections.Immutable.ImmutableArray<string>
......@@ -89,7 +83,6 @@ Microsoft.CodeAnalysis.SourceFileResolver.SourceFileResolver(System.Collections.
Microsoft.CodeAnalysis.XmlFileResolver
Microsoft.CodeAnalysis.XmlFileResolver.BaseDirectory.get -> string
Microsoft.CodeAnalysis.XmlFileResolver.XmlFileResolver(string baseDirectory) -> void
abstract Microsoft.CodeAnalysis.AbstractAnalyzerAssemblyLoader.LoadCore(string fullPath) -> System.Reflection.Assembly
abstract Microsoft.CodeAnalysis.CommandLineArguments.CompilationOptionsCore.get -> Microsoft.CodeAnalysis.CompilationOptions
abstract Microsoft.CodeAnalysis.CommandLineArguments.ParseOptionsCore.get -> Microsoft.CodeAnalysis.ParseOptions
abstract Microsoft.CodeAnalysis.CommandLineParser.RegularFileExtension.get -> string
......@@ -106,8 +99,6 @@ override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.FullPath.get -
override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetAnalyzers(string language) -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer>
override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetAnalyzersForAllLanguages() -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer>
override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetHashCode() -> int
override Microsoft.CodeAnalysis.ShadowCopyAnalyzerAssemblyLoader.LoadCore(string fullPath) -> System.Reflection.Assembly
override Microsoft.CodeAnalysis.SimpleAnalyzerAssemblyLoader.LoadCore(string fullPath) -> System.Reflection.Assembly
override Microsoft.CodeAnalysis.SourceFileResolver.Equals(object obj) -> bool
override Microsoft.CodeAnalysis.SourceFileResolver.GetHashCode() -> int
override Microsoft.CodeAnalysis.SourceFileResolver.NormalizePath(string path, string baseFilePath) -> string
......
......@@ -90,6 +90,12 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Helpers\AbstractAnalyzerAssemblyLoader.cs">
<Link>AbstractAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\ShadowCopyAnalyzerAssemblyLoader.cs">
<Link>ShadowCopyAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="Assembly.cs" />
<Compile Include="BuildProtocol.cs" />
<Compile Include="CompilerRequestHandler.cs" />
......
// 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 System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
internal abstract class AbstractAnalyzerAssemblyLoader : 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();
private bool _hookedAssemblyResolve = false;
/// <summary>
/// Add the path to an assembly to be considered while handling the
/// <see cref="AppDomain.AssemblyResolve"/> event.
/// </summary>
public void AddDependencyLocation(string fullPath)
{
if (fullPath == null)
{
throw new ArgumentNullException(nameof(fullPath));
}
lock (_guard)
{
if (!_dependencyPaths.Contains(fullPath, StringComparer.OrdinalIgnoreCase))
{
_dependencyPaths.Add(fullPath);
}
}
}
/// <summary>
/// Given a path to an assembly on disk, loads and returns the
/// corresponding <see cref="Assembly"/> object.
/// </summary>
/// <remarks>
/// Multiple calls with the same path will return the same
/// <see cref="Assembly"/> instance.
///
/// Also hooks the <see cref="AppDomain.AssemblyResolve"/> event in
/// case it needs to load a dependency.
/// </remarks>
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;
}
assembly = LoadInternal(fullPath);
if (!_hookedAssemblyResolve)
{
_hookedAssemblyResolve = true;
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
return assembly;
}
}
/// <summary>
///
/// </summary>
protected abstract Assembly LoadCore(string fullPath);
private Assembly LoadInternal(string fullPath)
{
Assembly assembly = LoadCore(fullPath);
string assemblyName = assembly.FullName;
_pathsToAssemblies[fullPath] = assembly;
_namesToAssemblies[assemblyName] = assembly;
return assembly;
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string requestedNameWithPolicyApplied = AppDomain.CurrentDomain.ApplyPolicy(args.Name);
lock (_guard)
{
Assembly assembly;
if (_namesToAssemblies.TryGetValue(requestedNameWithPolicyApplied, out assembly))
{
return assembly;
}
AssemblyIdentity requestedAssemblyIdentity;
if (!AssemblyIdentity.TryParseDisplayName(requestedNameWithPolicyApplied, out requestedAssemblyIdentity))
{
return null;
}
foreach (string candidatePath in _dependencyPaths)
{
if (AssemblyAlreadyLoaded(candidatePath) ||
!FileMatchesAssemblyName(candidatePath, requestedAssemblyIdentity.Name))
{
continue;
}
AssemblyIdentity candidateIdentity = TryGetAssemblyIdentity(candidatePath);
if (requestedAssemblyIdentity.Equals(candidateIdentity))
{
return LoadInternal(candidatePath);
}
}
return null;
}
}
private bool AssemblyAlreadyLoaded(string path)
{
return _pathsToAssemblies.ContainsKey(path);
}
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.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis
{
internal sealed class ShadowCopyAnalyzerAssemblyLoader : AbstractAnalyzerAssemblyLoader
{
/// <summary>
/// The base directory for shadow copies. Each instance of
/// <see cref="ShadowCopyAnalyzerAssemblyLoader"/> gets its own
/// subdirectory under this directory. This is also the starting point
/// for scavenge operations.
/// </summary>
private readonly string _baseDirectory;
/// <summary>
/// The directory where this instance of <see cref="ShadowCopyAnalyzerAssemblyLoader"/>
/// will shadow-copy assemblies.
/// </summary>
private string _shadowCopyDirectory;
private Mutex _shadowCopyDirectoryMutex;
/// <summary>
/// Used to generate unique names for per-assembly directories.
/// </summary>
private int _assemblyDirectoryId = 0;
public ShadowCopyAnalyzerAssemblyLoader(string baseDirectory = null)
{
if (baseDirectory != null)
{
_baseDirectory = baseDirectory;
}
else
{
_baseDirectory = Path.Combine(Path.GetTempPath(), "CodeAnalysis", "AnalyzerShadowCopies");
}
Task.Run((Action)DeleteLeftoverDirectories);
}
private void DeleteLeftoverDirectories()
{
foreach (var subDirectory in Directory.EnumerateDirectories(_baseDirectory))
{
string name = Path.GetFileName(subDirectory).ToLowerInvariant();
Mutex mutex = null;
try
{
// We only want to try deleting the directory if no one else is currently
// using it. That is, if there is no corresponding mutex.
if (!Mutex.TryOpenExisting(name, out mutex))
{
ClearReadOnlyFlagOnFiles(subDirectory);
Directory.Delete(subDirectory, recursive: true);
}
}
catch
{
// If something goes wrong we will leave it to the next run to clean up.
// Just swallow the exception and move on.
}
finally
{
if (mutex != null)
{
mutex.Dispose();
}
}
}
}
protected override Assembly LoadCore(string fullPath)
{
if (_shadowCopyDirectory == null)
{
_shadowCopyDirectory = CreateUniqueDirectoryForProcess();
}
string assemblyDirectory = CreateUniqueDirectoryForAssembly();
string shadowCopyPath = CopyFileAndResources(fullPath, assemblyDirectory);
return Assembly.LoadFrom(shadowCopyPath);
}
private string CopyFileAndResources(string fullPath, string assemblyDirectory)
{
string fileNameWithExtension = Path.GetFileName(fullPath);
string shadowCopyPath = Path.Combine(assemblyDirectory, fileNameWithExtension);
CopyFile(fullPath, shadowCopyPath);
string originalDirectory = Path.GetDirectoryName(fullPath);
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileNameWithExtension);
string resourcesNameWithoutExtension = fileNameWithoutExtension + ".resources";
string resourcesNameWithExtension = resourcesNameWithoutExtension + ".dll";
foreach (var directory in Directory.EnumerateDirectories(originalDirectory))
{
string directoryName = Path.GetFileName(directory);
string resourcesPath = Path.Combine(directory, resourcesNameWithExtension);
if (File.Exists(resourcesPath))
{
string resourcesShadowCopyPath = Path.Combine(assemblyDirectory, directoryName, resourcesNameWithExtension);
CopyFile(resourcesPath, resourcesShadowCopyPath);
}
resourcesPath = Path.Combine(directory, resourcesNameWithoutExtension, resourcesNameWithExtension);
if (File.Exists(resourcesPath))
{
string resourcesShadowCopyPath = Path.Combine(assemblyDirectory, directoryName, resourcesNameWithoutExtension, resourcesNameWithExtension);
CopyFile(resourcesPath, resourcesShadowCopyPath);
}
}
return shadowCopyPath;
}
private void CopyFile(string originalPath, string shadowCopyPath)
{
var directory = Path.GetDirectoryName(shadowCopyPath);
Directory.CreateDirectory(directory);
File.Copy(originalPath, shadowCopyPath);
ClearReadOnlyFlagOnFile(new FileInfo(shadowCopyPath));
}
private void ClearReadOnlyFlagOnFiles(string directoryPath)
{
DirectoryInfo directory = new DirectoryInfo(directoryPath);
foreach (var file in directory.EnumerateFiles(searchPattern: "*", searchOption: SearchOption.AllDirectories))
{
ClearReadOnlyFlagOnFile(file);
}
}
private void ClearReadOnlyFlagOnFile(FileInfo fileInfo)
{
try
{
if (fileInfo.IsReadOnly)
{
fileInfo.IsReadOnly = false;
}
}
catch
{
// There are many reasons this could fail. Ignore it and keep going.
}
}
private string CreateUniqueDirectoryForAssembly()
{
int directoryId = _assemblyDirectoryId++;
string directory = Path.Combine(_shadowCopyDirectory, directoryId.ToString());
Directory.CreateDirectory(directory);
return directory;
}
private string CreateUniqueDirectoryForProcess()
{
string guid = Guid.NewGuid().ToString("N").ToLowerInvariant();
string directory = Path.Combine(_baseDirectory, guid);
_shadowCopyDirectoryMutex = new Mutex(initiallyOwned: false, name: guid);
Directory.CreateDirectory(directory);
return directory;
}
}
}
// 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>
/// Loads analyzer assemblies from their original locations in the file system.
/// Assemblies will only be loaded from the locations specified when the loader
/// is instantiated.
/// </summary>
/// <remarks>
/// This type is meant to be used in scenarios where it is OK for the analyzer
/// assemblies to be locked on disk for the lifetime of the host; for example,
/// csc.exe and vbc.exe. In scenarios where support for updating or deleting
/// the analyzer on disk is required a different loader should be used.
/// </remarks>
internal sealed class SimpleAnalyzerAssemblyLoader : AbstractAnalyzerAssemblyLoader
{
protected override Assembly LoadCore(string fullPath)
{
return Assembly.LoadFrom(fullPath);
}
}
}
......@@ -104,6 +104,12 @@
<InternalsVisibleToTest Include="Roslyn.Test.Utilities" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\Helpers\AbstractAnalyzerAssemblyLoader.cs">
<Link>AbstractAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\..\Helpers\SimpleAnalyzerAssemblyLoader.cs">
<Link>SimpleAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="CSReflectionBasedKindProvider.cs" />
<Compile Include="Diagnostics\DiagnosticsHelper.cs" />
<Compile Include="Diagnostics\OptionsDiagnosticAnalyzer.cs" />
......
......@@ -68,6 +68,10 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\packages\System.Collections.Immutable.1.1.34-rc\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="System.Reflection.Metadata, Version=1.0.19.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\packages\System.Reflection.Metadata.1.0.19-rc\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Core\MSBuildTask\BuildClient.cs">
......@@ -82,9 +86,15 @@
<Compile Include="..\..\Core\VBCSCompiler\CompilerServerLogger.cs">
<Link>CompilerServerLogger.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\AbstractAnalyzerAssemblyLoader.cs">
<Link>AbstractAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\ConsoleUtil.cs">
<Link>ConsoleUtil.cs</Link>
</Compile>
<Compile Include="..\..\Helpers\SimpleAnalyzerAssemblyLoader.cs">
<Link>SimpleAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="Vbc.cs" />
<Compile Include="Program.cs" />
</ItemGroup>
......@@ -104,4 +114,4 @@
<Import Project="..\..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
......@@ -16,6 +16,9 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup Label="Linked Files">
<Compile Include="..\..\Compilers\Helpers\AbstractAnalyzerAssemblyLoader.cs">
<Link>AbstractAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\Compilers\Helpers\GlobalAssemblyCacheHelpers\FusionAssemblyIdentity.cs">
<Link>FusionAssemblyIdentity.cs</Link>
</Compile>
......@@ -84,6 +87,9 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Compilers\Helpers\SimpleAnalyzerAssemblyLoader.cs">
<Link>SimpleAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="AssemblyLoader.cs" />
<Compile Include="AssemblyLoadResult.cs" />
<Compile Include="ObjectFormatter.cs" />
......
......@@ -19,6 +19,9 @@
</PropertyGroup>
<ItemGroup Label="Build Items">
<Compile Include="..\..\..\Compilers\Core\Desktop\IVsSQM.cs" />
<Compile Include="..\..\..\Compilers\Helpers\ShadowCopyAnalyzerAssemblyLoader.cs">
<Link>InternalUtilities\ShadowCopyAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="Implementation\AnalyzerDependencyChecker.cs" />
<Compile Include="Implementation\AnalyzerDependencyCheckingService.cs" />
<Compile Include="Implementation\AnalyzerDependencyConflict.cs" />
......
......@@ -77,6 +77,9 @@
<Compile Include="..\..\..\Compilers\Core\Desktop\PathUtilities.cs">
<Link>InternalUtilities\PathUtilities.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Helpers\AbstractAnalyzerAssemblyLoader.cs">
<Link>InternalUtilities\AbstractAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Helpers\GlobalAssemblyCacheHelpers\FusionAssemblyIdentity.cs">
<Link>InternalUtilities\FusionAssemblyIdentity.cs</Link>
</Compile>
......@@ -89,6 +92,9 @@
<Compile Include="..\..\..\Compilers\Helpers\AssemblyIdentityExtensions.cs">
<Link>InternalUtilities\AssemblyIdentityExtensions.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Helpers\SimpleAnalyzerAssemblyLoader.cs">
<Link>InternalUtilities\SimpleAnalyzerAssemblyLoader.cs</Link>
</Compile>
<Compile Include="Options\ExportOptionAttribute.cs" />
<Compile Include="InternalUtilities\FilePathUtilities.cs" />
<Compile Include="Log\EtwLogger.cs" />
......@@ -181,4 +187,4 @@
<Import Project="..\..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册