internal static ImmutableArray <AttributeSyntax> GetConfigurationAttributes( AttributedMembers attrMembers, ITypeSymbol attributeType, FrameworkTypes frameworkTypes, ISymbol member ) { if (!attrMembers.AttributedSymbolsToAttributes.TryGetValue(member, out var attrs)) { return(ImmutableArray <AttributeSyntax> .Empty); } var relevantAttributes = ImmutableArray.CreateBuilder <AttributeSyntax>(); foreach (var(attr, attrType) in attrs) { if (attributeType.Equals(attrType, SymbolEqualityComparer.Default)) { relevantAttributes.Add(attr); } if (frameworkTypes.DataMemberAttribute != null && frameworkTypes.DataMemberAttribute.Equals(attrType, SymbolEqualityComparer.Default)) { relevantAttributes.Add(attr); } } return(relevantAttributes.ToImmutable()); }
internal static (SerializableMember?Member, ImmutableArray <Diagnostic> Diagnostics) ForField( Compilation compilation, AttributedMembers attrMembers, SerializerTypes types, INamedTypeSymbol serializingType, IFieldSymbol field, ImmutableArray <AttributeSyntax> attrs ) { var diags = ImmutableArray <Diagnostic> .Empty; var fieldLoc = field.Locations.FirstOrDefault(); var name = field.Name; var attrName = Utils.GetNameFromAttributes(attrMembers, fieldLoc, attrs, ref diags); name = attrName ?? name; var getter = new Getter(field); int?order = Utils.GetOrderFromAttributes(attrMembers, fieldLoc, types.Framework, types.OurTypes.SerializerMemberAttribute, attrs, ref diags); var emitDefaultValue = true; var attrEmitDefaultValue = GetEmitDefaultValueFromAttributes(attrMembers, fieldLoc, attrs, ref diags); emitDefaultValue = attrEmitDefaultValue ?? emitDefaultValue; var formatter = GetFormatter(compilation, attrMembers, types, field.Type, fieldLoc, attrs, ref diags); var shouldSerialize = GetShouldSerialize(compilation, attrMembers, types, serializingType, fieldLoc, attrs, ref diags); return(MakeMember(fieldLoc, types, name, getter, formatter, shouldSerialize, emitDefaultValue, order, diags)); }
internal static (DeserializableMember?Member, ImmutableArray <Diagnostic> Diagnostics) ForField( Compilation compilation, AttributedMembers attrMembers, DeserializerTypes types, INamedTypeSymbol deserializingType, IFieldSymbol field, ImmutableArray <AttributeSyntax> attrs ) { var diags = ImmutableArray <Diagnostic> .Empty; var fieldLoc = field.Locations.FirstOrDefault(); var attrName = Utils.GetNameFromAttributes(attrMembers, fieldLoc, attrs, ref diags); var name = attrName ?? field.Name; var setter = new Setter(field); int?order = Utils.GetOrderFromAttributes(attrMembers, fieldLoc, types.Framework, types.OurTypes.DeserializerMemberAttribute, attrs, ref diags); var isRequired = false; var attrIsRequiredValue = GetMemberRequiredFromAttributes(attrMembers, fieldLoc, attrs, ref diags); isRequired = attrIsRequiredValue ?? isRequired; var reset = GetReset(compilation, attrMembers, types, deserializingType, fieldLoc, attrs, ref diags); var parser = GetParser(compilation, attrMembers, types, setter.ValueType, fieldLoc, attrs, ref diags); return(MakeMember(fieldLoc, types, name, setter, parser, reset, isRequired, order, diags)); }
internal abstract ImmutableDictionary <INamedTypeSymbol, ImmutableArray <TMemberDescriber> > GetMembersToGenerateFor( GeneratorExecutionContext context, Compilation compilation, ImmutableArray <TypeDeclarationSyntax> toGenerateFor, AttributedMembers members, TNeededTypes types );
internal static InstanceProvider?ForDefault(AttributedMembers attrMembers, INamedTypeSymbol type, ref ImmutableArray <Diagnostic> diags) { var(isRecord, recordCons, _) = type.IsRecord(); if (isRecord) { recordCons = Utils.NonNull(recordCons); return(new InstanceProvider(true, recordCons, type)); } var defaultCons = type.InstanceConstructors.SingleOrDefault(p => p.Parameters.Length == 0); if (defaultCons != null) { var accessible = defaultCons.IsAccessible(attrMembers); if (!accessible) { var diag = Diagnostics.MethodNotPublicOrInternal(defaultCons.Locations.FirstOrDefault(), defaultCons); diags = diags.Add(diag); return(null); } return(new InstanceProvider(type)); } else { var diag = Diagnostics.NoInstanceProvider(type.Locations.FirstOrDefault(), type); diags = diags.Add(diag); return(null); } }
private static bool?GetMemberRequiredFromAttributes( AttributedMembers attrMembers, Location?location, ImmutableArray <AttributeSyntax> attrs, ref ImmutableArray <Diagnostic> diags ) { var requiredByte = Utils.GetConstantsWithName <byte>(attrMembers, attrs, "MemberRequired", ref diags); var requiredBool = Utils.GetConstantsWithName <bool>(attrMembers, attrs, "IsRequired", ref diags); var total = requiredByte.Length + requiredBool.Length; if (total > 1) { var diag = Diagnostics.IsRequiredSpecifiedMultipleTimes(location); diags = diags.Add(diag); return(null); } if (total == 0) { return(null); } if (requiredByte.Length == 1) { var byteVal = requiredByte.Single(); var logicalVal = byteVal switch { 1 => true, 2 => false, _ => default(bool?) }; if (logicalVal == null) { var diag = Diagnostics.UnexpectedConstantValue(location, byteVal.ToString(), new[] { "Yes", "No" }); diags = diags.Add(diag); return(null); } return(logicalVal); } var boolVal = requiredBool.Single(); return(boolVal); }
internal static (SerializableMember?Member, ImmutableArray <Diagnostic> Diagnostics) ForProperty( Compilation compilation, AttributedMembers attrMembers, SerializerTypes types, INamedTypeSymbol serializingType, IPropertySymbol prop, ImmutableArray <AttributeSyntax> attrs ) { var diags = ImmutableArray <Diagnostic> .Empty; var propLoc = prop.Locations.FirstOrDefault(); if (prop.GetMethod == null) { var diag = Diagnostics.NoGetterOnSerializableProperty(propLoc); diags = diags.Add(diag); } if (prop.Parameters.Any()) { var diag = Diagnostics.SerializablePropertyCannotHaveParameters(propLoc); diags = diags.Add(diag); } var name = prop.Name; var attrName = Utils.GetNameFromAttributes(attrMembers, propLoc, attrs, ref diags); name = attrName ?? name; var getter = new Getter(prop); int?order = Utils.GetOrderFromAttributes(attrMembers, propLoc, types.Framework, types.OurTypes.SerializerMemberAttribute, attrs, ref diags); var emitDefaultValue = true; var attrEmitDefaultValue = GetEmitDefaultValueFromAttributes(attrMembers, propLoc, attrs, ref diags); emitDefaultValue = attrEmitDefaultValue ?? emitDefaultValue; var formatter = GetFormatter(compilation, attrMembers, types, prop.Type, propLoc, attrs, ref diags); var shouldSerialize = GetShouldSerialize(compilation, attrMembers, types, serializingType, propLoc, attrs, ref diags); // only do this for properties shouldSerialize ??= InferDefaultShouldSerialize(attrMembers, types, serializingType, prop.Name, attrs, propLoc, ref diags); return(MakeMember(propLoc, types, name, getter, formatter, shouldSerialize, emitDefaultValue, order, diags)); }
internal static (DeserializableMember?Member, ImmutableArray <Diagnostic> Diagnostics) ForConstructorParameter( Compilation compilation, AttributedMembers attrMembers, DeserializerTypes types, INamedTypeSymbol deserializingType, IParameterSymbol parameter, ImmutableArray <AttributeSyntax> attrs ) { var diags = ImmutableArray <Diagnostic> .Empty; var parameterLoc = parameter.Locations.FirstOrDefault(); var attrName = Utils.GetNameFromAttributes(attrMembers, parameterLoc, attrs, ref diags); var name = attrName ?? parameter.Name; var setter = new Setter(parameter); int?order = Utils.GetOrderFromAttributes(attrMembers, parameterLoc, types.Framework, types.OurTypes.DeserializerMemberAttribute, attrs, ref diags); // note that this defaults to TRUE var isRequired = true; var attrIsRequiredValue = GetMemberRequiredFromAttributes(attrMembers, parameterLoc, attrs, ref diags); isRequired = attrIsRequiredValue ?? isRequired; if (!isRequired) { var diag = Diagnostics.ParametersMustBeRequired(parameterLoc, deserializingType, parameter); diags = diags.Add(diag); return(null, diags); } var reset = GetReset(compilation, attrMembers, types, deserializingType, parameterLoc, attrs, ref diags); if (reset != null && !reset.IsStatic) { var diag = Diagnostics.BadReset_MustBeStaticForParameters(parameterLoc, deserializingType, parameter, reset.Method); diags = diags.Add(diag); return(null, diags); } var parser = GetParser(compilation, attrMembers, types, setter.ValueType, parameterLoc, attrs, ref diags); return(MakeMember(parameterLoc, types, name, setter, parser, reset, isRequired, order, diags)); }
internal static (DeserializableMember?Member, ImmutableArray <Diagnostic> Diagnostics) ForProperty( Compilation compilation, AttributedMembers attrMembers, DeserializerTypes types, INamedTypeSymbol deserializingType, IPropertySymbol prop, ImmutableArray <AttributeSyntax> attrs ) { var diags = ImmutableArray <Diagnostic> .Empty; var propLoc = prop.Locations.FirstOrDefault(); if (prop.SetMethod == null) { var diag = Diagnostics.NoSetterOnDeserializableProperty(propLoc); diags = diags.Add(diag); } if (prop.Parameters.Any()) { var diag = Diagnostics.DeserializablePropertyCannotHaveParameters(propLoc); diags = diags.Add(diag); } var attrName = Utils.GetNameFromAttributes(attrMembers, propLoc, attrs, ref diags); var name = attrName ?? prop.Name; var setter = new Setter(prop); int?order = Utils.GetOrderFromAttributes(attrMembers, propLoc, types.Framework, types.OurTypes.DeserializerMemberAttribute, attrs, ref diags); var isRequired = false; var attrIsRequiredValue = GetMemberRequiredFromAttributes(attrMembers, propLoc, attrs, ref diags); isRequired = attrIsRequiredValue ?? isRequired; var reset = GetReset(compilation, attrMembers, types, deserializingType, propLoc, attrs, ref diags); var parser = GetParser(compilation, attrMembers, types, setter.ValueType, propLoc, attrs, ref diags); // only do this for properties reset ??= InferDefaultReset(attrMembers, types, deserializingType, prop.Name, attrs, propLoc, ref diags); return(MakeMember(propLoc, types, name, setter, parser, reset, isRequired, order, diags)); }
internal static (SerializableMember?Member, ImmutableArray <Diagnostic> Diagnostics) ForMethod( Compilation compilation, AttributedMembers attrMembers, SerializerTypes types, INamedTypeSymbol serializingType, IMethodSymbol mtd, ImmutableArray <AttributeSyntax> attrs ) { var diags = ImmutableArray <Diagnostic> .Empty; var mtdLoc = mtd.Locations.FirstOrDefault(); var attrName = Utils.GetNameFromAttributes(attrMembers, mtdLoc, attrs, ref diags); if (attrName == null) { var diag = Diagnostics.SerializableMemberMustHaveNameSetForMethod(mtdLoc, mtd); diags = diags.Add(diag); attrName = "--UNKNOWN--"; } var getter = GetGetterForMethod(compilation, types, serializingType, mtd, mtdLoc, ref diags); int?order = Utils.GetOrderFromAttributes(attrMembers, mtdLoc, types.Framework, types.OurTypes.SerializerMemberAttribute, attrs, ref diags); var emitDefaultValue = true; var attrEmitDefaultValue = GetEmitDefaultValueFromAttributes(attrMembers, mtdLoc, attrs, ref diags); emitDefaultValue = attrEmitDefaultValue ?? emitDefaultValue; var shouldSerialize = GetShouldSerialize(compilation, attrMembers, types, serializingType, mtdLoc, attrs, ref diags); // after this point, we need to know what we're working with if (getter == null) { return(null, diags); } var formatter = GetFormatter(compilation, attrMembers, types, getter.ForType, mtdLoc, attrs, ref diags); return(MakeMember(mtdLoc, types, attrName, getter, formatter, shouldSerialize, emitDefaultValue, order, diags)); }
internal static (DeserializableMember?Member, ImmutableArray <Diagnostic> Diagnostics) ForMethod( Compilation compilation, AttributedMembers attrMembers, DeserializerTypes types, INamedTypeSymbol deserializingType, IMethodSymbol mtd, ImmutableArray <AttributeSyntax> attrs ) { var diags = ImmutableArray <Diagnostic> .Empty; var mtdLoc = mtd.Locations.FirstOrDefault(); var attrName = Utils.GetNameFromAttributes(attrMembers, mtdLoc, attrs, ref diags); if (attrName == null) { var diag = Diagnostics.DeserializableMemberMustHaveNameSetForMethod(mtdLoc, mtd); diags = diags.Add(diag); attrName = "--UNKNOWN--"; } var setter = GetSetterForMethod(compilation, types, deserializingType, mtd, mtdLoc, ref diags); int?order = Utils.GetOrderFromAttributes(attrMembers, mtdLoc, types.Framework, types.OurTypes.DeserializerMemberAttribute, attrs, ref diags); var isRequired = false; var attrIsRequiredValue = GetMemberRequiredFromAttributes(attrMembers, mtdLoc, attrs, ref diags); isRequired = attrIsRequiredValue ?? isRequired; var reset = GetReset(compilation, attrMembers, types, deserializingType, mtdLoc, attrs, ref diags); // after this point, we need to know what we're working with if (setter == null) { return(null, diags); } var parser = GetParser(compilation, attrMembers, types, setter.ValueType, mtdLoc, attrs, ref diags); return(MakeMember(mtdLoc, types, attrName, setter, parser, reset, isRequired, order, diags)); }
internal static Reset?InferDefaultReset( AttributedMembers attrMembers, DeserializerTypes types, ITypeSymbol declaringType, string propertyName, ImmutableArray <AttributeSyntax> attrs, Location?location, ref ImmutableArray <Diagnostic> diags ) { var ignoredDiags = ImmutableArray <Diagnostic> .Empty; var resetType = Utils.GetTypeConstantWithName(attrMembers, attrs, "ResetType", ref ignoredDiags); var resetMethod = Utils.GetConstantsWithName <string>(attrMembers, attrs, "ResetMethodName", ref ignoredDiags); // if anything _tried_ to set a non-default, don't include any defaults if (!resetType.IsEmpty || !resetMethod.IsEmpty) { return(null); } foreach (var candidate in declaringType.GetMembers("Reset" + propertyName)) { var mtd = candidate as IMethodSymbol; if (mtd == null) { continue; } if (mtd.ReturnType.SpecialType != SpecialType.System_Void) { continue; } bool isStatic, takesContext; var ps = mtd.Parameters; if (mtd.IsStatic) { isStatic = true; if (ps.Length == 0) { takesContext = false; } else if (ps.Length == 1) { takesContext = ps[0].IsInReadContext(types.OurTypes); if (!takesContext && !ps[0].Equals(declaringType, SymbolEqualityComparer.Default)) { var diag = Diagnostics.BadResetParameters_StaticOne(location, mtd, ps[0].Type); diags = diags.Add(diag); return(null); } } else { continue; } } else { isStatic = false; takesContext = false; if (ps.Length != 0) { continue; } } return(new Reset(mtd, isStatic, false, false, takesContext)); } return(null); }
private static Reset?GetReset( Compilation compilation, AttributedMembers attrMembers, DeserializerTypes types, INamedTypeSymbol rowType, Location?location, ImmutableArray <AttributeSyntax> attrs, ref ImmutableArray <Diagnostic> diags ) { var reset = Utils.GetMethodFromAttribute( attrMembers, "ResetType", Diagnostics.ResetTypeSpecifiedMultipleTimes, "ResetMethodName", Diagnostics.ResetMethodNameSpecifiedMultipleTimes, Diagnostics.ResetBothMustBeSet, location, attrs, ref diags ); if (reset == null) { return(null); } var(type, name) = reset.Value; var resetMtd = Utils.GetMethod(type, name, location, ref diags); if (resetMtd == null) { return(null); } var methodReturnType = resetMtd.ReturnType; if (methodReturnType.SpecialType != SpecialType.System_Void) { var diag = Diagnostics.MethodMustReturnVoid(location, resetMtd); diags = diags.Add(diag); return(null); } if (resetMtd.IsGenericMethod) { var diag = Diagnostics.MethodCannotBeGeneric(location, resetMtd); diags = diags.Add(diag); return(null); } var accessible = resetMtd.IsAccessible(attrMembers); if (!accessible) { var diag = Diagnostics.MethodNotPublicOrInternal(location, resetMtd); diags = diags.Add(diag); return(null); } var ps = resetMtd.Parameters; bool isStatic; bool takesRow; bool takesRowByRef; bool takesContext; if (resetMtd.IsStatic) { isStatic = true; // Options: // - zero parameters or // - a single parameter of the row type or // - a single parameter of `in ReadContext` or // - two parameters, the first of the row type (which may be by ref) and the second of `in ReadContext` if (ps.Length == 0) { // zero parameters takesRow = false; takesRowByRef = false; takesContext = false; } else if (ps.Length == 1) { var p0 = ps[0]; if (p0.RefKind == RefKind.In) { // a single parameter of `in ReadContext` if (!p0.IsInReadContext(types.OurTypes)) { var diag = Diagnostics.BadResetParameters_StaticOne(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } takesRow = false; takesRowByRef = false; takesContext = true; } else if (p0.RefKind == RefKind.None) { // a single parameter of the row type if (!p0.IsNormalParameterOfType(compilation, rowType)) { var diag = Diagnostics.BadResetParameters_StaticOne(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } takesRow = true; takesRowByRef = false; takesContext = false; } else { var diag = Diagnostics.BadResetParameters_StaticOne(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } } else if (ps.Length == 2) { // two parameters, the first of the row type (which may be by ref) and the second of `in ReadContext` var p0 = ps[0]; if (!p0.RefKind.IsNormalOrByRef()) { var diag = Diagnostics.BadResetParameters_StaticTwo(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } if (!p0.Type.Equals(rowType, SymbolEqualityComparer.Default)) { var diag = Diagnostics.BadResetParameters_StaticTwo(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } var p1 = ps[1]; if (!p1.IsInReadContext(types.OurTypes)) { var diag = Diagnostics.BadResetParameters_StaticTwo(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } takesRow = true; takesRowByRef = p0.RefKind == RefKind.Ref; takesContext = true; } else { var diag = Diagnostics.BadResetParameters_TooMany(location, resetMtd); diags = diags.Add(diag); return(null); } } else { isStatic = false; // be on the row type... var declaredOn = Utils.NonNull(resetMtd.ContainingType); var conversion = compilation.ClassifyConversion(rowType, declaredOn); var canConvert = conversion.IsImplicit || conversion.IsIdentity; if (!canConvert) { var diag = Diagnostics.BadReset_NotOnRow(location, resetMtd, rowType); diags = diags.Add(diag); return(null); } // Options: // - zero parameters or // - a single `in ReadContext` parameter. if (ps.Length == 0) { takesRow = true; takesRowByRef = false; takesContext = false; } else if (ps.Length == 1) { var p0 = ps[0]; if (!p0.IsInReadContext(types.OurTypes)) { var diag = Diagnostics.BadResetParameters_InstanceOne(location, resetMtd); diags = diags.Add(diag); return(null); } takesRow = true; takesRowByRef = false; takesContext = true; } else { var diag = Diagnostics.BadResetParameters_TooMany(location, resetMtd); diags = diags.Add(diag); return(null); } } return(new Reset(resetMtd, isStatic, takesRow, takesRowByRef, takesContext)); }
private static Formatter?GetFormatter( Compilation compilation, AttributedMembers attrMembers, SerializerTypes types, ITypeSymbol toFormatType, Location?location, ImmutableArray <AttributeSyntax> attrs, ref ImmutableArray <Diagnostic> diags ) { var formatter = Utils.GetMethodFromAttribute( attrMembers, "FormatterType", Diagnostics.FormatterTypeSpecifiedMultipleTimes, "FormatterMethodName", Diagnostics.FormatterMethodNameSpecifiedMultipleTimes, Diagnostics.FormatterBothMustBeSet, location, attrs, ref diags ); if (formatter == null) { return(null); } var(type, mtd) = formatter.Value; var formatterMtd = Utils.GetMethod(type, mtd, location, ref diags); if (formatterMtd == null) { return(null); } if (formatterMtd.IsGenericMethod) { var diag = Diagnostics.MethodCannotBeGeneric(location, formatterMtd); diags = diags.Add(diag); return(null); } var accessible = formatterMtd.IsAccessible(attrMembers); if (!accessible) { var diag = Diagnostics.MethodNotPublicOrInternal(location, formatterMtd); diags = diags.Add(diag); return(null); } if (!formatterMtd.IsStatic) { var diag = Diagnostics.MethodNotStatic(location, formatterMtd); diags = diags.Add(diag); return(null); } if (!formatterMtd.ReturnType.Equals(types.BuiltIn.Bool, SymbolEqualityComparer.Default)) { var diag = Diagnostics.MethodMustReturnBool(location, formatterMtd); diags = diags.Add(diag); return(null); } var formatterParams = formatterMtd.Parameters; if (formatterParams.Length != 3) { var diag = Diagnostics.BadFormatterParameters(location, formatterMtd, toFormatType); diags = diags.Add(diag); return(null); } var p0 = formatterParams[0]; if (!p0.IsNormalParameterOfType(compilation, toFormatType)) { var diag = Diagnostics.BadFormatterParameters(location, formatterMtd, toFormatType); diags = diags.Add(diag); return(null); } var p1 = formatterParams[1]; if (!p1.IsInWriteContext(types.OurTypes)) { var diag = Diagnostics.BadFormatterParameters(location, formatterMtd, toFormatType); diags = diags.Add(diag); return(null); } var p2 = formatterParams[2]; if (!p2.IsNormalParameterOfType(compilation, types.Framework.IBufferWriterOfChar)) { var diag = Diagnostics.BadFormatterParameters(location, formatterMtd, toFormatType); diags = diags.Add(diag); return(null); } return(new Formatter(formatterMtd, toFormatType)); }
private static ShouldSerialize?GetShouldSerialize( Compilation compilation, AttributedMembers attrMembers, SerializerTypes types, INamedTypeSymbol rowType, Location?location, ImmutableArray <AttributeSyntax> attrs, ref ImmutableArray <Diagnostic> diags ) { var shouldSerialize = Utils.GetMethodFromAttribute( attrMembers, "ShouldSerializeType", Diagnostics.ShouldSerializeTypeSpecifiedMultipleTimes, "ShouldSerializeMethodName", Diagnostics.ShouldSerializeMethodNameSpecifiedMultipleTimes, Diagnostics.ShouldSerializeBothMustBeSet, location, attrs, ref diags ); if (shouldSerialize == null) { return(null); } var(type, mtd) = shouldSerialize.Value; var shouldSerializeMtd = Utils.GetMethod(type, mtd, location, ref diags); if (shouldSerializeMtd == null) { return(null); } if (shouldSerializeMtd.IsGenericMethod) { var diag = Diagnostics.MethodCannotBeGeneric(location, shouldSerializeMtd); diags = diags.Add(diag); return(null); } var accessible = shouldSerializeMtd.IsAccessible(attrMembers); if (!accessible) { var diag = Diagnostics.MethodNotPublicOrInternal(location, shouldSerializeMtd); diags = diags.Add(diag); return(null); } if (!shouldSerializeMtd.ReturnType.Equals(types.BuiltIn.Bool, SymbolEqualityComparer.Default)) { var diag = Diagnostics.MethodMustReturnBool(location, shouldSerializeMtd); diags = diags.Add(diag); return(null); } var shouldSerializeParams = shouldSerializeMtd.Parameters; var isStatic = shouldSerializeMtd.IsStatic; bool takesContext; bool takesRow; if (isStatic) { // can legally take // 1. no parameters // 2. one parameter, a type which declares the annotated member // 3. one parameter, in WriteContext // 4. two parameters // 1. the type which declares the annotated member, or one which can be assigned to it, and // 2. in WriteContext if (shouldSerializeParams.Length == 0) { // fine! takesContext = false; takesRow = false; } else if (shouldSerializeParams.Length == 1) { var p0 = shouldSerializeParams[0]; if (p0.IsInWriteContext(types.OurTypes)) { takesRow = false; takesContext = true; } else { if (!p0.IsNormalParameterOfType(compilation, rowType)) { var diag = Diagnostics.BadShouldSerializeParameters_StaticOne(location, shouldSerializeMtd, rowType); diags = diags.Add(diag); return(null); } takesRow = true; takesContext = false; } } else if (shouldSerializeParams.Length == 2) { var p0 = shouldSerializeParams[0]; if (!p0.IsNormalParameterOfType(compilation, rowType)) { var diag = Diagnostics.BadShouldSerializeParameters_StaticTwo(location, shouldSerializeMtd, rowType); diags = diags.Add(diag); return(null); } var p1 = shouldSerializeParams[1]; if (!p1.IsInWriteContext(types.OurTypes)) { var diag = Diagnostics.BadShouldSerializeParameters_StaticTwo(location, shouldSerializeMtd, rowType); diags = diags.Add(diag); return(null); } takesRow = true; takesContext = true; } else { var diag = Diagnostics.BadShouldSerializeParameters_TooMany(location, shouldSerializeMtd); diags = diags.Add(diag); return(null); } } else { // can legally take // 1. no parameters // 2. one in WriteContext parameter var onType = shouldSerializeMtd.ContainingType; if (!onType.Equals(rowType, SymbolEqualityComparer.Default)) { var diag = Diagnostics.ShouldSerializeInstanceOnWrongType(location, shouldSerializeMtd, rowType); diags = diags.Add(diag); return(null); } takesRow = true; if (shouldSerializeParams.Length == 0) { takesContext = false; } else if (shouldSerializeParams.Length == 1) { var p0 = shouldSerializeParams[0]; if (!p0.IsInWriteContext(types.OurTypes)) { var diag = Diagnostics.BadShouldSerializeParameters_InstanceOne(location, shouldSerializeMtd); diags = diags.Add(diag); return(null); } takesContext = true; } else { var diag = Diagnostics.BadShouldSerializeParameters_TooMany(location, shouldSerializeMtd); diags = diags.Add(diag); return(null); } } return(new ShouldSerialize(shouldSerializeMtd, isStatic, takesRow, takesContext)); }
private static Parser?GetParser( Compilation compilation, AttributedMembers attrMembers, DeserializerTypes types, ITypeSymbol toParseType, Location?location, ImmutableArray <AttributeSyntax> attrs, ref ImmutableArray <Diagnostic> diags ) { var parser = Utils.GetMethodFromAttribute( attrMembers, "ParserType", Diagnostics.ParserTypeSpecifiedMultipleTimes, "ParserMethodName", Diagnostics.ParserMethodNameSpecifiedMultipleTimes, Diagnostics.ParserBothMustBeSet, location, attrs, ref diags ); if (parser == null) { return(null); } var(type, name) = parser.Value; var parserMtd = Utils.GetMethod(type, name, location, ref diags); if (parserMtd == null) { return(null); } var methodReturnType = parserMtd.ReturnType; if (methodReturnType.SpecialType != SpecialType.System_Boolean) { var diag = Diagnostics.MethodMustReturnBool(location, parserMtd); diags = diags.Add(diag); return(null); } if (!parserMtd.IsStatic) { var diag = Diagnostics.MethodNotStatic(location, parserMtd); diags = diags.Add(diag); return(null); } var accessible = parserMtd.IsAccessible(attrMembers); if (!accessible) { var diag = Diagnostics.MethodNotPublicOrInternal(location, parserMtd); diags = diags.Add(diag); return(null); } var ps = parserMtd.Parameters; if (ps.Length != 3) { var diag = Diagnostics.BadParserParameters(location, parserMtd); diags = diags.Add(diag); return(null); } // Parameters // * ReadOnlySpan(char) // * in ReadContext, // * out assignable to outputType var p0 = ps[0]; if (!p0.IsNormalParameterOfType(compilation, types.Framework.ReadOnlySpanOfChar)) { var diag = Diagnostics.BadParserParameters(location, parserMtd); diags = diags.Add(diag); return(null); } var p1 = ps[1]; if (!p1.IsInReadContext(types.OurTypes)) { var diag = Diagnostics.BadParserParameters(location, parserMtd); diags = diags.Add(diag); return(null); } var p2 = ps[2]; if (p2.RefKind != RefKind.Out) { var diag = Diagnostics.BadParserParameters(location, parserMtd); diags = diags.Add(diag); return(null); } var conversion = compilation.ClassifyConversion(p2.Type, toParseType); var canConvert = conversion.IsImplicit || conversion.IsIdentity; if (!canConvert) { var diag = Diagnostics.BadParserParameters(location, parserMtd); diags = diags.Add(diag); return(null); } return(new Parser(parserMtd, p2.Type)); }
internal abstract ImmutableArray <TypeDeclarationSyntax> GetTypesToGenerateFor(AttributedMembers attrMembers, TNeededTypes types);
// todo: can this be made to handle InternalsVisibleTo? internal static bool IsAccessible(this IMethodSymbol mtd, AttributedMembers attrMembers) => mtd.DeclaredAccessibility == Accessibility.Public || (attrMembers.CompilingAssembly.Equals(mtd.ContainingAssembly, SymbolEqualityComparer.Default) && mtd.DeclaredAccessibility == Accessibility.Internal);
internal static InstanceProvider?ForMethod( Compilation compilation, AttributedMembers attrMembers, DeserializerTypes types, Location?loc, INamedTypeSymbol rowType, INamedTypeSymbol hostType, string mtdName, ref ImmutableArray <Diagnostic> diags ) { var instanceProviderMtd = Utils.GetMethod(hostType, mtdName, loc, ref diags); if (instanceProviderMtd == null) { return(null); } var instanceProviderLoc = instanceProviderMtd.Locations.FirstOrDefault(); var methodReturnType = instanceProviderMtd.ReturnType; if (methodReturnType.SpecialType != SpecialType.System_Boolean) { var diag = Diagnostics.MethodMustReturnBool(instanceProviderLoc, instanceProviderMtd); diags = diags.Add(diag); return(null); } if (!instanceProviderMtd.IsStatic) { var diag = Diagnostics.MethodNotStatic(instanceProviderLoc, instanceProviderMtd); diags = diags.Add(diag); return(null); } var accessible = instanceProviderMtd.IsAccessible(attrMembers); if (!accessible) { var diag = Diagnostics.MethodNotPublicOrInternal(instanceProviderLoc, instanceProviderMtd); diags = diags.Add(diag); return(null); } var ps = instanceProviderMtd.Parameters; if (ps.Length != 2) { var diag = Diagnostics.BadInstanceProviderParameters(instanceProviderLoc, instanceProviderMtd); diags = diags.Add(diag); return(null); } var p0 = ps[0]; if (!p0.IsInReadContext(types.OurTypes)) { var diag = Diagnostics.BadInstanceProviderParameters(instanceProviderLoc, instanceProviderMtd); diags = diags.Add(diag); return(null); } var p1 = ps[1]; if (p1.RefKind != RefKind.Out) { var diag = Diagnostics.BadInstanceProviderParameters(instanceProviderLoc, instanceProviderMtd); diags = diags.Add(diag); return(null); } var conversion = compilation.ClassifyConversion(p1.Type, rowType); var canConvert = conversion.IsImplicit || conversion.IsIdentity; if (!canConvert) { var diag = Diagnostics.BadInstanceProviderParameters(instanceProviderLoc, instanceProviderMtd); diags = diags.Add(diag); return(null); } return(new InstanceProvider(false, instanceProviderMtd, p1.Type)); }