/// <summary>
        /// Verify if the attribute type can be applied to given owner symbol.
        /// Generate a diagnostic if it cannot be applied
        /// </summary>
        /// <param name="ownerSymbol">Symbol on which the attribute is applied</param>
        /// <param name="attributeType">Attribute class for the attribute</param>
        /// <param name="node">Syntax node for attribute specification</param>
        /// <param name="attributeLocation">Attribute target specifier location</param>
        /// <param name="diagnostics">Diagnostics</param>
        /// <returns>Whether attribute specification is allowed for the given symbol</returns>
        internal bool VerifyAttributeUsageTarget(Symbol ownerSymbol, NamedTypeSymbol attributeType, AttributeSyntax node, AttributeLocation attributeLocation, DiagnosticBag diagnostics)
        {
            var attributeUsageInfo = attributeType.AttributeUsageInfo(Compilation);
            if (attributeUsageInfo != null)
            {
                AttributeTargets attributeTarget;
                if (attributeLocation == AttributeLocation.Return)
                {
                    // attribute on return type
                    attributeTarget = AttributeTargets.ReturnValue;
                }
                else
                {
                    attributeTarget = ownerSymbol.GetAttributeTarget();
                }
                
                if ((attributeTarget & attributeUsageInfo.ValidTargets) != 0)
                {
                    return true;
                }

                // generate error
                Error(diagnostics, ErrorCode.ERR_AttributeOnBadSymbolType, node, GetAttributeNameFromSyntax(node), attributeUsageInfo.GetValidTargetsString());
            }

            return false;
        }
        public void Join_LocalAttributeToRelatedAttribute_MatchesExpected()
        {
            var definitionProvider = new DataAnnotationsDefinitionProvider();
            var actual             = new EntityRelation(EntityRelationType.InnerJoin);

            actual.Join <ChildRaisedRow>(row => row.ComplexEntityId, row => row.ComplexEntity.ComplexEntityId);

            var childDefinition = definitionProvider.Resolve <ChildRaisedRow>();
            var childReference  = new EntityReference {
                EntityType = typeof(ChildRaisedRow)
            };
            var childLocation           = definitionProvider.GetEntityLocation(childReference);
            var childAttributeLocation  = new AttributeLocation(typeof(ChildRaisedRow).GetProperty("ComplexEntityId"), childReference);
            var childComplexIdAttribute = childDefinition.Find(childAttributeLocation);

            Assert.AreEqual(childLocation, childDefinition.Find(actual.SourceExpression).Entity);
            Assert.AreEqual(childComplexIdAttribute, childDefinition.Find(actual.SourceExpression)); //// actual.SourceAttribute);

            var complexDefinition = definitionProvider.Resolve <ComplexRaisedRow>();
            var complexReference  = new EntityReference {
                EntityType = typeof(ComplexRaisedRow)
            };
            var complexLocation          = definitionProvider.GetEntityLocation(complexReference);
            var complexAttributeLocation = new AttributeLocation(typeof(ComplexRaisedRow).GetProperty("ComplexEntityId"), complexReference);
            var complexIdAttribute       = complexDefinition.Find(complexAttributeLocation);

            Assert.AreEqual(complexLocation, complexDefinition.Find(actual.RelationExpression).Entity); //// actual.RelationLocation);
            Assert.AreEqual(complexIdAttribute, complexDefinition.Find(actual.RelationExpression));
        }
        public void Join_ExplicitSourceAndRelationTypes_EntityRelationMatchesExpected()
        {
            var definitionProvider = new DataAnnotationsDefinitionProvider();
            var actual             = new EntityRelation(EntityRelationType.InnerJoin);

            actual.Join <FakeRelatedRow, DependencyRow>(row => row.RelatedId, row => row.FakeDependencyEntityId);

            var relatedDefinition = definitionProvider.Resolve <FakeRelatedRow>();
            var leftDefinition    = relatedDefinition;
            var leftReference     = new EntityReference {
                EntityType = typeof(FakeRelatedRow)
            };
            var leftLocation          = definitionProvider.GetEntityLocation(leftReference);
            var leftAttributeLocation = new AttributeLocation(typeof(FakeRelatedRow).GetProperty(nameof(FakeRelatedRow.RelatedId)), leftReference);
            var leftAttribute         = leftDefinition.Find(leftAttributeLocation);

            Assert.AreEqual(leftLocation, relatedDefinition.Find(actual.SourceExpression).Entity);
            Assert.AreEqual(leftAttribute, relatedDefinition.Find(actual.SourceExpression));

            var rightDefinition = definitionProvider.Resolve <DependencyRow>();
            var rightReference  = new EntityReference {
                EntityType = typeof(DependencyRow)
            };
            var rightLocation          = definitionProvider.GetEntityLocation(rightReference);
            var rightAttributeLocation = new AttributeLocation(typeof(DependencyRow).GetProperty(nameof(DependencyRow.FakeDependencyEntityId)), rightReference);
            var rightAttribute         = rightDefinition.Find(rightAttributeLocation);

            Assert.AreEqual(rightLocation, rightDefinition.Find(actual.RelationExpression).Entity);
            Assert.AreEqual(rightAttribute, rightDefinition.Find(actual.RelationExpression));
        }
Example #4
0
        /// <summary>
        /// Validate attribute usage target and duplicate attributes.
        /// </summary>
        /// <param name="attribute">Bound attribute</param>
        /// <param name="node">Syntax node for attribute specification</param>
        /// <param name="compilation">Compilation</param>
        /// <param name="symbolPart">Symbol part to which the attribute has been applied.</param>
        /// <param name="diagnostics">Diagnostics</param>
        /// <param name="uniqueAttributeTypes">Set of unique attribute types applied to the symbol</param>
        private bool ValidateAttributeUsage(
            CSharpAttributeData attribute,
            AttributeSyntax node,
            CSharpCompilation compilation,
            AttributeLocation symbolPart,
            DiagnosticBag diagnostics,
            HashSet <NamedTypeSymbol> uniqueAttributeTypes)
        {
            Debug.Assert(!attribute.HasErrors);

            NamedTypeSymbol    attributeType      = attribute.AttributeClass;
            AttributeUsageInfo attributeUsageInfo = attributeType.GetAttributeUsageInfo();

            // Given attribute can't be specified more than once if AllowMultiple is false.
            if (!uniqueAttributeTypes.Add(attributeType) && !attributeUsageInfo.AllowMultiple)
            {
                diagnostics.Add(ErrorCode.ERR_DuplicateAttribute, node.Name.Location, node.GetErrorDisplayName());
                return(false);
            }

            // Verify if the attribute type can be applied to given owner symbol.
            StarkAttributeTargets attributeTarget;

            if (symbolPart == AttributeLocation.Return)
            {
                // attribute on return type
                Debug.Assert(this.Kind == SymbolKind.Method);
                attributeTarget = StarkAttributeTargets.ReturnValue;
            }
            else
            {
                attributeTarget = this.GetAttributeTarget();
            }

            if ((attributeTarget & attributeUsageInfo.ValidTargets) == 0)
            {
                // generate error
                diagnostics.Add(ErrorCode.ERR_AttributeOnBadSymbolType, node.Name.Location, node.GetErrorDisplayName(), attributeUsageInfo.GetValidTargetsErrorArgument());
                return(false);
            }

            if (attribute.IsSecurityAttribute(compilation))
            {
                switch (this.Kind)
                {
                case SymbolKind.Assembly:
                case SymbolKind.NamedType:
                case SymbolKind.Method:
                    break;

                default:
                    // CS7070: Security attribute '{0}' is not valid on this declaration type. Security attributes are only valid on assembly, type and method declarations.
                    diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidTarget, node.Name.Location, node.GetErrorDisplayName());
                    return(false);
                }
            }

            return(true);
        }
Example #5
0
 internal virtual void PostDecodeWellKnownAttributes(
     ImmutableArray <CSharpAttributeData> boundAttributes,
     ImmutableArray <AttributeSyntax> allAttributeSyntaxNodes,
     BindingDiagnosticBag diagnostics,
     AttributeLocation symbolPart,
     WellKnownAttributeData decodedData
     )
 {
 }
Example #6
0
        private WellKnownAttributeData ValidateAttributeUsageAndDecodeWellKnownAttributes(
            ImmutableArray <Binder> binders,
            ImmutableArray <AttributeSyntax> attributeSyntaxList,
            ImmutableArray <CSharpAttributeData> boundAttributes,
            BindingDiagnosticBag diagnostics,
            AttributeLocation symbolPart
            )
        {
            Debug.Assert(binders.Any());
            Debug.Assert(attributeSyntaxList.Any());
            Debug.Assert(boundAttributes.Any());
            Debug.Assert(binders.Length == boundAttributes.Length);
            Debug.Assert(attributeSyntaxList.Length == boundAttributes.Length);

            int totalAttributesCount = boundAttributes.Length;
            HashSet <NamedTypeSymbol> uniqueAttributeTypes = new HashSet <NamedTypeSymbol>();
            var arguments =
                new DecodeWellKnownAttributeArguments <
                    AttributeSyntax,
                    CSharpAttributeData,
                    AttributeLocation
                    >();

            arguments.Diagnostics     = diagnostics;
            arguments.AttributesCount = totalAttributesCount;
            arguments.SymbolPart      = symbolPart;

            for (int i = 0; i < totalAttributesCount; i++)
            {
                CSharpAttributeData boundAttribute  = boundAttributes[i];
                AttributeSyntax     attributeSyntax = attributeSyntaxList[i];
                Binder binder = binders[i];

                // Decode attribute as a possible well-known attribute only if it has no binding errors and has valid AttributeUsage.
                if (
                    !boundAttribute.HasErrors &&
                    ValidateAttributeUsage(
                        boundAttribute,
                        attributeSyntax,
                        binder.Compilation,
                        symbolPart,
                        diagnostics,
                        uniqueAttributeTypes
                        )
                    )
                {
                    arguments.Attribute          = boundAttribute;
                    arguments.AttributeSyntaxOpt = attributeSyntax;
                    arguments.Index = i;

                    this.DecodeWellKnownAttribute(ref arguments);
                }
            }

            return(arguments.HasDecodedData ? arguments.DecodedData : null);
        }
