Removing Microsoft.AspNet.Razor.Runtime.Precompilation

This commit is contained in:
Pranav K 2016-01-11 16:27:04 -08:00
parent 605dceea02
commit c05551e167
35 changed files with 1 additions and 2427 deletions

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C0D6505-79B3-49D0-B4C3-176F0F1836ED}"
EndProject
@ -17,12 +17,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Razor.Runt
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Razor.Test.Sources", "src\Microsoft.AspNet.Razor.Test.Sources\Microsoft.AspNet.Razor.Test.Sources.xproj", "{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Razor.Runtime.Precompilation", "src\Microsoft.AspNet.Razor.Runtime.Precompilation\Microsoft.AspNet.Razor.Runtime.Precompilation.xproj", "{3B7ECD22-4C02-45CF-92E8-98C074DD9D0E}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Razor.Runtime.Precompilation.Test", "test\Microsoft.AspNet.Razor.Runtime.Precompilation.Test\Microsoft.AspNet.Razor.Runtime.Precompilation.Test.xproj", "{C626444C-5A63-42BC-ACAE-DBB2CD3EDE25}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Razor.Runtime.Precompilation.Files", "test\Microsoft.AspNet.Razor.Runtime.Precompilation.Files\Microsoft.AspNet.Razor.Runtime.Precompilation.Files.xproj", "{125D4CC1-5317-495F-88B8-472DFD9C1097}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -49,18 +43,6 @@ Global
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0}.Release|Any CPU.Build.0 = Release|Any CPU
{3B7ECD22-4C02-45CF-92E8-98C074DD9D0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B7ECD22-4C02-45CF-92E8-98C074DD9D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B7ECD22-4C02-45CF-92E8-98C074DD9D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B7ECD22-4C02-45CF-92E8-98C074DD9D0E}.Release|Any CPU.Build.0 = Release|Any CPU
{C626444C-5A63-42BC-ACAE-DBB2CD3EDE25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C626444C-5A63-42BC-ACAE-DBB2CD3EDE25}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C626444C-5A63-42BC-ACAE-DBB2CD3EDE25}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C626444C-5A63-42BC-ACAE-DBB2CD3EDE25}.Release|Any CPU.Build.0 = Release|Any CPU
{125D4CC1-5317-495F-88B8-472DFD9C1097}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{125D4CC1-5317-495F-88B8-472DFD9C1097}.Debug|Any CPU.Build.0 = Debug|Any CPU
{125D4CC1-5317-495F-88B8-472DFD9C1097}.Release|Any CPU.ActiveCfg = Release|Any CPU
{125D4CC1-5317-495F-88B8-472DFD9C1097}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -71,8 +53,5 @@ Global
{D0196096-1B01-4133-AACE-1A10A0F7247C} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{0535998A-E32C-4D1A-80D1-0B15A513C471} = {92463391-81BE-462B-AC3C-78C6C760741F}
{E3A2A305-634D-4BA6-95DB-AA06D6C442B0} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{3B7ECD22-4C02-45CF-92E8-98C074DD9D0E} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{C626444C-5A63-42BC-ACAE-DBB2CD3EDE25} = {92463391-81BE-462B-AC3C-78C6C760741F}
{125D4CC1-5317-495F-88B8-472DFD9C1097} = {92463391-81BE-462B-AC3C-78C6C760741F}
EndGlobalSection
EndGlobal

View File

@ -1,230 +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.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
/// <summary>
/// Utilities to work with creating <see cref="Attribute"/> instances from <see cref="AttributeData"/>.
/// </summary>
public static class CodeAnalysisAttributeUtilities
{
private static readonly ConcurrentDictionary<ConstructorInfo, Func<object[], Attribute>> _constructorCache =
new ConcurrentDictionary<ConstructorInfo, Func<object[], Attribute>>();
/// <summary>
/// Gets the sequence of <see cref="Attribute"/>s of type <typeparamref name="TAttribute"/>
/// that are declared on the specified <paramref name="symbol"/>.
/// </summary>
/// <typeparam name="TAttribute">The <see cref="Attribute"/> type.</typeparam>
/// <param name="symbol">The <see cref="ISymbol"/> to find attributes on.</param>
/// <returns></returns>
public static IEnumerable<TAttribute> GetCustomAttributes<TAttribute>(ISymbol symbol)
where TAttribute : Attribute
{
if (symbol == null)
{
throw new ArgumentNullException(nameof(symbol));
}
var attributes = symbol.GetAttributes();
if (attributes.Length > 0)
{
return attributes
.Where(attribute => CodeAnalysisSymbolBasedTypeInfo.IsType(
attribute.AttributeClass,
typeof(TAttribute).GetTypeInfo()))
.Select(attribute => CreateAttribute<TAttribute>(attribute))
.ToArray();
}
return Enumerable.Empty<TAttribute>();
}
private static TAttribute CreateAttribute<TAttribute>(AttributeData attributeData)
where TAttribute : Attribute
{
TAttribute attribute;
var matchInfo = MatchConstructor(typeof(TAttribute), attributeData.ConstructorArguments);
Func<object[], Attribute> constructorDelegate;
if (!_constructorCache.TryGetValue(matchInfo.Constructor, out constructorDelegate))
{
constructorDelegate = MakeFastConstructorInvoker(matchInfo);
_constructorCache[matchInfo.Constructor] = constructorDelegate;
}
attribute = (TAttribute)constructorDelegate(matchInfo.ArgumentValues);
if (attributeData.NamedArguments.Length > 0)
{
var helpers = PropertyHelper.GetVisibleProperties(attribute);
foreach (var item in attributeData.NamedArguments)
{
var helper = helpers.FirstOrDefault(
propertyHelper => string.Equals(propertyHelper.Name, item.Key, StringComparison.Ordinal));
if (helper == null)
{
throw new InvalidOperationException(
Resources.FormatCodeAnalysis_PropertyNotFound(item.Key, attribute.GetType().FullName));
}
var propertyValue = ConvertTypedConstantValue(
helper.Property.PropertyType,
item.Value);
helper.SetValue(attribute, propertyValue);
}
}
return attribute;
}
private static Func<object[], Attribute> MakeFastConstructorInvoker(ConstructorMatchInfo matchInfo)
{
var argsParameter = Expression.Parameter(typeof(object[]), "args");
var parameters = new Expression[matchInfo.ArgumentValues.Length];
for (var index = 0; index < matchInfo.ArgumentValues.Length; index++)
{
parameters[index] =
Expression.Convert(
Expression.ArrayIndex(
argsParameter,
Expression.Constant(index)),
matchInfo.ArgumentValues[index].GetType());
}
// () => new TAttribute(args)
var lambda =
Expression.Lambda<Func<object[], Attribute>>(
Expression.New(
matchInfo.Constructor,
parameters),
argsParameter);
return lambda.Compile();
}
private static ConstructorMatchInfo MatchConstructor(
Type type,
ImmutableArray<TypedConstant> symbolConstructorArguments)
{
var constructor = FindConstructor(type, symbolConstructorArguments);
var constructorParmaters = constructor.GetParameters();
var arguments = new object[symbolConstructorArguments.Length];
for (var i = 0; i < arguments.Length; i++)
{
var value = ConvertTypedConstantValue(
constructorParmaters[i].ParameterType,
symbolConstructorArguments[i]);
arguments[i] = value;
}
return new ConstructorMatchInfo
{
Constructor = constructor,
ArgumentValues = arguments
};
}
private static ConstructorInfo FindConstructor(
Type type,
ImmutableArray<TypedConstant> symbolConstructorArguments)
{
var constructors = type.GetConstructors();
foreach (var constructor in constructors)
{
var runtimeParameters = constructor.GetParameters();
if (runtimeParameters.Length != symbolConstructorArguments.Length)
{
continue;
}
var parametersMatched = true;
for (var index = 0; index < runtimeParameters.Length; index++)
{
var runtimeParameter = runtimeParameters[index].ParameterType;
if (symbolConstructorArguments[index].Kind == TypedConstantKind.Array &&
runtimeParameter.IsArray)
{
var arrayType = (IArrayTypeSymbol)symbolConstructorArguments[index].Type;
if (!CodeAnalysisSymbolBasedTypeInfo.IsType(
arrayType.ElementType,
runtimeParameter.GetElementType().GetTypeInfo()))
{
parametersMatched = false;
break;
}
}
else
{
if (!CodeAnalysisSymbolBasedTypeInfo.IsType(
symbolConstructorArguments[index].Type,
runtimeParameter.GetTypeInfo()))
{
parametersMatched = false;
break;
}
}
}
if (parametersMatched)
{
return constructor;
}
}
throw new InvalidOperationException(Resources.FormatCodeAnalysisConstructorNotFound(type.FullName));
}
private static object ConvertTypedConstantValue(
Type type,
TypedConstant constructorArgument)
{
switch (constructorArgument.Kind)
{
case TypedConstantKind.Enum:
return Enum.ToObject(type, constructorArgument.Value);
case TypedConstantKind.Primitive:
return constructorArgument.Value;
case TypedConstantKind.Type:
var typeSymbol = (INamedTypeSymbol)constructorArgument.Value;
var typeName = CodeAnalysisSymbolBasedTypeInfo.GetAssemblyQualifiedName(typeSymbol);
return Type.GetType(typeName);
case TypedConstantKind.Array:
Debug.Assert(type.IsArray && constructorArgument.Values != null);
var elementType = type.GetElementType();
var values = Array.CreateInstance(elementType, constructorArgument.Values.Length);
for (var index = 0; index < values.Length; index++)
{
values.SetValue(
ConvertTypedConstantValue(elementType, constructorArgument.Values[index]),
index);
}
return values;
default:
throw new NotSupportedException(
Resources.FormatCodeAnalysis_TypeConstantKindNotSupported(constructorArgument.Kind));
}
}
private struct ConstructorMatchInfo
{
public ConstructorInfo Constructor;
public object[] ArgumentValues;
}
}
}

