Exemple #1
0
        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));
        }
Exemple #2
0
        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));
        }
Exemple #3
0
        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));
        }
Exemple #4
0
        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));
        }
Exemple #5
0
        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));
        }