From ebb48551d8af3df016ca6278ce2ccfdd3e71a3d8 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Wed, 5 Sep 2018 18:18:04 -0700 Subject: [PATCH 1/3] Updated APIGenerator and other dependencies --- src/Directory.build.props | 9 +- .../ReactiveUI.Fody.Tests.csproj | 2 +- .../PublicApiGenerator.6.0.0/ApiGenerator.cs | 756 ------------------ src/ReactiveUI.Tests/ReactiveUI.Tests.csproj | 4 +- 4 files changed, 8 insertions(+), 763 deletions(-) delete mode 100644 src/ReactiveUI.Tests/App_Packages/PublicApiGenerator.6.0.0/ApiGenerator.cs diff --git a/src/Directory.build.props b/src/Directory.build.props index 1c42a672c5..910ff13a3c 100644 --- a/src/Directory.build.props +++ b/src/Directory.build.props @@ -18,6 +18,7 @@ AnyCPU embedded $(MSBuildProjectName.Contains('Tests')) + @@ -29,10 +30,10 @@ - - - - + + + + diff --git a/src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj b/src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj index 5e8c45be4f..a2e29bb7aa 100644 --- a/src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj +++ b/src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/ReactiveUI.Tests/App_Packages/PublicApiGenerator.6.0.0/ApiGenerator.cs b/src/ReactiveUI.Tests/App_Packages/PublicApiGenerator.6.0.0/ApiGenerator.cs deleted file mode 100644 index 50b4804f73..0000000000 --- a/src/ReactiveUI.Tests/App_Packages/PublicApiGenerator.6.0.0/ApiGenerator.cs +++ /dev/null @@ -1,756 +0,0 @@ -using System; -using System.CodeDom; -using System.CodeDom.Compiler; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using Microsoft.CSharp; -using Mono.Cecil; -using Mono.Cecil.Rocks; -using ICustomAttributeProvider = Mono.Cecil.ICustomAttributeProvider; -using TypeAttributes = System.Reflection.TypeAttributes; - -// ReSharper disable BitwiseOperatorOnEnumWithoutFlags -namespace PublicApiGenerator -{ - public static class ApiGenerator - { - public static string GeneratePublicApi(Assembly assemby, Type[] includeTypes = null, bool shouldIncludeAssemblyAttributes = true) - { - var assemblyResolver = new DefaultAssemblyResolver(); - var assemblyPath = assemby.Location; - assemblyResolver.AddSearchDirectory(Path.GetDirectoryName(assemblyPath)); - - var readSymbols = File.Exists(Path.ChangeExtension(assemblyPath, ".pdb")); - var asm = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters(ReadingMode.Deferred) - { - ReadSymbols = readSymbols, - AssemblyResolver = assemblyResolver, - }); - - return CreatePublicApiForAssembly(asm, tr => includeTypes == null || includeTypes.Any(t => t.FullName == tr.FullName && t.Assembly.FullName == tr.Module.Assembly.FullName), shouldIncludeAssemblyAttributes); - } - - // TODO: Assembly references? - // TODO: Better handle namespaces - using statements? - requires non-qualified type names - static string CreatePublicApiForAssembly(AssemblyDefinition assembly, Func shouldIncludeType, bool shouldIncludeAssemblyAttributes) - { - var publicApiBuilder = new StringBuilder(); - var cgo = new CodeGeneratorOptions - { - BracingStyle = "C", - BlankLinesBetweenMembers = false, - VerbatimOrder = false - }; - - using (var provider = new CSharpCodeProvider()) { - var compileUnit = new CodeCompileUnit(); - if (shouldIncludeAssemblyAttributes && assembly.HasCustomAttributes) { - PopulateCustomAttributes(assembly, compileUnit.AssemblyCustomAttributes); - } - - var publicTypes = assembly.Modules.SelectMany(m => m.GetTypes()) - .Where(t => !t.IsNested && ShouldIncludeType(t) && shouldIncludeType(t)) - .OrderBy(t => t.FullName); - foreach (var publicType in publicTypes) { - var @namespace = compileUnit.Namespaces.Cast() - .FirstOrDefault(n => n.Name == publicType.Namespace); - if (@namespace == null) { - @namespace = new CodeNamespace(publicType.Namespace); - compileUnit.Namespaces.Add(@namespace); - } - - var typeDeclaration = CreateTypeDeclaration(publicType); - @namespace.Types.Add(typeDeclaration); - } - - using (var writer = new StringWriter()) { - provider.GenerateCodeFromCompileUnit(compileUnit, writer, cgo); - var typeDeclarationText = NormaliseGeneratedCode(writer); - publicApiBuilder.AppendLine(typeDeclarationText); - } - } - return NormaliseLineEndings(publicApiBuilder.ToString().Trim()); - } - - static string NormaliseLineEndings(string value) - { - return Regex.Replace(value, @"\r\n|\n\r|\r|\n", Environment.NewLine); - } - - static bool IsDelegate(TypeDefinition publicType) - { - return publicType.BaseType != null && publicType.BaseType.FullName == "System.MulticastDelegate"; - } - - static bool ShouldIncludeType(TypeDefinition t) - { - return (t.IsPublic || t.IsNestedPublic || t.IsNestedFamily) && !IsCompilerGenerated(t); - } - - static bool ShouldIncludeMember(IMemberDefinition m) - { - return !IsCompilerGenerated(m) && !IsDotNetTypeMember(m) && !(m is FieldDefinition); - } - - static bool IsCompilerGenerated(IMemberDefinition m) - { - return m.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.CompilerGeneratedAttribute"); - } - - static bool IsDotNetTypeMember(IMemberDefinition m) - { - if (m.DeclaringType == null || m.DeclaringType.FullName == null) - return false; - return m.DeclaringType.FullName.StartsWith("System") || m.DeclaringType.FullName.StartsWith("Microsoft"); - } - - static void AddMemberToTypeDeclaration(CodeTypeDeclaration typeDeclaration, IMemberDefinition memberInfo) - { - var methodDefinition = memberInfo as MethodDefinition; - if (methodDefinition != null) { - if (methodDefinition.IsConstructor) - AddCtorToTypeDeclaration(typeDeclaration, methodDefinition); - else - AddMethodToTypeDeclaration(typeDeclaration, methodDefinition); - } else if (memberInfo is PropertyDefinition) { - AddPropertyToTypeDeclaration(typeDeclaration, (PropertyDefinition)memberInfo); - } else if (memberInfo is EventDefinition) { - typeDeclaration.Members.Add(GenerateEvent((EventDefinition)memberInfo)); - } else if (memberInfo is FieldDefinition) { - AddFieldToTypeDeclaration(typeDeclaration, (FieldDefinition)memberInfo); - } - } - - static string NormaliseGeneratedCode(StringWriter writer) - { - var gennedClass = writer.ToString(); - const string autoGeneratedHeader = @"^//-+\s*$.*^//-+\s*$"; - const string emptyGetSet = @"\s+{\s+get\s+{\s+}\s+set\s+{\s+}\s+}"; - const string emptyGet = @"\s+{\s+get\s+{\s+}\s+}"; - const string emptySet = @"\s+{\s+set\s+{\s+}\s+}"; - const string getSet = @"\s+{\s+get;\s+set;\s+}"; - const string get = @"\s+{\s+get;\s+}"; - const string set = @"\s+{\s+set;\s+}"; - gennedClass = Regex.Replace(gennedClass, autoGeneratedHeader, string.Empty, - RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline | RegexOptions.Singleline); - gennedClass = Regex.Replace(gennedClass, emptyGetSet, " { get; set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, getSet, " { get; set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, emptyGet, " { get; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, emptySet, " { set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, get, " { get; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, set, " { set; }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, @"\s+{\s+}", " { }", RegexOptions.IgnorePatternWhitespace); - gennedClass = Regex.Replace(gennedClass, @"\)\s+;", ");", RegexOptions.IgnorePatternWhitespace); - return gennedClass; - } - - static CodeTypeDeclaration CreateTypeDeclaration(TypeDefinition publicType) - { - if (IsDelegate(publicType)) - return CreateDelegateDeclaration(publicType); - - var @static = false; - TypeAttributes attributes = 0; - if (publicType.IsPublic || publicType.IsNestedPublic) - attributes |= TypeAttributes.Public; - if (publicType.IsNestedFamily) - attributes |= TypeAttributes.NestedFamily; - if (publicType.IsSealed && !publicType.IsAbstract) - attributes |= TypeAttributes.Sealed; - else if (!publicType.IsSealed && publicType.IsAbstract && !publicType.IsInterface) - attributes |= TypeAttributes.Abstract; - else if (publicType.IsSealed && publicType.IsAbstract) - @static = true; - - // Static support is a hack. CodeDOM does support it, and this isn't - // correct C#, but it's good enough for our API outline - var name = publicType.Name; - - var index = name.IndexOf('`'); - if (index != -1) - name = name.Substring(0, index); - var declaration = new CodeTypeDeclaration(@static ? "static " + name : name) - { - CustomAttributes = CreateCustomAttributes(publicType), - // TypeAttributes must be specified before the IsXXX as they manipulate TypeAttributes! - TypeAttributes = attributes, - IsClass = publicType.IsClass, - IsEnum = publicType.IsEnum, - IsInterface = publicType.IsInterface, - IsStruct = publicType.IsValueType && !publicType.IsPrimitive && !publicType.IsEnum, - }; - - if (declaration.IsInterface && publicType.BaseType != null) - throw new NotImplementedException("Base types for interfaces needs testing"); - - PopulateGenericParameters(publicType, declaration.TypeParameters); - - if (publicType.BaseType != null && ShouldOutputBaseType(publicType)) { - if (publicType.BaseType.FullName == "System.Enum") { - var underlyingType = publicType.GetEnumUnderlyingType(); - if (underlyingType.FullName != "System.Int32") - declaration.BaseTypes.Add(CreateCodeTypeReference(underlyingType)); - } else - declaration.BaseTypes.Add(CreateCodeTypeReference(publicType.BaseType)); - } - foreach (var @interface in publicType.Interfaces.OrderBy(i => i.FullName) - .Select(t => new { Reference = t, Definition = t.Resolve() }) - .Where(t => ShouldIncludeType(t.Definition)) - .Select(t => t.Reference)) - declaration.BaseTypes.Add(CreateCodeTypeReference(@interface)); - - foreach (var memberInfo in publicType.GetMembers().Where(ShouldIncludeMember).OrderBy(m => m.Name)) - AddMemberToTypeDeclaration(declaration, memberInfo); - - // Fields should be in defined order for an enum - var fields = !publicType.IsEnum - ? publicType.Fields.OrderBy(f => f.Name) - : (IEnumerable)publicType.Fields; - foreach (var field in fields) - AddMemberToTypeDeclaration(declaration, field); - - foreach (var nestedType in publicType.NestedTypes.Where(ShouldIncludeType).OrderBy(t => t.FullName)) { - var nestedTypeDeclaration = CreateTypeDeclaration(nestedType); - declaration.Members.Add(nestedTypeDeclaration); - } - - return declaration; - } - - static CodeTypeDeclaration CreateDelegateDeclaration(TypeDefinition publicType) - { - var invokeMethod = publicType.Methods.Single(m => m.Name == "Invoke"); - var name = publicType.Name; - var index = name.IndexOf('`'); - if (index != -1) - name = name.Substring(0, index); - var declaration = new CodeTypeDelegate(name) - { - Attributes = MemberAttributes.Public, - CustomAttributes = CreateCustomAttributes(publicType), - ReturnType = CreateCodeTypeReference(invokeMethod.ReturnType), - }; - - // CodeDOM. No support. Return type attributes. - PopulateCustomAttributes(invokeMethod.MethodReturnType, declaration.CustomAttributes, type => ModifyCodeTypeReference(type, "return:")); - PopulateGenericParameters(publicType, declaration.TypeParameters); - PopulateMethodParameters(invokeMethod, declaration.Parameters); - - // Of course, CodeDOM doesn't support generic type parameters for delegates. Of course. - if (declaration.TypeParameters.Count > 0) { - var parameterNames = from parameterType in declaration.TypeParameters.Cast() - select parameterType.Name; - declaration.Name = string.Format(CultureInfo.InvariantCulture, "{0}<{1}>", declaration.Name, string.Join(", ", parameterNames)); - } - - return declaration; - } - - static bool ShouldOutputBaseType(TypeDefinition publicType) - { - return publicType.BaseType.FullName != "System.Object" && publicType.BaseType.FullName != "System.ValueType"; - } - - static void PopulateGenericParameters(IGenericParameterProvider publicType, CodeTypeParameterCollection parameters) - { - foreach (var parameter in publicType.GenericParameters) { - if (parameter.HasCustomAttributes) - throw new NotImplementedException("Attributes on type parameters is not supported. And weird"); - - // A little hacky. Means we get "in" and "out" prefixed on any constraints, but it's either that - // or add it as a custom attribute, which looks even weirder - var name = parameter.Name; - if (parameter.IsCovariant) - name = "out " + name; - if (parameter.IsContravariant) - name = "in " + name; - - var typeParameter = new CodeTypeParameter(name) - { - HasConstructorConstraint = - parameter.HasDefaultConstructorConstraint && !parameter.HasNotNullableValueTypeConstraint - }; - if (parameter.HasNotNullableValueTypeConstraint) - typeParameter.Constraints.Add(" struct"); // Extra space is a hack! - if (parameter.HasReferenceTypeConstraint) - typeParameter.Constraints.Add(" class"); - foreach (var constraint in parameter.Constraints.Where(t => t.FullName != "System.ValueType")) { - typeParameter.Constraints.Add(CreateCodeTypeReference(constraint.GetElementType())); - } - parameters.Add(typeParameter); - } - } - - static CodeAttributeDeclarationCollection CreateCustomAttributes(ICustomAttributeProvider type) - { - var attributes = new CodeAttributeDeclarationCollection(); - PopulateCustomAttributes(type, attributes); - return attributes; - } - - static void PopulateCustomAttributes(ICustomAttributeProvider type, - CodeAttributeDeclarationCollection attributes) - { - PopulateCustomAttributes(type, attributes, ctr => ctr); - } - - static void PopulateCustomAttributes(ICustomAttributeProvider type, - CodeAttributeDeclarationCollection attributes, Func codeTypeModifier) - { - foreach (var customAttribute in type.CustomAttributes.Where(ShouldIncludeAttribute).OrderBy(a => a.AttributeType.FullName).ThenBy(a => ConvertAttrbuteToCode(codeTypeModifier, a))) { - var attribute = GenerateCodeAttributeDeclaration(codeTypeModifier, customAttribute); - attributes.Add(attribute); - } - } - - static CodeAttributeDeclaration GenerateCodeAttributeDeclaration(Func codeTypeModifier, CustomAttribute customAttribute) - { - var attribute = new CodeAttributeDeclaration(codeTypeModifier(CreateCodeTypeReference(customAttribute.AttributeType))); - foreach (var arg in customAttribute.ConstructorArguments) { - attribute.Arguments.Add(new CodeAttributeArgument(CreateInitialiserExpression(arg))); - } - foreach (var field in customAttribute.Fields.OrderBy(f => f.Name)) { - attribute.Arguments.Add(new CodeAttributeArgument(field.Name, CreateInitialiserExpression(field.Argument))); - } - foreach (var property in customAttribute.Properties.OrderBy(p => p.Name)) { - attribute.Arguments.Add(new CodeAttributeArgument(property.Name, CreateInitialiserExpression(property.Argument))); - } - return attribute; - } - - // Litee: This method is used for additional sorting of custom attributes when multiple values are allowed - static object ConvertAttrbuteToCode(Func codeTypeModifier, CustomAttribute customAttribute) - { - using (var provider = new CSharpCodeProvider()) { - var cgo = new CodeGeneratorOptions - { - BracingStyle = "C", - BlankLinesBetweenMembers = false, - VerbatimOrder = false - }; - var attribute = GenerateCodeAttributeDeclaration(codeTypeModifier, customAttribute); - var declaration = new CodeTypeDeclaration("DummyClass") - { - CustomAttributes = new CodeAttributeDeclarationCollection(new[] { attribute }), - }; - using (var writer = new StringWriter()) { - provider.GenerateCodeFromType(declaration, writer, cgo); - return writer.ToString(); - } - } - } - - static readonly HashSet SkipAttributeNames = new HashSet - { - "System.CodeDom.Compiler.GeneratedCodeAttribute", - "System.ComponentModel.EditorBrowsableAttribute", - "System.Runtime.CompilerServices.AsyncStateMachineAttribute", - "System.Runtime.CompilerServices.CompilerGeneratedAttribute", - "System.Runtime.CompilerServices.CompilationRelaxationsAttribute", - "System.Runtime.CompilerServices.ExtensionAttribute", - "System.Runtime.CompilerServices.RuntimeCompatibilityAttribute", - "System.Reflection.DefaultMemberAttribute", - "System.Diagnostics.DebuggableAttribute", - "System.Diagnostics.DebuggerNonUserCodeAttribute", - "System.Diagnostics.DebuggerStepThroughAttribute", - "System.Reflection.AssemblyCompanyAttribute", - "System.Reflection.AssemblyConfigurationAttribute", - "System.Reflection.AssemblyCopyrightAttribute", - "System.Reflection.AssemblyDescriptionAttribute", - "System.Reflection.AssemblyFileVersionAttribute", - "System.Reflection.AssemblyInformationalVersionAttribute", - "System.Reflection.AssemblyProductAttribute", - "System.Reflection.AssemblyTitleAttribute", - "System.Reflection.AssemblyTrademarkAttribute" - }; - - static bool ShouldIncludeAttribute(CustomAttribute attribute) - { - var attributeTypeDefinition = attribute.AttributeType.Resolve(); - return !SkipAttributeNames.Contains(attribute.AttributeType.FullName) && attributeTypeDefinition.IsPublic; - } - - static CodeExpression CreateInitialiserExpression(CustomAttributeArgument attributeArgument) - { - if (attributeArgument.Value is CustomAttributeArgument) { - return CreateInitialiserExpression((CustomAttributeArgument)attributeArgument.Value); - } - - if (attributeArgument.Value is CustomAttributeArgument[]) { - var initialisers = from argument in (CustomAttributeArgument[])attributeArgument.Value - select CreateInitialiserExpression(argument); - return new CodeArrayCreateExpression(CreateCodeTypeReference(attributeArgument.Type), initialisers.ToArray()); - } - - var type = attributeArgument.Type.Resolve(); - var value = attributeArgument.Value; - if (type.BaseType != null && type.BaseType.FullName == "System.Enum") { - var originalValue = Convert.ToInt64(value); - if (type.CustomAttributes.Any(a => a.AttributeType.FullName == "System.FlagsAttribute")) { - //var allFlags = from f in type.Fields - // where f.Constant != null - // let v = Convert.ToInt64(f.Constant) - // where v == 0 || (originalValue & v) != 0 - // select (CodeExpression)new CodeFieldReferenceExpression(typeExpression, f.Name); - //return allFlags.Aggregate((current, next) => new CodeBinaryOperatorExpression(current, CodeBinaryOperatorType.BitwiseOr, next)); - - // I'd rather use the above, as it's just using the CodeDOM, but it puts - // brackets around each CodeBinaryOperatorExpression - var flags = from f in type.Fields - where f.Constant != null - let v = Convert.ToInt64(f.Constant) - where v == 0 || (originalValue & v) != 0 - select type.FullName + "." + f.Name; - return new CodeSnippetExpression(flags.Aggregate((current, next) => current + " | " + next)); - } - - var allFlags = from f in type.Fields - where f.Constant != null - let v = Convert.ToInt64(f.Constant) - where v == originalValue - select new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(CreateCodeTypeReference(type)), f.Name); - return allFlags.FirstOrDefault(); - } - - if (type.FullName == "System.Type" && value is TypeReference) { - return new CodeTypeOfExpression(CreateCodeTypeReference((TypeReference)value)); - } - - if (value is string) { - // CodeDOM outputs a verbatim string. Any string with \n is treated as such, so normalise - // it to make it easier for comparisons - value = Regex.Replace((string)value, @"\n", "\\n"); - value = Regex.Replace((string)value, @"\r\n|\r\\n", "\\r\\n"); - } - - return new CodePrimitiveExpression(value); - } - - static void AddCtorToTypeDeclaration(CodeTypeDeclaration typeDeclaration, MethodDefinition member) - { - if (member.IsAssembly || member.IsPrivate) - return; - - var method = new CodeConstructor - { - CustomAttributes = CreateCustomAttributes(member), - Name = member.Name, - Attributes = GetMethodAttributes(member) - }; - PopulateMethodParameters(member, method.Parameters); - - typeDeclaration.Members.Add(method); - } - - static void AddMethodToTypeDeclaration(CodeTypeDeclaration typeDeclaration, MethodDefinition member) - { - if (member.IsAssembly || member.IsPrivate || member.IsSpecialName) - return; - - var returnType = CreateCodeTypeReference(member.ReturnType); - - var method = new CodeMemberMethod - { - Name = member.Name, - Attributes = GetMethodAttributes(member), - CustomAttributes = CreateCustomAttributes(member), - ReturnType = returnType, - }; - PopulateCustomAttributes(member.MethodReturnType, method.ReturnTypeCustomAttributes); - PopulateGenericParameters(member, method.TypeParameters); - PopulateMethodParameters(member, method.Parameters, IsExtensionMethod(member)); - - typeDeclaration.Members.Add(method); - } - - static bool IsExtensionMethod(ICustomAttributeProvider method) - { - return method.CustomAttributes.Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute"); - } - - static void PopulateMethodParameters(IMethodSignature member, - CodeParameterDeclarationExpressionCollection parameters, bool isExtension = false) - { - foreach (var parameter in member.Parameters) { - FieldDirection direction = 0; - if (parameter.IsOut) - direction |= FieldDirection.Out; - else if (parameter.ParameterType.IsByReference) - direction |= FieldDirection.Ref; - - var parameterType = parameter.ParameterType.IsByReference - ? parameter.ParameterType.GetElementType() - : parameter.ParameterType; - - var type = CreateCodeTypeReference(parameterType); - - if (isExtension) { - type = ModifyCodeTypeReference(type, "this"); - isExtension = false; - } - - var name = parameter.HasConstant - ? string.Format(CultureInfo.InvariantCulture, "{0} = {1}", parameter.Name, FormatParameterConstant(parameter)) - : parameter.Name; - var expression = new CodeParameterDeclarationExpression(type, name) - { - Direction = direction, - CustomAttributes = CreateCustomAttributes(parameter) - }; - parameters.Add(expression); - } - } - - static object FormatParameterConstant(IConstantProvider parameter) - { - return parameter.Constant is string ? string.Format(CultureInfo.InvariantCulture, "\"{0}\"", parameter.Constant) : (parameter.Constant ?? "null"); - } - - static MemberAttributes GetMethodAttributes(MethodDefinition method) - { - MemberAttributes access = 0; - if (method.IsFamily) - access = MemberAttributes.Family; - if (method.IsPublic) - access = MemberAttributes.Public; - if (method.IsAssembly) - access = MemberAttributes.Assembly; - if (method.IsFamilyAndAssembly) - access = MemberAttributes.FamilyAndAssembly; - if (method.IsFamilyOrAssembly) - access = MemberAttributes.FamilyOrAssembly; - - MemberAttributes scope = 0; - if (method.IsStatic) - scope |= MemberAttributes.Static; - if (method.IsFinal || !method.IsVirtual) - scope |= MemberAttributes.Final; - if (method.IsAbstract) - scope |= MemberAttributes.Abstract; - if (method.IsVirtual && !method.IsNewSlot) - scope |= MemberAttributes.Override; - - MemberAttributes vtable = 0; - if (IsHidingMethod(method)) - vtable = MemberAttributes.New; - - return access | scope | vtable; - } - - static bool IsHidingMethod(MethodDefinition method) - { - var typeDefinition = method.DeclaringType; - - // If we're an interface, just try and find any method with the same signature - // in any of the interfaces that we implement - if (typeDefinition.IsInterface) { - var interfaceMethods = from @interfaceReference in typeDefinition.Interfaces - let interfaceDefinition = @interfaceReference.Resolve() - where interfaceDefinition != null - select interfaceDefinition.Methods; - - return interfaceMethods.Any(ms => MetadataResolver.GetMethod(ms, method) != null); - } - - // If we're not an interface, find a base method that isn't virtual - return !method.IsVirtual && GetBaseTypes(typeDefinition).Any(d => MetadataResolver.GetMethod(d.Methods, method) != null); - } - - static IEnumerable GetBaseTypes(TypeDefinition type) - { - var baseType = type.BaseType; - while (baseType != null) { - var definition = baseType.Resolve(); - if (definition == null) - yield break; - yield return definition; - - baseType = baseType.DeclaringType; - } - } - - static void AddPropertyToTypeDeclaration(CodeTypeDeclaration typeDeclaration, PropertyDefinition member) - { - var getterAttributes = member.GetMethod != null ? GetMethodAttributes(member.GetMethod) : 0; - var setterAttributes = member.SetMethod != null ? GetMethodAttributes(member.SetMethod) : 0; - - if (!HasVisiblePropertyMethod(getterAttributes) && !HasVisiblePropertyMethod(setterAttributes)) - return; - - var propertyAttributes = GetPropertyAttributes(getterAttributes, setterAttributes); - - var propertyType = member.PropertyType.IsGenericParameter - ? new CodeTypeReference(member.PropertyType.Name) - : CreateCodeTypeReference(member.PropertyType); - - var property = new CodeMemberProperty - { - Name = member.Name, - Type = propertyType, - Attributes = propertyAttributes, - CustomAttributes = CreateCustomAttributes(member), - HasGet = member.GetMethod != null && HasVisiblePropertyMethod(getterAttributes), - HasSet = member.SetMethod != null && HasVisiblePropertyMethod(setterAttributes) - }; - - // Here's a nice hack, because hey, guess what, the CodeDOM doesn't support - // attributes on getters or setters - if (member.GetMethod != null && member.GetMethod.HasCustomAttributes) { - PopulateCustomAttributes(member.GetMethod, property.CustomAttributes, type => ModifyCodeTypeReference(type, "get:")); - } - if (member.SetMethod != null && member.SetMethod.HasCustomAttributes) { - PopulateCustomAttributes(member.SetMethod, property.CustomAttributes, type => ModifyCodeTypeReference(type, "set:")); - } - - foreach (var parameter in member.Parameters) { - property.Parameters.Add( - new CodeParameterDeclarationExpression(CreateCodeTypeReference(parameter.ParameterType), - parameter.Name)); - } - - // TODO: CodeDOM has no support for different access modifiers for getters and setters - // TODO: CodeDOM has no support for attributes on setters or getters - promote to property? - - typeDeclaration.Members.Add(property); - } - - static MemberAttributes GetPropertyAttributes(MemberAttributes getterAttributes, MemberAttributes setterAttributes) - { - MemberAttributes access = 0; - var getterAccess = getterAttributes & MemberAttributes.AccessMask; - var setterAccess = setterAttributes & MemberAttributes.AccessMask; - if (getterAccess == MemberAttributes.Public || setterAccess == MemberAttributes.Public) - access = MemberAttributes.Public; - else if (getterAccess == MemberAttributes.Family || setterAccess == MemberAttributes.Family) - access = MemberAttributes.Family; - else if (getterAccess == MemberAttributes.FamilyAndAssembly || setterAccess == MemberAttributes.FamilyAndAssembly) - access = MemberAttributes.FamilyAndAssembly; - else if (getterAccess == MemberAttributes.FamilyOrAssembly || setterAccess == MemberAttributes.FamilyOrAssembly) - access = MemberAttributes.FamilyOrAssembly; - else if (getterAccess == MemberAttributes.Assembly || setterAccess == MemberAttributes.Assembly) - access = MemberAttributes.Assembly; - else if (getterAccess == MemberAttributes.Private || setterAccess == MemberAttributes.Private) - access = MemberAttributes.Private; - - // Scope should be the same for getter and setter. If one isn't specified, it'll be 0 - var getterScope = getterAttributes & MemberAttributes.ScopeMask; - var setterScope = setterAttributes & MemberAttributes.ScopeMask; - var scope = (MemberAttributes)Math.Max((int)getterScope, (int)setterScope); - - // Vtable should be the same for getter and setter. If one isn't specified, it'll be 0 - var getterVtable = getterAttributes & MemberAttributes.VTableMask; - var setterVtable = setterAttributes & MemberAttributes.VTableMask; - var vtable = (MemberAttributes)Math.Max((int)getterVtable, (int)setterVtable); - - return access | scope | vtable; - } - - static bool HasVisiblePropertyMethod(MemberAttributes attributes) - { - var access = attributes & MemberAttributes.AccessMask; - return access == MemberAttributes.Public || access == MemberAttributes.Family || - access == MemberAttributes.FamilyOrAssembly; - } - - static CodeTypeMember GenerateEvent(EventDefinition eventDefinition) - { - var @event = new CodeMemberEvent - { - Name = eventDefinition.Name, - Attributes = MemberAttributes.Public | MemberAttributes.Final, - CustomAttributes = CreateCustomAttributes(eventDefinition), - Type = CreateCodeTypeReference(eventDefinition.EventType) - }; - - return @event; - } - - static void AddFieldToTypeDeclaration(CodeTypeDeclaration typeDeclaration, FieldDefinition memberInfo) - { - if (memberInfo.IsPrivate || memberInfo.IsAssembly || memberInfo.IsSpecialName) - return; - - MemberAttributes attributes = 0; - if (memberInfo.HasConstant) - attributes |= MemberAttributes.Const; - if (memberInfo.IsFamily) - attributes |= MemberAttributes.Family; - if (memberInfo.IsPublic) - attributes |= MemberAttributes.Public; - if (memberInfo.IsStatic && !memberInfo.HasConstant) - attributes |= MemberAttributes.Static; - - // TODO: Values for readonly fields are set in the ctor - var codeTypeReference = CreateCodeTypeReference(memberInfo.FieldType); - if (memberInfo.IsInitOnly) - codeTypeReference = MakeReadonly(codeTypeReference); - var field = new CodeMemberField(codeTypeReference, memberInfo.Name) - { - Attributes = attributes, - CustomAttributes = CreateCustomAttributes(memberInfo) - }; - - if (memberInfo.HasConstant) - field.InitExpression = new CodePrimitiveExpression(memberInfo.Constant); - - typeDeclaration.Members.Add(field); - } - - static CodeTypeReference MakeReadonly(CodeTypeReference typeReference) - { - return ModifyCodeTypeReference(typeReference, "readonly"); - } - - static CodeTypeReference ModifyCodeTypeReference(CodeTypeReference typeReference, string modifier) - { - using (var provider = new CSharpCodeProvider()) - return new CodeTypeReference(modifier + " " + provider.GetTypeOutput(typeReference)); - } - - static CodeTypeReference CreateCodeTypeReference(TypeReference type) - { - var typeName = GetTypeName(type); - return new CodeTypeReference(typeName, CreateGenericArguments(type)); - } - - static string GetTypeName(TypeReference type) - { - if (type.IsGenericParameter) - return type.Name; - - if (!type.IsNested) { - return (!string.IsNullOrEmpty(type.Namespace) ? (type.Namespace + ".") : "") + type.Name; - } - - return GetTypeName(type.DeclaringType) + "." + type.Name; - } - - static CodeTypeReference[] CreateGenericArguments(TypeReference type) - { - var genericInstance = type as IGenericInstance; - if (genericInstance == null) return null; - - var genericArguments = new List(); - foreach (var argument in genericInstance.GenericArguments) { - genericArguments.Add(CreateCodeTypeReference(argument)); - } - return genericArguments.ToArray(); - } - } - - static class CecilEx - { - public static IEnumerable GetMembers(this TypeDefinition type) - { - return type.Fields.Cast() - .Concat(type.Methods) - .Concat(type.Properties) - .Concat(type.Events); - } - } -} diff --git a/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj b/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj index d4d6d0cfae..9e61da3de6 100644 --- a/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj +++ b/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj @@ -14,9 +14,9 @@ - + - + From 4858fe5f1017ffabf72f6c452de38b133cda1786 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Fri, 7 Sep 2018 13:49:04 +1000 Subject: [PATCH 2/3] Made the approval files copy to output directory --- .../ReactiveUI.Fody.Tests.csproj | 6 ++++++ src/ReactiveUI.Tests/ReactiveUI.Tests.csproj | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj b/src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj index a2e29bb7aa..56a4a1cd7d 100644 --- a/src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj +++ b/src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj @@ -36,6 +36,12 @@ + + + + PreserveNewest + + - + diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.cs b/src/ReactiveUI.Tests/API/ApiApprovalTests.cs index 61f4e0ce3e..7c8f549ef8 100644 --- a/src/ReactiveUI.Tests/API/ApiApprovalTests.cs +++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.cs @@ -5,36 +5,34 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Linq; -using ApprovalTests; -using ApprovalTests.Reporters; using PublicApiGenerator; +using Shouldly; using Xunit; namespace ReactiveUI.Tests.API { [ExcludeFromCodeCoverage] - [UseReporter(typeof(DiffReporter))] public class ApiApprovalTests { [Fact] public void Blend() { var publicApi = Filter(ApiGenerator.GeneratePublicApi(typeof(Blend.ObservableTrigger).Assembly)); - Approvals.Verify(publicApi); + publicApi.ShouldMatchApproved(); } [Fact] public void Testing() { var publicApi = Filter(ApiGenerator.GeneratePublicApi(typeof(Testing.TestUtils).Assembly)); - Approvals.Verify(publicApi); + publicApi.ShouldMatchApproved(); } [Fact] public void ReactiveUI() { var publicApi = Filter(ApiGenerator.GeneratePublicApi(typeof(RxApp).Assembly)); - Approvals.Verify(publicApi); + publicApi.ShouldMatchApproved(); } [Fact] @@ -42,7 +40,7 @@ public void Winforms() { var publicApi = Filter(ApiGenerator.GeneratePublicApi(typeof(ReactiveUI.Winforms.WinformsCreatesObservableForProperty).Assembly)); - Approvals.Verify(publicApi); + publicApi.ShouldMatchApproved(); } private static string Filter(string text) diff --git a/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj b/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj index ae3e564900..396d40b292 100644 --- a/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj +++ b/src/ReactiveUI.Tests/ReactiveUI.Tests.csproj @@ -3,6 +3,7 @@ net461 false + full @@ -14,7 +15,7 @@ - + @@ -49,19 +50,4 @@ - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - -