提交 658c7286 编写于 作者: S Srivatsn Narayanan 提交者: GitHub

Merge pull request #19401 from tmeschter/FixAnalyzerNodeHookup

Use file path to hook up analyzers nodes in Solution Explorer
......@@ -121,7 +121,13 @@ private IAttachedCollectionSource CreateCollectionSourceCore(IVsHierarchyItem pr
{
var workspace = TryGetWorkspace();
var analyzerService = GetAnalyzerService();
return new CpsDiagnosticItemSource(workspace, projectId, item, _commandHandler, analyzerService);
var hierarchy = projectRootItem.HierarchyIdentity.NestedHierarchy;
var itemId = projectRootItem.HierarchyIdentity.NestedItemID;
if (hierarchy.GetCanonicalName(itemId, out string projectCanonicalName) == VSConstants.S_OK)
{
return new CpsDiagnosticItemSource(workspace, projectCanonicalName, projectId, item, _commandHandler, analyzerService);
}
}
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.ComponentModel;
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.Internal.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
......@@ -13,15 +14,17 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplore
internal partial class CpsDiagnosticItemSource : BaseDiagnosticItemSource, INotifyPropertyChanged
{
private readonly IVsHierarchyItem _item;
private readonly string _projectDirectoryPath;
private AnalyzerReference _analyzerReference;
public event PropertyChangedEventHandler PropertyChanged;
public CpsDiagnosticItemSource(Workspace workspace, ProjectId projectId, IVsHierarchyItem item, IAnalyzersCommandHandler commandHandler, IDiagnosticAnalyzerService analyzerService)
public CpsDiagnosticItemSource(Workspace workspace, string projectPath, ProjectId projectId, IVsHierarchyItem item, IAnalyzersCommandHandler commandHandler, IDiagnosticAnalyzerService analyzerService)
: base(workspace, projectId, commandHandler, analyzerService)
{
_item = item;
_projectDirectoryPath = Path.GetDirectoryName(projectPath);
_analyzerReference = TryGetAnalyzerReference(_workspace.CurrentSolution);
if (_analyzerReference == null)
......@@ -91,12 +94,15 @@ private AnalyzerReference TryGetAnalyzerReference(Solution solution)
return null;
}
if (!_item.HierarchyIdentity.NestedHierarchy.TryGetItemName(_item.HierarchyIdentity.NestedItemID, out string name))
var canonicalName = _item.CanonicalName;
var analyzerFilePath = CpsUtilities.ExtractAnalyzerFilePath(_projectDirectoryPath, canonicalName);
if (string.IsNullOrEmpty(analyzerFilePath))
{
return null;
}
return project.AnalyzerReferences.FirstOrDefault(r => r.Display.Equals(name));
return project.AnalyzerReferences.FirstOrDefault(r => r.FullPath.Equals(analyzerFilePath, StringComparison.OrdinalIgnoreCase));
}
}
}
\ No newline at end of file
// 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;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
{
internal static class CpsUtilities
{
/// <summary>
/// Given the canonical name of a node representing an analyzer assembly in the
/// CPS-based project system extracts out the full path to the assembly.
/// </summary>
/// <param name="projectDirectoryPath">The full path to the project directory</param>
/// <param name="analyzerNodeCanonicalName">The canonical name of the analyzer node in the hierarchy</param>
/// <returns>The full path to the analyzer assembly on disk, or null if <paramref name="analyzerNodeCanonicalName"/>
/// cannot be parsed.</returns>
/// <remarks>
/// The canonical name takes the following form:
///
/// [{path to project directory}\]{target framework}\analyzerdependency\{path to assembly}
///
/// e.g.:
///
/// C:\projects\solutions\MyProj\netstandard2.0\analyzerdependency\C:\users\me\.packages\somePackage\lib\someAnalyzer.dll
///
/// This method exists solely to extract out the "path to assembly" part, i.e.
/// "C:\users\me\.packages\somePackage\lib\someAnalyzer.dll". We don't need the
/// other parts.
///
/// Note that the path to the project directory is optional.
/// </remarks>
public static string ExtractAnalyzerFilePath(string projectDirectoryPath, string analyzerNodeCanonicalName)
{
// The canonical name may or may not start with the path to the project's directory.
if (analyzerNodeCanonicalName.StartsWith(projectDirectoryPath, StringComparison.OrdinalIgnoreCase))
{
// Extract the rest of the string, taking into account the "\" separating the directory
// path from the rest of the canonical name
analyzerNodeCanonicalName = analyzerNodeCanonicalName.Substring(projectDirectoryPath.Length + 1);
}
// Find the slash after the target framework
var backslashIndex = analyzerNodeCanonicalName.IndexOf('\\');
if (backslashIndex < 0)
{
return null;
}
// Find the slash after "analyzerdependency"
backslashIndex = analyzerNodeCanonicalName.IndexOf('\\', backslashIndex + 1);
if (backslashIndex < 0)
{
return null;
}
// The rest of the string is the path.
return analyzerNodeCanonicalName.Substring(backslashIndex + 1);
}
}
}
......@@ -99,6 +99,7 @@
<Compile Include="DiagnosticItem\CpsDiagnosticItemProvider.cs" />
<Compile Include="DiagnosticItem\CpsDiagnosticItemSource.cs" />
<Compile Include="DiagnosticItem\BaseDiagnosticItem.BrowseObject.cs" />
<Compile Include="DiagnosticItem\CpsUtilities.cs" />
<Compile Include="DiagnosticItem\LegacyDiagnosticItemProvider.cs" />
<Compile Include="AnalyzerReferenceManager.cs" />
<Compile Include="ContextMenuController.cs" />
......
......@@ -388,6 +388,7 @@
<Compile Include="Help\HelpTests.vb" />
<Compile Include="LanguageBlockTests.vb" />
<Compile Include="SolutionExplorer\CpsDiagnosticItemTests.vb" />
<Compile Include="SolutionExplorer\CpsUtilitiesTests.vb" />
<Compile Include="SymbolSearch\SymbolSearchUpdateEngineTests.vb" />
<Compile Include="Telemetry\VSTelemetryLoggerTest.vb" />
<Compile Include="Utilities\VsNavInfoHelpers.vb" />
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.VisualStudio.LanguageServices.Implementation.SolutionExplorer
Imports Roslyn.Test.Utilities
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SolutionExplorer
Public Class CpsUtilitiesTests
<Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)>
Public Sub ExtractAnalyzerFilePath_WithProjectPath()
Dim projectDirectoryFullPath = "C:\users\me\Solution\Project"
Dim analyzerCanonicalName = "C:\users\me\Solution\Project\netstandard2.0\analyzerdependency\C:\users\me\.nuget\package\analyzer\MyAnalyzer.dll"
Dim analyzerFileFullPath = CpsUtilities.ExtractAnalyzerFilePath(projectDirectoryFullPath, analyzerCanonicalName)
Assert.Equal(expected:="C:\users\me\.nuget\package\analyzer\MyAnalyzer.dll", actual:=analyzerFileFullPath)
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)>
Public Sub ExtractAnalyzerFilePath_WithoutProjectPath()
Dim projectDirectoryFullPath = "C:\users\me\Solution\Project"
Dim analyzerCanonicalName = "netstandard2.0\analyzerdependency\C:\users\me\.nuget\package\analyzer\MyAnalyzer.dll"
Dim analyzerFileFullPath = CpsUtilities.ExtractAnalyzerFilePath(projectDirectoryFullPath, analyzerCanonicalName)
Assert.Equal(expected:="C:\users\me\.nuget\package\analyzer\MyAnalyzer.dll", actual:=analyzerFileFullPath)
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)>
Public Sub ExtractAnalyzerFilePath_MalformedCanonicalName()
Dim projectDirectoryFullPath = "C:\users\me\Solution\Project"
Dim analyzerCanonicalName = "alpha beta gamma"
Dim analyzerFileFullPath = CpsUtilities.ExtractAnalyzerFilePath(projectDirectoryFullPath, analyzerCanonicalName)
Assert.Null(analyzerFileFullPath)
End Sub
End Class
End Namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册