View File

@ -1,68 +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.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.CodeAnalysis;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
/// <summary>
/// <see cref="IPropertyInfo"/> implementation using Code Analysis symbols.
/// </summary>
[DebuggerDisplay("{Name, PropertyType}")]
public class CodeAnalysisSymbolBasedPropertyInfo : IPropertyInfo
{
private readonly IPropertySymbol _propertySymbol;
/// <summary>
/// Initializes a new instance of <see cref="CodeAnalysisSymbolBasedPropertyInfo"/>.
/// </summary>
/// <param name="propertySymbol">The <see cref="IPropertySymbol"/>.</param>
public CodeAnalysisSymbolBasedPropertyInfo(IPropertySymbol propertySymbol)
{
if (propertySymbol == null)
{
throw new ArgumentNullException(nameof(propertySymbol));
}
_propertySymbol = propertySymbol;
PropertyType = new CodeAnalysisSymbolBasedTypeInfo(_propertySymbol.Type);
}
/// <inheritdoc />
public bool HasPublicGetter
{
get
{
return _propertySymbol.GetMethod != null &&
_propertySymbol.GetMethod.DeclaredAccessibility == Accessibility.Public;
}
}
/// <inheritdoc />
public bool HasPublicSetter
{
get
{
return _propertySymbol.SetMethod != null &&
_propertySymbol.SetMethod.DeclaredAccessibility == Accessibility.Public;
}
}
/// <inheritdoc />
public string Name => _propertySymbol.MetadataName;
/// <inheritdoc />
public ITypeInfo PropertyType { get; }
/// <inheritdoc />
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>()
where TAttribute : Attribute
{
return CodeAnalysisAttributeUtilities.GetCustomAttributes<TAttribute>(_propertySymbol);
}
}
}

View File

