Skip to content

Commit

Permalink
Search all Analyzer assembly paths when resolving dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeRobich committed Feb 8, 2021
1 parent b3e5183 commit ae02df0
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 8 deletions.
25 changes: 18 additions & 7 deletions src/Analyzers/AnalyzerReferenceInformationProvider.cs
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -43,7 +44,9 @@ private AnalyzersAndFixers GetAnalyzersAndFixers(Project project)

try
{
context.AssemblyFolderPath = Path.GetDirectoryName(path);
// Until types are realized not all dependencies are loaded. Track each
// assembly's path as a search path when resolving dependencies.
context.AddSearchPath(Path.GetDirectoryName(path));

// First try loading the assembly from disk.
return context.LoadFromAssemblyPath(path);
Expand All @@ -58,7 +61,12 @@ private AnalyzersAndFixers GetAnalyzersAndFixers(Project project)

internal sealed class AnalyzerLoadContext : AssemblyLoadContext
{
internal string AssemblyFolderPath { get; set; } = string.Empty;
internal readonly HashSet<string> _searchPaths = new HashSet<string>();

internal void AddSearchPath(string path)
{
_searchPaths.Add(path);
}

protected override Assembly Load(AssemblyName assemblyName)
{
Expand All @@ -68,12 +76,15 @@ protected override Assembly Load(AssemblyName assemblyName)

try
{
// Search for assembly based on assembly name and culture within the analyzer folder.
var assembly = AssemblyResolver.TryResolveAssemblyFromPaths(this, assemblyName, AssemblyFolderPath);

if (assembly != null)
foreach (var searchPath in _searchPaths)
{
return assembly;
// Search for assembly based on assembly name and culture within the analyzer folder.
var assembly = AssemblyResolver.TryResolveAssemblyFromPaths(this, assemblyName, searchPath);

if (assembly != null)
{
return assembly;
}
}
}
catch { }
Expand Down
49 changes: 48 additions & 1 deletion tests/Analyzers/ThirdPartyAnalyzerFormatterTests.cs
Expand Up @@ -120,7 +120,7 @@ void M()
}

[Fact]
public async Task TestIDisposableAnalyzer_Loads()
public async Task TestIDisposableAnalyzer_AddsUsing()
{
var analyzerReferences = GetAnalyzerReferences("IDisposable");

Expand All @@ -141,6 +141,53 @@ void M()
var expectedCode = @"
using System.IO;
class C
{
void M()
{
using (var stream = File.OpenRead(string.Empty))
{
var b = stream.ReadByte();
}
}
}
";

var editorConfig = new Dictionary<string, string>()
{
// Turn off all diagnostics analyzers
["dotnet_analyzer_diagnostic.severity"] = "none",

// Prefer using. IDISP017
["dotnet_diagnostic.IDISP017.severity"] = "error",
};

await AssertCodeChangedAsync(testCode, expectedCode, editorConfig, fixCategory: FixCategory.Analyzers, analyzerReferences: analyzerReferences);
}

[Fact]
public async Task TestLoadingAllAnalyzers_LoadsDependenciesFromAllSearchPaths()
{
// Loads all analyzer references.
var analyzerReferences = _analyzerReferencesProject.AnalyzerReferences;

var testCode = @"
using System.IO;
class C
{
void M()
{
var stream = File.OpenRead(string.Empty);
var b = stream.ReadByte();
stream.Dispose();
}
}
";

var expectedCode = @"
using System.IO;
class C
{
void M()
Expand Down
Expand Up @@ -9,6 +9,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="AspNetCoreAnalyzers" Version="0.2.0.1-dev" PrivateAssets="all" />
<PackageReference Include="IDisposableAnalyzers" Version="3.4.8" PrivateAssets="all" />
</ItemGroup>

Expand Down

0 comments on commit ae02df0

Please sign in to comment.