public void Conversions() { TypedConstant common = new TypedConstant(systemType, TypedConstantKind.Type, namedType); TypedConstant lang = (TypedConstant)common; TypedConstant common2 = lang; Assert.Equal(common.Value, lang.Value); Assert.Equal(common.Kind, lang.Kind); Assert.Equal<object>(common.Type, lang.Type); Assert.Equal(common.Value, common2.Value); Assert.Equal(common.Kind, common2.Kind); Assert.Equal(common.Type, common2.Type); TypedConstant commonArray = new TypedConstant(arrayType, new[] { new TypedConstant(systemType, TypedConstantKind.Type, namedType) }.AsImmutableOrNull()); TypedConstant langArray = (TypedConstant)commonArray; TypedConstant commonArray2 = langArray; Assert.Equal(commonArray.Values.Single(), langArray.Values.Single()); Assert.Equal(commonArray.Kind, langArray.Kind); Assert.Equal<object>(commonArray.Type, langArray.Type); Assert.Equal(commonArray.Values, commonArray2.Values); Assert.Equal(commonArray.Kind, commonArray2.Kind); Assert.Equal(commonArray.Type, commonArray2.Type); }
internal override void AddSynthesizedAttributes(ModuleCompilationState compilationState, ref ArrayBuilder<SynthesizedAttributeData> attributes) { base.AddSynthesizedAttributes(compilationState, ref attributes); var compilation = this.DeclaringCompilation; var systemType = compilation.GetWellKnownType(WellKnownType.System_Type); var intType = compilation.GetSpecialType(SpecialType.System_Int32); var item1 = new TypedConstant(systemType, TypedConstantKind.Type, ((PointerTypeSymbol)this.Type).PointedAtType); var item2 = new TypedConstant(intType, TypedConstantKind.Primitive, this.FixedSize); AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute( WellKnownMember.System_Runtime_CompilerServices_FixedBufferAttribute__ctor, ImmutableArray.Create<TypedConstant>(item1, item2))); }
// Decode the value of enum constant private static string DisplayEnumConstant(TypedConstant constant) { Debug.Assert(constant.Kind == TypedConstantKind.Enum); // Create a ConstantValue of enum underlying type SpecialType splType = ((INamedTypeSymbol)constant.Type).EnumUnderlyingType.SpecialType; ConstantValue valueConstant = ConstantValue.Create(constant.Value, splType); string typeName = constant.Type.ToDisplayString(SymbolDisplayFormat.QualifiedNameOnlyFormat); if (valueConstant.IsUnsigned) { return DisplayUnsignedEnumConstant(constant, splType, valueConstant.UInt64Value, typeName); } else { return DisplaySignedEnumConstant(constant, splType, valueConstant.Int64Value, typeName); } }
private Cci.IMetadataExpression CreateMetadataExpression(TypedConstant argument, EmitContext context) { if (argument.IsNull) { return CreateMetadataConstant(argument.Type, null, context); } switch (argument.Kind) { case TypedConstantKind.Array: return CreateMetadataArray(argument, context); case TypedConstantKind.Type: return CreateType(argument, context); default: return CreateMetadataConstant(argument.Type, argument.Value, context); } }
private static string GetLiteralString(TypedConstant constant) { var type = constant.Type; var value = constant.Value; if (type.TypeKind == TypeKind.Enum) { var namedType = (INamedTypeSymbol)type; var pairs = (from member in namedType.GetMembers().OfType<IFieldSymbol>() where member.IsConst && member.HasConstantValue select Tuple.Create(member.Name, member.ConstantValue)).ToDictionary(tuple => tuple.Item2, tuple => tuple.Item1); return $"{VisitorHelper.GetId(namedType)}.{pairs[value]}"; } if (value is ITypeSymbol) { return VisitorHelper.GetId((ITypeSymbol)value); } return value.ToString(); }
private static ExpressionSyntax GetLiteralExpression(TypedConstant constant) { if (constant.Type.TypeKind == TypeKind.Array) { if (constant.Values == null) { return GetLiteralExpression(null, constant.Type); } var items = (from value in constant.Values select GetLiteralExpression(value)).ToList(); if (items.TrueForAll(x => x != null)) { return SyntaxFactory.ArrayCreationExpression( (ArrayTypeSyntax)GetTypeSyntax(constant.Type), SyntaxFactory.InitializerExpression( SyntaxKind.ArrayInitializerExpression, SyntaxFactory.SeparatedList( from value in constant.Values select GetLiteralExpression(value)))); } return SyntaxFactory.ArrayCreationExpression( (ArrayTypeSyntax)GetTypeSyntax(constant.Type)); } var expr = GetLiteralExpression(constant.Value, constant.Type); if (expr == null) { return null; } switch (constant.Type.SpecialType) { case SpecialType.System_SByte: return SyntaxFactory.CastExpression( SyntaxFactory.PredefinedType( SyntaxFactory.Token(SyntaxKind.SByteKeyword)), expr); case SpecialType.System_Byte: return SyntaxFactory.CastExpression( SyntaxFactory.PredefinedType( SyntaxFactory.Token(SyntaxKind.ByteKeyword)), expr); case SpecialType.System_Int16: return SyntaxFactory.CastExpression( SyntaxFactory.PredefinedType( SyntaxFactory.Token(SyntaxKind.ShortKeyword)), expr); case SpecialType.System_UInt16: return SyntaxFactory.CastExpression( SyntaxFactory.PredefinedType( SyntaxFactory.Token(SyntaxKind.UShortKeyword)), expr); default: return expr; } }
internal SynthesizedAttributeData SynthesizeDebuggableAttribute() { TypeSymbol debuggableAttribute = GetWellKnownType(WellKnownType.System_Diagnostics_DebuggableAttribute); Debug.Assert((object)debuggableAttribute != null, "GetWellKnownType unexpectedly returned null"); if (debuggableAttribute is MissingMetadataTypeSymbol) { return(null); } TypeSymbol debuggingModesType = GetWellKnownType(WellKnownType.System_Diagnostics_DebuggableAttribute__DebuggingModes); Debug.Assert((object)debuggingModesType != null, "GetWellKnownType unexpectedly returned null"); if (debuggingModesType is MissingMetadataTypeSymbol) { return(null); } var defaulDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__Default); if ((object)defaulDebuggingMode == null || !defaulDebuggingMode.HasConstantValue) { return(null); } var disableOptsDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__DisableOptimizations); if ((object)disableOptsDebuggingMode == null || !disableOptsDebuggingMode.HasConstantValue) { return(null); } var enableENCDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__EnableEditAndContinue); if ((object)enableENCDebuggingMode == null || !enableENCDebuggingMode.HasConstantValue) { return(null); } var ignorePDBDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__IgnoreSymbolStoreSequencePoints); if ((object)ignorePDBDebuggingMode == null || !ignorePDBDebuggingMode.HasConstantValue) { return(null); } Debug.Assert(options.DebugInformationKind.IsValid() && options.DebugInformationKind != DebugInformationKind.None); bool emittingFullDebugInfo = options.DebugInformationKind == DebugInformationKind.Full; bool optimizationsDisabled = !options.Optimize; int constantVal = ignorePDBDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value; if (emittingFullDebugInfo) { constantVal |= defaulDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value; } if (optimizationsDisabled) { constantVal |= disableOptsDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value; if (emittingFullDebugInfo) { constantVal |= enableENCDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value; } } var typedConstantDebugMode = new TypedConstant(debuggingModesType, TypedConstantKind.Enum, constantVal); return(SynthesizeAttribute( WellKnownMember.System_Diagnostics_DebuggableAttribute__ctorDebuggingModes, ImmutableArray.Create(typedConstantDebugMode))); }
static bool TryBindTypedConstant(TypeSymbol target, LangElement element, PhpCompilation compilation, out TypedConstant result) { if (element is LongIntLiteral llit) { return(TryBindTypedConstant(target, llit.Value, out result)); } if (element is DoubleLiteral dlit) { return(TryBindTypedConstant(target, dlit.Value, out result)); } if (element is StringLiteral slit) { return(TryBindTypedConstant(target, slit.Value, out result)); } if (element is TypeRef tref) { var system_type = compilation.GetWellKnownType(WellKnownType.System_Type); result = new TypedConstant(system_type, TypedConstantKind.Type, compilation.GetTypeFromTypeRef(tref)); return(target == system_type); } if (element is GlobalConstUse gconst) { var qname = gconst.FullName.Name.QualifiedName; if (qname.IsSimpleName) { // common constants if (qname == QualifiedName.True) { return(TryBindTypedConstant(target, true, out result)); } if (qname == QualifiedName.False) { return(TryBindTypedConstant(target, true, out result)); } if (qname == QualifiedName.Null) { return(TryBindTypedConstant(target, (object)null, out result)); } // lookup constant var csymbol = compilation.GlobalSemantics.ResolveConstant(qname.Name.Value); if (csymbol is FieldSymbol fld && fld.HasConstantValue) { return(TryBindTypedConstant(target, fld.ConstantValue, out result)); } } // note: namespaced constants are unreachable } if (element is ClassConstUse cconst) { // lookup the type container var ctype = compilation.GetTypeFromTypeRef(cconst.TargetType); if (ctype.IsValidType()) { // lookup constant/enum field (both are FieldSymbol) var member = ctype.LookupMember <FieldSymbol>(cconst.Name.Value); if (member != null && member.HasConstantValue) { return(TryBindTypedConstant(target, member.ConstantValue, out result)); } } } // result = default; return(false); }
private IMetadataExpression TranslateMetadata(TypedConstant typedConstant) { return new CompileTimeConstant() { Type = this.Map(typedConstant.Type), Value = typedConstant.Value, }; }
internal override void AddSynthesizedAttributes(ModuleCompilationState compilationState, ref ArrayBuilder<SynthesizedAttributeData> attributes) { base.AddSynthesizedAttributes(compilationState, ref attributes); if (this.IsAsync || this.IsIterator) { var compilation = this.DeclaringCompilation; // The async state machine type is not synthesized until the async method body is rewritten. If we are // only emitting metadata the method body will not have been rewritten, and the async state machine // type will not have been created. In this case, omit the attribute. NamedTypeSymbol stateMachineType; if (compilationState.TryGetStateMachineType(this, out stateMachineType)) { WellKnownMember ctor = this.IsAsync ? WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor : WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor; var arg = new TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type), TypedConstantKind.Type, stateMachineType.GetUnboundGenericTypeOrSelf()); AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(ctor, ImmutableArray.Create(arg))); } } }
private static string DisplayUnsignedEnumConstant(TypedConstant constant, SpecialType specialType, ulong constantToDecode, string typeName) { Debug.Assert(constant.Kind == TypedConstantKind.Enum); // Specified valueConstant might have an exact matching enum field // or it might be a bitwise Or of multiple enum fields. // For the later case, we keep track of the current value of // bitwise Or of possible enum fields. ulong curValue = 0; // Initialize the value string to empty PooledStringBuilder?pooledBuilder = null; StringBuilder? valueStringBuilder = null; // Iterate through all the constant members in the enum type var members = constant.Type !.GetMembers(); foreach (var member in members) { var field = member as IFieldSymbol; if (field is object && field.HasConstantValue) { ConstantValue memberConstant = ConstantValue.Create(field.ConstantValue !, specialType); // use MemberNotNull when available https://github.com/dotnet/roslyn/issues/41964 ulong memberValue = memberConstant.UInt64Value; // Do we have an exact matching enum field if (memberValue == constantToDecode) { if (pooledBuilder != null) { pooledBuilder.Free(); } return(typeName + "." + field.Name); } // specifiedValue might be a bitwise Or of multiple enum fields // Is the current member included in the specified value? if ((memberValue & constantToDecode) == memberValue) { // update the current value curValue = curValue | memberValue; if (valueStringBuilder == null) { pooledBuilder = PooledStringBuilder.GetInstance(); valueStringBuilder = pooledBuilder.Builder; } else { valueStringBuilder.Append(" | "); } valueStringBuilder.Append(typeName); valueStringBuilder.Append("."); valueStringBuilder.Append(field.Name); } } } if (pooledBuilder != null) { if (curValue == constantToDecode) { // return decoded enum constant return(pooledBuilder.ToStringAndFree()); } // Unable to decode the enum constant pooledBuilder.Free(); } // Unable to decode the enum constant, just display the integral value Debug.Assert(constant.ValueInternal is object); var result = constant.ValueInternal.ToString(); Debug.Assert(result is object); return(result); }
/// <summary> /// Initializes a new instance of the <see cref="AttributeArgumentSemantics"/> class. /// </summary> /// <param name="semanticObject">The Roslyn semantic object.</param> public AttributeArgumentSemantics(TypedConstant semanticObject) : base(semanticObject) { }
static void VerifyUnion(DiagnosticsReportContext context, Location callerLocation, ITypeSymbol type) { var unionKeys = type.GetMembers().OfType <IPropertySymbol>().Where(x => x.GetAttributes().FindAttributeShortName(UnionKeyAttributeShortName) != null).ToArray(); if (unionKeys.Length == 0) { context.Add(Diagnostic.Create(UnionTypeRequiresUnionKey, callerLocation, type.Locations, type.Name)); return; } else if (unionKeys.Length != 1) { context.Add(Diagnostic.Create(UnionKeyDoesNotAllowMultipleKey, callerLocation, type.Locations, type.Name)); return; } var unionKeyProperty = unionKeys[0]; if (type.TypeKind != TypeKind.Interface && !unionKeyProperty.GetMethod.IsAbstract) { context.Add(Diagnostic.Create(UnionTypeRequiresUnionKey, callerLocation, type.Locations, type.Name)); return; } var ctorArguments = type.GetAttributes().FindAttributeShortName(UnionAttributeShortName)?.ConstructorArguments; var firstArguments = ctorArguments?.FirstOrDefault(); if (firstArguments == null) { return; } TypedConstant fallbackType = default(TypedConstant); if (ctorArguments.Value.Length == 2) { fallbackType = ctorArguments.Value[1]; } if (type.TypeKind != TypeKind.Interface) { foreach (var item in firstArguments.Value.Values.Concat(new[] { fallbackType }).Where(x => !x.IsNull).Select(x => x.Value).OfType <ITypeSymbol>()) { var found = item.FindBaseTargetType(type.ToDisplayString()); if (found == null) { context.Add(Diagnostic.Create(AllUnionSubTypesMustBeInheritedType, callerLocation, type.Locations, type.Name, item.Name)); return; } } } else { foreach (var item in firstArguments.Value.Values.Concat(new[] { fallbackType }).Where(x => !x.IsNull).Select(x => x.Value).OfType <ITypeSymbol>()) { var typeString = type.ToDisplayString(); if (!(item as INamedTypeSymbol).AllInterfaces.Any(x => x.OriginalDefinition?.ToDisplayString() == typeString)) { context.Add(Diagnostic.Create(AllUnionSubTypesMustBeInheritedType, callerLocation, type.Locations, type.Name, item.Name)); return; } } } }
private static object GetItem(TypedConstant arg) => arg.Kind == TypedConstantKind.Array ? arg.Values : arg.Value;
private DeclarativeSecurityAction DecodeSecurityAttributeAction( Symbol targetSymbol, CSharpCompilation compilation, AttributeSyntax?nodeOpt, out bool hasErrors, BindingDiagnosticBag diagnostics ) { Debug.Assert((object)targetSymbol != null); Debug.Assert( targetSymbol.Kind == SymbolKind.Assembly || targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method ); Debug.Assert(this.IsSecurityAttribute(compilation)); var ctorArgs = this.CommonConstructorArguments; if (!ctorArgs.Any()) { // NOTE: Security custom attributes must have a valid SecurityAction as its first argument, we have none here. // NOTE: Ideally, we should always generate 'CS7048: First argument to a security attribute must be a valid SecurityAction' for this case. // NOTE: However, native compiler allows applying System.Security.Permissions.HostProtectionAttribute attribute without any argument and uses // NOTE: SecurityAction.LinkDemand as the default SecurityAction in this case. We maintain compatibility with the native compiler for this case. // BREAKING CHANGE: Even though the native compiler intends to allow only HostProtectionAttribute to be applied without any arguments, // it doesn't quite do this correctly // The implementation issue leads to the native compiler allowing any user defined security attribute with a parameterless constructor and a named property argument as the first // attribute argument to have the above mentioned behavior, even though the comment clearly mentions that this behavior was intended only for the HostProtectionAttribute. // We currently allow this case only for the HostProtectionAttribute. In future if need arises, we can exactly match native compiler's behavior. if ( this.IsTargetAttribute( targetSymbol, AttributeDescription.HostProtectionAttribute ) ) { hasErrors = false; return(DeclarativeSecurityAction.LinkDemand); } } else { TypedConstant firstArg = ctorArgs.First(); var firstArgType = (TypeSymbol?)firstArg.TypeInternal; if ( firstArgType is object && firstArgType.Equals( compilation.GetWellKnownType( WellKnownType.System_Security_Permissions_SecurityAction ) ) ) { return(DecodeSecurityAction( firstArg, targetSymbol, nodeOpt, diagnostics, out hasErrors )); } } // CS7048: First argument to a security attribute must be a valid SecurityAction diagnostics.Add( ErrorCode.ERR_SecurityAttributeMissingAction, nodeOpt != null ? nodeOpt.Name.Location : NoLocation.Singleton ); hasErrors = true; return(DeclarativeSecurityAction.None); }
private static void ProcessField(CsharpCodeBuilder source, IFieldSymbol fieldSymbol, CodeWriter codeWriter) { // get the name and type of the field string fieldName = fieldSymbol.Name; ITypeSymbol fieldType = fieldSymbol.Type; AttributeData attributeData = fieldSymbol.GetAttributes() .Single(p => p.AttributeClass.SafeEquals(typeof(AutoNotifyAttribute))); // get the AutoNotify attribute from the field, and any associated data TypedConstant overridenNameOpt = attributeData.NamedArguments.SingleOrDefault(kvp => kvp.Key == nameof(AutoNotifyAttribute.PropertyName)).Value; string propertyName = chooseName(fieldName, overridenNameOpt); if (!System.Text.RegularExpressions.Regex.IsMatch(propertyName, "^[_a-zA-Z][_a-zA-Z0-9]*$")) { codeWriter.Context.ReportDiagnostic(KnifeDiagnostic.AutoNotify.InvalidPropertyName(propertyName)); } if (propertyName == fieldName) { codeWriter.Context.ReportDiagnostic(KnifeDiagnostic.AutoNotify.PropertyNameEqualFieldName(propertyName)); } source.AppendCodeLines($@" public {fieldType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)} {propertyName} {{ get {{ return this.{fieldName}; }} set {{ if(this.{fieldName} != value) {{ this.{fieldName} = value; this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof({propertyName}))); }} }} }} "); string chooseName(string field, TypedConstant overridenNameOption) { if (!overridenNameOption.IsNull) { return(overridenNameOption.Value.ToString()); } field = field.TrimStart('_'); if (field.Length == 0) { return(string.Empty); } if (field.Length == 1) { return(field.ToUpperInvariant()); } return(field.Substring(0, 1).ToUpperInvariant() + field.Substring(1)); } }
public void Execute(GeneratorExecutionContext context) { #if DEBUG //if (!Debugger.IsAttached) Debugger.Launch(); #endif if (!(context.Compilation is CSharpCompilation compilation)) { return; } if (!(context.ParseOptions is CSharpParseOptions parseOptions)) { return; } // check if required types exists. if (!(compilation.GetTypeByMetadataName("System.ReadOnlySpan`1") is { } readOnlySpanSymbol)) { return; } if (!(compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.Unsafe") is { } unsafeSymbol)) { return; } if (!(compilation.GetTypeByMetadataName("System.Runtime.InteropServices.MemoryMarshal") is { } memoryMarshalSymbol)) { return; } SourceText attributeSourceText = constractSourceText(new PrimitiveStaticDataAttributeTemplate().TransformText()); context.AddSource(PrimitiveStaticDataAttributeTemplate.TypeFullName, attributeSourceText); try { compilation = compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(attributeSourceText, options: parseOptions)); INamedTypeSymbol attrSymbol = compilation.GetTypeByMetadataName(PrimitiveStaticDataAttributeTemplate.TypeFullName) !; var candidateMethodSyntaxes = compilation. SyntaxTrees. SelectMany(tree => tree.GetRoot().DescendantNodes()). OfType <MethodDeclarationSyntax>(). Where(method => method.IsExtendedPartial() && method.Modifiers.Any(SyntaxKind.StaticKeyword) && method.AttributeLists.Count > 0 && method.ParentNodes().OfType <TypeDeclarationSyntax>().All(type => type.Modifiers.Any(SyntaxKind.PartialKeyword))); foreach (var methodSyntax in candidateMethodSyntaxes) { SemanticModel semantic = compilation.GetSemanticModel(methodSyntax.SyntaxTree); if (!(semantic.GetDeclaredSymbol(methodSyntax) is { } methodSymbol) || methodSymbol.MethodKind != MethodKind.Ordinary || methodSymbol.PartialImplementationPart is not null || !equalsSymbol(methodSymbol.ReturnType.OriginalDefinition, readOnlySpanSymbol)) { continue; } var returnSpanType = (INamedTypeSymbol)methodSymbol.ReturnType; if (!isPrimitiveType(returnSpanType.TypeArguments[0])) { continue; } foreach (AttributeData attr in methodSymbol.GetReturnTypeAttributes()) { if (!equalsSymbol(attr.AttributeClass, attrSymbol) || attr.ConstructorArguments.Length < 1) { continue; } TypedConstant arg1 = attr.ConstructorArguments[0]; bool argIsSingleByteValues = false; IArrayTypeSymbol arraySymbol; object[] values = default !;
private static ExpressionSyntax GetLiteralExpression(TypedConstant constant) { if (constant.Type.TypeKind == TypeKind.Array) { if (constant.Values == null) { return GetLiteralExpression(null, constant.Type); } var items = (from value in constant.Values select GetLiteralExpression(value)).ToList(); if (items.TrueForAll(x => x != null)) { return SyntaxFactory.ArrayCreationExpression( SyntaxFactory.Token(SyntaxKind.NewKeyword), default(SyntaxList<AttributeListSyntax>), GetTypeSyntax( ((IArrayTypeSymbol)constant.Type).ElementType ), null, SyntaxFactory.SingletonList( SyntaxFactory.ArrayRankSpecifier() ), SyntaxFactory.CollectionInitializer( SyntaxFactory.SeparatedList( from value in constant.Values select GetLiteralExpression(value) ) ) ); } return SyntaxFactory.ArrayCreationExpression( SyntaxFactory.Token(SyntaxKind.NewKeyword), default(SyntaxList<AttributeListSyntax>), GetTypeSyntax( ((IArrayTypeSymbol)constant.Type).ElementType ), null, new SyntaxList<ArrayRankSpecifierSyntax>(), SyntaxFactory.CollectionInitializer() ); } var expr = GetLiteralExpression(constant.Value, constant.Type); if (expr == null) { return null; } switch (constant.Type.SpecialType) { case SpecialType.System_SByte: return SyntaxFactory.CTypeExpression( expr, SyntaxFactory.PredefinedType( SyntaxFactory.Token(SyntaxKind.SByteKeyword))); case SpecialType.System_Byte: return SyntaxFactory.CTypeExpression( expr, SyntaxFactory.PredefinedType( SyntaxFactory.Token(SyntaxKind.ByteKeyword))); case SpecialType.System_Int16: return SyntaxFactory.CTypeExpression( expr, SyntaxFactory.PredefinedType( SyntaxFactory.Token(SyntaxKind.ShortKeyword))); case SpecialType.System_UInt16: return SyntaxFactory.CTypeExpression( expr, SyntaxFactory.PredefinedType( SyntaxFactory.Token(SyntaxKind.UShortKeyword))); default: return expr; } }
public OperatorInfo(int precedence, TypedConstant expression) { Precedence = precedence; Expression = expression; }
internal void ToUIText(InlineCollection block, TypedConstant constant) { switch (constant.Kind) { case TypedConstantKind.Primitive: if (constant.Value is bool) { block.Add(WpfHelper.Render((bool)constant.Value ? "true" : "false", Keyword)); } else if (constant.Value is string) { block.Add(WpfHelper.Render(constant.ToCSharpString(), Text)); } else { block.Add(WpfHelper.Render(constant.ToCSharpString(), Number)); } break; case TypedConstantKind.Enum: var en = constant.ToCSharpString(); if (en.IndexOf('|') != -1) { var items = constant.Type.GetMembers().Where(i => { var field = i as IFieldSymbol; return(field != null && field.HasConstantValue != false && UnsafeArithmeticHelper.Equals(UnsafeArithmeticHelper.And(constant.Value, field.ConstantValue), field.ConstantValue) && UnsafeArithmeticHelper.IsZero(field.ConstantValue) == false); }); var flags = items.ToArray(); for (int i = 0; i < flags.Length; i++) { if (i > 0) { block.Add(" | "); } block.Add(WpfHelper.Render(constant.Type.Name + "." + flags[i].Name, Enum)); } } else { block.Add(WpfHelper.Render(constant.Type.Name + en.Substring(en.LastIndexOf('.')), Enum)); } break; case TypedConstantKind.Type: block.Add(WpfHelper.Render("typeof", Keyword)); block.Add("("); ToUIText(block, constant.Value as ITypeSymbol, null); block.Add(")"); break; case TypedConstantKind.Array: block.Add("{"); bool c = false; foreach (var item in constant.Values) { if (c == false) { c = true; } else { block.Add(", "); } ToUIText(block, item); } block.Add("}"); break; default: block.Add(constant.ToCSharpString()); break; } }
void Format(InlineCollection block, TypedConstant constant) { if (constant.IsNull) { block.Add("null".Render(Keyword)); return; } switch (constant.Kind) { case TypedConstantKind.Primitive: if (constant.Value is bool) { block.Add(WpfHelper.Render((bool)constant.Value ? "true" : "false", Keyword)); } else if (constant.Value is string) { block.Add(constant.ToCSharpString().Render(Text)); } else { block.Add(constant.ToCSharpString().Render(Number)); } break; case TypedConstantKind.Enum: var en = constant.ToCSharpString(); int d; if (en.IndexOf('|') != -1) { var items = constant.Type.GetMembers().Where(i => { var field = i as IFieldSymbol; return(field != null && field.HasConstantValue && UnsafeArithmeticHelper.Equals(UnsafeArithmeticHelper.And(constant.Value, field.ConstantValue), field.ConstantValue) && UnsafeArithmeticHelper.IsZero(field.ConstantValue) == false); }); var flags = items.ToArray(); for (int i = 0; i < flags.Length; i++) { if (i > 0) { block.Add(" | "); } block.Add(constant.Type.Render(null, Enum)); block.Add("."); block.Add(flags[i].Render(null, EnumField)); } } else if ((d = en.LastIndexOf('.')) != -1) { block.Add(constant.Type.Render(null, Enum)); block.Add("."); block.Add(en.Substring(d + 1).Render(EnumField)); } else { block.Add(en.Render(Enum)); } break; case TypedConstantKind.Type: block.Add("typeof".Render(Keyword)); block.Add("("); Format(block, constant.Value as ISymbol, null, false); block.Add(")"); break; case TypedConstantKind.Array: block.Add("new".Render(Keyword)); block.Add("[] { "); bool c = false; foreach (var item in constant.Values) { if (c) { block.Add(", "); } else { c = true; } Format(block, item); } block.Add(" }"); break; default: block.Add(constant.ToCSharpString()); break; } }
private static TypedConstant GetParamArrayArgument(ParameterSymbol parameter, ImmutableArray<TypedConstant> constructorArgsArray, int argumentsCount, int argsConsumedCount, Conversions conversions) { Debug.Assert(argsConsumedCount <= argumentsCount); int paramArrayArgCount = argumentsCount - argsConsumedCount; if (paramArrayArgCount == 0) { return new TypedConstant(parameter.Type, ImmutableArray<TypedConstant>.Empty); } // If there's exactly one argument and it's an array of an appropriate type, then just return it. if (paramArrayArgCount == 1 && constructorArgsArray[argsConsumedCount].Kind == TypedConstantKind.Array) { TypeSymbol argumentType = (TypeSymbol)constructorArgsArray[argsConsumedCount].Type; // Easy out (i.e. don't both classifying conversion). if (argumentType == parameter.Type) { return constructorArgsArray[argsConsumedCount]; } HashSet<DiagnosticInfo> useSiteDiagnostics = null; // ignoring, since already bound argument and parameter Conversion conversion = conversions.ClassifyConversion(argumentType, parameter.Type, ref useSiteDiagnostics, builtinOnly: true); // NOTE: Won't always succeed, even though we've performed overload resolution. // For example, passing int[] to params object[] actually treats the int[] as an element of the object[]. if (conversion.IsValid && conversion.Kind == ConversionKind.ImplicitReference) { return constructorArgsArray[argsConsumedCount]; } } Debug.Assert(!constructorArgsArray.IsDefault); Debug.Assert(argsConsumedCount <= constructorArgsArray.Length); var values = new TypedConstant[paramArrayArgCount]; for (int i = 0; i < paramArrayArgCount; i++) { values[i] = constructorArgsArray[argsConsumedCount++]; } return new TypedConstant(parameter.Type, values.AsImmutableOrNull()); }
private static string DisplayUnsignedEnumConstant(TypedConstant constant, SpecialType specialType, ulong constantToDecode, string typeName) { // Specified valueConstant might have an exact matching enum field // or it might be a bitwise Or of multiple enum fields. // For the later case, we keep track of the current value of // bitwise Or of possible enum fields. ulong curValue = 0; // Initialize the value string to empty PooledStringBuilder pooledBuilder = null; StringBuilder valueStringBuilder = null; // Iterate through all the constant members in the enum type var members = constant.Type.GetMembers(); foreach (var member in members) { var field = member as IFieldSymbol; if ((object)field != null && field.HasConstantValue) { ConstantValue memberConstant = ConstantValue.Create(field.ConstantValue, specialType); ulong memberValue = memberConstant.UInt64Value; // Do we have an exact matching enum field if (memberValue == constantToDecode) { if (pooledBuilder != null) { pooledBuilder.Free(); } return typeName + "." + field.Name; } // specifiedValue might be a bitwise Or of multiple enum fields // Is the current member included in the specified value? if ((memberValue & constantToDecode) == memberValue) { // update the current value curValue = curValue | memberValue; if (valueStringBuilder == null) { pooledBuilder = PooledStringBuilder.GetInstance(); valueStringBuilder = pooledBuilder.Builder; } else { valueStringBuilder.Append(" | "); } valueStringBuilder.Append(typeName); valueStringBuilder.Append("."); valueStringBuilder.Append(field.Name); } } } if (pooledBuilder != null) { if (curValue == constantToDecode) { // return decoded enum constant return pooledBuilder.ToStringAndFree(); } // Unable to decode the enum constant pooledBuilder.Free(); } // Unable to decode the enum constant, just display the integral value return constant.Value.ToString(); }
private DeclarativeSecurityAction DecodeSecurityAction(TypedConstant typedValue, Symbol targetSymbol, AttributeSyntax?nodeOpt, BindingDiagnosticBag diagnostics, out bool hasErrors) { Debug.Assert((object)targetSymbol != null); Debug.Assert(targetSymbol.Kind == SymbolKind.Assembly || targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method); Debug.Assert(typedValue.ValueInternal is object); int securityAction = (int)typedValue.ValueInternal; bool isPermissionRequestAction; switch (securityAction) { case (int)DeclarativeSecurityAction.InheritanceDemand: case (int)DeclarativeSecurityAction.LinkDemand: if (this.IsTargetAttribute(targetSymbol, AttributeDescription.PrincipalPermissionAttribute)) { // CS7052: SecurityAction value '{0}' is invalid for PrincipalPermission attribute object displayString; Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); diagnostics.Add(ErrorCode.ERR_PrincipalPermissionInvalidAction, syntaxLocation, displayString); hasErrors = true; return(DeclarativeSecurityAction.None); } isPermissionRequestAction = false; break; case 1: // Native compiler allows security action value 1 for security attributes on types/methods, even though there is no corresponding field in System.Security.Permissions.SecurityAction enum. // We will maintain compatibility. case (int)DeclarativeSecurityAction.Assert: case (int)DeclarativeSecurityAction.Demand: case (int)DeclarativeSecurityAction.PermitOnly: case (int)DeclarativeSecurityAction.Deny: isPermissionRequestAction = false; break; case (int)DeclarativeSecurityAction.RequestMinimum: case (int)DeclarativeSecurityAction.RequestOptional: case (int)DeclarativeSecurityAction.RequestRefuse: isPermissionRequestAction = true; break; default: { // CS7049: Security attribute '{0}' has an invalid SecurityAction value '{1}' object displayString; Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidAction, syntaxLocation, nodeOpt != null ? nodeOpt.GetErrorDisplayName() : "", displayString); hasErrors = true; return(DeclarativeSecurityAction.None); } } // Validate security action for symbol kind if (isPermissionRequestAction) { if (targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method) { // Types and methods cannot take permission requests. // CS7051: SecurityAction value '{0}' is invalid for security attributes applied to a type or a method object displayString; Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidActionTypeOrMethod, syntaxLocation, displayString); hasErrors = true; return(DeclarativeSecurityAction.None); } } else { if (targetSymbol.Kind == SymbolKind.Assembly) { // Assemblies cannot take declarative security. // CS7050: SecurityAction value '{0}' is invalid for security attributes applied to an assembly object displayString; Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidActionAssembly, syntaxLocation, displayString); hasErrors = true; return(DeclarativeSecurityAction.None); } } hasErrors = false; return((DeclarativeSecurityAction)securityAction); }
internal override void AddSynthesizedAttributes(ModuleCompilationState compilationState, ref ArrayBuilder<SynthesizedAttributeData> attributes) { base.AddSynthesizedAttributes(compilationState, ref attributes); if (this.IsAsync || this.IsIterator) { var compilation = this.DeclaringCompilation; // The async state machine type is not synthesized until the async method body is rewritten. If we are // only emitting metadata the method body will not have been rewritten, and the async state machine // type will not have been created. In this case, omit the attribute. NamedTypeSymbol stateMachineType; if (compilationState.TryGetStateMachineType(this, out stateMachineType)) { WellKnownMember ctor = this.IsAsync ? WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor : WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor; var arg = new TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type), TypedConstantKind.Type, stateMachineType.GetUnboundGenericTypeOrSelf()); AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(ctor, ImmutableArray.Create(arg))); } if (this.IsAsync) { // Async kick-off method calls MoveNext, which contains user code. // This means we need to emit DebuggerStepThroughAttribute in order // to have correct stepping behavior during debugging. AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDebuggerStepThroughAttribute()); } } }
private static string GetArgumentValue(TypedConstant typedConstant) { switch (typedConstant.Kind) { case TypedConstantKind.Error: case TypedConstantKind.Enum: case TypedConstantKind.Primitive: return typedConstant.Value.ToString(); case TypedConstantKind.Type: case TypedConstantKind.Array: return typedConstant.ToCSharpString(); default: throw new ArgumentOutOfRangeException(nameof(typedConstant)); } }
/// <remarks> /// These won't be returned by GetAttributes on source methods, but they /// will be returned by GetAttributes on metadata symbols. /// </remarks> internal override void AddSynthesizedAttributes(ModuleCompilationState compilationState, ref ArrayBuilder<SynthesizedAttributeData> attributes) { base.AddSynthesizedAttributes(compilationState, ref attributes); CSharpCompilation compilation = this.DeclaringCompilation; if (this.ContainsExtensionMethods) { // No need to check if [Extension] attribute was explicitly set since // we'll issue CS1112 error in those cases and won't generate IL. AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor)); } if (this.Indexers.Any()) { string defaultMemberName = this.Indexers.First().MetadataName; // UNDONE: IndexerNameAttribute var defaultMemberNameConstant = new TypedConstant(compilation.GetSpecialType(SpecialType.System_String), TypedConstantKind.Primitive, defaultMemberName); AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute( WellKnownMember.System_Reflection_DefaultMemberAttribute__ctor, ImmutableArray.Create(defaultMemberNameConstant))); } NamedTypeSymbol baseType = this.BaseTypeNoUseSiteDiagnostics; if ((object)baseType != null && baseType.ContainsDynamic()) { AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDynamicAttribute(baseType, customModifiersCount: 0)); } }
public RoslynAttrubuteArgumentMetadata(TypedConstant typeConstant) { _typeConstant = typeConstant; }
private static MetadataTypeOf CreateType(TypedConstant argument, EmitContext context) { Debug.Assert(argument.Value != null); var moduleBeingBuilt = (PEModuleBuilder)context.Module; var syntaxNodeOpt = (SyntaxNode)context.SyntaxNodeOpt; var diagnostics = context.Diagnostics; return new MetadataTypeOf(moduleBeingBuilt.Translate((TypeSymbol)argument.Value, syntaxNodeOpt, diagnostics), moduleBeingBuilt.Translate((TypeSymbol)argument.Type, syntaxNodeOpt, diagnostics)); }
private static (Type type, int executionOrder) GetCodeGeneratorTypeForAttribute(GeneratorKnownTypes generatorKnownTypes, AttributeData attributeData, Func <AssemblyName, Assembly> assemblyLoader) { Requires.NotNull(assemblyLoader, nameof(assemblyLoader)); var attributeType = attributeData.AttributeClass; if (attributeType != null) { foreach (var generatorCandidateAttribute in attributeType.GetAttributes()) { if (generatorCandidateAttribute.AttributeClass.OriginalDefinition.Equals(generatorKnownTypes.CodeGenerationAttributeAttributeTypeSymbol)) { var executionOrder = 0; var hasOrderInterface = attributeType.AllInterfaces.Any(i => i.OriginalDefinition.Equals(generatorKnownTypes.IOrderCodeGenerationTypeSymbol)); if (hasOrderInterface) { var executionOrderArgument = attributeData.NamedArguments.FirstOrDefault(a => a.Key == nameof(IOrderedCodeGeneration.ExecutionOrder)); if (!string.IsNullOrEmpty(executionOrderArgument.Key)) { executionOrder = (int)executionOrderArgument.Value.Value; } } string assemblyName = null; string fullTypeName = null; TypedConstant firstArg = generatorCandidateAttribute.ConstructorArguments.Single(); if (firstArg.Value is string typeName) { // This string is the full name of the type, which MAY be assembly-qualified. int commaIndex = typeName.IndexOf(','); bool isAssemblyQualified = commaIndex >= 0; if (isAssemblyQualified) { fullTypeName = typeName.Substring(0, commaIndex); assemblyName = typeName.Substring(commaIndex + 1).Trim(); } else { fullTypeName = typeName; assemblyName = generatorCandidateAttribute.AttributeClass.ContainingAssembly.Name; } } else if (firstArg.Value is INamedTypeSymbol typeOfValue) { // This was a typeof(T) expression fullTypeName = GetFullTypeName(typeOfValue); assemblyName = typeOfValue.ContainingAssembly.Name; } if (assemblyName != null) { Logger.Info($"assemblyLoader assemblyName = {assemblyName}, fullTypeName = {fullTypeName}"); var assembly = assemblyLoader(new AssemblyName(assemblyName)); if (assembly != null) { return(assembly.GetType(fullTypeName), executionOrder); } } Verify.FailOperation("Unable to find code generator: {0} in {1}", fullTypeName, assemblyName); } } } return(null, 0); }
bool TryResolveCtor(NamedTypeSymbol type, PhpCompilation compilation, out MethodSymbol ctor, out ImmutableArray <TypedConstant> args) { if (type.IsValidType()) { var candidates = type.InstanceConstructors; for (int i = 0; i < candidates.Length; i++) { var m = candidates[i]; if (m.DeclaredAccessibility != Accessibility.Public) { continue; // TODO: or current class context } if (m.IsGenericMethod) { Debug.Fail("unexpected"); continue; } // NS if (m.ParameterCount < _arguments.Length) { continue; // be strict } var match = true; var ps = m.Parameters; var boundargs = new TypedConstant[ps.Length]; for (var pi = 0; match && pi < ps.Length; pi++) { if (pi >= _arguments.Length) { //if (ps[pi].IsOptional) //{ // boundargs[pi] = ps[pi].ExplicitDefaultConstantValue.AsTypedConstant(); // continue; // ok //} //else { match = false; break; } } if (TryBindTypedConstant(ps[pi].Type, _arguments[pi], compilation, out var arg)) { boundargs[pi] = arg; } else { match = false; break; } } if (match) { ctor = m; args = boundargs.AsImmutable(); return(true); } } } // ctor = new MissingMethodSymbol(); args = ImmutableArray <TypedConstant> .Empty; return(false); }
private static string GetArgumentString(TypedConstant argument) { if (argument.Type == null || argument.Type.SpecialType != SpecialType.System_String || argument.IsNull) { return null; } return ((string)argument.Value).Trim(); }
/// <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); } }
private MetadataCreateArray CreateMetadataArray(TypedConstant argument, EmitContext context) { Debug.Assert(!argument.Values.IsDefault); var values = argument.Values; var arrayType = Emit.PEModuleBuilder.Translate((ArrayTypeSymbol)argument.Type); if (values.Length == 0) { return new MetadataCreateArray(arrayType, arrayType.GetElementType(context), ImmutableArray<Cci.IMetadataExpression>.Empty); } var metadataExprs = new Cci.IMetadataExpression[values.Length]; for (int i = 0; i < values.Length; i++) { metadataExprs[i] = CreateMetadataExpression(values[i], context); } return new MetadataCreateArray(arrayType, arrayType.GetElementType(context), metadataExprs.AsImmutableOrNull()); }
private static Location GetSecurityAttributeActionSyntaxLocation(AttributeSyntax?nodeOpt, TypedConstant typedValue, out object displayString) { if (nodeOpt == null) { displayString = ""; return(NoLocation.Singleton); } var argList = nodeOpt.ArgumentList; if (argList == null || argList.Arguments.IsEmpty()) { // Optional SecurityAction parameter with default value. displayString = (FormattableString)$"{typedValue.ValueInternal}"; return(nodeOpt.Location); } AttributeArgumentSyntax argSyntax = argList.Arguments[0]; displayString = argSyntax.ToString(); return(argSyntax.Location); }
private static void AppendConstant(StringBuilder result, TypedConstant constant) { switch (constant.Kind) { case TypedConstantKind.Array: result.Append("{"); int i = 0; foreach (var item in constant.Values) { if (i > 0) { result.Append(", "); } AppendConstant(result, item); } result.Append("}"); break; case TypedConstantKind.Type: result.Append("typeof("); result.Append(constant.Value); result.Append(")"); break; case TypedConstantKind.Enum: case TypedConstantKind.Primitive: var value = constant.Value; if (value.GetType() == typeof(string)) { result.Append("\""); result.Append(value); result.Append("\""); } else if (value.GetType() == typeof(bool)) { result.Append(value.ToString().ToLower()); } else { result.Append(value); } break; default: throw ExceptionUtilities.UnexpectedValue(constant.Kind); } }
/// <summary> /// Gets the set of logging classes containing methods to output. /// </summary> public IReadOnlyList <LoggerClass> GetLogClasses(IEnumerable <ClassDeclarationSyntax> classes) { INamedTypeSymbol loggerMessageAttribute = _compilation.GetBestTypeByMetadataName(LoggerMessageAttribute); if (loggerMessageAttribute == null) { // nothing to do if this type isn't available return(Array.Empty <LoggerClass>()); } INamedTypeSymbol loggerSymbol = _compilation.GetBestTypeByMetadataName("Microsoft.Extensions.Logging.ILogger"); if (loggerSymbol == null) { // nothing to do if this type isn't available return(Array.Empty <LoggerClass>()); } INamedTypeSymbol logLevelSymbol = _compilation.GetBestTypeByMetadataName("Microsoft.Extensions.Logging.LogLevel"); if (logLevelSymbol == null) { // nothing to do if this type isn't available return(Array.Empty <LoggerClass>()); } INamedTypeSymbol exceptionSymbol = _compilation.GetBestTypeByMetadataName("System.Exception"); if (exceptionSymbol == null) { Diag(DiagnosticDescriptors.MissingRequiredType, null, "System.Exception"); return(Array.Empty <LoggerClass>()); } INamedTypeSymbol enumerableSymbol = _compilation.GetSpecialType(SpecialType.System_Collections_IEnumerable); INamedTypeSymbol stringSymbol = _compilation.GetSpecialType(SpecialType.System_String); var results = new List <LoggerClass>(); var ids = new HashSet <int>(); // we enumerate by syntax tree, to minimize the need to instantiate semantic models (since they're expensive) foreach (var group in classes.GroupBy(x => x.SyntaxTree)) { SemanticModel?sm = null; foreach (ClassDeclarationSyntax classDec in group) { // stop if we're asked to _cancellationToken.ThrowIfCancellationRequested(); LoggerClass?lc = null; string nspace = string.Empty; string? loggerField = null; bool multipleLoggerFields = false; ids.Clear(); foreach (MemberDeclarationSyntax member in classDec.Members) { var method = member as MethodDeclarationSyntax; if (method == null) { // we only care about methods continue; } sm ??= _compilation.GetSemanticModel(classDec.SyntaxTree); IMethodSymbol logMethodSymbol = sm.GetDeclaredSymbol(method, _cancellationToken) as IMethodSymbol; Debug.Assert(logMethodSymbol != null, "log method is present."); (int eventId, int?level, string message, string?eventName, bool skipEnabledCheck) = (-1, null, string.Empty, null, false); foreach (AttributeListSyntax mal in method.AttributeLists) { foreach (AttributeSyntax ma in mal.Attributes) { IMethodSymbol attrCtorSymbol = sm.GetSymbolInfo(ma, _cancellationToken).Symbol as IMethodSymbol; if (attrCtorSymbol == null || !loggerMessageAttribute.Equals(attrCtorSymbol.ContainingType, SymbolEqualityComparer.Default)) { // badly formed attribute definition, or not the right attribute continue; } bool hasMisconfiguredInput = false; ImmutableArray <AttributeData>?boundAttributes = logMethodSymbol?.GetAttributes(); if (boundAttributes == null || boundAttributes !.Value.Length == 0) { continue; } foreach (AttributeData attributeData in boundAttributes) { if (!SymbolEqualityComparer.Default.Equals(attributeData.AttributeClass, loggerMessageAttribute)) { continue; } // supports: [LoggerMessage(0, LogLevel.Warning, "custom message")] // supports: [LoggerMessage(eventId: 0, level: LogLevel.Warning, message: "custom message")] if (attributeData.ConstructorArguments.Any()) { foreach (TypedConstant typedConstant in attributeData.ConstructorArguments) { if (typedConstant.Kind == TypedConstantKind.Error) { hasMisconfiguredInput = true; } } ImmutableArray <TypedConstant> items = attributeData.ConstructorArguments; Debug.Assert(items.Length == 3); eventId = items[0].IsNull ? -1 : (int)GetItem(items[0]); level = items[1].IsNull ? null : (int?)GetItem(items[1]); message = items[2].IsNull ? "" : (string)GetItem(items[2]); } // argument syntax takes parameters. e.g. EventId = 0 // supports: e.g. [LoggerMessage(EventId = 0, Level = LogLevel.Warning, Message = "custom message")] if (attributeData.NamedArguments.Any()) { foreach (KeyValuePair <string, TypedConstant> namedArgument in attributeData.NamedArguments) { TypedConstant typedConstant = namedArgument.Value; if (typedConstant.Kind == TypedConstantKind.Error) { hasMisconfiguredInput = true; } else { TypedConstant value = namedArgument.Value; switch (namedArgument.Key) { case "EventId": eventId = (int)GetItem(value); break; case "Level": level = value.IsNull ? null : (int?)GetItem(value); break; case "SkipEnabledCheck": skipEnabledCheck = (bool)GetItem(value); break; case "EventName": eventName = (string?)GetItem(value); break; case "Message": message = value.IsNull ? "" : (string)GetItem(value); break; } } } } } if (hasMisconfiguredInput) { // skip further generator execution and let compiler generate the errors break; } IMethodSymbol?methodSymbol = sm.GetDeclaredSymbol(method, _cancellationToken); if (methodSymbol != null) { var lm = new LoggerMethod { Name = methodSymbol.Name, Level = level, Message = message, EventId = eventId, EventName = eventName, IsExtensionMethod = methodSymbol.IsExtensionMethod, Modifiers = method.Modifiers.ToString(), SkipEnabledCheck = skipEnabledCheck }; ExtractTemplates(message, lm.TemplateMap, lm.TemplateList); bool keepMethod = true; // whether or not we want to keep the method definition or if it's got errors making it so we should discard it instead if (lm.Name[0] == '_') { // can't have logging method names that start with _ since that can lead to conflicting symbol names // because the generated symbols start with _ Diag(DiagnosticDescriptors.InvalidLoggingMethodName, method.Identifier.GetLocation()); keepMethod = false; } if (!methodSymbol.ReturnsVoid) { // logging methods must return void Diag(DiagnosticDescriptors.LoggingMethodMustReturnVoid, method.ReturnType.GetLocation()); keepMethod = false; } if (method.Arity > 0) { // we don't currently support generic methods Diag(DiagnosticDescriptors.LoggingMethodIsGeneric, method.Identifier.GetLocation()); keepMethod = false; } bool isStatic = false; bool isPartial = false; foreach (SyntaxToken mod in method.Modifiers) { if (mod.IsKind(SyntaxKind.PartialKeyword)) { isPartial = true; } else if (mod.IsKind(SyntaxKind.StaticKeyword)) { isStatic = true; } } if (!isPartial) { Diag(DiagnosticDescriptors.LoggingMethodMustBePartial, method.GetLocation()); keepMethod = false; } if (method.Body != null) { Diag(DiagnosticDescriptors.LoggingMethodHasBody, method.Body.GetLocation()); keepMethod = false; } // ensure there are no duplicate ids. if (ids.Contains(lm.EventId)) { Diag(DiagnosticDescriptors.ShouldntReuseEventIds, ma.GetLocation(), lm.EventId, classDec.Identifier.Text); } else { _ = ids.Add(lm.EventId); } string msg = lm.Message; if (msg.StartsWith("INFORMATION:", StringComparison.OrdinalIgnoreCase) || msg.StartsWith("INFO:", StringComparison.OrdinalIgnoreCase) || msg.StartsWith("WARNING:", StringComparison.OrdinalIgnoreCase) || msg.StartsWith("WARN:", StringComparison.OrdinalIgnoreCase) || msg.StartsWith("ERROR:", StringComparison.OrdinalIgnoreCase) || msg.StartsWith("ERR:", StringComparison.OrdinalIgnoreCase)) { Diag(DiagnosticDescriptors.RedundantQualifierInMessage, ma.GetLocation(), method.Identifier.ToString()); } bool foundLogger = false; bool foundException = false; bool foundLogLevel = level != null; foreach (IParameterSymbol paramSymbol in methodSymbol.Parameters) { string paramName = paramSymbol.Name; bool needsAtSign = false; if (paramSymbol.DeclaringSyntaxReferences.Length > 0) { ParameterSyntax paramSyntax = paramSymbol.DeclaringSyntaxReferences[0].GetSyntax(_cancellationToken) as ParameterSyntax; if (paramSyntax != null && !string.IsNullOrEmpty(paramSyntax.Identifier.Text)) { needsAtSign = paramSyntax.Identifier.Text[0] == '@'; } } if (string.IsNullOrWhiteSpace(paramName)) { // semantic problem, just bail quietly keepMethod = false; break; } ITypeSymbol paramTypeSymbol = paramSymbol !.Type; if (paramTypeSymbol is IErrorTypeSymbol) { // semantic problem, just bail quietly keepMethod = false; break; } string?qualifier = null; if (paramSymbol.RefKind == RefKind.In) { qualifier = "in"; } else if (paramSymbol.RefKind == RefKind.Ref) { qualifier = "ref"; } string typeName = paramTypeSymbol.ToDisplayString( SymbolDisplayFormat.FullyQualifiedFormat.WithMiscellaneousOptions( SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier)); var lp = new LoggerParameter { Name = paramName, Type = typeName, Qualifier = qualifier, CodeName = needsAtSign ? "@" + paramName : paramName, IsLogger = !foundLogger && IsBaseOrIdentity(paramTypeSymbol !, loggerSymbol), IsException = !foundException && IsBaseOrIdentity(paramTypeSymbol !, exceptionSymbol), IsLogLevel = !foundLogLevel && IsBaseOrIdentity(paramTypeSymbol !, logLevelSymbol), IsEnumerable = IsBaseOrIdentity(paramTypeSymbol !, enumerableSymbol) && !IsBaseOrIdentity(paramTypeSymbol !, stringSymbol), }; foundLogger |= lp.IsLogger; foundException |= lp.IsException; foundLogLevel |= lp.IsLogLevel; bool forceAsTemplateParams = false; if (lp.IsLogger && lm.TemplateMap.ContainsKey(paramName)) { Diag(DiagnosticDescriptors.ShouldntMentionLoggerInMessage, paramSymbol.Locations[0], paramName); forceAsTemplateParams = true; } else if (lp.IsException && lm.TemplateMap.ContainsKey(paramName)) { Diag(DiagnosticDescriptors.ShouldntMentionExceptionInMessage, paramSymbol.Locations[0], paramName); forceAsTemplateParams = true; } else if (lp.IsLogLevel && lm.TemplateMap.ContainsKey(paramName)) { Diag(DiagnosticDescriptors.ShouldntMentionLogLevelInMessage, paramSymbol.Locations[0], paramName); forceAsTemplateParams = true; } else if (lp.IsLogLevel && level != null && !lm.TemplateMap.ContainsKey(paramName)) { Diag(DiagnosticDescriptors.ArgumentHasNoCorrespondingTemplate, paramSymbol.Locations[0], paramName); } else if (lp.IsTemplateParameter && !lm.TemplateMap.ContainsKey(paramName)) { Diag(DiagnosticDescriptors.ArgumentHasNoCorrespondingTemplate, paramSymbol.Locations[0], paramName); } if (paramName[0] == '_') { // can't have logging method parameter names that start with _ since that can lead to conflicting symbol names // because all generated symbols start with _ Diag(DiagnosticDescriptors.InvalidLoggingMethodParameterName, paramSymbol.Locations[0]); } lm.AllParameters.Add(lp); if (lp.IsTemplateParameter || forceAsTemplateParams) { lm.TemplateParameters.Add(lp); } } if (keepMethod) { if (isStatic && !foundLogger) { Diag(DiagnosticDescriptors.MissingLoggerArgument, method.GetLocation(), lm.Name); keepMethod = false; } else if (!isStatic && foundLogger) { Diag(DiagnosticDescriptors.LoggingMethodShouldBeStatic, method.GetLocation()); } else if (!isStatic && !foundLogger) { if (loggerField == null) { (loggerField, multipleLoggerFields) = FindLoggerField(sm, classDec, loggerSymbol); } if (multipleLoggerFields) { Diag(DiagnosticDescriptors.MultipleLoggerFields, method.GetLocation(), classDec.Identifier.Text); keepMethod = false; } else if (loggerField == null) { Diag(DiagnosticDescriptors.MissingLoggerField, method.GetLocation(), classDec.Identifier.Text); keepMethod = false; } else { lm.LoggerField = loggerField; } } if (level == null && !foundLogLevel) { Diag(DiagnosticDescriptors.MissingLogLevel, method.GetLocation()); keepMethod = false; } foreach (KeyValuePair <string, string> t in lm.TemplateMap) { bool found = false; foreach (LoggerParameter p in lm.AllParameters) { if (t.Key.Equals(p.Name, StringComparison.OrdinalIgnoreCase)) { found = true; break; } } if (!found) { Diag(DiagnosticDescriptors.TemplateHasNoCorrespondingArgument, ma.GetLocation(), t.Key); } } } if (lc == null) { // determine the namespace the class is declared in, if any SyntaxNode?potentialNamespaceParent = classDec.Parent; while (potentialNamespaceParent != null && potentialNamespaceParent is not NamespaceDeclarationSyntax #if ROSLYN4_0_OR_GREATER && potentialNamespaceParent is not FileScopedNamespaceDeclarationSyntax #endif ) { potentialNamespaceParent = potentialNamespaceParent.Parent; } #if ROSLYN4_0_OR_GREATER if (potentialNamespaceParent is BaseNamespaceDeclarationSyntax namespaceParent) #else if (potentialNamespaceParent is NamespaceDeclarationSyntax namespaceParent) #endif { nspace = namespaceParent.Name.ToString(); while (true) { namespaceParent = namespaceParent.Parent as NamespaceDeclarationSyntax; if (namespaceParent == null) { break; } nspace = $"{namespaceParent.Name}.{nspace}"; } } } if (keepMethod) { lc ??= new LoggerClass { Keyword = classDec.Keyword.ValueText, Namespace = nspace, Name = classDec.Identifier.ToString() + classDec.TypeParameterList, ParentClass = null, }; LoggerClass currentLoggerClass = lc; var parentLoggerClass = (classDec.Parent as TypeDeclarationSyntax);
private Cci.IMetadataNamedArgument CreateMetadataNamedArgument(string name, TypedConstant argument, EmitContext context) { var symbol = LookupName(name); var value = CreateMetadataExpression(argument, context); TypeSymbol type; var fieldSymbol = symbol as FieldSymbol; if ((object)fieldSymbol != null) { type = fieldSymbol.Type; } else { type = ((PropertySymbol)symbol).Type; } PEModuleBuilder moduleBeingBuilt = (PEModuleBuilder)context.Module; return new MetadataNamedArgument(symbol, moduleBeingBuilt.Translate(type, syntaxNodeOpt: context.SyntaxNodeOpt, diagnostics: context.Diagnostics), value); }
protected abstract string ToString(TypedConstant typedConstant);
private MetadataCreateArray CreateMetadataArray(TypedConstant argument, EmitContext context) { Debug.Assert(!argument.Values.IsDefault); var values = argument.Values; var arrayType = (IArrayTypeSymbol)argument.Type; // Emit.PEModuleBuilder.Translate((ArrayTypeSymbol)argument.Type); throw new System.NotImplementedException(); //if (values.Length == 0) //{ // return new MetadataCreateArray(arrayType, // arrayType.GetElementType(context), // ImmutableArray<Cci.IMetadataExpression>.Empty); //} //var metadataExprs = new Cci.IMetadataExpression[values.Length]; //for (int i = 0; i < values.Length; i++) //{ // metadataExprs[i] = CreateMetadataExpression(values[i], context); //} //return new MetadataCreateArray(arrayType, // arrayType.GetElementType(context), // metadataExprs.AsImmutableOrNull()); }
/// <remarks> /// Since this method is expected to be called on every nested expression of the argument, it doesn't /// need to recurse (directly). /// </remarks> internal static bool CanBeValidAttributeArgument(ExpressionSyntax node, Binder typeBinder) { Debug.Assert(node != null); switch (node.Kind()) { // ObjectCreationExpression for primitive types, such as "new int()", are treated as constants and allowed in attribute arguments. case SyntaxKind.ObjectCreationExpression: { var objectCreation = (ObjectCreationExpressionSyntax)node; if (objectCreation.Initializer == null) { var unusedDiagnostics = DiagnosticBag.GetInstance(); var type = typeBinder.BindType(objectCreation.Type, unusedDiagnostics).Type; unusedDiagnostics.Free(); var kind = TypedConstant.GetTypedConstantKind(type, typeBinder.Compilation); switch (kind) { case TypedConstantKind.Primitive: case TypedConstantKind.Enum: switch (type.TypeKind) { case TypeKind.Struct: case TypeKind.Class: case TypeKind.Enum: return(true); default: return(false); } } } return(false); } // sizeof(int) case SyntaxKind.SizeOfExpression: // typeof(int) case SyntaxKind.TypeOfExpression: // constant expressions // SPEC: Section 7.19: Only the following constructs are permitted in constant expressions: // Literals (including the null literal). case SyntaxKind.NumericLiteralExpression: case SyntaxKind.StringLiteralExpression: case SyntaxKind.CharacterLiteralExpression: case SyntaxKind.TrueLiteralExpression: case SyntaxKind.FalseLiteralExpression: case SyntaxKind.NullLiteralExpression: // References to const members of class and struct types. // References to members of enumeration types. case SyntaxKind.IdentifierName: case SyntaxKind.GenericName: case SyntaxKind.AliasQualifiedName: case SyntaxKind.QualifiedName: case SyntaxKind.PredefinedType: case SyntaxKind.SimpleMemberAccessExpression: // References to const parameters or local variables. Not valid for attribute arguments, so skipped here. // Parenthesized sub-expressions, which are themselves constant expressions. case SyntaxKind.ParenthesizedExpression: // Cast expressions, provided the target type is one of the types listed above. case SyntaxKind.CastExpression: // checked and unchecked expressions case SyntaxKind.UncheckedExpression: case SyntaxKind.CheckedExpression: // Default value expressions case SyntaxKind.DefaultExpression: // The predefined +, –, !, and ~ unary operators. case SyntaxKind.UnaryPlusExpression: case SyntaxKind.UnaryMinusExpression: case SyntaxKind.LogicalNotExpression: case SyntaxKind.BitwiseNotExpression: // The predefined +, –, *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, and >= binary operators, provided each operand is of a type listed above. case SyntaxKind.AddExpression: case SyntaxKind.MultiplyExpression: case SyntaxKind.SubtractExpression: case SyntaxKind.DivideExpression: case SyntaxKind.ModuloExpression: case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.ExclusiveOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.LogicalOrExpression: case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.LessThanExpression: case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.InvocationExpression: // To support nameof(); anything else will be a compile-time error case SyntaxKind.ConditionalExpression: // The ?: conditional operator. return(true); default: return(false); } }
private static void CheckLanguage(TypedConstant argument, ref bool supportsCSharp, ref bool supportsVB) { if (argument.Kind == TypedConstantKind.Primitive && argument.Type != null && argument.Type.SpecialType == SpecialType.System_String) { string supportedLanguage = (string)argument.Value; if (supportedLanguage == LanguageNames.CSharp) { supportsCSharp = true; } else if (supportedLanguage == LanguageNames.VisualBasic) { supportsVB = true; } } }
internal SynthesizedAttributeData SynthesizeDebuggableAttribute() { TypeSymbol debuggableAttribute = GetWellKnownType(WellKnownType.System_Diagnostics_DebuggableAttribute); Debug.Assert((object)debuggableAttribute != null, "GetWellKnownType unexpectedly returned null"); if (debuggableAttribute is MissingMetadataTypeSymbol) { return(null); } TypeSymbol debuggingModesType = GetWellKnownType(WellKnownType.System_Diagnostics_DebuggableAttribute__DebuggingModes); Debug.Assert((object)debuggingModesType != null, "GetWellKnownType unexpectedly returned null"); if (debuggingModesType is MissingMetadataTypeSymbol) { return(null); } // IgnoreSymbolStoreDebuggingMode flag is checked by the CLR, it is not referred to by the debugger. // It tells the JIT that it doesn't need to load the PDB at the time it generates jitted code. // The PDB would still be used by a debugger, or even by the runtime for putting source line information // on exception stack traces. We always set this flag to avoid overhead of JIT loading the PDB. // The theoretical scenario for not setting it would be a language compiler that wants their sequence points // at specific places, but those places don't match what CLR's heuristics calculate when scanning the IL. var ignoreSymbolStoreDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__IgnoreSymbolStoreSequencePoints); if ((object)ignoreSymbolStoreDebuggingMode == null || !ignoreSymbolStoreDebuggingMode.HasConstantValue) { return(null); } int constantVal = ignoreSymbolStoreDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value; // Since .NET 2.0 the combinations of None, Default and DisableOptimizations have the following effect: // // None JIT optimizations enabled // Default JIT optimizations enabled // DisableOptimizations JIT optimizations enabled // Default | DisableOptimizations JIT optimizations disabled if (_options.OptimizationLevel == OptimizationLevel.Debug) { var defaultDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__Default); if ((object)defaultDebuggingMode == null || !defaultDebuggingMode.HasConstantValue) { return(null); } var disableOptimizationsDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__DisableOptimizations); if ((object)disableOptimizationsDebuggingMode == null || !disableOptimizationsDebuggingMode.HasConstantValue) { return(null); } constantVal |= defaultDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value; constantVal |= disableOptimizationsDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value; } if (_options.EnableEditAndContinue) { var enableEncDebuggingMode = (FieldSymbol)GetWellKnownTypeMember(WellKnownMember.System_Diagnostics_DebuggableAttribute_DebuggingModes__EnableEditAndContinue); if ((object)enableEncDebuggingMode == null || !enableEncDebuggingMode.HasConstantValue) { return(null); } constantVal |= enableEncDebuggingMode.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false).Int32Value; } var typedConstantDebugMode = new TypedConstant(debuggingModesType, TypedConstantKind.Enum, constantVal); return(TrySynthesizeAttribute( WellKnownMember.System_Diagnostics_DebuggableAttribute__ctorDebuggingModes, ImmutableArray.Create(typedConstantDebugMode))); }
/// <summary> /// Gets the rewritten attribute constructor arguments, i.e. the arguments /// are in the order of parameters, which may differ from the source /// if named constructor arguments are used. /// /// For example: /// void Foo(int x, int y, int z, int w = 3); /// /// Foo(0, z: 2, y: 1); /// /// Arguments returned: 0, 1, 2, 3 /// </summary> /// <returns>Rewritten attribute constructor arguments</returns> /// <remarks> /// CONSIDER: Can we share some code will call rewriting in the local rewriter? /// </remarks> private ImmutableArray<TypedConstant> GetRewrittenAttributeConstructorArguments( out ImmutableArray<int> constructorArgumentsSourceIndices, MethodSymbol attributeConstructor, ImmutableArray<TypedConstant> constructorArgsArray, ImmutableArray<string> constructorArgumentNamesOpt, AttributeSyntax syntax, DiagnosticBag diagnostics, ref bool hasErrors) { Debug.Assert((object)attributeConstructor != null); Debug.Assert(!constructorArgsArray.IsDefault); Debug.Assert(!hasErrors); int argumentsCount = constructorArgsArray.Length; // argsConsumedCount keeps track of the number of constructor arguments // consumed from this.ConstructorArguments array int argsConsumedCount = 0; bool hasNamedCtorArguments = !constructorArgumentNamesOpt.IsDefault; Debug.Assert(!hasNamedCtorArguments || constructorArgumentNamesOpt.Length == argumentsCount); // index of the first named constructor argument int firstNamedArgIndex = -1; ImmutableArray<ParameterSymbol> parameters = attributeConstructor.Parameters; int parameterCount = parameters.Length; var reorderedArguments = new TypedConstant[parameterCount]; int[] sourceIndices = null; for (int i = 0; i < parameterCount; i++) { Debug.Assert(argsConsumedCount <= argumentsCount); ParameterSymbol parameter = parameters[i]; TypedConstant reorderedArgument; if (parameter.IsParams && parameter.Type.IsSZArray() && i + 1 == parameterCount) { reorderedArgument = GetParamArrayArgument(parameter, constructorArgsArray, argumentsCount, argsConsumedCount, this.Conversions); sourceIndices = sourceIndices ?? CreateSourceIndicesArray(i, parameterCount); } else if (argsConsumedCount < argumentsCount) { if (!hasNamedCtorArguments || constructorArgumentNamesOpt[argsConsumedCount] == null) { // positional constructor argument reorderedArgument = constructorArgsArray[argsConsumedCount]; if (sourceIndices != null) { sourceIndices[i] = argsConsumedCount; } argsConsumedCount++; } else { // named constructor argument // Store the index of the first named constructor argument if (firstNamedArgIndex == -1) { firstNamedArgIndex = argsConsumedCount; } // Current parameter must either have a matching named argument or a default value // For the former case, argsConsumedCount must be incremented to note that we have // consumed a named argument. For the latter case, argsConsumedCount stays same. int matchingArgumentIndex; reorderedArgument = GetMatchingNamedOrOptionalConstructorArgument(out matchingArgumentIndex, constructorArgsArray, constructorArgumentNamesOpt, parameter, firstNamedArgIndex, argumentsCount, ref argsConsumedCount, syntax, diagnostics); sourceIndices = sourceIndices ?? CreateSourceIndicesArray(i, parameterCount); sourceIndices[i] = matchingArgumentIndex; } } else { reorderedArgument = GetDefaultValueArgument(parameter, syntax, diagnostics); sourceIndices = sourceIndices ?? CreateSourceIndicesArray(i, parameterCount); } if (!hasErrors) { if (reorderedArgument.Kind == TypedConstantKind.Error) { hasErrors = true; } else if (reorderedArgument.Kind == TypedConstantKind.Array && parameter.Type.TypeKind == TypeKind.Array && (TypeSymbol)reorderedArgument.Type != parameter.Type) { // NOTE: As in dev11, we don't allow array covariance conversions (presumably, we don't have a way to // represent the conversion in metadata). diagnostics.Add(ErrorCode.ERR_BadAttributeArgument, syntax.Location); hasErrors = true; } } reorderedArguments[i] = reorderedArgument; } constructorArgumentsSourceIndices = sourceIndices != null ? sourceIndices.AsImmutableOrNull() : default(ImmutableArray<int>); return reorderedArguments.AsImmutableOrNull(); }
private static string DisplayUnsignedEnumConstant(TypedConstant constant, SpecialType specialType, ulong constantToDecode, string typeName) { // Specified valueConstant might have an exact matching enum field // or it might be a bitwise Or of multiple enum fields. // For the later case, we keep track of the current value of // bitwise Or of possible enum fields. ulong curValue = 0; // Initialize the value string to empty PooledStringBuilder pooledBuilder = null; StringBuilder valueStringBuilder = null; // Iterate through all the constant members in the enum type var members = constant.Type.GetMembers(); foreach (var member in members) { var field = member as IFieldSymbol; if ((object)field != null && field.HasConstantValue) { ConstantValue memberConstant = ConstantValue.Create(field.ConstantValue, specialType); ulong memberValue = memberConstant.UInt64Value; // Do we have an exact matching enum field if (memberValue == constantToDecode) { if (pooledBuilder != null) { pooledBuilder.Free(); } return(typeName + "." + field.Name); } // specifiedValue might be a bitwise Or of multiple enum fields // Is the current member included in the specified value? if ((memberValue & constantToDecode) == memberValue) { // update the current value curValue = curValue | memberValue; if (valueStringBuilder == null) { pooledBuilder = PooledStringBuilder.GetInstance(); valueStringBuilder = pooledBuilder.Builder; } else { valueStringBuilder.Append(" | "); } valueStringBuilder.Append(typeName); valueStringBuilder.Append("."); valueStringBuilder.Append(field.Name); } } } if (pooledBuilder != null) { if (curValue == constantToDecode) { // return decoded enum constant return(pooledBuilder.ToStringAndFree()); } // Unable to decode the enum constant pooledBuilder.Free(); } // Unable to decode the enum constant, just display the integral value return(constant.Value.ToString()); }
protected override string ToString(TypedConstant typedConstant) => typedConstant.ToCSharpString();
void CollectUnion(INamedTypeSymbol type) { var unionKeys = type.GetMembers().OfType <IPropertySymbol>().Where(x => x.GetAttributes().FindAttributeShortName(UnionKeyAttributeShortName) != null).ToArray(); if (unionKeys.Length == 0) { throw new Exception($"Union class requires abstract [UnionKey]property. Type: {type.Name}. Location:{type.Locations[0]}"); } else if (unionKeys.Length != 1) { throw new Exception($"[UnionKey]property does not allow multiple key. Type: {type.Name}. Location:{type.Locations[0]}"); } var unionKeyProperty = unionKeys[0]; if (type.TypeKind != TypeKind.Interface) { if (!unionKeyProperty.GetMethod.IsAbstract) { throw new Exception($"Union class requires abstract [UnionKey]property. Type: {type.Name}. Location:{type.Locations[0]}"); } } var ctorArguments = type.GetAttributes().FindAttributeShortName(UnionAttributeShortName)?.ConstructorArguments; var firstArguments = ctorArguments?.FirstOrDefault(); if (firstArguments == null) { return; } TypedConstant fallbackType = default(TypedConstant); if (ctorArguments.Value.Length == 2) { fallbackType = ctorArguments.Value[1]; } var subTypList = new List <string>(); if (type.TypeKind != TypeKind.Interface) { foreach (var item in firstArguments.Value.Values.Concat(new[] { fallbackType }).Where(x => !x.IsNull).Select(x => x.Value).OfType <ITypeSymbol>()) { var found = item.FindBaseTargetType(type.ToDisplayString()); if (found == null) { throw new Exception($"All Union subTypes must be inherited type. Type: {type.Name}, SubType: {item.Name}. Location:{type.Locations[0]}"); } subTypList.Add(item.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); } } else { foreach (var item in firstArguments.Value.Values.Concat(new[] { fallbackType }).Where(x => !x.IsNull).Select(x => x.Value).OfType <ITypeSymbol>()) { var typeString = type.ToDisplayString(); if (!(item as INamedTypeSymbol).AllInterfaces.Any(x => x.OriginalDefinition?.ToDisplayString() == typeString)) { throw new Exception($"All Union subTypes must be inherited type. Type: {type.Name}, SubType: {item.Name}. Location:{type.Locations[0]}"); } subTypList.Add(item.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); } } unionTypeContainer.Add(new UnionType { Name = type.Name, FullName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), Namespace = type.ContainingNamespace.IsGlobalNamespace ? null : type.ContainingNamespace.ToDisplayString(), UnionKeyTypeName = unionKeyProperty.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), UnionKeyPropertyName = unionKeyProperty.Name, SubTypeNames = subTypList.ToArray(), FallbackTypeName = fallbackType.IsNull ? null : (fallbackType.Value as INamedTypeSymbol).ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) }); }