@ -1,383 +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.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.CodeAnalysis;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
/// <summary>
/// <see cref="ITypeInfo"/> implementation using Code Analysis symbols.
/// </summary>
[DebuggerDisplay("{Name}")]
public class CodeAnalysisSymbolBasedTypeInfo : ITypeInfo
{
private static readonly System.Reflection.TypeInfo OpenGenericDictionaryTypeInfo =
typeof(IDictionary<,>).GetTypeInfo();
private readonly ITypeSymbol _type;
private readonly ITypeSymbol _underlyingType;
private string _fullName;
private string _sanitizedFullName;
private List<IPropertyInfo> _properties;
/// <summary>
/// Initializes a new instance of <see cref="CodeAnalysisSymbolBasedTypeInfo"/>.
/// </summary>
/// <param name="propertySymbol">The <see cref="IPropertySymbol"/>.</param>
public CodeAnalysisSymbolBasedTypeInfo(ITypeSymbol type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
_type = type;
_underlyingType = UnwrapArrayType(type);
}
/// <inheritdoc />
public string FullName
{
get
{
if (_fullName == null)
{
_fullName = GetFullName(_type);
}
return _fullName;
}
}
/// <summary>
/// The <see cref="ITypeSymbol"/> instance.
/// </summary>
public ITypeSymbol TypeSymbol => _type;
/// <inheritdoc />
public bool IsEnum => _type.TypeKind == TypeKind.Enum;
/// <inheritdoc />
public bool IsAbstract => _type.IsAbstract;
/// <inheritdoc />
public bool IsGenericType
{
get
{
return _type.Kind == SymbolKind.NamedType &&
((INamedTypeSymbol)_type).IsGenericType;
}
}
/// <inheritdoc />
public bool IsNested => _underlyingType.ContainingType != null;
/// <inheritdoc />
public bool IsPublic
{
get
{
return _type.DeclaredAccessibility == Accessibility.Public ||
_type.TypeKind == TypeKind.Array;
}
}
/// <inheritdoc />
public string Name
{
get
{
if (_type.TypeKind == TypeKind.Array)
{
return _underlyingType.MetadataName + "[]";
}
return _type.MetadataName;
}
}
/// <inheritdoc />
public IEnumerable<IPropertyInfo> Properties
{
get
{
if (_properties == null)
{
_properties = GetProperties(_type);
}
return _properties;
}
}
/// <inheritdoc />
public bool ImplementsInterface(ITypeInfo interfaceTypeInfo)
{
if (interfaceTypeInfo == null)
{
throw new ArgumentNullException(nameof(interfaceTypeInfo));
}
var runtimeTypeInfo = interfaceTypeInfo as RuntimeTypeInfo;
if (runtimeTypeInfo != null)
{
return runtimeTypeInfo.TypeInfo.IsInterface &&
_type.AllInterfaces.Any(implementedInterface => IsType(implementedInterface, runtimeTypeInfo.TypeInfo));
}
var codeAnalysisTypeInfo = interfaceTypeInfo as CodeAnalysisSymbolBasedTypeInfo;
if (codeAnalysisTypeInfo != null)
{
return codeAnalysisTypeInfo.TypeSymbol.TypeKind == TypeKind.Interface &&
_type.AllInterfaces.Any(
implementedInterface => implementedInterface == codeAnalysisTypeInfo.TypeSymbol);
}
throw new ArgumentException(
Resources.FormatArgumentMustBeAnInstanceOf(
typeof(RuntimeTypeInfo).FullName,
typeof(CodeAnalysisSymbolBasedTypeInfo).FullName),
nameof(interfaceTypeInfo));
}
private string SanitizedFullName
{
get
{
if (_sanitizedFullName == null)
{
_sanitizedFullName = RuntimeTypeInfo.SanitizeFullName(FullName);
}
return _sanitizedFullName;
}
}
/// <inheritdoc />
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>()
where TAttribute : Attribute
{
return CodeAnalysisAttributeUtilities.GetCustomAttributes<TAttribute>(_type);
}
/// <inheritdoc />
public ITypeInfo[] GetGenericDictionaryParameters()
{
INamedTypeSymbol dictionaryInterface;
if (_type.Kind == SymbolKind.NamedType &&
IsType(((INamedTypeSymbol)_type).ConstructedFrom, OpenGenericDictionaryTypeInfo))
{
dictionaryInterface = (INamedTypeSymbol)_type;
}
else
{
dictionaryInterface = _type
.AllInterfaces
.FirstOrDefault(implementedInterface =>
IsType(implementedInterface.ConstructedFrom, OpenGenericDictionaryTypeInfo));
}
if (dictionaryInterface != null)
{
Debug.Assert(dictionaryInterface.TypeArguments.Length == 2);
return new[]
{
new CodeAnalysisSymbolBasedTypeInfo(dictionaryInterface.TypeArguments[0]),
new CodeAnalysisSymbolBasedTypeInfo(dictionaryInterface.TypeArguments[1]),
};
}
return null;
}
/// <summary>
/// Gets a value that indicates if <paramref name="targetTypeInfo"/> is represented using
/// <paramref name="sourceTypeSymbol"/> in the symbol graph.
/// </summary>
/// <param name="sourceTypeSymbol">The <see cref="ITypeSymbol"/>.</param>
/// <param name="targetTypeInfo">The <see cref="System.Reflection.TypeInfo"/>.</param>
/// <returns><c>true</c> if <paramref name="targetTypeInfo"/> is a symbol for
/// <paramref name="sourceTypeSymbol"/>.</returns>
public static bool IsType(
ITypeSymbol sourceTypeSymbol,
System.Reflection.TypeInfo targetTypeInfo)
{
return string.Equals(
RuntimeTypeInfo.SanitizeFullName(targetTypeInfo.FullName),
RuntimeTypeInfo.SanitizeFullName(GetFullName(sourceTypeSymbol)),
StringComparison.Ordinal);
}
/// <summary>
/// Gets the assembly qualified named of the specified <paramref name="symbol"/>.
/// </summary>
/// <param name="symbol">The <see cref="ITypeSymbol" /> to generate the name for.</param>
/// <returns>The assembly qualified name.</returns>
public static string GetAssemblyQualifiedName(ITypeSymbol symbol)
{
if (symbol == null)
{
throw new ArgumentNullException(nameof(symbol));
}
var builder = new StringBuilder();
GetAssemblyQualifiedName(builder, symbol);
return builder.ToString();
}
/// <inheritdoc />
public override bool Equals(object obj)
{
return Equals(obj as ITypeInfo);
}
/// <inheritdoc />
public bool Equals(ITypeInfo other)
{
if (other == null)
{
return false;
}
var otherSymbolBasedType = other as CodeAnalysisSymbolBasedTypeInfo;
if (otherSymbolBasedType != null)
{
return otherSymbolBasedType.TypeSymbol == TypeSymbol;
}
return string.Equals(
SanitizedFullName,
RuntimeTypeInfo.SanitizeFullName(other.FullName),
StringComparison.Ordinal);
}
/// <inheritdoc />
public override int GetHashCode() => SanitizedFullName.GetHashCode();
private static List<IPropertyInfo> GetProperties(ITypeSymbol typeSymbol)
{
var properties = new List<IPropertyInfo>();
var overridenProperties = new HashSet<IPropertySymbol>();
do
{
foreach (var member in typeSymbol.GetMembers().Where(m => m.Kind == SymbolKind.Property))
{
var propertySymbol = (IPropertySymbol)member;
if (!propertySymbol.IsIndexer && !overridenProperties.Contains(propertySymbol))
{
var propertyInfo = new CodeAnalysisSymbolBasedPropertyInfo(propertySymbol);
properties.Add(propertyInfo);
}
if (propertySymbol.IsOverride)
{
overridenProperties.Add(propertySymbol.OverriddenProperty);
}
}
typeSymbol = typeSymbol.BaseType;
} while (typeSymbol != null);
return properties;
}
private static string GetFullName(ITypeSymbol typeSymbol)
{
var nameBuilder = new StringBuilder();
GetFullName(nameBuilder, typeSymbol);
return nameBuilder.Length == 0 ? null : nameBuilder.ToString();
}
private static void GetFullName(StringBuilder nameBuilder, ITypeSymbol typeSymbol)
{
if (typeSymbol.Kind == SymbolKind.TypeParameter)
{
return;
}
var insertIndex = nameBuilder.Length;
if (typeSymbol.TypeKind == TypeKind.Array)
{
var arrayType = (IArrayTypeSymbol)typeSymbol;
GetAssemblyQualifiedName(nameBuilder, arrayType.ElementType);
nameBuilder.Append("[]");
return;
}
nameBuilder.Append(typeSymbol.MetadataName);
if (typeSymbol.Kind == SymbolKind.NamedType)
{
var namedSymbol = (INamedTypeSymbol)typeSymbol;
// The symbol represents a generic but not open generic type
if (namedSymbol.IsGenericType &&
namedSymbol.ConstructedFrom != namedSymbol)
{
nameBuilder.Append('[');
foreach (var typeArgument in namedSymbol.TypeArguments)
{
nameBuilder.Append('[');
GetAssemblyQualifiedName(nameBuilder, typeArgument);
nameBuilder.Append("],");
}
// Removing trailing slash
Debug.Assert(nameBuilder.Length > 0 && nameBuilder[nameBuilder.Length - 1] == ',');
nameBuilder.Length--;
nameBuilder.Append("]");
}
}
var containingType = typeSymbol.ContainingType;
while (containingType != null)
{
nameBuilder
.Insert(insertIndex, '+')
.Insert(insertIndex, containingType.MetadataName);
containingType = containingType.ContainingType;
}
var containingNamespace = typeSymbol.ContainingNamespace;
while (!containingNamespace.IsGlobalNamespace)
{
nameBuilder
.Insert(insertIndex, '.')
.Insert(insertIndex, containingNamespace.MetadataName);
containingNamespace = containingNamespace.ContainingNamespace;
}
}
private static void GetAssemblyQualifiedName(StringBuilder builder, ITypeSymbol typeSymbol)
{
GetFullName(builder, typeSymbol);
typeSymbol = UnwrapArrayType(typeSymbol);
builder
.Append(", ")
.Append(typeSymbol.ContainingAssembly.Identity);
}
private static ITypeSymbol UnwrapArrayType(ITypeSymbol type)
{
if (type.TypeKind == TypeKind.Array)
{
return ((IArrayTypeSymbol)type).ElementType;
}
return type;
}
}
}

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>3b7ecd22-4c02-45cf-92e8-98c074dd9d0e</ProjectGuid>
<RootNamespace>Microsoft.AspNet.Razor.Runtime.Precompilation</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -1,117 +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.
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.CodeAnalysis;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
/// <summary>
/// <see cref="TagHelperTypeResolver"/> used during Razor precompilation.
/// </summary>
public class PrecompilationTagHelperTypeResolver : TagHelperTypeResolver
{
private readonly object _assemblyLookupLock = new object();
private readonly Dictionary<string, IEnumerable<ITypeInfo>> _assemblyLookup
= new Dictionary<string, IEnumerable<ITypeInfo>>(StringComparer.Ordinal);
private readonly CodeAnalysis.Compilation _compilation;
/// <summary>
/// Initializes a new instance of <see cref="PrecompilationTagHelperTypeResolver"/>.
/// </summary>
/// <param name="compilation">The <see cref="CodeAnalysis.Compilation"/>.</param>
public PrecompilationTagHelperTypeResolver(CodeAnalysis.Compilation compilation)
{
if (compilation == null)
{
throw new ArgumentNullException(nameof(compilation));
}
_compilation = compilation;
}
/// <inheritdoc />
protected override IEnumerable<ITypeInfo> GetTopLevelExportedTypes(AssemblyName assemblyName)
{
if (assemblyName == null)
{
throw new ArgumentNullException(nameof(assemblyName));
}
lock (_assemblyLookupLock)
{
IEnumerable<ITypeInfo> result;
if (!_assemblyLookup.TryGetValue(assemblyName.Name, out result))
{
result = GetExportedTypes(assemblyName.Name);
_assemblyLookup[assemblyName.Name] = result;
}
return result;
}
}
// Internal for unit testing
internal IEnumerable<ITypeInfo> GetExportedTypes(string assemblyName)
{
if (string.Equals(_compilation.AssemblyName, assemblyName, StringComparison.Ordinal))
{
return GetExportedTypes(_compilation.Assembly);
}
else
{
foreach (var reference in _compilation.References)
{
var compilationReference = reference as CompilationReference;
if (compilationReference != null &&
string.Equals(
compilationReference.Compilation.AssemblyName,
assemblyName,
StringComparison.Ordinal))
{
return GetExportedTypes(compilationReference.Compilation.Assembly);
}
var assemblySymbol = _compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol;
if (string.Equals(
assemblySymbol?.Identity.Name,
assemblyName,
StringComparison.Ordinal))
{
return GetExportedTypes(assemblySymbol);
}
}
}
throw new InvalidOperationException(
Resources.FormatCodeAnalysis_UnableToLoadAssemblyReference(assemblyName));
}
private static List<ITypeInfo> GetExportedTypes(IAssemblySymbol assembly)
{
var exportedTypes = new List<ITypeInfo>();
GetExportedTypes(assembly.GlobalNamespace, exportedTypes);
return exportedTypes;
}
private static void GetExportedTypes(INamespaceSymbol namespaceSymbol, List<ITypeInfo> exportedTypes)
{
foreach (var type in namespaceSymbol.GetTypeMembers())
{
if (type.TypeKind == TypeKind.Class &&
type.DeclaredAccessibility == Accessibility.Public)
{
exportedTypes.Add(new CodeAnalysisSymbolBasedTypeInfo(type));
}
}
foreach (var subNamespace in namespaceSymbol.GetNamespaceMembers())
{
GetExportedTypes(subNamespace, exportedTypes);
}
}
}
}

View File

@ -1,10 +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.
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNet.Razor.Runtime.Precompilation.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: NeutralResourcesLanguage("en-us")]
[assembly: AssemblyMetadata("Serviceable", "True")]

View File

@ -1,110 +0,0 @@
// <auto-generated />
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
using System.Globalization;
using System.Reflection;
using System.Resources;
internal static class Resources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNet.Razor.Runtime.Precompilation.Resources", typeof(Resources).GetTypeInfo().Assembly);
/// <summary>
/// Argument must be an instance of '{0}' or '{1}'.
/// </summary>
internal static string ArgumentMustBeAnInstanceOf
{
get { return GetString("ArgumentMustBeAnInstanceOf"); }
}
/// <summary>
/// Argument must be an instance of '{0}' or '{1}'.
/// </summary>
internal static string FormatArgumentMustBeAnInstanceOf(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentMustBeAnInstanceOf"), p0, p1);
}
/// <summary>
/// Unable to find a suitable constructor for type '{0}'.
/// </summary>
internal static string CodeAnalysisConstructorNotFound
{
get { return GetString("CodeAnalysisConstructorNotFound"); }
}
/// <summary>
/// Unable to find a suitable constructor for type '{0}'.
/// </summary>
internal static string FormatCodeAnalysisConstructorNotFound(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("CodeAnalysisConstructorNotFound"), p0);
}
/// <summary>
/// Unable to find property {0} on type {1}.
/// </summary>
internal static string CodeAnalysis_PropertyNotFound
{
get { return GetString("CodeAnalysis_PropertyNotFound"); }
}
/// <summary>
/// Unable to find property {0} on type {1}.
/// </summary>
internal static string FormatCodeAnalysis_PropertyNotFound(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("CodeAnalysis_PropertyNotFound"), p0, p1);
}
/// <summary>
/// The type constant kind '{0}' is not supported.
/// </summary>
internal static string CodeAnalysis_TypeConstantKindNotSupported
{
get { return GetString("CodeAnalysis_TypeConstantKindNotSupported"); }
}
/// <summary>
/// The type constant kind '{0}' is not supported.
/// </summary>
internal static string FormatCodeAnalysis_TypeConstantKindNotSupported(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("CodeAnalysis_TypeConstantKindNotSupported"), p0);
}
/// <summary>
/// Unable to load assembly reference '{0}'.
/// </summary>
internal static string CodeAnalysis_UnableToLoadAssemblyReference
{
get { return GetString("CodeAnalysis_UnableToLoadAssemblyReference"); }
}
/// <summary>
/// Unable to load assembly reference '{0}'.
/// </summary>
internal static string FormatCodeAnalysis_UnableToLoadAssemblyReference(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("CodeAnalysis_UnableToLoadAssemblyReference"), p0);
}
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
System.Diagnostics.Debug.Assert(value != null);
if (formatterNames != null)
{
for (var i = 0; i < formatterNames.Length; i++)
{
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
}
}
return value;
}
}
}

View File

@ -1,135 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArgumentMustBeAnInstanceOf" xml:space="preserve">
<value>Argument must be an instance of '{0}' or '{1}'.</value>
</data>
<data name="CodeAnalysisConstructorNotFound" xml:space="preserve">
<value>Unable to find a suitable constructor for type '{0}'.</value>
</data>
<data name="CodeAnalysis_PropertyNotFound" xml:space="preserve">
<value>Unable to find property {0} on type {1}.</value>
</data>
<data name="CodeAnalysis_TypeConstantKindNotSupported" xml:space="preserve">
<value>The type constant kind '{0}' is not supported.</value>
</data>
<data name="CodeAnalysis_UnableToLoadAssemblyReference" xml:space="preserve">
<value>Unable to load assembly reference '{0}'.</value>
</data>
</root>

View File

@ -1,38 +0,0 @@
{
"description": "Supports tag helper resolution during precompilation.",
"version": "4.0.0-*",
"repository": {
"type": "git",
"url": "git://github.com/aspnet/razor"
},
"compilationOptions": {
"warningsAsErrors": true,
"keyFile": "../../tools/Key.snk"
},
"dependencies": {
"Microsoft.Extensions.PropertyActivator.Sources": {
"version": "1.0.0-*",
"type": "build"
},
"Microsoft.Extensions.PropertyHelper.Sources": {
"version": "1.0.0-*",
"type": "build"
},
"Microsoft.AspNet.Razor.Runtime": "4.0.0-*",
"Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*"
},
"frameworks": {
"net451": {
"frameworkAssemblies": {
"System.Runtime": ""
}
},
"dotnet5.4": {
"dependencies": {
"System.Collections.Concurrent": "4.0.11-*",
"System.Linq.Expressions": "4.0.11-*",
"System.Reflection.TypeExtensions": "4.1.0-*"
}
}
}
}

View File

@ -1,36 +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.
using System;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class AttributesWithArrayConstructorArgumentsAttribute : Attribute
{
public AttributesWithArrayConstructorArgumentsAttribute(string[] stringArgs, int[] intArgs)
{
StringArgs = stringArgs;
IntArgs = intArgs;
}
public AttributesWithArrayConstructorArgumentsAttribute(string[] stringArgs, Type[] typeArgs, int[] intArgs)
{
StringArgs = stringArgs;
TypeArgs = typeArgs;
IntArgs = intArgs;
}
public AttributesWithArrayConstructorArgumentsAttribute(int[] intArgs, Type[] typeArgs)
{
IntArgs = intArgs;
TypeArgs = typeArgs;
}
public string[] StringArgs { get; }
public Type[] TypeArgs { get; }
public int[] IntArgs { get; }
}
}

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.
using System;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public class ArrayPropertiesAttribute : Attribute
{
public Type[] ArrayOfTypes { get; set; }
public int[] ArrayOfInts { get; set; }
public DayOfWeek[] Days { get; set; }
}
}

View File

@ -1,28 +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.
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
internal class InternalType
{
}
public class PublicType
{
private class NestedPrivateType
{
}
}
public class ContainerType
{
public class NestedType
{
}
}
public class GenericType<TVal>
{
}
}

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.
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public struct MyStruct
{
}
public enum MyEnum
{
}
public interface MyInterface
{
}
public abstract class MyAbstractClass
{
}
public partial class MyPartialClass
{
}
public partial class MyPartialClass
{
}
public sealed class MySealedClass
{
}
}

View File

@ -1,38 +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.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Microsoft.AspNet.Razor.Runtime
{
public class DerivingFromIList : IReadOnlyList<string>
{
public string this[int index]
{
get
{
throw new NotImplementedException();
}
}
public int Count
{
get
{
throw new NotImplementedException();
}
}
public IEnumerator<string> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
}

View File

@ -1,11 +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.
using System.Collections.Generic;
namespace Microsoft.AspNet.Razor.Runtime
{
public class DerivingFromList : List<string>
{
}
}

View File

@ -1,12 +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.
using System;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public class EnumPropertyAttribute : Attribute
{
public DayOfWeek DayOfWeek { get; set; }
}
}

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>125d4cc1-5317-495f-88b8-472dfd9c1097</ProjectGuid>
<RootNamespace>Microsoft.AspNet.Razor.Runtime.Precompilation.Files</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -1,24 +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.
using System;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class MultipleConstructorArgumentsAttribute : Attribute
{
public MultipleConstructorArgumentsAttribute(string firstArgument, string secondArgument, int thirdArgument)
{
FirstArgument = firstArgument;
SecondArgument = secondArgument;
ThirdArgument = thirdArgument;
}
public string FirstArgument { get; }
public string SecondArgument { get; }
public int ThirdArgument { get; }
}
}

View File

@ -1,21 +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.
using System;
using System.Collections.Generic;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public class TypeWithArrayProperties
{
public MyAbstractClass[] AbstractArray { get; set; }
public IDisposable[] DisposableArray { get; }
public ContainerType.NestedType[] NestedArrayType { get; }
internal InternalType[] InternalArray { get; set; }
public ICollection<IDictionary<string, IList<object[]>>>[] GenericArray { get; set; }
}
}

View File

@ -1,52 +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.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Resources;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
[HtmlTargetElement("img", Attributes = AppendVersionAttributeName + "," + SrcAttributeName)]
[HtmlTargetElement("image", Attributes = SrcAttributeName)]
[EditorBrowsable(EditorBrowsableState.Never)]
[EnumProperty(DayOfWeek = DayOfWeek.Friday)]
[CustomValidation(typeof(Validator), "ValidationMethod", ErrorMessageResourceType = typeof(ResourceManager))]
[RestrictChildren("ol", "ul", "li", "dl", "dd")]
[ArrayProperties(
ArrayOfInts = new[] { 7, 8, 9 },
ArrayOfTypes = new[] { typeof(ITagHelper), typeof(Guid) },
Days = new[] { DayOfWeek.Saturday })]
public class TypeWithAttributes
{
private const string AppendVersionAttributeName = "asp-append-version";
private const string SrcAttributeName = "src";
[HtmlAttributeName(SrcAttributeName)]
[Required(AllowEmptyStrings = true)]
public string Src { get; set; }
[HtmlAttributeName(AppendVersionAttributeName, DictionaryAttributePrefix = "prefix")]
[HtmlAttributeNotBound]
public bool AppendVersion { get; set; }
[Required]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[ArrayProperties(
ArrayOfInts = new int[0],
ArrayOfTypes = new[] { typeof(TypeWithAttributes) },
Days = new[] { DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Sunday })]
public ViewContext ViewContext { get; set; }
[AttributesWithArrayConstructorArguments(new[] { 1, 2 }, new[] { typeof(Uri), typeof(IList<>) })]
[AttributesWithArrayConstructorArguments(new[] { "Hello", "world" }, new[] { typeof(List<Guid>) }, new int[0])]
[AttributesWithArrayConstructorArguments(
new[] { "world", "Hello" },
new[] { typeof(IDictionary<string, object>) },
new[] { 1 })]
protected IEditableObject HostingEnvironment { get; }
}
}

View File

@ -1,23 +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.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public class TypeWithComplexPropertyFullNames
{
public int Property1 { get; set; }
public int[] Property2 { get; set; }
public List<long> Property3 { get; set; }
public List<Tuple<string, DateTimeOffset>> Property4 { get; }
public IDictionary<ILookup<string, TagHelper>, IList<Comparer<byte[]>>> Property5 { get; }
}
}

View File

@ -1,30 +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.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public class TypeWithDictionaryProperties
{
public IDictionary<string, string> RouteValues1 { get; set; } =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
public Dictionary<int, string> RouteValues2 { get; set; } =
new Dictionary<int, string>();
public Dictionary<List<string>, float> RouteValues3 { get; set; } =
new Dictionary<List<string>, float>();
public IDictionary<string, ParserResults> CustomDictionary { get; set; } =
new Dictionary<string, ParserResults>();
public IDictionary NonGenericDictionary { get; set; } =
new Dictionary<string, string>();
public object ObjectType { get; set; } =
new Dictionary<string, string>();
}
}

View File

@ -1,12 +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.
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
[MultipleConstructorArguments(firstArgument: "First1", secondArgument: "Second1", thirdArgument: 31)]
[MultipleConstructorArguments(secondArgument: "Second2", firstArgument: "First2", thirdArgument: 32)]
[MultipleConstructorArguments(thirdArgument: 33, secondArgument: "Second3", firstArgument: "First3")]
public class TypeWithNamedAttributes
{
}
}

View File

@ -1,20 +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.
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public class Animal
{
public virtual string Name { get; set; }
}
public class Mammal : Animal
{
public override string Name { get; set; }
}
public class Dog : Mammal
{
public override string Name { get; set; }
}
}

View File

@ -1,9 +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.
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public class ViewContext
{
}
}

View File

@ -1,22 +0,0 @@
{
"version": "1.0.0-*",
"compilationOptions": {
"warningsAsErrors": true,
"keyFile": "../../tools/Key.snk"
},
"dependencies": {
"Microsoft.AspNet.Razor.Runtime.Precompilation": "4.0.0-*"
},
"frameworks": {
"dnx451": {
"frameworkAssemblies": {
"System.ComponentModel.DataAnnotations": "4.0.0.0"
}
},
"dnxcore50": {
"dependencies": {
"System.ComponentModel.Annotations": "4.0.11-*"
}
}
}
}

View File