Example #7
0
        internal EarlyWellKnownAttributeData EarlyDecodeWellKnownAttributes(
            ImmutableArray <Binder> binders,
            ImmutableArray <NamedTypeSymbol> boundAttributeTypes,
            ImmutableArray <AttributeSyntax> attributesToBind,
            AttributeLocation symbolPart,
            CSharpAttributeData[] boundAttributesBuilder
            )
        {
            Debug.Assert(boundAttributeTypes.Any());
            Debug.Assert(attributesToBind.Any());
            Debug.Assert(binders.Any());
            Debug.Assert(boundAttributesBuilder != null);
            Debug.Assert(!boundAttributesBuilder.Contains((attr) => attr != null));

            var earlyBinder = new EarlyWellKnownAttributeBinder(binders[0]);
            var arguments   =
                new EarlyDecodeWellKnownAttributeArguments <
                    EarlyWellKnownAttributeBinder,
                    NamedTypeSymbol,
                    AttributeSyntax,
                    AttributeLocation
                    >();

            arguments.SymbolPart = symbolPart;

            for (int i = 0; i < boundAttributeTypes.Length; i++)
            {
                NamedTypeSymbol boundAttributeType = boundAttributeTypes[i];
                if (!boundAttributeType.IsErrorType())
                {
                    if (binders[i] != earlyBinder.Next)
                    {
                        earlyBinder = new EarlyWellKnownAttributeBinder(binders[i]);
                    }

                    arguments.Binder          = earlyBinder;
                    arguments.AttributeType   = boundAttributeType;
                    arguments.AttributeSyntax = attributesToBind[i];

                    // Early bind some well-known attributes
                    CSharpAttributeData earlyBoundAttributeOpt = this.EarlyDecodeWellKnownAttribute(
                        ref arguments
                        );
                    Debug.Assert(
                        earlyBoundAttributeOpt == null || !earlyBoundAttributeOpt.HasErrors
                        );

                    boundAttributesBuilder[i] = earlyBoundAttributeOpt;
                }
            }

            return(arguments.HasDecodedData ? arguments.DecodedData : null);
        }
Example #8
0
        public void AttributeLocation_ConstructWithLambda_MatchesExpected()
        {
            Expression <Func <Document, object> > expr = document => document.Identifier;
            var expected = new AttributeLocation(
                expr.GetProperty(),
                new EntityReference
            {
                EntityType = typeof(Document)
            });
            var actual = new AttributeLocation(expr);

            Assert.AreEqual(expected, actual, string.Join(Environment.NewLine, expected.GetDifferences(actual)));
        }
        internal override void PostDecodeWellKnownAttributes(
            ImmutableArray <CSharpAttributeData> boundAttributes,
            ImmutableArray <AttributeSyntax> allAttributeSyntaxNodes,
            BindingDiagnosticBag diagnostics,
            AttributeLocation symbolPart,
            WellKnownAttributeData decodedData
            )
        {
            base.PostDecodeWellKnownAttributes(
                boundAttributes,
                allAttributeSyntaxNodes,
                diagnostics,
                symbolPart,
                decodedData
                );

            if (!allAttributeSyntaxNodes.IsEmpty && _property.IsAutoPropertyWithGetAccessor)
            {
                CheckForFieldTargetedAttribute(diagnostics);
            }
        }
Example #10
0
        internal override void PostDecodeWellKnownAttributes(ImmutableArray <CSharpAttributeData> boundAttributes, ImmutableArray <AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
        {
            Debug.Assert(!boundAttributes.IsDefault);
            Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
            Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length);
            Debug.Assert(this.lazyCustomAttributesBag != null);
            Debug.Assert(this.lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed);
            Debug.Assert(symbolPart == AttributeLocation.None);

            var data        = (CommonFieldWellKnownAttributeData)decodedData;
            int?fieldOffset = data != null ? data.Offset : null;

            if (fieldOffset.HasValue)
            {
                if (this.ContainingType.Layout.Kind != LayoutKind.Explicit)
                {
                    Debug.Assert(boundAttributes.Any());

                    // error CS0636: The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit)
                    int i = boundAttributes.IndexOfAttribute(this, AttributeDescription.FieldOffsetAttribute);
                    diagnostics.Add(ErrorCode.ERR_StructOffsetOnBadStruct, allAttributeSyntaxNodes[i].Name.Location);
                }
            }
            else if (!this.IsStatic && !this.IsConst)
            {
                if (this.ContainingType.Layout.Kind == LayoutKind.Explicit)
                {
                    // error CS0625: '<field>': instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute
                    diagnostics.Add(ErrorCode.ERR_MissingStructOffset, this.ErrorLocation, this);
                }
            }

            base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData);
        }
Example #11
0
        internal override void PostDecodeWellKnownAttributes(ImmutableArray <CSharpAttributeData> boundAttributes, ImmutableArray <AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
        {
            Debug.Assert(!boundAttributes.IsDefault);
            Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
            Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length);
            Debug.Assert(this.lazyCustomAttributesBag != null);
            Debug.Assert(this.lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed);
            Debug.Assert(symbolPart == AttributeLocation.None);

            var data = (TypeWellKnownAttributeData)decodedData;

            if (this.IsComImport)
            {
                Debug.Assert(boundAttributes.Any());

                // Symbol with ComImportAttribute must have a GuidAttribute
                if (data == null || data.GuidString == null)
                {
                    int index = boundAttributes.IndexOfAttribute(this, AttributeDescription.ComImportAttribute);
                    diagnostics.Add(ErrorCode.ERR_ComImportWithoutUuidAttribute, allAttributeSyntaxNodes[index].Name.Location, this.Name);
                }

                if (this.TypeKind == TypeKind.Class)
                {
                    var baseType = this.BaseTypeNoUseSiteDiagnostics;
                    if ((object)baseType != null && baseType.SpecialType != SpecialType.System_Object)
                    {
                        // CS0424: '{0}': a class with the ComImport attribute cannot specify a base class
                        diagnostics.Add(ErrorCode.ERR_ComImportWithBase, this.Locations[0], this.Name);
                    }

                    var initializers = this.StaticInitializers;
                    if (!initializers.IsDefaultOrEmpty)
                    {
                        foreach (var initializerGroup in initializers)
                        {
                            foreach (var singleInitializer in initializerGroup)
                            {
                                if (!singleInitializer.FieldOpt.IsMetadataConstant)
                                {
                                    // CS8028: '{0}': a class with the ComImport attribute cannot specify field initializers.
                                    diagnostics.Add(ErrorCode.ERR_ComImportWithInitializers, singleInitializer.Syntax.GetLocation(), this.Name);
                                }
                            }
                        }
                    }

                    initializers = this.InstanceInitializers;
                    if (!initializers.IsDefaultOrEmpty)
                    {
                        foreach (var initializerGroup in initializers)
                        {
                            foreach (var singleInitializer in initializerGroup)
                            {
                                // CS8028: '{0}': a class with the ComImport attribute cannot specify field initializers.
                                diagnostics.Add(ErrorCode.ERR_ComImportWithInitializers, singleInitializer.Syntax.GetLocation(), this.Name);
                            }
                        }
                    }
                }
            }
            else if ((object)this.ComImportCoClass != null)
            {
                Debug.Assert(boundAttributes.Any());

                // Symbol with CoClassAttribute must have a ComImportAttribute
                int index = boundAttributes.IndexOfAttribute(this, AttributeDescription.CoClassAttribute);
                diagnostics.Add(ErrorCode.WRN_CoClassWithoutComImport, allAttributeSyntaxNodes[index].Location, this.Name);
            }

            // Report ERR_DefaultMemberOnIndexedType if type has a default member attribute and has indexers.
            if (data != null && data.HasDefaultMemberAttribute && this.Indexers.Any())
            {
                Debug.Assert(boundAttributes.Any());

                int index = boundAttributes.IndexOfAttribute(this, AttributeDescription.DefaultMemberAttribute);
                diagnostics.Add(ErrorCode.ERR_DefaultMemberOnIndexedType, allAttributeSyntaxNodes[index].Name.Location);
            }

            base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData);
        }
        internal override void PostDecodeWellKnownAttributes(ImmutableArray <CSharpAttributeData> boundAttributes, ImmutableArray <AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
        {
            Debug.Assert(!boundAttributes.IsDefault);
            Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
            Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length);
            Debug.Assert(this.lazyCustomAttributesBag != null);
            Debug.Assert(this.lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed);
            Debug.Assert(symbolPart == AttributeLocation.None);

            var data = (CommonParameterWellKnownAttributeData)decodedData;

            if (data != null)
            {
                if (this.RefKind == RefKind.Ref && data.HasOutAttribute && !data.HasInAttribute)
                {
                    // error CS0662: '...' cannot specify only Out attribute on a ref parameter. Use both In and Out attributes, or neither.
                    diagnostics.Add(ErrorCode.ERR_OutAttrOnRefParam, this.Locations[0]);
                }
            }

            base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData);
        }
