Esempio n. 1
0
        static void PopulateGenericParameters(IGenericParameterProvider publicType, CodeTypeParameterCollection parameters, AttributeFilter attributeFilter, Func <GenericParameter, bool> shouldUseParameter)
        {
            foreach (var parameter in publicType.GenericParameters.Where(shouldUseParameter))
            {
                // 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
                var name = parameter.Name;
                if (parameter.IsCovariant)
                {
                    name = "out " + name;
                }
                if (parameter.IsContravariant)
                {
                    name = "in " + name;
                }

                var attributeCollection = new CodeAttributeDeclarationCollection();
                if (parameter.HasCustomAttributes)
                {
                    PopulateCustomAttributes(parameter, attributeCollection, attributeFilter);
                }

                var typeParameter = new CodeTypeParameter(name)
                {
                    HasConstructorConstraint =
                        parameter.HasDefaultConstructorConstraint && !parameter.HasNotNullableValueTypeConstraint
                };

                typeParameter.CustomAttributes.AddRange(attributeCollection.OfType <CodeAttributeDeclaration>().ToArray());

                var nullableConstraint  = parameter.GetNullabilityMap().First();
                var unmanagedConstraint = parameter.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.Runtime.CompilerServices.IsUnmanagedAttribute");

                if (parameter.HasNotNullableValueTypeConstraint)
                {
                    typeParameter.Constraints.Add(unmanagedConstraint ? " unmanaged" : " struct");
                }

                if (parameter.HasReferenceTypeConstraint)
                {
                    typeParameter.Constraints.Add(nullableConstraint == true ? " class?" : " class");
                }
                else if (nullableConstraint == false)
                {
                    typeParameter.Constraints.Add(" notnull");
                }

                using (NullableContext.Push(parameter))
                {
                    foreach (var constraint in parameter.Constraints.Where(constraint => !IsSpecialConstraint(constraint)))
                    {
                        // for generic constraints like IEnumerable<T> call to GetElementType() returns TypeReference with Name = !0
                        var typeReference = constraint.ConstraintType /*.GetElementType()*/.CreateCodeTypeReference(constraint);
                        typeParameter.Constraints.Add(typeReference);
                    }
                }
                parameters.Add(typeParameter);
            }

            bool IsSpecialConstraint(GenericParameterConstraint constraint)
            {
                // struct
                if (constraint.ConstraintType is TypeReference reference && reference.FullName == "System.ValueType")
                {
                    return(true);
                }

                // unmanaged
                if (constraint.ConstraintType.IsUnmanaged())
                {
                    return(true);
                }

                return(false);
            }
        }
Esempio n. 2
0
        static CodeTypeDeclaration CreateTypeDeclaration(TypeDefinition publicType, string[] whitelistedNamespacePrefixes, AttributeFilter attributeFilter)
        {
            if (publicType.IsDelegate())
            {
                return(CreateDelegateDeclaration(publicType, attributeFilter));
            }

            var            @static    = false;
            TypeAttributes attributes = 0;

            if (publicType.IsPublic || publicType.IsNestedPublic)
            {
                attributes |= TypeAttributes.Public;
            }
            if (publicType.IsNestedFamily || publicType.IsNestedFamilyOrAssembly)
            {
                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 isStruct = publicType.IsValueType && !publicType.IsPrimitive && !publicType.IsEnum;

            var @readonly = isStruct && publicType.CustomAttributes.Any(a =>
                                                                        a.AttributeType.FullName == "System.Runtime.CompilerServices.IsReadOnlyAttribute");

            var index = name.IndexOf('`');

            if (index != -1)
            {
                name = name.Substring(0, index);
            }

            var declarationName = string.Empty;

            if (@readonly)
            {
                declarationName += CodeNormalizer.ReadonlyMarker;
            }
            if (@static)
            {
                declarationName += CodeNormalizer.StaticMarker;
            }

            declarationName += name;

            var declaration = new CodeTypeDeclaration(declarationName)
            {
                CustomAttributes = CreateCustomAttributes(publicType, attributeFilter),
                // TypeAttributes must be specified before the IsXXX as they manipulate TypeAttributes!
                TypeAttributes = attributes,
                IsClass        = publicType.IsClass,
                IsEnum         = publicType.IsEnum,
                IsInterface    = publicType.IsInterface,
                IsStruct       = isStruct,
            };

            if (declaration.IsInterface && publicType.BaseType != null)
            {
                throw new NotImplementedException("Base types for interfaces needs testing");
            }

            PopulateGenericParameters(publicType, declaration.TypeParameters, attributeFilter, parameter =>
            {
                var declaringType = publicType.DeclaringType;

                while (declaringType != null)
                {
                    if (declaringType.GenericParameters.Any(p => p.Name == parameter.Name))
                    {
                        return(false); // https://github.com/ApiApprover/ApiApprover/issues/108
                    }
                    declaringType = declaringType.DeclaringType;
                }

                return(true);
            });

            if (publicType.BaseType != null && ShouldOutputBaseType(publicType))
            {
                if (publicType.BaseType.FullName == "System.Enum")
                {
                    var underlyingType = publicType.GetEnumUnderlyingType();
                    if (underlyingType.FullName != "System.Int32")
                    {
                        declaration.BaseTypes.Add(underlyingType.CreateCodeTypeReference());
                    }
                }
                else
                {
                    declaration.BaseTypes.Add(publicType.BaseType.CreateCodeTypeReference(publicType));
                }
            }
            foreach (var @interface in publicType.Interfaces.OrderBy(i => i.InterfaceType.FullName, StringComparer.Ordinal)
                     .Select(t => new { Reference = t, Definition = t.InterfaceType.Resolve() })
                     .Where(t => ShouldIncludeType(t.Definition))
                     .Select(t => t.Reference))
            {
                declaration.BaseTypes.Add(@interface.InterfaceType.CreateCodeTypeReference(@interface));
            }

            foreach (var memberInfo in publicType.GetMembers().Where(memberDefinition => ShouldIncludeMember(memberDefinition, whitelistedNamespacePrefixes)).OrderBy(m => m.Name, StringComparer.Ordinal))
            {
                AddMemberToTypeDeclaration(declaration, memberInfo, attributeFilter);
            }

            // Fields should be in defined order for an enum
            var fields = !publicType.IsEnum
                ? publicType.Fields.OrderBy(f => f.Name, StringComparer.Ordinal)
                : (IEnumerable <FieldDefinition>)publicType.Fields;

            foreach (var field in fields)
            {
                AddMemberToTypeDeclaration(declaration, field, attributeFilter);
            }

            foreach (var nestedType in publicType.NestedTypes.Where(ShouldIncludeType).OrderBy(t => t.FullName, StringComparer.Ordinal))
            {
                using (NullableContext.Push(nestedType))
                {
                    var nestedTypeDeclaration = CreateTypeDeclaration(nestedType, whitelistedNamespacePrefixes, attributeFilter);
                    declaration.Members.Add(nestedTypeDeclaration);
                }
            }

            return(declaration);
        }