private void GenerateAssemblyAttributes(IAssemblySymbol assembly, IProjectFileSystem fileSystem)
        {
            var assemblyAttributes = assembly.GetAttributes()
                                     .AddRange(PseudoCustomAttributeFacts.GenerateApiAttributes(assembly));

            if (options.RemoveAssemblySigningAttributes)
            {
                assemblyAttributes = assemblyAttributes.RemoveAll(a =>
                                                                  a.AttributeClass?.Name is
                                                                  "AssemblyDelaySignAttribute"
                                                                  or "AssemblyKeyFileAttribute"
                                                                  or "AssemblyKeyNameAttribute"
                                                                  or "AssemblySignatureKeyAttribute" &&
                                                                  a.AttributeClass.ContainingNamespace.HasFullName("System", "Reflection"));
            }

            GenerateAttributesFile(fileSystem, "Properties/AssemblyInfo.cs", assemblyAttributes, "assembly", initialLines: ImmutableArray.Create(
                                       "[assembly: System.Runtime.CompilerServices.ReferenceAssembly]",
                                       $"[assembly: System.Reflection.AssemblyVersion(\"{assembly.Identity.Version}\")]"));

            if (!MetadataFacts.CanAccessType(assembly, "System.Runtime.CompilerServices.ReferenceAssemblyAttribute"))
            {
                fileSystem.WriteAllLines(
                    "System/Runtime/CompilerServices/ReferenceAssemblyAttribute.cs",
                    "namespace System.Runtime.CompilerServices",
                    "{",
                    "    internal sealed class ReferenceAssemblyAttribute : Attribute { }",
                    "}");
            }
        }
Example #2
0
        public static IEnumerable <AttributeData> GenerateApiAttributes(IMethodSymbol method)
        {
            var(options, codeType) = MetadataFacts.GetImplementationAttributes(method);
            if (options == 0 & codeType == 0)
            {
                yield break;
            }

            var attributeClass = MetadataFacts.GetFirstTypeAccessibleToAssembly(
                method.ContainingAssembly,
                "System.Runtime.CompilerServices.MethodImplAttribute");

            if (attributeClass is null)
            {
                yield break;
            }

            var attributeConstructor = attributeClass.InstanceConstructors.FirstOrDefault(c =>
                                                                                          c.Parameters.Length == 1 &&
                                                                                          c.Parameters[0].Type is { TypeKind: TypeKind.Enum } type &&
                                                                                          type.HasFullName("System", "Runtime", "CompilerServices", "MethodImplOptions"));

            if (attributeConstructor is null)
            {
                yield break;
            }

            var codeTypeEnum = MetadataFacts.GetFirstTypeAccessibleToAssembly(
                method.ContainingAssembly,
                "System.Runtime.CompilerServices.MethodCodeType");

            if (codeTypeEnum is null)
            {
                yield break;
            }

            var constructorArguments = ImmutableArray.Create(
                InternalAccessUtils.CreateTypedConstant(attributeConstructor.Parameters.Single().Type, TypedConstantKind.Enum, (int)options));

            var namedArguments = codeType == 0
                ? ImmutableArray <KeyValuePair <string, TypedConstant> > .Empty
                : ImmutableArray.Create(KeyValuePair.Create(
                                            nameof(MethodImplAttribute.MethodCodeType),
                                            InternalAccessUtils.CreateTypedConstant(codeTypeEnum, TypedConstantKind.Enum, (int)codeType)));

            yield return(new SynthesizedAttributeData(attributeClass, attributeConstructor, constructorArguments, namedArguments));
        }
        private static void WriteAttributes(IEnumerable <AttributeData> attributes, string?target, GenerationContext context, bool onlyWriteAttributeUsageAttribute = false)
        {
            foreach (var attribute in attributes.OrderBy(a => a.AttributeClass, NamespaceOrTypeFullNameComparer.Instance))
            {
                if (onlyWriteAttributeUsageAttribute && !MetadataFacts.IsAttributeUsageAttribute(attribute.AttributeClass))
                {
                    continue;
                }

                var buffer          = new StringWriter();
                var bufferedWriter  = new IndentedTextWriter(buffer);
                var bufferedContext = context.WithWriter(bufferedWriter);

                bufferedContext.Writer.Write('[');

                if (target is not null)
                {
                    bufferedContext.Writer.Write(target);
                    bufferedContext.Writer.Write(": ");
                }

                bufferedContext.WriteTypeReference(attribute.AttributeClass !, asAttribute: true);

                if (attribute.ConstructorArguments.Any() || attribute.NamedArguments.Any())
                {
                    bufferedContext.Writer.Write('(');

                    for (var i = 0; i < attribute.ConstructorArguments.Length; i++)
                    {
                        if (i != 0)
                        {
                            bufferedContext.Writer.Write(", ");
                        }

                        var value = attribute.ConstructorArguments[i];

                        if (value.Kind == TypedConstantKind.Primitive &&
                            value.Value is 0 or(short) 0 or(ushort) 0 or(byte) 0 or(sbyte) 0 &&
                            attribute.AttributeClass !.InstanceConstructors.Any(c =>
                                                                                c.Parameters.ElementAtOrDefault(i) is { } p &&
                                                                                CanImplicitlyConvertFromZeroLiteralSyntax(p.Type) &&
                                                                                !SymbolEqualityComparer.Default.Equals(p.Type, value.Type)))
                        {
                            bufferedContext.Writer.Write('(');
                            bufferedContext.WriteTypeReference(value.Type);
                            bufferedContext.Writer.Write(')');
                        }

                        bufferedContext.WriteTypedConstant(value);
                    }

                    var isFirst = attribute.ConstructorArguments.IsEmpty;

                    foreach (var(name, value) in attribute.NamedArguments)
                    {
                        if (isFirst)
                        {
                            isFirst = false;
                        }
                        else
                        {
                            bufferedContext.Writer.Write(", ");
                        }

                        bufferedContext.WriteIdentifier(name);
                        bufferedContext.Writer.Write(" = ");
                        bufferedContext.WriteTypedConstant(value);
                    }

                    bufferedContext.Writer.Write(')');
                }

                bufferedContext.Writer.WriteLine(']');

                var bufferedText = buffer.ToString();
                if (bufferedText.Contains(GenerationContext.ErrorText))
                {
                    context.WriteComment(bufferedText);
                }
                else
                {
                    context.Writer.Write(bufferedText);
                }
            }
        }