Example #13
0
        private ImmutableArray <AttributeSyntax> GetAttributesToBind(
            OneOrMany <SyntaxList <AttributeListSyntax> > attributeDeclarationSyntaxLists,
            AttributeLocation symbolPart,
            BindingDiagnosticBag diagnostics,
            CSharpCompilation compilation,
            Func <AttributeSyntax, bool> attributeMatchesOpt,
            Binder rootBinderOpt,
            out ImmutableArray <Binder> binders)
        {
            var attributeTarget = (IAttributeTargetSymbol)this;

            ArrayBuilder <AttributeSyntax> syntaxBuilder  = null;
            ArrayBuilder <Binder>          bindersBuilder = null;
            int attributesToBindCount = 0;

            for (int listIndex = 0; listIndex < attributeDeclarationSyntaxLists.Count; listIndex++)
            {
                var attributeDeclarationSyntaxList = attributeDeclarationSyntaxLists[listIndex];
                if (attributeDeclarationSyntaxList.Any())
                {
                    int prevCount = attributesToBindCount;
                    foreach (var attributeDeclarationSyntax in attributeDeclarationSyntaxList)
                    {
                        // We bind the attribute only if it has a matching target for the given ownerSymbol and attributeLocation.
                        if (MatchAttributeTarget(attributeTarget, symbolPart, attributeDeclarationSyntax.Target, diagnostics))
                        {
                            if (syntaxBuilder == null)
                            {
                                syntaxBuilder  = new ArrayBuilder <AttributeSyntax>();
                                bindersBuilder = new ArrayBuilder <Binder>();
                            }

                            var attributesToBind = attributeDeclarationSyntax.Attributes;
                            if (attributeMatchesOpt is null)
                            {
                                syntaxBuilder.AddRange(attributesToBind);
                                attributesToBindCount += attributesToBind.Count;
                            }
                            else
                            {
                                foreach (var attribute in attributesToBind)
                                {
                                    if (attributeMatchesOpt(attribute))
                                    {
                                        syntaxBuilder.Add(attribute);
                                        attributesToBindCount++;
                                    }
                                }
                            }
                        }
                    }

                    if (attributesToBindCount != prevCount)
                    {
                        Debug.Assert(attributeDeclarationSyntaxList.Node != null);
                        Debug.Assert(bindersBuilder != null);

                        var syntaxTree = attributeDeclarationSyntaxList.Node.SyntaxTree;
                        var binder     = rootBinderOpt ?? compilation.GetBinderFactory(syntaxTree).GetBinder(attributeDeclarationSyntaxList.Node);

                        binder = new ContextualAttributeBinder(binder, this);
                        Debug.Assert(!binder.InAttributeArgument || this is MethodSymbol {
                            MethodKind: MethodKind.LambdaMethod
                        }, "Possible cycle in attribute binding");
        internal override void PostDecodeWellKnownAttributes(ImmutableArray<CSharpAttributeData> boundAttributes, ImmutableArray<AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
        {
            Debug.Assert(!boundAttributes.IsDefault);
            Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
            Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length);
            Debug.Assert(_lazyCustomAttributesBag != null);
            Debug.Assert(_lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed);
            Debug.Assert(symbolPart == AttributeLocation.None);

            var data = (TypeWellKnownAttributeData)decodedData;

            if (this.IsComImport)
            {
                Debug.Assert(boundAttributes.Any());

                // Symbol with ComImportAttribute must have a GuidAttribute
                if (data == null || data.GuidString == null)
                {
                    int index = boundAttributes.IndexOfAttribute(this, AttributeDescription.ComImportAttribute);
                    diagnostics.Add(ErrorCode.ERR_ComImportWithoutUuidAttribute, allAttributeSyntaxNodes[index].Name.Location, this.Name);
                }

                if (this.TypeKind == TypeKind.Class)
                {
                    var baseType = this.BaseTypeNoUseSiteDiagnostics;
                    if ((object)baseType != null && baseType.SpecialType != SpecialType.System_Object)
                    {
                        // CS0424: '{0}': a class with the ComImport attribute cannot specify a base class
                        diagnostics.Add(ErrorCode.ERR_ComImportWithBase, this.Locations[0], this.Name);
                    }

                    var initializers = this.StaticInitializers;
                    if (!initializers.IsDefaultOrEmpty)
                    {
                        foreach (var initializerGroup in initializers)
                        {
                            foreach (var singleInitializer in initializerGroup)
                            {
                                if (!singleInitializer.FieldOpt.IsMetadataConstant)
                                {
                                    // CS8028: '{0}': a class with the ComImport attribute cannot specify field initializers.
                                    diagnostics.Add(ErrorCode.ERR_ComImportWithInitializers, singleInitializer.Syntax.GetLocation(), this.Name);
                                }
                            }
                        }
                    }

                    initializers = this.InstanceInitializers;
                    if (!initializers.IsDefaultOrEmpty)
                    {
                        foreach (var initializerGroup in initializers)
                        {
                            foreach (var singleInitializer in initializerGroup)
                            {
                                // CS8028: '{0}': a class with the ComImport attribute cannot specify field initializers.
                                diagnostics.Add(ErrorCode.ERR_ComImportWithInitializers, singleInitializer.Syntax.GetLocation(), this.Name);
                            }
                        }
                    }
                }
            }
            else if ((object)this.ComImportCoClass != null)
            {
                Debug.Assert(boundAttributes.Any());

                // Symbol with CoClassAttribute must have a ComImportAttribute
                int index = boundAttributes.IndexOfAttribute(this, AttributeDescription.CoClassAttribute);
                diagnostics.Add(ErrorCode.WRN_CoClassWithoutComImport, allAttributeSyntaxNodes[index].Location, this.Name);
            }

            // Report ERR_DefaultMemberOnIndexedType if type has a default member attribute and has indexers.
            if (data != null && data.HasDefaultMemberAttribute && this.Indexers.Any())
            {
                Debug.Assert(boundAttributes.Any());

                int index = boundAttributes.IndexOfAttribute(this, AttributeDescription.DefaultMemberAttribute);
                diagnostics.Add(ErrorCode.ERR_DefaultMemberOnIndexedType, allAttributeSyntaxNodes[index].Name.Location);
            }

            base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData);
        }
Example #15
0
        /// <summary>
        /// Method to merge attributes from the given attributesSyntaxLists and filter out attributes by attribute target.
        /// This is the first step in attribute binding.
        /// </summary>
        /// <remarks>
        /// This method can generate diagnostics for few cases where we have an invalid target specifier and the parser hasn't generated the necessary diagnostics.
        /// It should not perform any bind operations as it can lead to an attribute binding cycle.
        /// </remarks>
        private ImmutableArray <AttributeSyntax> GetAttributesToBind(
            OneOrMany <SyntaxList <AttributeSyntax> > attributeDeclarationSyntaxLists,
            AttributeLocation symbolPart,
            DiagnosticBag diagnostics,
            CSharpCompilation compilation,
            Func <AttributeSyntax, bool> attributeMatchesOpt,
            Binder rootBinderOpt,
            out ImmutableArray <Binder> binders,
            Func <Binder, Binder> contextualBinder = null)
        {
            var attributeTarget = (IAttributeTargetSymbol)this;

            ArrayBuilder <AttributeSyntax> syntaxBuilder  = null;
            ArrayBuilder <Binder>          bindersBuilder = null;
            int attributesToBindCount = 0;

            for (int listIndex = 0; listIndex < attributeDeclarationSyntaxLists.Count; listIndex++)
            {
                var attributeDeclarationSyntaxList = attributeDeclarationSyntaxLists[listIndex];
                if (attributeDeclarationSyntaxList.Any())
                {
                    int prevCount = attributesToBindCount;
                    foreach (var attribute in attributeDeclarationSyntaxList)
                    {
                        // We bind the attribute only if it has a matching target for the given ownerSymbol and attributeLocation.
                        if (MatchAttributeTarget(attributeTarget, symbolPart, attribute.Target, diagnostics))
                        {
                            if (syntaxBuilder == null)
                            {
                                syntaxBuilder  = new ArrayBuilder <AttributeSyntax>();
                                bindersBuilder = new ArrayBuilder <Binder>();
                            }

                            if (attributeMatchesOpt is null || attributeMatchesOpt(attribute))
                            {
                                syntaxBuilder.Add(attribute);
                                attributesToBindCount++;
                            }
                        }
                    }

                    if (attributesToBindCount != prevCount)
                    {
                        Debug.Assert(attributeDeclarationSyntaxList.Node != null);
                        Debug.Assert(bindersBuilder != null);

                        var syntaxTree = attributeDeclarationSyntaxList.Node.SyntaxTree;
                        var binder     = rootBinderOpt ?? compilation.GetBinderFactory(syntaxTree).GetBinder(attributeDeclarationSyntaxList.Node);

                        // We are wrapping the binder with a contextual binder
                        if (contextualBinder != null)
                        {
                            binder = contextualBinder(binder);
                        }

                        binder = new ContextualAttributeBinder(binder, this);
                        Debug.Assert(!binder.InAttributeArgument, "Possible cycle in attribute binding");

                        for (int i = 0; i < attributesToBindCount - prevCount; i++)
                        {
                            bindersBuilder.Add(binder);
                        }
                    }
                }
            }

            if (syntaxBuilder != null)
            {
                binders = bindersBuilder.ToImmutableAndFree();
                return(syntaxBuilder.ToImmutableAndFree());
            }
            else
            {
                binders = ImmutableArray <Binder> .Empty;
                return(ImmutableArray <AttributeSyntax> .Empty);
            }
        }
        /// <summary>
        /// Verify if the attribute type can be applied to given owner symbol.
        /// Generate a diagnostic if it cannot be applied
        /// </summary>
        /// <param name="ownerSymbol">Symbol on which the attribute is applied</param>
        /// <param name="attributeType">Attribute class for the attribute</param>
        /// <param name="node">Syntax node for attribute specification</param>
        /// <param name="attributeLocation">Attribute target specifier location</param>
        /// <param name="diagnostics">Diagnostics</param>
        /// <returns>Whether attribute specification is allowed for the given symbol</returns>
        internal bool VerifyAttributeUsageTarget(Symbol ownerSymbol, NamedTypeSymbol attributeType, AttributeSyntax node, AttributeLocation attributeLocation, DiagnosticBag diagnostics)
        {
            var attributeUsageInfo = attributeType.AttributeUsageInfo(Compilation);

            if (attributeUsageInfo != null)
            {
                AttributeTargets attributeTarget;
                if (attributeLocation == AttributeLocation.Return)
                {
                    // attribute on return type
                    attributeTarget = AttributeTargets.ReturnValue;
                }
                else
                {
                    attributeTarget = ownerSymbol.GetAttributeTarget();
                }

                if ((attributeTarget & attributeUsageInfo.ValidTargets) != 0)
                {
                    return(true);
                }

                // generate error
                Error(diagnostics, ErrorCode.ERR_AttributeOnBadSymbolType, node, GetAttributeNameFromSyntax(node), attributeUsageInfo.GetValidTargetsString());
            }

            return(false);
        }
Example #17
0
        /// <summary>
        /// Validate attribute usage target and duplicate attributes.
        /// </summary>
        /// <param name="attribute">Bound attribute</param>
        /// <param name="node">Syntax node for attribute specification</param>
        /// <param name="compilation">Compilation</param>
        /// <param name="symbolPart">Symbol part to which the attribute has been applied.</param>
        /// <param name="diagnostics">Diagnostics</param>
        /// <param name="uniqueAttributeTypes">Set of unique attribute types applied to the symbol</param>
        private bool ValidateAttributeUsage(
            CSharpAttributeData attribute,
            AttributeSyntax node,
            CSharpCompilation compilation,
            AttributeLocation symbolPart,
            DiagnosticBag diagnostics,
            HashSet<NamedTypeSymbol> uniqueAttributeTypes)
        {
            Debug.Assert(!attribute.HasErrors);

            NamedTypeSymbol attributeType = attribute.AttributeClass;
            AttributeUsageInfo attributeUsageInfo = attributeType.GetAttributeUsageInfo();

            // Given attribute can't be specified more than once if AllowMultiple is false.
            if (!uniqueAttributeTypes.Add(attributeType) && !attributeUsageInfo.AllowMultiple)
            {
                diagnostics.Add(ErrorCode.ERR_DuplicateAttribute, node.Name.Location, node.Name);
                return false;
            }

            // Verify if the attribute type can be applied to given owner symbol.
            AttributeTargets attributeTarget;
            if (symbolPart == AttributeLocation.Return)
            {
                // attribute on return type
                Debug.Assert(this.Kind == SymbolKind.Method);
                attributeTarget = AttributeTargets.ReturnValue;
            }
            else
            {
                attributeTarget = this.GetAttributeTarget();
            }

            if ((attributeTarget & attributeUsageInfo.ValidTargets) == 0)
            {
                // generate error
                diagnostics.Add(ErrorCode.ERR_AttributeOnBadSymbolType, node.Name.Location, node.Name, attributeUsageInfo.GetValidTargetsErrorArgument());
                return false;
            }

            if (attribute.IsSecurityAttribute(compilation))
            {
                switch (this.Kind)
                {
                    case SymbolKind.Assembly:
                    case SymbolKind.NamedType:
                    case SymbolKind.Method:
                        break;

                    default:
                        // CS7070: Security attribute '{0}' is not valid on this declaration type. Security attributes are only valid on assembly, type and method declarations.
                        diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidTarget, node.Name.Location, node.GetErrorDisplayName());
                        return false;
                }
            }

            return true;
        }
Example #18
0
        /// <summary>
        /// Method to early decode certain well-known attributes which can be queried by the binder.
        /// This method is called during attribute binding after we have bound the attribute types for all attributes,
        /// but haven't yet bound the attribute arguments/attribute constructor.
        /// Early decoding certain well-known attributes enables the binder to use this decoded information on this symbol
        /// when binding the attribute arguments/attribute constructor without causing attribute binding cycle.
        /// </summary>
        internal EarlyWellKnownAttributeData EarlyDecodeWellKnownAttributes(
            ImmutableArray<Binder> binders,
            ImmutableArray<NamedTypeSymbol> boundAttributeTypes,
            ImmutableArray<AttributeSyntax> attributesToBind,
            AttributeLocation symbolPart,
            CSharpAttributeData[] boundAttributesBuilder)
        {
            Debug.Assert(boundAttributeTypes.Any());
            Debug.Assert(attributesToBind.Any());
            Debug.Assert(binders.Any());
            Debug.Assert(boundAttributesBuilder != null);
            Debug.Assert(!boundAttributesBuilder.Contains((attr) => attr != null));

            var earlyBinder = new EarlyWellKnownAttributeBinder(binders[0]);
            var arguments = new EarlyDecodeWellKnownAttributeArguments<EarlyWellKnownAttributeBinder, NamedTypeSymbol, AttributeSyntax, AttributeLocation>();
            arguments.SymbolPart = symbolPart;

            for (int i = 0; i < boundAttributeTypes.Length; i++)
            {
                NamedTypeSymbol boundAttributeType = boundAttributeTypes[i];
                if (!boundAttributeType.IsErrorType())
                {
                    if (binders[i] != earlyBinder.Next)
                    {
                        earlyBinder = new EarlyWellKnownAttributeBinder(binders[i]);
                    }

                    arguments.Binder = earlyBinder;
                    arguments.AttributeType = boundAttributeType;
                    arguments.AttributeSyntax = attributesToBind[i];

                    // Early bind some well-known attributes
                    CSharpAttributeData earlyBoundAttributeOpt = this.EarlyDecodeWellKnownAttribute(ref arguments);
                    Debug.Assert(earlyBoundAttributeOpt == null || !earlyBoundAttributeOpt.HasErrors);

                    boundAttributesBuilder[i] = earlyBoundAttributeOpt;
                }
            }

            return arguments.HasDecodedData ? arguments.DecodedData : null;
        }
Example #19
0
        /// <summary>
        /// Method to merge attributes from the given attributesSyntaxLists and filter out attributes by attribute target.
        /// This is the first step in attribute binding.
        /// </summary>
        /// <remarks>
        /// This method can generate diagnostics for few cases where we have an invalid target specifier and the parser hasn't generated the necessary diagnostics.
        /// It should not perform any bind operations as it can lead to an attribute binding cycle.
        /// </remarks>
        private ImmutableArray<AttributeSyntax> GetAttributesToBind(
            OneOrMany<SyntaxList<AttributeListSyntax>> attributeDeclarationSyntaxLists,
            AttributeLocation symbolPart,
            DiagnosticBag diagnostics,
            CSharpCompilation compilation,
            out ImmutableArray<Binder> binders)
        {
            var attributeTarget = (IAttributeTargetSymbol)this;

            ArrayBuilder<AttributeSyntax> syntaxBuilder = null;
            ArrayBuilder<Binder> bindersBuilder = null;
            int attributesToBindCount = 0;

            for (int listIndex = 0; listIndex < attributeDeclarationSyntaxLists.Count; listIndex++)
            {
                var attributeDeclarationSyntaxList = attributeDeclarationSyntaxLists[listIndex];
                if (attributeDeclarationSyntaxList.Any())
                {
                    int prevCount = attributesToBindCount;
                    foreach (var attributeDeclarationSyntax in attributeDeclarationSyntaxList)
                    {
                        // We bind the attribute only if it has a matching target for the given ownerSymbol and attributeLocation.
                        if (MatchAttributeTarget(attributeTarget, symbolPart, attributeDeclarationSyntax.Target, diagnostics))
                        {
                            if (syntaxBuilder == null)
                            {
                                syntaxBuilder = new ArrayBuilder<AttributeSyntax>();
                                bindersBuilder = new ArrayBuilder<Binder>();
                            }

                            var attributesToBind = attributeDeclarationSyntax.Attributes;
                            syntaxBuilder.AddRange(attributesToBind);
                            attributesToBindCount += attributesToBind.Count;
                        }
                    }

                    if (attributesToBindCount != prevCount)
                    {
                        Debug.Assert(attributeDeclarationSyntaxList.Node != null);
                        Debug.Assert(bindersBuilder != null);

                        var syntaxTree = attributeDeclarationSyntaxList.Node.SyntaxTree;
                        var binder = compilation.GetBinderFactory(syntaxTree).GetBinder((CSharpSyntaxNode)attributeDeclarationSyntaxList.Node);

                        binder = new ContextualAttributeBinder(binder, this);
                        Debug.Assert(!binder.InAttributeArgument, "Possible cycle in attribute binding");

                        for (int i = 0; i < attributesToBindCount - prevCount; i++)
                        {
                            bindersBuilder.Add(binder);
                        }
                    }
                }
            }

            if (syntaxBuilder != null)
            {
                binders = bindersBuilder.ToImmutableAndFree();
                return syntaxBuilder.ToImmutableAndFree();
            }
            else
            {
                binders = ImmutableArray<Binder>.Empty;
                return ImmutableArray<AttributeSyntax>.Empty;
            }
        }
Example #20
0
 /// <summary>
 /// Called to report attribute related diagnostics after all attributes have been bound and decoded.
 /// Called even if there are no attributes.
 /// </summary>
 /// <remarks>
 /// This method is called by the binder from <see cref="LoadAndValidateAttributes"/> after it has finished binding attributes on the symbol,
 /// has executed <see cref="DecodeWellKnownAttribute"/> for attributes applied on the symbol and has stored the decoded data in the
 /// lazyCustomAttributesBag on the symbol. Bound attributes haven't been stored on the bag yet.
 /// 
 /// Post-validation for attributes that is dependant on other attributes can be done here.
 /// 
 /// This method should not have any side effects on the symbol, i.e. it SHOULD NOT change the symbol state.
 /// </remarks>
 /// <param name="boundAttributes">Bound attributes.</param>
 /// <param name="allAttributeSyntaxNodes">Syntax nodes of attributes in order they are specified in source, or null if there are no attributes.</param>
 /// <param name="diagnostics">Diagnostic bag.</param>
 /// <param name="symbolPart">Specific part of the symbol to which the attributes apply, or <see cref="AttributeLocation.None"/> if the attributes apply to the symbol itself.</param>
 /// <param name="decodedData">Decoded well-known attribute data, could be null.</param>
 internal virtual void PostDecodeWellKnownAttributes(ImmutableArray<CSharpAttributeData> boundAttributes, ImmutableArray<AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
 {
 }
        internal static string ToDisplayString(this AttributeLocation locations)
        {
            StringBuilder result = new StringBuilder();

            for (int i = 1; i < (int)AttributeLocation.Unknown; i <<= 1)
            {
                if ((locations & (AttributeLocation)i) != 0)
                {
                    if (result.Length > 0)
                    {
                        result.Append(", ");
                    }

                    switch ((AttributeLocation)i)
                    {
                    case AttributeLocation.Assembly:
                        result.Append("assembly");
                        break;

                    case AttributeLocation.Module:
                        result.Append("module");
                        break;

                    case AttributeLocation.Type:
                        result.Append("type");
                        break;

                    case AttributeLocation.Method:
                        result.Append("method");
                        break;

                    case AttributeLocation.Field:
                        result.Append("field");
                        break;

                    case AttributeLocation.Property:
                        result.Append("property");
                        break;

                    case AttributeLocation.Event:
                        result.Append("event");
                        break;

                    case AttributeLocation.Return:
                        result.Append("return");
                        break;

                    case AttributeLocation.Parameter:
                        result.Append("param");
                        break;

                    case AttributeLocation.TypeParameter:
                        result.Append("typevar");
                        break;

                    default:
                        throw ExceptionUtilities.UnexpectedValue(i);
                    }
                }
            }

            return(result.ToString());
        }
Example #22
0
        /// <summary>
        /// This method does the following set of operations in the specified order:
        /// (1) GetAttributesToBind: Merge attributes from the given attributesSyntaxLists and filter out attributes by attribute target.
        /// (2) BindAttributeTypes: Bind all the attribute types to enable early decode of certain well-known attributes by type.
        /// (3) EarlyDecodeWellKnownAttributes: Perform early decoding of certain well-known attributes that could be queried by the binder in subsequent steps.
        ///     (NOTE: This step has the side effect of updating the symbol state based on the data extracted from well known attributes).
        /// (4) GetAttributes: Bind the attributes (attribute arguments and constructor) using bound attribute types.
        /// (5) DecodeWellKnownAttributes: Decode and validate bound well known attributes.
        ///     (NOTE: This step has the side effect of updating the symbol state based on the data extracted from well known attributes).
        /// (6) StoreBoundAttributesAndDoPostValidation:
        ///     (a) Store the bound attributes in lazyCustomAttributes in a thread safe manner.
        ///     (b) Perform some additional post attribute validations, such as
        ///         1) Duplicate attributes, attribute usage target validation, etc.
        ///         2) Post validation for attributes dependant on other attributes
        ///         These validations cannot be performed prior to step 6(a) as we might need to
        ///         perform a GetAttributes() call on a symbol which can introduce a cycle in attribute binding.
        ///         We avoid this cycle by performing such validations in PostDecodeWellKnownAttributes after lazyCustomAttributes have been set.
        ///     NOTE: PostDecodeWellKnownAttributes SHOULD NOT change the symbol state.
        /// </summary>
        /// <remarks>
        /// Current design of early decoding well-known attributes doesn't permit decoding attribute arguments/constructor as this can lead to binding cycles.
        /// For well-known attributes used by the binder, where we need the decoded arguments, we must handle them specially in one of the following possible ways:
        ///   (a) Avoid decoding the attribute arguments during binding and delay the corresponding binder tasks to a separate post-pass executed after binding.
        ///   (b) As the cycles can be caused only when we are binding attribute arguments/constructor, special case the corresponding binder tasks based on the current BinderFlags.
        /// </remarks>
        /// <param name="attributesSyntaxLists"></param>
        /// <param name="lazyCustomAttributesBag"></param>
        /// <param name="symbolPart">Specific part of the symbol to which the attributes apply, or <see cref="AttributeLocation.None"/> if the attributes apply to the symbol itself.</param>
        /// <param name="earlyDecodingOnly">Indicates that only early decoding should be performed.  WARNING: the resulting bag will not be sealed.</param>
        /// <returns>Flag indicating whether lazyCustomAttributes were stored on this thread. Caller should check for this flag and perform NotePartComplete if true.</returns>
        internal bool LoadAndValidateAttributes(
            OneOrMany<SyntaxList<AttributeListSyntax>> attributesSyntaxLists,
            ref CustomAttributesBag<CSharpAttributeData> lazyCustomAttributesBag,
            AttributeLocation symbolPart = AttributeLocation.None,
            bool earlyDecodingOnly = false)
        {
            var diagnostics = DiagnosticBag.GetInstance();
            var compilation = this.DeclaringCompilation;

            ImmutableArray<Binder> binders;
            ImmutableArray<AttributeSyntax> attributesToBind = this.GetAttributesToBind(attributesSyntaxLists, symbolPart, diagnostics, compilation, out binders);
            Debug.Assert(!attributesToBind.IsDefault);

            ImmutableArray<CSharpAttributeData> boundAttributes;
            WellKnownAttributeData wellKnownAttributeData;

            if (attributesToBind.Any())
            {
                Debug.Assert(!binders.IsDefault);
                Debug.Assert(binders.Length == attributesToBind.Length);

                // Initialize the bag so that data decoded from early attributes can be stored onto it.
                if (lazyCustomAttributesBag == null)
                {
                    Interlocked.CompareExchange(ref lazyCustomAttributesBag, new CustomAttributesBag<CSharpAttributeData>(), null);
                }

                // Bind the attribute types and then early decode them.
                int totalAttributesCount = attributesToBind.Length;
                var attributeTypesBuilder = new NamedTypeSymbol[totalAttributesCount];

                Binder.BindAttributeTypes(binders, attributesToBind, this, attributeTypesBuilder, diagnostics);
                ImmutableArray<NamedTypeSymbol> boundAttributeTypes = attributeTypesBuilder.AsImmutableOrNull();

                this.EarlyDecodeWellKnownAttributeTypes(boundAttributeTypes, attributesToBind);
                this.PostEarlyDecodeWellKnownAttributeTypes();

                // Bind the attribute in two stages - early and normal.
                var attributesBuilder = new CSharpAttributeData[totalAttributesCount];

                // Early bind and decode some well-known attributes.
                EarlyWellKnownAttributeData earlyData = this.EarlyDecodeWellKnownAttributes(binders, boundAttributeTypes, attributesToBind, symbolPart, attributesBuilder);
                Debug.Assert(!attributesBuilder.Contains((attr) => attr != null && attr.HasErrors));

                // Store data decoded from early bound well-known attributes.
                // TODO: what if this succeeds on another thread, not ours?
                lazyCustomAttributesBag.SetEarlyDecodedWellKnownAttributeData(earlyData);

                if (earlyDecodingOnly)
                {
                    diagnostics.Free(); //NOTE: dropped.
                    return false;
                }

                // Bind attributes.
                Binder.GetAttributes(binders, attributesToBind, boundAttributeTypes, attributesBuilder, diagnostics);
                boundAttributes = attributesBuilder.AsImmutableOrNull();

                // All attributes must be bound by now.
                Debug.Assert(!boundAttributes.Any((attr) => attr == null));

                // Validate attribute usage and Decode remaining well-known attributes.
                wellKnownAttributeData = this.ValidateAttributeUsageAndDecodeWellKnownAttributes(binders, attributesToBind, boundAttributes, diagnostics, symbolPart);

                // Store data decoded from remaining well-known attributes.
                // TODO: what if this succeeds on another thread but not this thread?
                lazyCustomAttributesBag.SetDecodedWellKnownAttributeData(wellKnownAttributeData);
            }
            else if (earlyDecodingOnly)
            {
                diagnostics.Free(); //NOTE: dropped.
                return false;
            }
            else
            {
                boundAttributes = ImmutableArray<CSharpAttributeData>.Empty;
                wellKnownAttributeData = null;
                Interlocked.CompareExchange(ref lazyCustomAttributesBag, CustomAttributesBag<CSharpAttributeData>.WithEmptyData(), null);
                this.PostEarlyDecodeWellKnownAttributeTypes();
            }

            this.PostDecodeWellKnownAttributes(boundAttributes, attributesToBind, diagnostics, symbolPart, wellKnownAttributeData);

            // Store attributes into the bag.
            bool lazyAttributesStoredOnThisThread = false;
            if (lazyCustomAttributesBag.SetAttributes(boundAttributes))
            {
                this.RecordPresenceOfBadAttributes(boundAttributes);
                this.AddDeclarationDiagnostics(diagnostics);
                lazyAttributesStoredOnThisThread = true;
                if (lazyCustomAttributesBag.IsEmpty) lazyCustomAttributesBag = CustomAttributesBag<CSharpAttributeData>.Empty;
            }

            Debug.Assert(lazyCustomAttributesBag.IsSealed);
            diagnostics.Free();
            return lazyAttributesStoredOnThisThread;
        }
        internal override void PostDecodeWellKnownAttributes(ImmutableArray<CSharpAttributeData> boundAttributes, ImmutableArray<AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
        {
            Debug.Assert(!boundAttributes.IsDefault);
            Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
            Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length);
            Debug.Assert(_lazyCustomAttributesBag != null);
            Debug.Assert(_lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed);
            Debug.Assert(symbolPart == AttributeLocation.None);

            var data = (CommonParameterWellKnownAttributeData)decodedData;
            if (data != null)
            {
                if (this.RefKind == RefKind.Ref && data.HasOutAttribute && !data.HasInAttribute)
                {
                    // error CS0662: '...' cannot specify only Out attribute on a ref parameter. Use both In and Out attributes, or neither.
                    diagnostics.Add(ErrorCode.ERR_OutAttrOnRefParam, this.Locations[0]);
                }
            }

            base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData);
        }
Example #24
0
        private static bool MatchAttributeTarget(IAttributeTargetSymbol attributeTarget, AttributeLocation symbolPart, AttributeTargetSpecifierSyntax targetOpt, DiagnosticBag diagnostics)
        {
            IAttributeTargetSymbol attributesOwner = attributeTarget.AttributesOwner;

            // Determine if the target symbol owns the attribute declaration. 
            // We need to report diagnostics only once, so do it when visiting attributes for the owner.
            bool isOwner = symbolPart == AttributeLocation.None && ReferenceEquals(attributesOwner, attributeTarget);

            if (targetOpt == null)
            {
                // only attributes with an explicit target match if the symbol doesn't own the attributes:
                return isOwner;
            }

            AttributeLocation explicitTarget = targetOpt.GetAttributeLocation();
            if (explicitTarget == AttributeLocation.None)
            {
                // error: unknown attribute location
                if (isOwner)
                {
                    //NOTE: ValueText so that we accept targets like "@return", to match dev10 (DevDiv #2591).
                    diagnostics.Add(ErrorCode.WRN_InvalidAttributeLocation,
                        targetOpt.Identifier.GetLocation(), targetOpt.Identifier.ValueText);
                }

                return false;
            }

            AttributeLocation allowedTargets = attributesOwner.AllowedAttributeLocations;
            if ((explicitTarget & allowedTargets) == 0)
            {
                // error: invalid target for symbol
                if (isOwner)
                {
                    if (allowedTargets == AttributeLocation.None)
                    {
                        switch (attributeTarget.DefaultAttributeLocation)
                        {
                            case AttributeLocation.Assembly:
                            case AttributeLocation.Module:
                                // global attributes are disallowed in interactive code:
                                diagnostics.Add(ErrorCode.ERR_GlobalAttributesNotAllowed, targetOpt.Identifier.GetLocation());
                                break;

                            default:
                                // currently this can't happen
                                throw ExceptionUtilities.UnexpectedValue(attributeTarget.DefaultAttributeLocation);
                        }
                    }
                    else
                    {
                        diagnostics.Add(ErrorCode.WRN_AttributeLocationOnBadDeclaration,
                            targetOpt.Identifier.GetLocation(), targetOpt.Identifier.ToString(), allowedTargets.ToDisplayString());
                    }
                }

                return false;
            }

            if (symbolPart == AttributeLocation.None)
            {
                return explicitTarget == attributeTarget.DefaultAttributeLocation;
            }
            else
            {
                return explicitTarget == symbolPart;
            }
        }
Example #25
0
        internal override void PostDecodeWellKnownAttributes(ImmutableArray<CSharpAttributeData> boundAttributes, ImmutableArray<AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
        {
            Debug.Assert(!boundAttributes.IsDefault);
            Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
            Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length);
            Debug.Assert(symbolPart == AttributeLocation.None || symbolPart == AttributeLocation.Return);

            if (symbolPart != AttributeLocation.Return)
            {
                Debug.Assert(this.lazyCustomAttributesBag != null);
                Debug.Assert(this.lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed);

                if (this.containingType.IsComImport && this.containingType.TypeKind == TypeKind.Class)
                {
                    switch (this.MethodKind)
                    {
                        case MethodKind.Constructor:
                        case MethodKind.StaticConstructor:
                            if (!this.IsImplicitlyDeclared)
                            {
                                // CS0669: A class with the ComImport attribute cannot have a user-defined constructor
                                diagnostics.Add(ErrorCode.ERR_ComImportWithUserCtor, this.Locations[0]);
                            }

                            break;

                        default:
                            if (!this.IsAbstract && !this.IsExtern)
                            {
                                // CS0423: Since '{1}' has the ComImport attribute, '{0}' must be extern or abstract
                                diagnostics.Add(ErrorCode.ERR_ComImportWithImpl, this.Locations[0], this, this.containingType);
                            }

                            break;
                    }
                }
            }

            base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData);
        }
Example #26
0
        /// <summary>
        /// This method validates attribute usage for each bound attribute and calls <see cref="DecodeWellKnownAttribute"/>
        /// on attributes with valid attribute usage.
        /// This method is called by the binder when it is finished binding a set of attributes on the symbol so that
        /// the symbol can extract data from the attribute arguments and potentially perform validation specific to
        /// some well known attributes.
        /// </summary>
        private WellKnownAttributeData ValidateAttributeUsageAndDecodeWellKnownAttributes(
            ImmutableArray<Binder> binders,
            ImmutableArray<AttributeSyntax> attributeSyntaxList,
            ImmutableArray<CSharpAttributeData> boundAttributes,
            DiagnosticBag diagnostics,
            AttributeLocation symbolPart)
        {
            Debug.Assert(binders.Any());
            Debug.Assert(attributeSyntaxList.Any());
            Debug.Assert(boundAttributes.Any());
            Debug.Assert(binders.Length == boundAttributes.Length);
            Debug.Assert(attributeSyntaxList.Length == boundAttributes.Length);

            int totalAttributesCount = boundAttributes.Length;
            HashSet<NamedTypeSymbol> uniqueAttributeTypes = new HashSet<NamedTypeSymbol>();
            var arguments = new DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation>();
            arguments.Diagnostics = diagnostics;
            arguments.AttributesCount = totalAttributesCount;
            arguments.SymbolPart = symbolPart;

            for (int i = 0; i < totalAttributesCount; i++)
            {
                CSharpAttributeData boundAttribute = boundAttributes[i];
                AttributeSyntax attributeSyntax = attributeSyntaxList[i];
                Binder binder = binders[i];

                // Decode attribute as a possible well-known attribute only if it has no binding errors and has valid AttributeUsage.
                if (!boundAttribute.HasErrors && ValidateAttributeUsage(boundAttribute, attributeSyntax, binder.Compilation, symbolPart, diagnostics, uniqueAttributeTypes))
                {
                    arguments.Attribute = boundAttribute;
                    arguments.AttributeSyntaxOpt = attributeSyntax;
                    arguments.Index = i;

                    this.DecodeWellKnownAttribute(ref arguments);
                }
            }

            return arguments.HasDecodedData ? arguments.DecodedData : null;
        }
Example #27
0
        internal override void PostDecodeWellKnownAttributes(ImmutableArray<CSharpAttributeData> boundAttributes, ImmutableArray<AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
        {
            Debug.Assert(!boundAttributes.IsDefault);
            Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
            Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length);
            Debug.Assert(_lazyCustomAttributesBag != null);
            Debug.Assert(_lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed);
            Debug.Assert(symbolPart == AttributeLocation.None);

            var data = (CommonFieldWellKnownAttributeData)decodedData;
            int? fieldOffset = data != null ? data.Offset : null;

            if (fieldOffset.HasValue)
            {
                if (this.ContainingType.Layout.Kind != LayoutKind.Explicit)
                {
                    Debug.Assert(boundAttributes.Any());

                    // error CS0636: The FieldOffset attribute can only be placed on members of types marked with the StructLayout(LayoutKind.Explicit)
                    int i = boundAttributes.IndexOfAttribute(this, AttributeDescription.FieldOffsetAttribute);
                    diagnostics.Add(ErrorCode.ERR_StructOffsetOnBadStruct, allAttributeSyntaxNodes[i].Name.Location);
                }
            }
            else if (!this.IsStatic && !this.IsConst)
            {
                if (this.ContainingType.Layout.Kind == LayoutKind.Explicit)
                {
                    // error CS0625: '<field>': instance field types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute
                    diagnostics.Add(ErrorCode.ERR_MissingStructOffset, this.ErrorLocation, this);
                }
            }

            base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData);
        }
