internal override CSharpAttributeData EarlyDecodeWellKnownAttribute(ref EarlyDecodeWellKnownAttributeArguments <EarlyWellKnownAttributeBinder, NamedTypeSymbol, AttributeSyntax, AttributeLocation> arguments) { if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.DefaultParameterValueAttribute)) { return(EarlyDecodeAttributeForDefaultParameterValue(AttributeDescription.DefaultParameterValueAttribute, ref arguments)); } else if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.DecimalConstantAttribute)) { return(EarlyDecodeAttributeForDefaultParameterValue(AttributeDescription.DecimalConstantAttribute, ref arguments)); } else if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.DateTimeConstantAttribute)) { return(EarlyDecodeAttributeForDefaultParameterValue(AttributeDescription.DateTimeConstantAttribute, ref arguments)); } else if (!IsOnPartialImplementation(arguments.AttributeSyntax)) { if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.CallerLineNumberAttribute)) { arguments.GetOrCreateData <ParameterEarlyWellKnownAttributeData>().HasCallerLineNumberAttribute = true; } else if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.CallerFilePathAttribute)) { arguments.GetOrCreateData <ParameterEarlyWellKnownAttributeData>().HasCallerFilePathAttribute = true; } else if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.CallerMemberNameAttribute)) { arguments.GetOrCreateData <ParameterEarlyWellKnownAttributeData>().HasCallerMemberNameAttribute = true; } } return(base.EarlyDecodeWellKnownAttribute(ref arguments)); }
internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments <AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments) { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); var attribute = arguments.Attribute; Debug.Assert(!attribute.HasErrors); Debug.Assert(arguments.SymbolPart == AttributeLocation.None); if (attribute.IsTargetAttribute(this, AttributeDescription.DefaultCharSetAttribute)) { CharSet charSet = attribute.GetConstructorArgument <CharSet>(0, SpecialType.System_Enum); if (!ModuleWellKnownAttributeData.IsValidCharSet(charSet)) { CSharpSyntaxNode attributeArgumentSyntax = attribute.GetAttributeArgumentSyntax(0, arguments.AttributeSyntaxOpt); arguments.Diagnostics.Add(ErrorCode.ERR_InvalidAttributeArgument, attributeArgumentSyntax.Location, arguments.AttributeSyntaxOpt.GetErrorDisplayName()); } else { arguments.GetOrCreateData <ModuleWellKnownAttributeData>().DefaultCharacterSet = charSet; } } else if (attribute.IsTargetAttribute(this, AttributeDescription.NullableContextAttribute)) { ReportExplicitUseOfNullabilityAttribute(in arguments, AttributeDescription.NullableContextAttribute); } else if (attribute.IsTargetAttribute(this, AttributeDescription.NullablePublicOnlyAttribute)) { ReportExplicitUseOfNullabilityAttribute(in arguments, AttributeDescription.NullablePublicOnlyAttribute); } else if (attribute.IsTargetAttribute(this, AttributeDescription.SkipLocalsInitAttribute)) { CSharpAttributeData.DecodeSkipLocalsInitAttribute <ModuleWellKnownAttributeData>(DeclaringCompilation, ref arguments); } }
internal sealed override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments <AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments) { var attribute = arguments.Attribute; Debug.Assert(!attribute.HasErrors); Debug.Assert(arguments.SymbolPart == AttributeLocation.None); if (attribute.IsTargetAttribute(this, AttributeDescription.SpecialNameAttribute)) { arguments.GetOrCreateData <CommonEventWellKnownAttributeData>().HasSpecialNameAttribute = true; } else if (attribute.IsTargetAttribute(this, AttributeDescription.NullableAttribute)) { // NullableAttribute should not be set explicitly. RoslynDebug.AssertNotNull(arguments.AttributeSyntaxOpt); arguments.Diagnostics.Add(ErrorCode.ERR_ExplicitNullableAttribute, arguments.AttributeSyntaxOpt.Location); } else if (attribute.IsTargetAttribute(this, AttributeDescription.ExcludeFromCodeCoverageAttribute)) { arguments.GetOrCreateData <CommonEventWellKnownAttributeData>().HasExcludeFromCodeCoverageAttribute = true; } else if (attribute.IsTargetAttribute(this, AttributeDescription.TupleElementNamesAttribute)) { RoslynDebug.AssertNotNull(arguments.AttributeSyntaxOpt); arguments.Diagnostics.Add(ErrorCode.ERR_ExplicitTupleElementNamesAttribute, arguments.AttributeSyntaxOpt.Location); } else if (attribute.IsTargetAttribute(this, AttributeDescription.SkipLocalsInitAttribute)) { CSharpAttributeData.DecodeSkipLocalsInitAttribute <CommonEventWellKnownAttributeData>(DeclaringCompilation, ref arguments); } }
internal override void EarlyDecodeWellKnownAttributeType(NamedTypeSymbol attributeType, AttributeSyntax attributeSyntax) { Debug.Assert(!attributeType.IsErrorType()); // NOTE: OptionalAttribute is decoded specially before any of the other attributes and stored in the parameter // symbol (rather than in the EarlyWellKnownAttributeData) because it is needed during overload resolution. if (CSharpAttributeData.IsTargetEarlyAttribute(attributeType, attributeSyntax, AttributeDescription.OptionalAttribute)) { lazyHasOptionalAttribute = ThreeState.True; } }
internal bool EarlyDecodeDeprecatedOrObsoleteAttribute( ref EarlyDecodeWellKnownAttributeArguments<EarlyWellKnownAttributeBinder, NamedTypeSymbol, AttributeSyntax, AttributeLocation> arguments, out CSharpAttributeData attributeData, out ObsoleteAttributeData obsoleteData) { bool hasAnyDiagnostics; if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.ObsoleteAttribute)) { attributeData = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, out hasAnyDiagnostics); if (!attributeData.HasErrors) { obsoleteData = attributeData.DecodeObsoleteAttribute(); if (hasAnyDiagnostics) { attributeData = null; } } else { obsoleteData = null; attributeData = null; } return true; } if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.DeprecatedAttribute)) { attributeData = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, out hasAnyDiagnostics); if (!attributeData.HasErrors) { obsoleteData = attributeData.DecodeDeprecatedAttribute(); if (hasAnyDiagnostics) { attributeData = null; } } else { obsoleteData = null; attributeData = null; } return true; } obsoleteData = null; attributeData = null; return false; }
// Method to bind all attributes (attribute arguments and constructor) internal static void GetAttributes( ImmutableArray<Binder> binders, ImmutableArray<AttributeSyntax> attributesToBind, ImmutableArray<NamedTypeSymbol> boundAttributeTypes, CSharpAttributeData[] attributesBuilder, DiagnosticBag diagnostics) { Debug.Assert(binders.Any()); Debug.Assert(attributesToBind.Any()); Debug.Assert(boundAttributeTypes.Any()); Debug.Assert(binders.Length == attributesToBind.Length); Debug.Assert(boundAttributeTypes.Length == attributesToBind.Length); Debug.Assert(attributesBuilder != null); for (int i = 0; i < attributesToBind.Length; i++) { AttributeSyntax attributeSyntax = attributesToBind[i]; NamedTypeSymbol boundAttributeType = boundAttributeTypes[i]; Binder binder = binders[i]; var attribute = (SourceAttributeData)attributesBuilder[i]; if (attribute == null) { attributesBuilder[i] = binder.GetAttribute(attributeSyntax, boundAttributeType, diagnostics); } else { // attributesBuilder might contain some early bound well-known attributes, which had no errors. // We don't rebind the early bound attributes, but need to compute isConditionallyOmitted. // Note that AttributeData.IsConditionallyOmitted is required only during emit, but must be computed here as // its value depends on the values of conditional symbols, which in turn depends on the source file where the attribute is applied. Debug.Assert(!attribute.HasErrors); HashSet<DiagnosticInfo> useSiteDiagnostics = null; bool isConditionallyOmitted = binder.IsAttributeConditionallyOmitted(attribute.AttributeClass, attributeSyntax.SyntaxTree, ref useSiteDiagnostics); diagnostics.Add(attributeSyntax, useSiteDiagnostics); attributesBuilder[i] = attribute.WithOmittedCondition(isConditionallyOmitted); } } }
private void ValidateConditionalAttribute(CSharpAttributeData attribute, AttributeSyntax node, DiagnosticBag diagnostics) { Debug.Assert(this.IsConditional); Debug.Assert(!attribute.HasErrors); if (!this.DeclaringCompilation.IsAttributeType(this)) { // CS1689: Attribute '{0}' is only valid on methods or attribute classes diagnostics.Add(ErrorCode.ERR_ConditionalOnNonAttributeClass, node.Location, node.GetErrorDisplayName()); } else { string name = attribute.GetConstructorArgument <string>(0, SpecialType.System_String); if (name == null || !SyntaxFacts.IsValidIdentifier(name)) { // CS0633: The argument to the '{0}' attribute must be a valid identifier CSharpSyntaxNode attributeArgumentSyntax = attribute.GetAttributeArgumentSyntax(0, node); diagnostics.Add(ErrorCode.ERR_BadArgumentToAttribute, attributeArgumentSyntax.Location, node.GetErrorDisplayName()); } } }
// 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); } }
private void ValidateIndexerNameAttribute(CSharpAttributeData attribute, AttributeSyntax node, DiagnosticBag diagnostics) { if (!this.IsIndexer || this.IsExplicitInterfaceImplementation) { diagnostics.Add(ErrorCode.ERR_BadIndexerNameAttr, node.Name.Location, node.GetErrorDisplayName()); } else { string indexerName = attribute.CommonConstructorArguments[0].DecodeValue<string>(SpecialType.System_String); if (indexerName == null || !SyntaxFacts.IsValidIdentifier(indexerName)) { diagnostics.Add(ErrorCode.ERR_BadArgumentToAttribute, node.ArgumentList.Arguments[0].Location, node.GetErrorDisplayName()); } } }
/// <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; }
/// <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; }
/// <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 static string?DecodeNotNullIfNotNullAttribute(this CSharpAttributeData attribute) { var arguments = attribute.CommonConstructorArguments; return(arguments.Length == 1 && arguments[0].TryDecodeValue(SpecialType.System_String, out string?value) ? value : null); }
private void VerifySynthesizedDebuggableAttribute(CSharpAttributeData attribute, SourceAssemblySymbol sourceAssembly, OptimizationLevel optimizations) { var expectedDebuggingMode = DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints; if (optimizations == OptimizationLevel.Debug) { expectedDebuggingMode |= DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.EnableEditAndContinue; } VerifyDebuggableAttribute(attribute, sourceAssembly, expectedDebuggingMode); }
private void VerifyRuntimeCompatibilityAttribute(CSharpAttributeData attribute, SourceAssemblySymbol sourceAssembly, bool isSynthesized) { ModuleSymbol module = sourceAssembly.Modules[0]; NamespaceSymbol compilerServicesNS = Get_System_Runtime_CompilerServices_NamespaceSymbol(module); NamedTypeSymbol runtimeCompatibilityAttrType = compilerServicesNS.GetTypeMember("RuntimeCompatibilityAttribute"); var runtimeCompatibilityCtor = (MethodSymbol)sourceAssembly.DeclaringCompilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_RuntimeCompatibilityAttribute__ctor); Assert.Equal(runtimeCompatibilityAttrType, attribute.AttributeClass); Assert.Equal(runtimeCompatibilityCtor, attribute.AttributeConstructor); Assert.Equal(0, attribute.CommonConstructorArguments.Length); if (isSynthesized) { Assert.Equal(1, attribute.CommonNamedArguments.Length); attribute.VerifyNamedArgumentValue<bool>(0, "WrapNonExceptionThrows", TypedConstantKind.Primitive, true); } else { Assert.Equal(0, attribute.CommonNamedArguments.Length); } }
private ConstantValue DecodeDefaultParameterValueAttribute(AttributeDescription description, CSharpAttributeData attribute, AttributeSyntax node, bool diagnose, DiagnosticBag diagnosticsOpt) { Debug.Assert(!attribute.HasErrors); if (description.Equals(AttributeDescription.DefaultParameterValueAttribute)) { return DecodeDefaultParameterValueAttribute(attribute, node, diagnose, diagnosticsOpt); } else if (description.Equals(AttributeDescription.DecimalConstantAttribute)) { return attribute.DecodeDecimalConstantValue(); } else { Debug.Assert(description.Equals(AttributeDescription.DateTimeConstantAttribute)); return attribute.DecodeDateTimeConstantValue(); } }
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)); }
private void ValidateConditionalAttribute(CSharpAttributeData attribute, AttributeSyntax node, DiagnosticBag diagnostics) { Debug.Assert(this.IsConditional); Debug.Assert(!attribute.HasErrors); if (!this.DeclaringCompilation.IsAttributeType(this)) { // CS1689: Attribute '{0}' is only valid on methods or attribute classes diagnostics.Add(ErrorCode.ERR_ConditionalOnNonAttributeClass, node.Location, node.GetErrorDisplayName()); } else { string name = attribute.GetConstructorArgument<string>(0, SpecialType.System_String); if (name == null || !SyntaxFacts.IsValidIdentifier(name)) { // CS0633: The argument to the '{0}' attribute must be a valid identifier CSharpSyntaxNode attributeArgumentSyntax = attribute.GetAttributeArgumentSyntax(0, node); diagnostics.Add(ErrorCode.ERR_BadArgumentToAttribute, attributeArgumentSyntax.Location, node.GetErrorDisplayName()); } } }
// 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; } }
private void ValidateConditionalAttribute(CSharpAttributeData attribute, AttributeSyntax node, DiagnosticBag diagnostics) { Debug.Assert(this.IsConditional); if (this.IsAccessor()) { // CS1667: Attribute '{0}' is not valid on property or event accessors. It is only valid on '{1}' declarations. AttributeUsageInfo attributeUsage = attribute.AttributeClass.GetAttributeUsageInfo(); diagnostics.Add(ErrorCode.ERR_AttributeNotOnAccessor, node.Name.Location, node.GetErrorDisplayName(), attributeUsage.GetValidTargetsString()); } else if (this.ContainingType.IsInterfaceType()) { // CS0582: The Conditional attribute is not valid on interface members diagnostics.Add(ErrorCode.ERR_ConditionalOnInterfaceMethod, node.Location); } else if (this.IsOverride) { // CS0243: The Conditional attribute is not valid on '{0}' because it is an override method diagnostics.Add(ErrorCode.ERR_ConditionalOnOverride, node.Location, this); } else if (!this.CanBeReferencedByName || this.MethodKind == MethodKind.Destructor) { // CS0577: The Conditional attribute is not valid on '{0}' because it is a constructor, destructor, operator, or explicit interface implementation diagnostics.Add(ErrorCode.ERR_ConditionalOnSpecialMethod, node.Location, this); } else if (!this.ReturnsVoid) { // CS0578: The Conditional attribute is not valid on '{0}' because its return type is not void diagnostics.Add(ErrorCode.ERR_ConditionalMustReturnVoid, node.Location, this); } else if (this.HasAnyOutParameter()) { // CS0685: Conditional member '{0}' cannot have an out parameter diagnostics.Add(ErrorCode.ERR_ConditionalWithOutParam, node.Location, this); } else { string name = attribute.GetConstructorArgument<string>(0, SpecialType.System_String); if (name == null || !SyntaxFacts.IsValidIdentifier(name)) { // CS0633: The argument to the '{0}' attribute must be a valid identifier CSharpSyntaxNode attributeArgumentSyntax = attribute.GetAttributeArgumentSyntax(0, node); diagnostics.Add(ErrorCode.ERR_BadArgumentToAttribute, attributeArgumentSyntax.Location, node.GetErrorDisplayName()); } } }
internal static void VerifyUnverifiableCodeAttribute(CSharpAttributeData moduleAttribute, CSharpCompilation compilation) { Assert.Equal(compilation.GetWellKnownType(WellKnownType.System_Security_UnverifiableCodeAttribute), moduleAttribute.AttributeClass); Assert.Equal(compilation.GetWellKnownTypeMember(WellKnownMember.System_Security_UnverifiableCodeAttribute__ctor), moduleAttribute.AttributeConstructor); Assert.Equal(0, moduleAttribute.CommonConstructorArguments.Length); Assert.Equal(0, moduleAttribute.CommonNamedArguments.Length); }
private bool TryGetAttributeWarningLocation(CSharpAttributeData attribute, out Location location) { SyntaxReference syntaxRef = attribute.ApplicationSyntaxReference; if (syntaxRef == null && _filterTree == null) { location = NoLocation.Singleton; return true; } else if (_filterTree == null || (syntaxRef != null && syntaxRef.SyntaxTree == _filterTree)) { System.Diagnostics.Debug.Assert(syntaxRef.SyntaxTree.HasCompilationUnitRoot); location = new SourceLocation(syntaxRef); return true; } location = null; return false; }
private void VerifyCompilationRelaxationsAttribute(CSharpAttributeData attribute, SourceAssemblySymbol sourceAssembly, bool isSynthesized) { ModuleSymbol module = sourceAssembly.Modules[0]; NamespaceSymbol compilerServicesNS = Get_System_Runtime_CompilerServices_NamespaceSymbol(module); NamedTypeSymbol compilationRelaxationsAttrType = compilerServicesNS.GetTypeMember("CompilationRelaxationsAttribute"); var compilationRelaxationsCtor = (MethodSymbol)sourceAssembly.DeclaringCompilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_CompilationRelaxationsAttribute__ctorInt32); Assert.Equal(compilationRelaxationsAttrType, attribute.AttributeClass); Assert.Equal(compilationRelaxationsCtor, attribute.AttributeConstructor); int expectedArgValue = isSynthesized ? (int)CompilationRelaxations.NoStringInterning : 0; Assert.Equal(1, attribute.CommonConstructorArguments.Length); attribute.VerifyValue<int>(0, TypedConstantKind.Primitive, expectedArgValue); Assert.Equal(0, attribute.CommonNamedArguments.Length); }
private ConstantValue DecodeDefaultParameterValueAttribute(AttributeDescription description, CSharpAttributeData attribute, AttributeSyntax node, bool diagnose, DiagnosticBag diagnosticsOpt) { Debug.Assert(!attribute.HasErrors); if (description.Equals(AttributeDescription.DefaultParameterValueAttribute)) { return(DecodeDefaultParameterValueAttribute(attribute, node, diagnose, diagnosticsOpt)); } else if (description.Equals(AttributeDescription.DecimalConstantAttribute)) { return(attribute.DecodeDecimalConstantValue()); } else { Debug.Assert(description.Equals(AttributeDescription.DateTimeConstantAttribute)); return(attribute.DecodeDateTimeConstantValue()); } }
// NYI: /addmodule support // TODO: Add tests for assembly attributes emitted into netmodules which suppress synthesized CompilationRelaxationsAttribute/RuntimeCompatibilityAttribute #endregion #region DebuggableAttribute private void VerifyDebuggableAttribute(CSharpAttributeData attribute, SourceAssemblySymbol sourceAssembly, DebuggableAttribute.DebuggingModes expectedDebuggingMode) { ModuleSymbol module = sourceAssembly.Modules[0]; NamespaceSymbol diagnosticsNS = Get_System_Diagnostics_NamespaceSymbol(module); NamedTypeSymbol debuggableAttributeType = diagnosticsNS.GetTypeMember("DebuggableAttribute"); var debuggableAttributeCtor = (MethodSymbol)sourceAssembly.DeclaringCompilation.GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute__ctorDebuggingModes); Assert.Equal(debuggableAttributeType, attribute.AttributeClass); Assert.Equal(debuggableAttributeCtor, attribute.AttributeConstructor); Assert.Equal(1, attribute.CommonConstructorArguments.Length); attribute.VerifyValue(0, TypedConstantKind.Enum, (int)expectedDebuggingMode); Assert.Equal(0, attribute.CommonNamedArguments.Length); }
private ConstantValue DecodeDefaultParameterValueAttribute(CSharpAttributeData attribute, AttributeSyntax node, bool diagnose, DiagnosticBag diagnosticsOpt) { Debug.Assert(!diagnose || diagnosticsOpt != null); if (HasDefaultArgumentSyntax) { // error CS1745: Cannot specify default parameter value in conjunction with DefaultParameterAttribute or OptionalAttribute if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueUsedWithAttributes, node.Name.Location); } return(ConstantValue.Bad); } // BREAK: In dev10, DefaultParameterValueAttribute could not be applied to System.Type or array parameters. // When this was attempted, dev10 produced CS1909, ERR_DefaultValueBadParamType. Roslyn takes a different // approach: instead of looking at the parameter type, we look at the argument type. There's nothing wrong // with providing a default value for a System.Type or array parameter, as long as the default parameter // is not a System.Type or an array (i.e. null is fine). Since we are no longer interested in the type of // the parameter, all occurrences of CS1909 have been replaced with CS1910, ERR_DefaultValueBadValueType, // to indicate that the argument type, rather than the parameter type, is the source of the problem. Debug.Assert(attribute.CommonConstructorArguments.Length == 1); // the type of the value is the type of the expression in the attribute: var arg = attribute.CommonConstructorArguments[0]; SpecialType specialType = arg.Kind == TypedConstantKind.Enum ? ((INamedTypeSymbol)arg.Type).EnumUnderlyingType.SpecialType : arg.Type.SpecialType; var compilation = this.DeclaringCompilation; var constantValueDiscriminator = ConstantValue.GetDiscriminator(specialType); HashSet <DiagnosticInfo> useSiteDiagnostics = null; if (constantValueDiscriminator == ConstantValueTypeDiscriminator.Bad) { if (arg.Kind != TypedConstantKind.Array && arg.Value == null) { if (this.Type.IsReferenceType) { constantValueDiscriminator = ConstantValueTypeDiscriminator.Null; } else { // error CS1908: The type of the argument to the DefaultParameterValue attribute must match the parameter type if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueTypeMustMatch, node.Name.Location); } return(ConstantValue.Bad); } } else { // error CS1910: Argument of type '{0}' is not applicable for the DefaultParameterValue attribute if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueBadValueType, node.Name.Location, arg.Type); } return(ConstantValue.Bad); } } else if (!compilation.Conversions.ClassifyConversion((TypeSymbol)arg.Type, this.Type, ref useSiteDiagnostics).Kind.IsImplicitConversion()) { // error CS1908: The type of the argument to the DefaultParameterValue attribute must match the parameter type if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueTypeMustMatch, node.Name.Location); diagnosticsOpt.Add(node.Name.Location, useSiteDiagnostics); } return(ConstantValue.Bad); } if (diagnose) { diagnosticsOpt.Add(node.Name.Location, useSiteDiagnostics); } return(ConstantValue.Create(arg.Value, constantValueDiscriminator)); }
private void VerifySynthesizedDebuggableAttribute(CSharpAttributeData attribute, SourceAssemblySymbol sourceAssembly, DebugInformationKind emitDebugInfoKind, bool optimizationsEnabled) { Assert.NotEqual(DebugInformationKind.None, emitDebugInfoKind); var expectedDebuggingMode = DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints; bool emittingFullDebugInfo = emitDebugInfoKind == DebugInformationKind.Full; if (emittingFullDebugInfo) { expectedDebuggingMode |= DebuggableAttribute.DebuggingModes.Default; } if (!optimizationsEnabled) { expectedDebuggingMode |= DebuggableAttribute.DebuggingModes.DisableOptimizations; if (emittingFullDebugInfo) { expectedDebuggingMode |= DebuggableAttribute.DebuggingModes.EnableEditAndContinue; } } VerifyDebuggableAttribute(attribute, sourceAssembly, expectedDebuggingMode); }
private ConstantValue DecodeDefaultParameterValueAttribute(CSharpAttributeData attribute, AttributeSyntax node, bool diagnose, DiagnosticBag diagnosticsOpt) { Debug.Assert(!diagnose || diagnosticsOpt != null); if (HasDefaultArgumentSyntax) { // error CS1745: Cannot specify default parameter value in conjunction with DefaultParameterAttribute or OptionalAttribute if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueUsedWithAttributes, node.Name.Location); } return ConstantValue.Bad; } // BREAK: In dev10, DefaultParameterValueAttribute could not be applied to System.Type or array parameters. // When this was attempted, dev10 produced CS1909, ERR_DefaultValueBadParamType. Roslyn takes a different // approach: instead of looking at the parameter type, we look at the argument type. There's nothing wrong // with providing a default value for a System.Type or array parameter, as long as the default parameter // is not a System.Type or an array (i.e. null is fine). Since we are no longer interested in the type of // the parameter, all occurrences of CS1909 have been replaced with CS1910, ERR_DefaultValueBadValueType, // to indicate that the argument type, rather than the parameter type, is the source of the problem. Debug.Assert(attribute.CommonConstructorArguments.Length == 1); // the type of the value is the type of the expression in the attribute: var arg = attribute.CommonConstructorArguments[0]; SpecialType specialType = arg.Kind == TypedConstantKind.Enum ? ((INamedTypeSymbol)arg.Type).EnumUnderlyingType.SpecialType : arg.Type.SpecialType; var compilation = this.DeclaringCompilation; var constantValueDiscriminator = ConstantValue.GetDiscriminator(specialType); HashSet<DiagnosticInfo> useSiteDiagnostics = null; if (constantValueDiscriminator == ConstantValueTypeDiscriminator.Bad) { if (arg.Kind != TypedConstantKind.Array && arg.Value == null) { if (this.Type.IsReferenceType) { constantValueDiscriminator = ConstantValueTypeDiscriminator.Null; } else { // error CS1908: The type of the argument to the DefaultParameterValue attribute must match the parameter type if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueTypeMustMatch, node.Name.Location); } return ConstantValue.Bad; } } else { // error CS1910: Argument of type '{0}' is not applicable for the DefaultParameterValue attribute if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueBadValueType, node.Name.Location, arg.Type); } return ConstantValue.Bad; } } else if (!compilation.Conversions.ClassifyConversion((TypeSymbol)arg.Type, this.Type, ref useSiteDiagnostics).Kind.IsImplicitConversion()) { // error CS1908: The type of the argument to the DefaultParameterValue attribute must match the parameter type if (diagnose) { diagnosticsOpt.Add(ErrorCode.ERR_DefaultValueTypeMustMatch, node.Name.Location); diagnosticsOpt.Add(node.Name.Location, useSiteDiagnostics); } return ConstantValue.Bad; } if (diagnose) { diagnosticsOpt.Add(node.Name.Location, useSiteDiagnostics); } return ConstantValue.Create(arg.Value, constantValueDiscriminator); }