Example #4
0
        private void GenerateType(INamedTypeSymbol type, TypeDeclarationReason reason, TypeDeclarationAnalysis typeDeclarationAnalysis, IProjectFileSystem fileSystem)
        {
            using var textWriter = fileSystem.CreateText(GetPathForType(type));
            using var writer     = new IndentedTextWriter(textWriter);

            var context = new GenerationContext(writer, type.ContainingNamespace);

            if (!type.ContainingNamespace.IsGlobalNamespace)
            {
                writer.Write("namespace ");
                context.WriteNamespace(type.ContainingNamespace);
                writer.WriteLine();
                writer.WriteLine('{');
                writer.Indent++;
            }

            var containingTypes = MetadataFacts.GetContainingTypes(type);

            foreach (var containingType in containingTypes)
            {
                WriteContainerTypeHeader(containingType, declareAsPartial: true, context);
                writer.WriteLine();
                writer.WriteLine('{');
                writer.Indent++;
            }

            var filteredAttributes = type.GetAttributes()
                                     .AddRange(PseudoCustomAttributeFacts.GenerateApiAttributes(type))
                                     .Where(a => a.AttributeClass?.HasFullName("System", "Reflection", "DefaultMemberAttribute") != true);

            if ((reason & (TypeDeclarationReason.ExternallyVisible | TypeDeclarationReason.DeclaresUsedAttribute)) != 0)
            {
                WriteAttributes(
                    filteredAttributes,
                    target: null,
                    context,
                    onlyWriteAttributeUsageAttribute: (reason & TypeDeclarationReason.ExternallyVisible) == 0);
            }

            WriteAccessibility(type.DeclaredAccessibility, reason, writer);

            var declareAsPartial = type.GetTypeMembers().Any(typeDeclarationAnalysis.ReasonsByType.ContainsKey);

            if (type.TypeKind == TypeKind.Delegate)
            {
                GenerateDelegate(type, context);
            }
            else if (type.TypeKind == TypeKind.Enum)
            {
                if (declareAsPartial)
                {
                    writer.Write("partial ");
                }
                GenerateEnum(type, context);
            }
            else
            {
                if (type.TypeKind == TypeKind.Class)
                {
                    if (type.IsAbstract && type.IsSealed)
                    {
                        writer.Write("static ");
                    }

                    if (MetadataFacts.HidesBaseMember(type, typeDeclarationAnalysis))
                    {
                        writer.Write("new ");
                    }

                    if (type.IsSealed)
                    {
                        writer.Write("sealed ");
                    }
                    else if (type.IsAbstract)
                    {
                        writer.Write("abstract ");
                    }
                }

                WriteContainerTypeHeader(type, declareAsPartial, context);

                var generatedBaseType = type.BaseType;

                if (reason.HasFlag(TypeDeclarationReason.ExternallyVisible))
                {
                    var baseTypes = new List <INamedTypeSymbol>();

                    if (type.BaseType is { SpecialType : not(SpecialType.System_Object or SpecialType.System_ValueType) })