Update our diagnostics window

Updates our diagnostics window to use the 'in the box' version of the
assembly/version discovery logic.
This commit is contained in:
Ryan Nowak 2017-09-06 14:01:55 -07:00
parent 67f255adca
commit 00dc95098f
7 changed files with 13 additions and 232 deletions

View File

@ -1,153 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if RAZOR_EXTENSION_DEVELOPER_MODE
using System;
using System.Collections.Generic;
using System.Composition;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using static Microsoft.VisualStudio.LanguageServices.Razor.ReflectionNames;
namespace Microsoft.VisualStudio.LanguageServices.Razor
{
[Export(typeof(IRazorEngineAssemblyResolver))]
internal class DefaultRazorEngineAssemblyResolver : IRazorEngineAssemblyResolver
{
public async Task<IEnumerable<RazorEngineAssembly>> GetRazorEngineAssembliesAsync(Project project)
{
try
{
var compilation = await project.GetCompilationAsync().ConfigureAwait(false);
var assemblies = GetRazorCustomizationAssemblies(compilation);
return assemblies;
}
catch (Exception exception)
{
throw new RazorLanguageServiceException(
typeof(DefaultRazorEngineAssemblyResolver).FullName,
nameof(GetRazorEngineAssembliesAsync),
exception);
}
}
private static List<RazorEngineAssembly> GetRazorCustomizationAssemblies(Compilation compilation)
{
// The goal here is to find the set of assemblies + paths that have some kind of
// Razor extensibility.
//
// We do that by making a compilation and then looking through the set of assembly names
// (AssemblyIdentity) and references to dlls on disk (PortableExecutableReference) to find
// uses of RazorEngineCustomizationAttribute and RazorEngineDependencyAttribute.
//
// We're limited to supporting files on disk because we will need to shadow copy them
// and manually load them.
//
// Also note that we're not doing anything here to explicitly uniquify this list, since
// we're limiting the set of candidates to the set of assemblies used for compilation, which
// has already been processed by Roslyn.
var results = new List<RazorEngineAssembly>();
// The RazorEngineDependencyAttribute also allows specifying an assembly name to go along
// with a piece of extensibility. We'll collect these on the first pass through the assemblies
// and then look those up by name.
var unresolvedIdentities = new List<AssemblyIdentity>();
foreach (var reference in compilation.References)
{
var peReference = reference as PortableExecutableReference;
if (peReference == null || peReference.FilePath == null)
{
// No path, can't load it.
continue;
}
var assemblySymbol = compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol;
if (assemblySymbol == null)
{
// It's unlikely, but possible that a reference might be a module instead of an assembly.
// We can't load that, so just skip it.
continue;
}
var identity = assemblySymbol.Identity;
if (identity.Name == RazorAssemblyName)
{
// This is the main Razor assembly.
results.Add(new RazorEngineAssembly(identity, peReference.FilePath));
}
// Now we're looking for the Razor exensibility attributes.
var attributes = assemblySymbol.GetAttributes();
for (var i = 0; i < attributes.Length; i++)
{
var attribute = attributes[i];
var name = attribute.AttributeClass.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
if (string.Equals(
CustomizationAttribute,
name,
StringComparison.Ordinal))
{
results.Add(new RazorEngineAssembly(identity, peReference.FilePath));
}
if (string.Equals(
DependencyAttribute,
name,
StringComparison.Ordinal))
{
// This attribute refers to a separate assembly for which we will need to resolve a path.
//
// Ignore parsing failures here.
AssemblyIdentity dependency;
if (AssemblyIdentity.TryParseDisplayName((string)attribute.ConstructorArguments[0].Value, out dependency))
{
unresolvedIdentities.Add(dependency);
}
}
}
}
// Now we need to do another pass to resolve all the unresolved names.
if (unresolvedIdentities.Count > 0)
{
//while (identities.MoveNext() && references.MoveNext())
//{
// var peReference = references.Current as PortableExecutableReference;
// if (peReference == null || peReference.FilePath == null)
// {
// // No path, can't load it.
// continue;
// }
// var assemblySymbol = compilation.GetAssemblyOrModuleSymbol(peReference) as IAssemblySymbol;
// if (assemblySymbol == null)
// {
// // It's unlikely, but possible that a reference might be a module instead of an assembly.
// // We can't load that, so just skip it.
// continue;
// }
// for (var i = 0; i < unresolvedIdentities.Count; i++)
// {
// // Note: argument ordering here is significant. We expect that the attribute will often refer to a
// // partial name and omit details like the version and public-key, therefore the value from the
// // attribute must be the first argument.
// if (AssemblyIdentityComparer.Default.ReferenceMatchesDefinition(
// unresolvedIdentities[i],
// identities.Current))
// {
// results.Add(new RazorEngineAssembly(identities.Current, peReference.FilePath));
// break;
// }
// }
//}
}
return results;
}
}
}
#endif

View File

@ -1,16 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if RAZOR_EXTENSION_DEVELOPER_MODE
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
namespace Microsoft.VisualStudio.LanguageServices.Razor
{
internal interface IRazorEngineAssemblyResolver
{
Task<IEnumerable<RazorEngineAssembly>> GetRazorEngineAssembliesAsync(Project project);
}
}
#endif

View File

@ -1,33 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if RAZOR_EXTENSION_DEVELOPER_MODE
using System;
using Microsoft.CodeAnalysis;
namespace Microsoft.VisualStudio.LanguageServices.Razor
{
internal struct RazorEngineAssembly
{
public RazorEngineAssembly(AssemblyIdentity identity, string filePath)
{
if (identity == null)
{
throw new ArgumentNullException(nameof(identity));
}
if (filePath == null)
{
throw new ArgumentNullException(nameof(filePath));
}
Identity = identity;
FilePath = filePath;
}
public string FilePath { get; }
public AssemblyIdentity Identity { get; }
}
}
#endif

View File

@ -1,16 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if RAZOR_EXTENSION_DEVELOPER_MODE
namespace Microsoft.VisualStudio.LanguageServices.Razor
{
internal static class ReflectionNames
{
public static readonly string RazorAssemblyName = "Microsoft.AspNetCore.Razor.Language";
public static readonly string CustomizationAttribute = RazorAssemblyName + ".RazorEngineCustomizationAttribute";
public static readonly string DependencyAttribute = RazorAssemblyName + ".RazorEngineDependencyAttribute";
}
}
#endif

View File

@ -2,25 +2,22 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if RAZOR_EXTENSION_DEVELOPER_MODE
using Microsoft.VisualStudio.LanguageServices.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.VisualStudio.RazorExtension.RazorInfo
{
public class AssemblyViewModel : NotifyPropertyChanged
{
private readonly RazorEngineAssembly _assembly;
private readonly ProjectExtensibilityAssembly _assembly;
internal AssemblyViewModel(RazorEngineAssembly assembly)
internal AssemblyViewModel(ProjectExtensibilityAssembly assembly)
{
_assembly = assembly;
Name = _assembly.Identity.GetDisplayName();
FilePath = assembly.FilePath;
}
public string Name { get; }
public string FilePath { get; }
}
}
#endif

View File

