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 Setter?GetSetterForMethod( Compilation compilation, DeserializerTypes types, ITypeSymbol rowType, IMethodSymbol method, Location?location, ref ImmutableArray <Diagnostic> diags ) { var methodReturnType = method.ReturnType; if (methodReturnType.SpecialType != SpecialType.System_Void) { var diag = Diagnostics.MethodMustReturnVoid(location, method); diags = diags.Add(diag); return(null); } if (method.IsGenericMethod) { var diag = Diagnostics.MethodCannotBeGeneric(location, method); diags = diags.Add(diag); return(null); } ITypeSymbol takesValue; bool takesRow; bool takesRowByRef; bool takesContext; var ps = method.Parameters; if (method.IsStatic) { // Options: // - take 1 parameter (the result of the parser) or // - take 2 parameters, the result of the parser and an `in ReadContext` or // - take 2 parameters, the row type (which may be passed by ref), and the result of the parser or // - take 3 parameters, the row type (which may be passed by ref), the result of the parser, and `in ReadContext` if (ps.Length == 0) { var diag = Diagnostics.BadSetterParameters_TooFew(location, method); diags = diags.Add(diag); return(null); } else if (ps.Length == 1) { // take 1 parameter (the result of the parser) var p0 = ps[0]; if (p0.RefKind != RefKind.None) { var diag = Diagnostics.BadSetterParameters_StaticOne(location, method); diags = diags.Add(diag); return(null); } takesValue = p0.Type; takesRow = false; takesRowByRef = false; takesContext = false; } else if (ps.Length == 2) { var p1 = ps[1]; if (p1.IsInReadContext(types.OurTypes)) { // take 2 parameters, the result of the parser and an `in ReadContext` var p0 = ps[0]; if (p0.RefKind != RefKind.None) { var diag = Diagnostics.BadSetterParameters_StaticTwo(location, method, rowType); diags = diags.Add(diag); return(null); } takesValue = p0.Type; takesRow = false; takesRowByRef = false; takesContext = true; } else { // take 2 parameters, the row type (which may be passed by ref), and the result of the parser var p0 = ps[0]; if (!p0.Type.Equals(rowType, SymbolEqualityComparer.Default)) { var diag = Diagnostics.BadSetterParameters_StaticTwo(location, method, rowType); diags = diags.Add(diag); return(null); } var p0RefKind = p0.RefKind; if (!p0RefKind.IsNormalOrByRef()) { var diag = Diagnostics.BadSetterParameters_StaticTwo(location, method, rowType); diags = diags.Add(diag); return(null); } if (p1.RefKind != RefKind.None) { var diag = Diagnostics.BadSetterParameters_StaticTwo(location, method, rowType); diags = diags.Add(diag); return(null); } takesValue = p1.Type; takesRow = true; takesRowByRef = p0RefKind == RefKind.Ref; takesContext = false; } } else if (ps.Length == 3) { // take 3 parameters, the row type (which may be passed by ref), the result of the parser, and `in ReadContext` var p0 = ps[0]; if (!p0.RefKind.IsNormalOrByRef()) { var diag = Diagnostics.BadSetterParameters_StaticThree(location, method, rowType); diags = diags.Add(diag); return(null); } if (!p0.Type.Equals(rowType, SymbolEqualityComparer.Default)) { var diag = Diagnostics.BadSetterParameters_StaticThree(location, method, rowType); diags = diags.Add(diag); return(null); } var p1 = ps[1]; if (p1.RefKind != RefKind.None) { var diag = Diagnostics.BadSetterParameters_StaticThree(location, method, rowType); diags = diags.Add(diag); return(null); } var p2 = ps[2]; if (!p2.IsInReadContext(types.OurTypes)) { var diag = Diagnostics.BadSetterParameters_StaticThree(location, method, rowType); diags = diags.Add(diag); return(null); } takesValue = p1.Type; takesRow = true; takesRowByRef = p0.RefKind == RefKind.Ref; takesContext = true; } else { var diag = Diagnostics.BadSetterParameters_TooMany(location, method); diags = diags.Add(diag); return(null); } } else { takesRow = false; takesRowByRef = false; // Options: // - be on the row type, and take 1 parameter (the result of the parser) or // - be on the row type, and take 2 parameters, the result of the parser and an `in ReadContext` if (ps.Length == 0) { var diag = Diagnostics.BadSetterParameters_TooFew(location, method); diags = diags.Add(diag); return(null); } else if (ps.Length == 1) { // take 1 parameter (the result of the parser) or var p0 = ps[0]; if (p0.RefKind != RefKind.None) { var diag = Diagnostics.BadSetterParameters_InstanceOne(location, method); diags = diags.Add(diag); return(null); } takesValue = p0.Type; takesContext = false; } else if (ps.Length == 2) { // take 2 parameters, the result of the parser and an `in ReadContext` var p0 = ps[0]; if (p0.RefKind != RefKind.None) { var diag = Diagnostics.BadSetterParameters_InstanceTwo(location, method); diags = diags.Add(diag); return(null); } var p1 = ps[1]; if (!p1.IsInReadContext(types.OurTypes)) { var diag = Diagnostics.BadSetterParameters_InstanceTwo(location, method); diags = diags.Add(diag); return(null); } takesValue = p0.Type; takesContext = true; } else { var diag = Diagnostics.BadSetterParameters_TooMany(location, method); diags = diags.Add(diag); return(null); } } return(new Setter(method, takesValue, takesRow, takesRowByRef, takesContext)); }
private static Getter?GetGetterForMethod( Compilation compilation, SerializerTypes types, ITypeSymbol rowType, IMethodSymbol method, Location?location, ref ImmutableArray <Diagnostic> diags ) { if (method.MethodKind != MethodKind.Ordinary) { var diag = Diagnostics.MethodMustBeOrdinary(location, method); diags = diags.Add(diag); return(null); } var methodReturnType = method.ReturnType; if (methodReturnType.SpecialType == SpecialType.System_Void) { var diag = Diagnostics.MethodMustReturnNonVoid(location, method); diags = diags.Add(diag); return(null); } if (method.IsGenericMethod) { var diag = Diagnostics.MethodCannotBeGeneric(location, method); diags = diags.Add(diag); return(null); } bool takesContext; bool takesRow; if (method.IsStatic) { // 0 parameters are allow // if there is 1 parameter, it may be an `in WriteContext` or the row type // if there are 2 parameters, the first must be the row type, and the second must be `in WriteContext` var ps = method.Parameters; if (ps.Length == 0) { takesContext = false; takesRow = false; } else if (ps.Length == 1) { var p0 = ps[0]; if (p0.IsInWriteContext(types.OurTypes)) { takesContext = true; takesRow = false; } else if (p0.IsNormalParameterOfType(compilation, rowType)) { takesContext = false; takesRow = true; } else { var diag = Diagnostics.BadGetterParameters_StaticOne(location, method, rowType); diags = diags.Add(diag); return(null); } } else if (ps.Length == 2) { var p0 = ps[0]; if (!p0.IsNormalParameterOfType(compilation, rowType)) { var diag = Diagnostics.BadGetterParameters_StaticTwo(location, method, rowType); diags = diags.Add(diag); return(null); } var p1 = ps[1]; if (!p1.IsInWriteContext(types.OurTypes)) { var diag = Diagnostics.BadGetterParameters_StaticTwo(location, method, rowType); diags = diags.Add(diag); return(null); } takesContext = true; takesRow = true; } else { var diag = Diagnostics.BadGetterParameters_TooMany(location, method); diags = diags.Add(diag); return(null); } } else { // 0 is allowed // if it takes a parameter, it must be an `in WriteContext` takesRow = false; var ps = method.Parameters; if (ps.Length == 0) { takesContext = false; } else if (ps.Length == 1) { var p0 = ps[0]; if (!p0.IsInWriteContext(types.OurTypes)) { var diag = Diagnostics.BadGetterParameters_InstanceOne(location, method); diags = diags.Add(diag); return(null); } takesContext = true; } else { var diag = Diagnostics.BadGetterParameters_TooMany(location, method); diags = diags.Add(diag); return(null); } } return(new Getter(method, takesRow, 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)); }