@ -1,18 +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.
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
{
[RestrictChildren(Never)]
[CustomValidation(typeof(TypeDoesNotExist)]
[HtmlTargetElement("img"
public class TypeWithMalformedAttribute
{
}
}

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.
using System;
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
{
public class TypeWithMalformedProperties
{
public DateTime DateTime { get }
public int DateTime2 => "Hello world";
public string CustomOrder { get; set; }
}
}

View File

@ -1,10 +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.
namespace Microsoft.AspNet.Mvc.Razor.Precompilation
{
public class TypeWithMissingReferences : ITagHelper
{
}
}

View File

@ -1,83 +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.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.Extensions.PlatformAbstractions;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public static class CompilationUtility
{
private static readonly ConcurrentDictionary<string, AssemblyMetadata> _metadataCache =
new ConcurrentDictionary<string, AssemblyMetadata>(StringComparer.Ordinal);
private static readonly Assembly ExecutingAssembly = typeof(CompilationUtility).GetTypeInfo().Assembly;
public static readonly string GeneratedAssemblyName = Path.GetRandomFileName() + "." + Path.GetRandomFileName();
public static CodeAnalysis.Compilation GetCompilation(params string[] resourceFiles)
{
var assemblyVersion = ExecutingAssembly.GetName().Version;
var syntaxTrees = new List<SyntaxTree>
{
CSharpSyntaxTree.ParseText(
$"[assembly: {typeof(AssemblyVersionAttribute).FullName}(\"{assemblyVersion}\")]")
};
foreach (var resourceFile in resourceFiles)
{
var resourceContent = ReadManifestResource(resourceFile);
syntaxTrees.Add(CSharpSyntaxTree.ParseText(resourceContent));
}
var libraryExporter = CompilationServices.Default.LibraryExporter;
var applicationName = ExecutingAssembly.GetName().Name;
var libraryExport = libraryExporter.GetExport(applicationName);
var references = new List<MetadataReference>();
var roslynReference = libraryExport.MetadataReferences[0] as IRoslynMetadataReference;
var compilationReference = roslynReference?.MetadataReference as CompilationReference;
if (compilationReference != null)
{
references.AddRange(compilationReference.Compilation.References);
references.Add(roslynReference.MetadataReference);
}
else
{
var export = libraryExporter.GetAllExports(applicationName);
foreach (var metadataReference in export.MetadataReferences)
{
var reference = metadataReference.ConvertMetadataReference(
fileReference => _metadataCache.GetOrAdd(
fileReference.Path,
_ => fileReference.CreateAssemblyMetadata()));
references.Add(reference);
}
}
return CSharpCompilation.Create(
GeneratedAssemblyName,
syntaxTrees,
references);
}
private static string ReadManifestResource(string path)
{
path = $"{ExecutingAssembly.GetName().Name}.{path}.cs";
using (var contentStream = ExecutingAssembly.GetManifestResourceStream(path))
{
using (var reader = new StreamReader(contentStream))
{
return reader.ReadToEnd();
}
}
}
}
}

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>c626444c-5a63-42bc-acae-dbb2cd3ede25</ProjectGuid>
<RootNamespace>Microsoft.AspNet.Razor.Runtime.Precompilation.Test</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -1,80 +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.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.AspNet.Razor.Test.Internal;
using Xunit;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public class PrecompilationTagHelperDescriptorFactoryTest : TagHelperDescriptorFactoryTest
{
public override ITypeInfo GetTypeInfo(Type tagHelperType)
{
var paths = new[]
{
$"TagHelperDescriptorFactoryTagHelpers",
$"CommonTagHelpers",
};
var compilation = CompilationUtility.GetCompilation(paths);
var typeResolver = new PrecompilationTagHelperTypeResolver(compilation);
return Assert.Single(typeResolver.GetExportedTypes(CompilationUtility.GeneratedAssemblyName),
generatedType => string.Equals(generatedType.FullName, tagHelperType.FullName, StringComparison.Ordinal));
}
[Theory]
[MemberData(nameof(TagHelperWithPrefixData))]
public void CreateDescriptors_WithPrefixes_ReturnsExpectedAttributeDescriptors(
Type tagHelperType,
IEnumerable<TagHelperAttributeDescriptor> expectedAttributeDescriptors,
string[] expectedErrorMessages)
{
// Arrange
var errorSink = new ErrorSink();
var factory = new TagHelperDescriptorFactory(designTime: false);
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
errorSink: errorSink);
// Assert
var errors = errorSink.Errors.ToArray();
Assert.Equal(expectedErrorMessages.Length, errors.Length);
for (var i = 0; i < errors.Length; i++)
{
Assert.Equal(0, errors[i].Length);
Assert.Equal(SourceLocation.Zero, errors[i].Location);
Assert.Equal(expectedErrorMessages[i], errors[i].Message, StringComparer.Ordinal);
}
var descriptor = Assert.Single(descriptors);
#if DNXCORE50
// In CoreCLR type forwarding of System.Runtime types causes issues with comparing FullNames for generic types.
// We'll work around this by sanitizing the type names so that the assembly qualification is removed.
foreach (var attributeDescriptor in expectedAttributeDescriptors)
{
attributeDescriptor.TypeName = RuntimeTypeInfo.SanitizeFullName(attributeDescriptor.TypeName);
}
foreach (var attributeDescriptor in descriptor.Attributes)
{
attributeDescriptor.TypeName = RuntimeTypeInfo.SanitizeFullName(attributeDescriptor.TypeName);
}
#endif
Assert.Equal(
expectedAttributeDescriptors,
descriptor.Attributes,
TagHelperAttributeDescriptorComparer.Default);
}
}
}

View File

