/// <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); }
private static string ResolveAttribute(AttributeUsageInfo info, bool single = true) { var attribute = info.Name; if (!string.IsNullOrWhiteSpace(info.InitializationString)) { attribute = string.Format("{0}({1})", attribute, info.InitializationString); } if (single) { attribute = string.Format("[{0}]", attribute); } return(attribute); }
// Process the specified AttributeUsage attribute on the given ownerSymbol private void ProcessAttributeUsageAttribute(SourceAttributeData attributeUsageAttribute, Symbol ownerSymbol, AttributeSyntax node, DiagnosticBag diagnostics) { // Validate first ctor argument for AtributeUsage specification is a valid AttributeTargets enum member Debug.Assert(attributeUsageAttribute.AttributeConstructor == GetWellKnownTypeMember(WellKnownMember.System_AttributeUsageAttribute__ctor, diagnostics, node)); var targetArgument = (int)attributeUsageAttribute.PositionalArguments[0].Value; if (!AttributeUsageInfo.IsValidValueForAttributeTargets(targetArgument)) { // invalid attribute target Error(diagnostics, ErrorCode.ERR_InvalidAttributeArgument, node.ArgumentList.Arguments[0], GetAttributeNameFromSyntax(node)); } // AttributeUsage can only be specified for attribute classes if (ownerSymbol.Kind == SymbolKind.NamedType && !((NamedTypeSymbol)ownerSymbol).IsAttributeType(Compilation)) { Error(diagnostics, ErrorCode.ERR_AttributeUsageOnNonAttributeClass, node, GetAttributeNameFromSyntax(node)); } }
// Process the specified AttributeUsage attribute on the given ownerSymbol private AttributeUsageInfo DecodeAttributeUsageAttribute(CSharpAttributeData attribute, AttributeSyntax node, bool diagnose, DiagnosticBag diagnosticsOpt = null) { Debug.Assert(diagnose == (diagnosticsOpt != null)); Debug.Assert(!attribute.HasErrors); Debug.Assert(!this.IsErrorType()); // AttributeUsage can only be specified for attribute classes if (!this.DeclaringCompilation.IsAttributeType(this)) { if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_AttributeUsageOnNonAttributeClass, node.Name.Location, node.GetErrorDisplayName()); } return(AttributeUsageInfo.Null); } else { AttributeUsageInfo info = attribute.DecodeAttributeUsageAttribute(); // Validate first ctor argument for AtributeUsage specification is a valid AttributeTargets enum member if (!info.HasValidAttributeTargets) { if (diagnose) { // invalid attribute target CSharpSyntaxNode attributeArgumentSyntax = attribute.GetAttributeArgumentSyntax(0, node); diagnosticsOpt.Add(ErrorCode.ERR_InvalidAttributeArgument, attributeArgumentSyntax.Location, node.GetErrorDisplayName()); } return(AttributeUsageInfo.Null); } return(info); } }
internal override CSharpAttributeData EarlyDecodeWellKnownAttribute(ref EarlyDecodeWellKnownAttributeArguments <EarlyWellKnownAttributeBinder, NamedTypeSymbol, AttributeSyntax, AttributeLocation> arguments) { bool hasAnyDiagnostics; CSharpAttributeData boundAttribute; if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.ComImportAttribute)) { boundAttribute = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, out hasAnyDiagnostics); if (!boundAttribute.HasErrors) { arguments.GetOrCreateData <CommonTypeEarlyWellKnownAttributeData>().HasComImportAttribute = true; if (!hasAnyDiagnostics) { return(boundAttribute); } } return(null); } if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.ConditionalAttribute)) { boundAttribute = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, out hasAnyDiagnostics); if (!boundAttribute.HasErrors) { string name = boundAttribute.GetConstructorArgument <string>(0, SpecialType.System_String); arguments.GetOrCreateData <CommonTypeEarlyWellKnownAttributeData>().AddConditionalSymbol(name); if (!hasAnyDiagnostics) { return(boundAttribute); } } return(null); } ObsoleteAttributeData obsoleteData; if (EarlyDecodeDeprecatedOrObsoleteAttribute(ref arguments, out boundAttribute, out obsoleteData)) { if (obsoleteData != null) { arguments.GetOrCreateData <CommonTypeEarlyWellKnownAttributeData>().ObsoleteAttributeData = obsoleteData; } return(boundAttribute); } if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.AttributeUsageAttribute)) { boundAttribute = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, out hasAnyDiagnostics); if (!boundAttribute.HasErrors) { AttributeUsageInfo info = this.DecodeAttributeUsageAttribute(boundAttribute, arguments.AttributeSyntax, diagnose: false); if (!info.IsNull) { var typeData = arguments.GetOrCreateData <CommonTypeEarlyWellKnownAttributeData>(); if (typeData.AttributeUsageInfo.IsNull) { typeData.AttributeUsageInfo = info; } if (!hasAnyDiagnostics) { return(boundAttribute); } } } return(null); } return(base.EarlyDecodeWellKnownAttribute(ref arguments)); }
/// <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); }