Example #28
0
        /// <summary>
        /// This method does the following set of operations in the specified order:
        /// (1) GetAttributesToBind: Merge attributes from the given attributesSyntaxLists and filter out attributes by attribute target.
        /// (2) BindAttributeTypes: Bind all the attribute types to enable early decode of certain well-known attributes by type.
        /// (3) EarlyDecodeWellKnownAttributes: Perform early decoding of certain well-known attributes that could be queried by the binder in subsequent steps.
        ///     (NOTE: This step has the side effect of updating the symbol state based on the data extracted from well known attributes).
        /// (4) GetAttributes: Bind the attributes (attribute arguments and constructor) using bound attribute types.
        /// (5) DecodeWellKnownAttributes: Decode and validate bound well known attributes.
        ///     (NOTE: This step has the side effect of updating the symbol state based on the data extracted from well known attributes).
        /// (6) StoreBoundAttributesAndDoPostValidation:
        ///     (a) Store the bound attributes in lazyCustomAttributes in a thread safe manner.
        ///     (b) Perform some additional post attribute validations, such as
        ///         1) Duplicate attributes, attribute usage target validation, etc.
        ///         2) Post validation for attributes dependent on other attributes
        ///         These validations cannot be performed prior to step 6(a) as we might need to
        ///         perform a GetAttributes() call on a symbol which can introduce a cycle in attribute binding.
        ///         We avoid this cycle by performing such validations in PostDecodeWellKnownAttributes after lazyCustomAttributes have been set.
        ///     NOTE: PostDecodeWellKnownAttributes SHOULD NOT change the symbol state.
        /// </summary>
        /// <remarks>
        /// Current design of early decoding well-known attributes doesn't permit decoding attribute arguments/constructor as this can lead to binding cycles.
        /// For well-known attributes used by the binder, where we need the decoded arguments, we must handle them specially in one of the following possible ways:
        ///   (a) Avoid decoding the attribute arguments during binding and delay the corresponding binder tasks to a separate post-pass executed after binding.
        ///   (b) As the cycles can be caused only when we are binding attribute arguments/constructor, special case the corresponding binder tasks based on the current BinderFlags.
        /// </remarks>
        /// <param name="attributesSyntaxLists"></param>
        /// <param name="lazyCustomAttributesBag"></param>
        /// <param name="symbolPart">Specific part of the symbol to which the attributes apply, or <see cref="AttributeLocation.None"/> if the attributes apply to the symbol itself.</param>
        /// <param name="earlyDecodingOnly">Indicates that only early decoding should be performed.  WARNING: the resulting bag will not be sealed.</param>
        /// <param name="binderOpt">Binder to use. If null, <see cref="DeclaringCompilation"/> GetBinderFactory will be used.</param>
        /// <param name="attributeMatchesOpt">If specified, only load attributes that match this predicate, and any diagnostics produced will be dropped.</param>
        /// <returns>Flag indicating whether lazyCustomAttributes were stored on this thread. Caller should check for this flag and perform NotePartComplete if true.</returns>
        internal bool LoadAndValidateAttributes(
            OneOrMany <SyntaxList <AttributeSyntax> > attributesSyntaxLists,
            ref CustomAttributesBag <CSharpAttributeData> lazyCustomAttributesBag,
            AttributeLocation symbolPart = AttributeLocation.None,
            bool earlyDecodingOnly       = false,
            Binder binderOpt             = null,
            Func <AttributeSyntax, bool> attributeMatchesOpt = null,
            Func <Binder, Binder> contextualBinder           = null
            )
        {
            var diagnostics = DiagnosticBag.GetInstance();
            var compilation = this.DeclaringCompilation;

            ImmutableArray <Binder>          binders;
            ImmutableArray <AttributeSyntax> attributesToBind = this.GetAttributesToBind(attributesSyntaxLists, symbolPart, diagnostics, compilation, attributeMatchesOpt, binderOpt, out binders, contextualBinder);

            Debug.Assert(!attributesToBind.IsDefault);

            ImmutableArray <CSharpAttributeData> boundAttributes;
            WellKnownAttributeData wellKnownAttributeData;

            if (attributesToBind.Any())
            {
                Debug.Assert(!binders.IsDefault);
                Debug.Assert(binders.Length == attributesToBind.Length);

                // Initialize the bag so that data decoded from early attributes can be stored onto it.
                if (lazyCustomAttributesBag == null)
                {
                    Interlocked.CompareExchange(ref lazyCustomAttributesBag, new CustomAttributesBag <CSharpAttributeData>(), null);
                }

                // Bind the attribute types and then early decode them.
                int totalAttributesCount  = attributesToBind.Length;
                var attributeTypesBuilder = new NamedTypeSymbol[totalAttributesCount];

                Binder.BindAttributeTypes(binders, attributesToBind, this, attributeTypesBuilder, diagnostics);
                ImmutableArray <NamedTypeSymbol> boundAttributeTypes = attributeTypesBuilder.AsImmutableOrNull();

                this.EarlyDecodeWellKnownAttributeTypes(boundAttributeTypes, attributesToBind);
                this.PostEarlyDecodeWellKnownAttributeTypes();

                // Bind the attribute in two stages - early and normal.
                var attributesBuilder = new CSharpAttributeData[totalAttributesCount];

                // Early bind and decode some well-known attributes.
                EarlyWellKnownAttributeData earlyData = this.EarlyDecodeWellKnownAttributes(binders, boundAttributeTypes, attributesToBind, symbolPart, attributesBuilder);
                Debug.Assert(!attributesBuilder.Contains((attr) => attr != null && attr.HasErrors));

                // Store data decoded from early bound well-known attributes.
                // TODO: what if this succeeds on another thread, not ours?
                lazyCustomAttributesBag.SetEarlyDecodedWellKnownAttributeData(earlyData);

                if (earlyDecodingOnly)
                {
                    diagnostics.Free(); //NOTE: dropped.
                    return(false);
                }

                // Bind attributes.
                Binder.GetAttributes(binders, attributesToBind, boundAttributeTypes, attributesBuilder, diagnostics);
                boundAttributes = attributesBuilder.AsImmutableOrNull();

                // All attributes must be bound by now.
                Debug.Assert(!boundAttributes.Any((attr) => attr == null));

                // Validate attribute usage and Decode remaining well-known attributes.
                wellKnownAttributeData = this.ValidateAttributeUsageAndDecodeWellKnownAttributes(binders, attributesToBind, boundAttributes, diagnostics, symbolPart);

                // Store data decoded from remaining well-known attributes.
                // TODO: what if this succeeds on another thread but not this thread?
                lazyCustomAttributesBag.SetDecodedWellKnownAttributeData(wellKnownAttributeData);
            }
            else if (earlyDecodingOnly)
            {
                diagnostics.Free(); //NOTE: dropped.
                return(false);
            }
            else
            {
                boundAttributes        = ImmutableArray <CSharpAttributeData> .Empty;
                wellKnownAttributeData = null;
                Interlocked.CompareExchange(ref lazyCustomAttributesBag, CustomAttributesBag <CSharpAttributeData> .WithEmptyData(), null);
                this.PostEarlyDecodeWellKnownAttributeTypes();
            }

            this.PostDecodeWellKnownAttributes(boundAttributes, attributesToBind, diagnostics, symbolPart, wellKnownAttributeData);

            // Store attributes into the bag.
            bool lazyAttributesStoredOnThisThread = false;

            if (lazyCustomAttributesBag.SetAttributes(boundAttributes))
            {
                if (attributeMatchesOpt is null)
                {
                    this.RecordPresenceOfBadAttributes(boundAttributes);
                    AddDeclarationDiagnostics(diagnostics);
                }
                lazyAttributesStoredOnThisThread = true;
                if (lazyCustomAttributesBag.IsEmpty)
                {
                    lazyCustomAttributesBag = CustomAttributesBag <CSharpAttributeData> .Empty;
                }
            }

            Debug.Assert(lazyCustomAttributesBag.IsSealed);
            diagnostics.Free();
            return(lazyAttributesStoredOnThisThread);
        }
        /// <summary>
        /// Validate attribute usage target and duplicate attributes.
        /// </summary>
        /// <param name="attribute">Bound attribute</param>
        /// <param name="node">Syntax node for attribute specification</param>
        /// <param name="compilation">Compilation</param>
        /// <param name="symbolPart">Symbol part to which the attribute has been applied.</param>
        /// <param name="diagnostics">Diagnostics</param>
        /// <param name="uniqueAttributeTypes">Set of unique attribute types applied to the symbol</param>
        private bool ValidateAttributeUsage(
            CSharpAttributeData attribute,
            AttributeSyntax node,
            CSharpCompilation compilation,
            AttributeLocation symbolPart,
            DiagnosticBag diagnostics,
            HashSet <NamedTypeSymbol> uniqueAttributeTypes)
        {
            Debug.Assert(!attribute.HasErrors);

            NamedTypeSymbol    attributeType      = attribute.AttributeClass;
            AttributeUsageInfo attributeUsageInfo = attributeType.GetAttributeUsageInfo();

            // Given attribute can't be specified more than once if AllowMultiple is false.
            if (!uniqueAttributeTypes.Add(attributeType) && !attributeUsageInfo.AllowMultiple)
            {
                diagnostics.Add(ErrorCode.ERR_DuplicateAttribute, node.Name.Location, node.GetErrorDisplayName());
                return(false);
            }

            // Verify if the attribute type can be applied to given owner symbol.
            AttributeTargets attributeTarget;

            if (symbolPart == AttributeLocation.Return)
            {
                // attribute on return type
                Debug.Assert(this.Kind == SymbolKind.Method);
                attributeTarget = AttributeTargets.ReturnValue;
            }
            else
            {
                attributeTarget = this.GetAttributeTarget();
            }

            if ((attributeTarget & attributeUsageInfo.ValidTargets) == 0)
            {
#if XSHARP
                // The ClipperCallingConvention Attribute in VulcanRT has incorrect Targets (Method, but should also be allowed on Constructors)
                if (node.Name.ToString().ToLower().IndexOf(OurTypeNames.ClipperCallingConventionAttribute, XSharpString.Comparison) == -1)
                {
#endif
                // generate error
                diagnostics.Add(ErrorCode.ERR_AttributeOnBadSymbolType, node.Name.Location, node.GetErrorDisplayName(), attributeUsageInfo.GetValidTargetsErrorArgument());
                return(false);

#if XSHARP
            }
#endif
            }

            if (attribute.IsSecurityAttribute(compilation))
            {
                switch (this.Kind)
                {
                case SymbolKind.Assembly:
                case SymbolKind.NamedType:
                case SymbolKind.Method:
                    break;

                default:
                    // CS7070: Security attribute '{0}' is not valid on this declaration type. Security attributes are only valid on assembly, type and method declarations.
                    diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidTarget, node.Name.Location, node.GetErrorDisplayName());
                    return(false);
                }
            }

            return(true);
        }