@ -1,625 +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.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.AspNet.Testing;
using Microsoft.CodeAnalysis.CSharp;
using Xunit;
namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public class PrecompilationTagHelperTypeResolverTest
{
private static readonly ITypeInfo TagHelperTypeInfo = new RuntimeTypeInfo(typeof(ITagHelper).GetTypeInfo());
[Theory]
[InlineData(typeof(TypeDerivingFromITagHelper))]
[InlineData(typeof(AttributeTargetingTagHelper))]
[InlineData(typeof(TagHelperInGlobalNamespace))]
public void TypesReturnedFromGetTopLevelExportedTypes_ReturnsTopLevelTypeInfo(Type expected)
{
// Arrange
var compilation = CompilationUtility.GetCompilation("TagHelperDescriptorFactoryTagHelpers");
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var actual = Assert.Single(exportedTypes, type => type.FullName == expected.FullName);
AssertEqual(expected, actual);
}
[Fact]
public void ImplementsInterface_ThrowsIfPassedInParameterIsNotRuntimeTypeOrCodeAnalysisBasedTypeInfo()
{
// Arrange
var interfaceType = new TestTypeInfo();
var compilation = CompilationUtility.GetCompilation(nameof(DerivingFromList));
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var actual = Assert.Single(exportedTypes);
ExceptionAssert.ThrowsArgument(() => actual.ImplementsInterface(interfaceType),
"interfaceTypeInfo",
$"Argument must be an instance of '{typeof(RuntimeTypeInfo)}' or '{typeof(CodeAnalysisSymbolBasedTypeInfo)}'.");
}
[Theory]
[InlineData(typeof(DerivingFromList))]
[InlineData(typeof(DerivingFromIList))]
public void ImplementsInterface_ReturnsTrueIfTypeDerivesFromInterface(Type expected)
{
// Arrange
var interfaceType = new RuntimeTypeInfo(typeof(IEnumerable<string>).GetTypeInfo());
var compilation = CompilationUtility.GetCompilation(expected.Name);
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var actual = Assert.Single(exportedTypes);
Assert.True(actual.ImplementsInterface(interfaceType));
}
[Theory]
[InlineData(typeof(TagHelper))]
[InlineData(typeof(IEnumerable<string>))]
public void ImplementsInterface_ReturnsFalseIfTypeDoesNotDerivesFromInterface(Type interfaceType)
{
// Arrange
var interfaceTypeInfo = new RuntimeTypeInfo(interfaceType.GetTypeInfo());
var compilation = CompilationUtility.GetCompilation("TagHelperDescriptorFactoryTagHelpers");
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var actual = Assert.Single(exportedTypes, type => type.Name == nameof(RequiredParentTagHelper));
Assert.False(actual.ImplementsInterface(interfaceTypeInfo));
}
[Fact]
public void PropertyNamesForComplexPropertiesAreGeneratedCorrectly()
{
// Arrange
var expectedType = typeof(TypeWithComplexPropertyFullNames);
var compilation = CompilationUtility.GetCompilation(expectedType.Name);
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var actual = Assert.Single(exportedTypes);
AssertEqual(expectedType, actual);
}
[Fact]
public void PropertyNamesForArrayPropertiesAreGeneratedCorrectly()
{
// Arrange
var expectedType = typeof(TypeWithArrayProperties);
var compilation = CompilationUtility.GetCompilation(expectedType.Name);
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var actual = Assert.Single(exportedTypes);
AssertEqual(expectedType, actual);
}
[Fact]
public void GetTopLevelExportedTypes_DoesNotReturnNonPublicOrNestedTypes()
{
// Arrange
var compilation = CompilationUtility.GetCompilation("AssemblyWithNonPublicTypes");
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
Assert.Collection(exportedTypes,
typeInfo =>
{
AssertEqual(typeof(PublicType), typeInfo);
},
typeInfo =>
{
AssertEqual(typeof(ContainerType), typeInfo);
},
typeInfo =>
{
AssertEqual(typeof(GenericType<>), typeInfo);
});
}
[Fact]
public void GetTopLevelExportedTypes_DoesNotReturnValueTypesOrInterfaces()
{
// Arrange
var compilation = CompilationUtility.GetCompilation("AssemblyWithNonTypes");
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
Assert.Collection(exportedTypes,
typeInfo =>
{
AssertEqual(typeof(MyAbstractClass), typeInfo);
},
typeInfo =>
{
AssertEqual(typeof(MyPartialClass), typeInfo);
},
typeInfo =>
{
AssertEqual(typeof(MySealedClass), typeInfo);
});
}
[Fact]
public void GetExportedTypes_PopulatesAttributes()
{
// Arrange
var expected = typeof(TypeWithAttributes).GetTypeInfo();
var compilation = CompilationUtility.GetCompilation(expected.Name);
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var actual = Assert.Single(exportedTypes);
AssertEqual(expected.AsType(), actual);
AssertAttributes<HtmlTargetElementAttribute>(
expected,
actual,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.Tag, actualAttribute.Tag);
Assert.Equal(expectedAttribute.Attributes, actualAttribute.Attributes);
},
discoveredAttributes => discoveredAttributes.OrderBy(attribute => attribute.Tag));
// Verify if enum in attribute constructors works.
AssertAttributes<EditorBrowsableAttribute>(
expected,
actual,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.State, actualAttribute.State);
});
// Verify if enum in attribute property works.
AssertAttributes<EnumPropertyAttribute>(
expected,
actual,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.DayOfWeek, actualAttribute.DayOfWeek);
});
// Verify if Type in attribute constructor and property works.
AssertAttributes<CustomValidationAttribute>(
expected,
actual,
(expectedAttribute, actualAttribute) =>
{
Assert.Same(expectedAttribute.ValidatorType, actualAttribute.ValidatorType);
Assert.Equal(expectedAttribute.Method, actualAttribute.Method);
Assert.Same(
expectedAttribute.ErrorMessageResourceType,
actualAttribute.ErrorMessageResourceType);
});
// Verify if array arguments work in constructor.
AssertAttributes<RestrictChildrenAttribute>(
expected,
actual,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(
expectedAttribute.ChildTags,
actualAttribute.ChildTags);
});
// Complex array bindings
AssertAttributes<ArrayPropertiesAttribute>(
expected,
actual,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.ArrayOfTypes, actualAttribute.ArrayOfTypes);
Assert.Equal(expectedAttribute.ArrayOfInts, actualAttribute.ArrayOfInts);
Assert.Equal(expectedAttribute.Days, actualAttribute.Days);
});
var expectedProperties = expected.DeclaredProperties;
Assert.Collection(actual.Properties,
property =>
{
Assert.Equal(nameof(TypeWithAttributes.Src), property.Name);
var expectedProperty = Assert.Single(expectedProperties, p => p.Name == property.Name);
AssertAttributes<HtmlAttributeNameAttribute>(
expectedProperty,
property,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.Name, actualAttribute.Name);
Assert.Equal(expectedAttribute.DictionaryAttributePrefix, actualAttribute.DictionaryAttributePrefix);
});
// Verify boolean values bind.
AssertAttributes<RequiredAttribute>(
expectedProperty,
property,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.AllowEmptyStrings, actualAttribute.AllowEmptyStrings);
});
},
property =>
{
Assert.Equal(nameof(TypeWithAttributes.AppendVersion), property.Name);
var expectedProperty = Assert.Single(expectedProperties, p => p.Name == property.Name);
AssertAttributes<HtmlAttributeNameAttribute>(
expectedProperty,
property,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.Name, actualAttribute.Name);
Assert.Equal(expectedAttribute.DictionaryAttributePrefix, actualAttribute.DictionaryAttributePrefix);
});
// Attribute without constructor arguments or properties.
Assert.Single(expectedProperty.GetCustomAttributes<HtmlAttributeNotBoundAttribute>());
Assert.Single(property.GetCustomAttributes<HtmlAttributeNotBoundAttribute>());
},
property =>
{
Assert.Equal(nameof(TypeWithAttributes.ViewContext), property.Name);
var expectedProperty = Assert.Single(expectedProperties, p => p.Name == property.Name);
AssertAttributes<EditorBrowsableAttribute>(
expectedProperty,
property,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.State, actualAttribute.State);
});
// Complex array bindings in properties
AssertAttributes<ArrayPropertiesAttribute>(
expected,
actual,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.ArrayOfTypes, actualAttribute.ArrayOfTypes);
Assert.Equal(expectedAttribute.ArrayOfInts, actualAttribute.ArrayOfInts);
Assert.Equal(expectedAttribute.Days, actualAttribute.Days);
});
},
property =>
{
Assert.Equal("HostingEnvironment", property.Name);
Assert.Single(expectedProperties, p => p.Name == property.Name);
// Complex array bindings in constructor arguments
AssertAttributes<AttributesWithArrayConstructorArgumentsAttribute>(
expected,
actual,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.StringArgs, actualAttribute.StringArgs);
Assert.Equal(expectedAttribute.IntArgs, actualAttribute.IntArgs);
Assert.Equal(expectedAttribute.TypeArgs, actualAttribute.TypeArgs);
});
});
}
[Fact]
public void GetExportedTypes_WithDerivedAttributes()
{
// Arrange
var expected = typeof(DerivedTagHelper);
var compilation = CompilationUtility.GetCompilation("TagHelperDescriptorFactoryTagHelpers");
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var actual = Assert.Single(exportedTypes, type => type.Name == expected.Name);
AssertEqual(expected, actual);
var expectedProperties = expected.GetProperties();
AssertAttributes<BaseAttribute>(
expectedProperties.First(p => p.Name == nameof(DerivedTagHelper.DerivedProperty)),
actual.Properties.First(p => p.Name == nameof(DerivedTagHelper.DerivedProperty)),
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.BaseProperty, actualAttribute.BaseProperty);
});
AssertAttributes<HtmlAttributeNameAttribute>(
expectedProperties.First(p => p.Name == nameof(DerivedTagHelper.NewProperty) &&
p.PropertyType == typeof(Type)),
actual.Properties.First(p => p.Name == nameof(DerivedTagHelper.NewProperty) &&
p.PropertyType.Name == typeof(Type).Name),
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.Name, actualAttribute.Name);
Assert.Equal(
expectedAttribute.DictionaryAttributePrefix,
actualAttribute.DictionaryAttributePrefix);
});
var expectedVirtualProperty = expectedProperties.First(
p => p.Name == nameof(DerivedTagHelper.VirtualProperty));
var actualVirtualProperty = actual.Properties.First(
p => p.Name == nameof(DerivedTagHelper.VirtualProperty));
Assert.Empty(expectedVirtualProperty.GetCustomAttributes<HtmlAttributeNotBoundAttribute>());
Assert.Empty(actualVirtualProperty.GetCustomAttributes<HtmlAttributeNotBoundAttribute>());
}
[Fact]
public void GetExportedTypes_CorrectlyIdentifiesIfTypeDerivesFromDictionary()
{
// Arrange
var compilation = CompilationUtility.GetCompilation(nameof(TypeWithDictionaryProperties));
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var exportedType = Assert.Single(exportedTypes);
AssertEqual(typeof(TypeWithDictionaryProperties), exportedType);
}
[Fact]
public void GetExportedTypes_WorksCorrectlyForOverridenProperties()
{
// Arrange
var compilation = CompilationUtility.GetCompilation("TypesWithInheritedProperties");
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
Assert.Collection(exportedTypes,
typeInfo =>
{
AssertEqual(typeof(Animal), typeInfo);
},
typeInfo =>
{
AssertEqual(typeof(Mammal), typeInfo);
},
typeInfo =>
{
AssertEqual(typeof(Dog), typeInfo);
});
}
[Fact]
public void GetExportedTypes_WorksIfAttributeConstructorArgumentsAreOutOfOrder()
{
// Arrange
var expectedType = typeof(TypeWithNamedAttributes);
var compilation = CompilationUtility.GetCompilation(expectedType.Name);
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var exportedType = Assert.Single(exportedTypes);
AssertEqual(expectedType, exportedType);
var attributes = exportedType.GetCustomAttributes<MultipleConstructorArgumentsAttribute>();
AssertAttributes<MultipleConstructorArgumentsAttribute>(
expectedType.GetTypeInfo(),
exportedType,
(expectedAttribute, actualAttribute) =>
{
Assert.Equal(expectedAttribute.FirstArgument, actualAttribute.FirstArgument);
Assert.Equal(expectedAttribute.SecondArgument, actualAttribute.SecondArgument);
Assert.Equal(expectedAttribute.ThirdArgument, actualAttribute.ThirdArgument);
},
discoveredAttributes => discoveredAttributes.OrderBy(attribute => attribute.FirstArgument));
}
[Fact]
public void GetExportedTypes_WorksIfAttributesAreMalformedErrors()
{
// Arrange
var compilation = CompilationUtility.GetCompilation("BadFiles.TypeWithMalformedAttribute");
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var actual = Assert.Single(exportedTypes);
var targetElementAttribute = Assert.Single(actual.GetCustomAttributes<HtmlTargetElementAttribute>());
Assert.Equal("img", targetElementAttribute.Tag);
Assert.Null(targetElementAttribute.Attributes);
Assert.Empty(actual.GetCustomAttributes<EditorBrowsableAttribute>());
var ex = Assert.Throws<InvalidOperationException>(
() => actual.GetCustomAttributes<CustomValidationAttribute>());
Assert.Equal($"Unable to find a suitable constructor for type '{typeof(CustomValidationAttribute).FullName}'.",
ex.Message);
ex = Assert.Throws<InvalidOperationException>(
() => actual.GetCustomAttributes<RestrictChildrenAttribute>());
Assert.Equal($"Unable to find a suitable constructor for type '{typeof(RestrictChildrenAttribute).FullName}'.",
ex.Message);
}
[Fact]
public void GetExportedTypes_WorksForPropertiesWithErrors()
{
// Arrange
var compilation = CompilationUtility.GetCompilation("BadFiles.TypeWithMalformedProperties");
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var actual = Assert.Single(exportedTypes);
Assert.Collection(actual.Properties,
property =>
{
Assert.Equal("DateTime", property.Name);
Assert.Equal(typeof(DateTime).Name, property.PropertyType.Name);
Assert.True(property.HasPublicGetter);
Assert.False(property.HasPublicSetter);
},
property =>
{
Assert.Equal("DateTime2", property.Name);
Assert.Equal(typeof(int).Name, property.PropertyType.Name);
Assert.True(property.HasPublicGetter);
Assert.False(property.HasPublicSetter);
},
property =>
{
Assert.Equal("CustomOrder", property.Name);
Assert.Equal(typeof(string).Name, property.PropertyType.Name);
Assert.True(property.HasPublicGetter);
Assert.True(property.HasPublicSetter);
});
}
[Fact]
public void GetExportedTypes_WorksForTypesWithErrors()
{
// Arrange
var compilation = CompilationUtility.GetCompilation("BadFiles.TypeWithMissingReferences");
var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
// Act
var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
// Assert
var type = Assert.Single(exportedTypes);
Assert.False(type.ImplementsInterface(TagHelperTypeInfo));
}
private static void AssertAttributes<TAttribute>(
MemberInfo expected,
IMemberInfo actual,
Action<TAttribute, TAttribute> assertItem)
where TAttribute : Attribute
{
AssertAttributes(expected, actual, assertItem, attributes => attributes);
}
private static void AssertAttributes<TAttribute>(
MemberInfo expected,
IMemberInfo actual,
Action<TAttribute, TAttribute> assertItem,
Func<IEnumerable<TAttribute>, IEnumerable<TAttribute>> reorderDiscoveredAttributes)
where TAttribute : Attribute
{
var expectedAttributes = reorderDiscoveredAttributes(expected.GetCustomAttributes<TAttribute>());
var actualAttributes = reorderDiscoveredAttributes(actual.GetCustomAttributes<TAttribute>());
Assert.Equal(expectedAttributes, actualAttributes, new DelegateAssertion<TAttribute>(assertItem));
}
private static void AssertEqual(Type expected, ITypeInfo actual)
{
AssertEqual(new RuntimeTypeInfo(expected.GetTypeInfo()), actual, assertProperties: true);
}
private static void AssertEqual(ITypeInfo expected, ITypeInfo actual, bool assertProperties)
{
var runtimeType = Assert.IsType<RuntimeTypeInfo>(expected);
var actualFullName = actual.FullName.Replace(
CompilationUtility.GeneratedAssemblyName,
runtimeType.TypeInfo.Assembly.GetName().Name);
Assert.Equal(expected.Name, actual.Name);
#if DNXCORE50
Assert.Equal(
RuntimeTypeInfo.SanitizeFullName(expected.FullName),
RuntimeTypeInfo.SanitizeFullName(actualFullName));
#endif
Assert.Equal(expected.IsPublic, actual.IsPublic);
Assert.Equal(expected.IsAbstract, actual.IsAbstract);
Assert.Equal(expected.IsGenericType, actual.IsGenericType);
Assert.Equal(
expected.ImplementsInterface(TagHelperTypeInfo),
actual.ImplementsInterface(TagHelperTypeInfo));
Assert.Equal(
expected.GetGenericDictionaryParameters(),
actual.GetGenericDictionaryParameters(),
new DelegateAssertion<ITypeInfo>((x, y) => AssertEqual(x, y, assertProperties: false)));
if (assertProperties)
{
Assert.Equal(
expected.Properties.OrderBy(p => p.Name),
actual.Properties.OrderBy(p => p.Name),
new DelegateAssertion<IPropertyInfo>((x, y) => AssertEqual(x, y)));
}
Assert.True(actual.Equals(expected));
Assert.True(expected.Equals(actual));
Assert.Equal(expected.GetHashCode(), actual.GetHashCode());
}
private static void AssertEqual(IPropertyInfo expected, IPropertyInfo actual)
{
Assert.Equal(expected.Name, actual.Name);
Assert.Equal(expected.HasPublicGetter, actual.HasPublicGetter);
Assert.Equal(expected.HasPublicSetter, actual.HasPublicSetter);
AssertEqual(expected.PropertyType, actual.PropertyType, assertProperties: false);
}
private class DelegateAssertion<T> : IEqualityComparer<T>
{
private readonly Action<T, T> _assert;
public DelegateAssertion(Action<T, T> assert)
{
_assert = assert;
}
public bool Equals(T x, T y)
{
_assert(x, y);
return true;
}
public int GetHashCode(T obj) => 0;
}
}
}

View File

@ -1,36 +0,0 @@
{
"version": "1.0.0",
"compilationOptions": {
"warningsAsErrors": true,
"keyFile": "../../tools/Key.snk"
},
"dependencies": {
"Microsoft.AspNet.Razor.Runtime.Precompilation.Files": "1.0.0-*",
"Microsoft.AspNet.Razor.Runtime.Test": "1.0.0-*",
"Microsoft.AspNet.Razor.Test.Sources": {
"version": "4.0.0-*",
"type": "build"
},
"Microsoft.Dnx.Compilation.CSharp.Common": "1.0.0-*",
"Microsoft.Extensions.HashCodeCombiner.Sources": {
"type": "build",
"version": "1.0.0-*"
}
},
"resource": [
"../Microsoft.AspNet.Razor.Runtime.Precompilation.Files/*.cs",
"../Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TestTagHelpers/*.cs",
"BadFiles/*.cs"
],
"commands": {
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnx451": {
"frameworkAssemblies": {
"System.Text.Encoding": ""
}
},
"dnxcore50": {}
}
}