public static void VerifyValue <T>(this CSharpAttributeData attr, int i, TypedConstantKind kind, T v) { var arg = attr.CommonConstructorArguments[i]; Assert.Equal(kind, arg.Kind); Assert.True(IsEqual(arg, v)); }
internal TypedConstant(ITypeSymbol type, TypedConstantKind kind, object value) { Debug.Assert(kind == TypedConstantKind.Array || !(value is ImmutableArray <TypedConstant>)); _kind = kind; _type = type; _value = value; }
public TypedConstant(ITypeSymbol type, TypedConstantKind kind, object value) { Debug.Assert(kind == TypedConstantKind.Array || !(value is TypedConstant[])); _kind = kind; _type = type; _value = value; }
internal TypedConstant(ITypeSymbolInternal?type, TypedConstantKind kind, object?value) { Debug.Assert(kind == TypedConstantKind.Array || !(value is ImmutableArray <TypedConstant>)); Debug.Assert(!(value is ISymbol) || value is ISymbolInternal); Debug.Assert(type is object || kind == TypedConstantKind.Error); _kind = kind; _type = type; _value = value; }
public static void VerifyNamedArgumentValue <T>( this CSharpAttributeData attr, int i, string name, TypedConstantKind kind, T v ) { var namedArg = attr.CommonNamedArguments[i]; Assert.Equal(namedArg.Key, name); var arg = namedArg.Value; Assert.Equal(arg.Kind, kind); Assert.True(IsEqual(arg, v)); }
private TypedConstant VisitExpression(BoundExpression node, TypedConstantKind typedConstantKind, DiagnosticBag diagnostics, ref bool attrHasErrors, bool curArgumentHasErrors) { // Validate Statement 2) of the spec comment above. ConstantValue constantValue = node.ConstantValue; if (constantValue != null) { if (constantValue.IsBad) { typedConstantKind = TypedConstantKind.Error; } return CreateTypedConstant(node, typedConstantKind, diagnostics, ref attrHasErrors, curArgumentHasErrors, simpleValue: node.ConstantValue.Value); } switch (node.Kind) { case BoundKind.Conversion: return VisitConversion((BoundConversion)node, diagnostics, ref attrHasErrors, curArgumentHasErrors); case BoundKind.TypeOfOperator: return VisitTypeOfExpression((BoundTypeOfOperator)node, diagnostics, ref attrHasErrors, curArgumentHasErrors); case BoundKind.ArrayCreation: return VisitArrayCreation((BoundArrayCreation)node, diagnostics, ref attrHasErrors, curArgumentHasErrors); default: return CreateTypedConstant(node, TypedConstantKind.Error, diagnostics, ref attrHasErrors, curArgumentHasErrors); } }
private static TypedConstant CreateTypedConstant(BoundExpression node, TypedConstantKind typedConstantKind, DiagnosticBag diagnostics, ref bool attrHasErrors, bool curArgumentHasErrors, object simpleValue = null, ImmutableArray<TypedConstant> arrayValue = default(ImmutableArray<TypedConstant>)) { var type = node.Type; if (typedConstantKind != TypedConstantKind.Error && type.ContainsTypeParameter()) { // Devdiv Bug #12636: Constant values of open types should not be allowed in attributes // SPEC ERROR: C# language specification does not explicitly disallow constant values of open types. For e.g. // public class C<T> // { // public enum E { V } // } // // [SomeAttr(C<T>.E.V)] // case (a): Constant value of open type. // [SomeAttr(C<int>.E.V)] // case (b): Constant value of constructed type. // Both expressions 'C<T>.E.V' and 'C<int>.E.V' satisfy the requirements for a valid attribute-argument-expression: // (a) Its type is a valid attribute parameter type as per section 17.1.3 of the specification. // (b) It has a compile time constant value. // However, native compiler disallows both the above cases. // We disallow case (a) as it cannot be serialized correctly, but allow case (b) to compile. typedConstantKind = TypedConstantKind.Error; } if (typedConstantKind == TypedConstantKind.Error) { if (!curArgumentHasErrors) { Binder.Error(diagnostics, ErrorCode.ERR_BadAttributeArgument, node.Syntax); attrHasErrors = true; } return new TypedConstant(type, TypedConstantKind.Error, null); } else if (typedConstantKind == TypedConstantKind.Array) { return new TypedConstant(type, arrayValue); } else { return new TypedConstant(type, typedConstantKind, simpleValue); } }
public static TypedConstant CreateTypedConstant(ITypeSymbol typeSymbol, TypedConstantKind kind, object?value) => createTypeConstant(typeSymbol, kind, value);
/// <summary> /// Gets the typed constant kind for the given attribute parameter type. /// </summary> /// <param name="type">Type to validated</param> /// <param name="compilation">compilation</param> /// <returns>TypedConstantKind for the attribute parameter type.</returns> public static TypedConstantKind GetAttributeParameterTypedConstantKind(this TypeSymbol type, CSharpCompilation compilation) { // Spec (17.1.3) // The types of positional and named parameters for an attribute class are limited to the attribute parameter types, which are: // 1) One of the following types: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort. // 2) The type object. // 3) The type System.Type. // 4) An enum type, provided it has public accessibility and the types in which it is nested (if any) also have public accessibility. // 5) Single-dimensional arrays of the above types. // A constructor argument or public field which does not have one of these types, cannot be used as a positional // or named parameter in an attribute specification. TypedConstantKind kind = TypedConstantKind.Error; if ((object)type == null) { return(TypedConstantKind.Error); } if (type.Kind == SymbolKind.ArrayType) { var arrayType = (ArrayTypeSymbol)type; if (arrayType.Rank != 1) { return(TypedConstantKind.Error); } kind = TypedConstantKind.Array; type = arrayType.ElementType; } // enum or enum[] if (type.IsEnumType()) { // SPEC VIOLATION: Dev11 doesn't enforce either the Enum type or its enclosing types (if any) to have public accessibility. // We will be consistent with Dev11 behavior. if (kind == TypedConstantKind.Error) { // set only if kind is not already set (i.e. its not an array of enum) kind = TypedConstantKind.Enum; } type = type.GetEnumUnderlyingType(); } var typedConstantKind = TypedConstant.GetTypedConstantKind(type, compilation); switch (typedConstantKind) { case TypedConstantKind.Array: case TypedConstantKind.Enum: case TypedConstantKind.Error: return(TypedConstantKind.Error); default: if (kind == TypedConstantKind.Array || kind == TypedConstantKind.Enum) { // Array/Enum type with valid element/underlying type return(kind); } return(typedConstantKind); } }