Example #30
0
        private static bool MatchAttributeTarget(IAttributeTargetSymbol attributeTarget, AttributeLocation symbolPart, AttributeTargetSpecifierSyntax targetOpt, DiagnosticBag diagnostics)
        {
            IAttributeTargetSymbol attributesOwner = attributeTarget.AttributesOwner;

            // Determine if the target symbol owns the attribute declaration.
            // We need to report diagnostics only once, so do it when visiting attributes for the owner.
            bool isOwner = symbolPart == AttributeLocation.None && ReferenceEquals(attributesOwner, attributeTarget);

            if (targetOpt == null)
            {
                // only attributes with an explicit target match if the symbol doesn't own the attributes:
                return(isOwner);
            }

            AttributeLocation allowedTargets = attributesOwner.AllowedAttributeLocations;

            AttributeLocation explicitTarget = targetOpt.GetAttributeLocation();

            if (explicitTarget == AttributeLocation.None)
            {
                // error: unknown attribute location
                if (isOwner)
                {
                    //NOTE: ValueText so that we accept targets like "@return", to match dev10 (DevDiv #2591).
                    diagnostics.Add(ErrorCode.WRN_InvalidAttributeLocation,
                                    targetOpt.Identifier.GetLocation(), targetOpt.Identifier.ValueText, allowedTargets.ToDisplayString());
                }

                return(false);
            }

            if ((explicitTarget & allowedTargets) == 0)
            {
                // error: invalid target for symbol
                if (isOwner)
                {
                    if (allowedTargets == AttributeLocation.None)
                    {
                        switch (attributeTarget.DefaultAttributeLocation)
                        {
                        case AttributeLocation.Assembly:
                        case AttributeLocation.Module:
                            // global attributes are disallowed in interactive code:
                            diagnostics.Add(ErrorCode.ERR_GlobalAttributesNotAllowed, targetOpt.Identifier.GetLocation());
                            break;

                        default:
                            // currently this can't happen
                            throw ExceptionUtilities.UnexpectedValue(attributeTarget.DefaultAttributeLocation);
                        }
                    }
                    else
                    {
                        diagnostics.Add(ErrorCode.WRN_AttributeLocationOnBadDeclaration,
                                        targetOpt.Identifier.GetLocation(), targetOpt.Identifier.ToString(), allowedTargets.ToDisplayString());
                    }
                }

                return(false);
            }

            if (symbolPart == AttributeLocation.None)
            {
                return(explicitTarget == attributeTarget.DefaultAttributeLocation);
            }
            else
            {
                return(explicitTarget == symbolPart);
            }
        }