@ -6,6 +6,7 @@ using System;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices;
using Microsoft.VisualStudio.LanguageServices.Razor;
@ -17,7 +18,7 @@ namespace Microsoft.VisualStudio.RazorExtension.RazorInfo
[Guid("079e9499-d150-40af-8876-3047f7942c2a")]
public class RazorInfoToolWindow : ToolWindowPane
{
private IRazorEngineAssemblyResolver _assemblyResolver;
private ProjectExtensibilityConfigurationFactory _configurationFactory;
private IRazorEngineDocumentGenerator _documentGenerator;
private IRazorEngineDirectiveResolver _directiveResolver;
private TagHelperResolver _tagHelperResolver;
@ -35,7 +36,7 @@ namespace Microsoft.VisualStudio.RazorExtension.RazorInfo
var componentModel = (IComponentModel)GetService(typeof(SComponentModel));
_assemblyResolver = componentModel.GetService<IRazorEngineAssemblyResolver>();
_configurationFactory = componentModel.GetService<ProjectExtensibilityConfigurationFactory>();
_documentGenerator = componentModel.GetService<IRazorEngineDocumentGenerator>();
_directiveResolver = componentModel.GetService<IRazorEngineDirectiveResolver>();
_tagHelperResolver = componentModel.GetService<TagHelperResolver>();
@ -64,7 +65,7 @@ namespace Microsoft.VisualStudio.RazorExtension.RazorInfo
return;
}
var viewModel = new RazorInfoViewModel(this, _workspace, _assemblyResolver, _directiveResolver, _tagHelperResolver, _documentGenerator, OnException);
var viewModel = new RazorInfoViewModel(this, _workspace, _configurationFactory, _directiveResolver, _tagHelperResolver, _documentGenerator, OnException);
foreach (var project in solution.Projects)
{
if (project.Language == LanguageNames.CSharp)

View File

@ -10,6 +10,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Input;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.VisualStudio.LanguageServices;
using Microsoft.VisualStudio.LanguageServices.Razor;
using Microsoft.VisualStudio.Shell;
@ -22,7 +23,7 @@ namespace Microsoft.VisualStudio.RazorExtension.RazorInfo
{
internal class RazorInfoViewModel : NotifyPropertyChanged
{
private readonly IRazorEngineAssemblyResolver _assemblyResolver;
private readonly ProjectExtensibilityConfigurationFactory _configurationFactory;
private readonly IRazorEngineDirectiveResolver _directiveResolver;
private readonly IRazorEngineDocumentGenerator _documentGenerator;
private readonly TagHelperResolver _tagHelperResolver;
@ -41,7 +42,7 @@ namespace Microsoft.VisualStudio.RazorExtension.RazorInfo
public RazorInfoViewModel(
IServiceProvider services,
Workspace workspace,
IRazorEngineAssemblyResolver assemblyResolver,
ProjectExtensibilityConfigurationFactory configurationFactory,
IRazorEngineDirectiveResolver directiveResolver,
TagHelperResolver tagHelperResolver,
IRazorEngineDocumentGenerator documentGenerator,
@ -49,7 +50,7 @@ namespace Microsoft.VisualStudio.RazorExtension.RazorInfo
{
_services = services;
_workspace = workspace;
_assemblyResolver = assemblyResolver;
_configurationFactory = configurationFactory;
_directiveResolver = directiveResolver;
_tagHelperResolver = tagHelperResolver;
_documentGenerator = documentGenerator;
@ -169,7 +170,7 @@ namespace Microsoft.VisualStudio.RazorExtension.RazorInfo
var project = solution.GetProject(projectViewModel.Id);
var documents = GetCshtmlDocuments(project);
var assemblies = await _assemblyResolver.GetRazorEngineAssembliesAsync(project);
var configuration = await _configurationFactory.GetConfigurationAsync(project);
var directives = await _directiveResolver.GetRazorEngineDirectivesAsync(_workspace, project);
var assemblyFilters = project.MetadataReferences
@ -182,7 +183,7 @@ namespace Microsoft.VisualStudio.RazorExtension.RazorInfo
CurrentProjectInfo = new ProjectInfoViewModel()
{
Assemblies = new ObservableCollection<AssemblyViewModel>(assemblies.Select(a => new AssemblyViewModel(a))),
Assemblies = new ObservableCollection<AssemblyViewModel>(configuration.Assemblies.Select(a => new AssemblyViewModel(a))),
Directives = new ObservableCollection<DirectiveViewModel>(directives.Select(d => new DirectiveViewModel(d))),
Documents = new ObservableCollection<DocumentViewModel>(documents.Select(d => new DocumentViewModel(d))),
TagHelpers = new ObservableCollection<TagHelperViewModel>(resolutionResult.Descriptors.Select(t => new TagHelperViewModel(t))),