Example #31
0
        internal override void PostDecodeWellKnownAttributes(ImmutableArray <CSharpAttributeData> boundAttributes, ImmutableArray <AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
        {
            Debug.Assert(!boundAttributes.IsDefault);
            Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
            Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length);
            Debug.Assert(_lazyCustomAttributesBag != null);
            Debug.Assert(_lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed);
            Debug.Assert(symbolPart == AttributeLocation.None);

            var data = (TypeWellKnownAttributeData)decodedData;

            // Report ERR_DefaultMemberOnIndexedType if type has a default member attribute and has indexers.
            if (data != null && data.HasDefaultMemberAttribute && this.Indexers.Any())
            {
                Debug.Assert(boundAttributes.Any());

                int index = boundAttributes.IndexOfAttribute(this, AttributeDescription.DefaultMemberAttribute);
                diagnostics.Add(ErrorCode.ERR_DefaultMemberOnIndexedType, allAttributeSyntaxNodes[index].Name.Location);
            }

            base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData);
        }
        internal override void PostDecodeWellKnownAttributes(ImmutableArray<CSharpAttributeData> boundAttributes, ImmutableArray<AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
        {
            Debug.Assert(!boundAttributes.IsDefault);
            Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
            Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length);
            Debug.Assert(_lazyCustomAttributesBag != null);
            Debug.Assert(_lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed);
            Debug.Assert(symbolPart == AttributeLocation.None);

            if (this.IsAutoProperty && !this.IsStatic && this.ContainingType.Layout.Kind == LayoutKind.Explicit)
            {
                // error CS0842: '<property>': Automatically implemented properties cannot be used inside a type marked with StructLayout(LayoutKind.Explicit)
                diagnostics.Add(ErrorCode.ERR_ExplicitLayoutAndAutoImplementedProperty, this.Location, this);
            }

            base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData);
        }
Example #33
0
        internal override void PostDecodeWellKnownAttributes(ImmutableArray <CSharpAttributeData> boundAttributes, ImmutableArray <AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
        {
            Debug.Assert(!boundAttributes.IsDefault);
            Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
            Debug.Assert(boundAttributes.Length == allAttributeSyntaxNodes.Length);
            Debug.Assert(_lazyCustomAttributesBag != null);
            Debug.Assert(_lazyCustomAttributesBag.IsDecodedWellKnownAttributeDataComputed);
            Debug.Assert(symbolPart == AttributeLocation.None);

            var data = (CommonParameterWellKnownAttributeData)decodedData;

            if (data != null)
            {
                switch (RefKind)
                {
                case RefKind.Ref:
                    if (data.HasOutAttribute && !data.HasInAttribute)
                    {
                        // error CS0662: Cannot specify the Out attribute on a ref parameter without also specifying the In attribute.
                        diagnostics.Add(ErrorCode.ERR_OutAttrOnRefParam, this.Locations[0]);
                    }
                    break;

                case RefKind.Out:
                    if (data.HasInAttribute)
                    {
                        // error CS0036: An out parameter cannot have the In attribute.
                        diagnostics.Add(ErrorCode.ERR_InAttrOnOutParam, this.Locations[0]);
                    }
                    break;

                case RefKind.In:
                    if (data.HasOutAttribute)
                    {
                        // error CS8355: An in parameter cannot have the Out attribute.
                        diagnostics.Add(ErrorCode.ERR_OutAttrOnInParam, this.Locations[0]);
                    }
                    break;
                }
            }

            base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart, decodedData);
        }