protected override bool DoesConversionExist(Compilation compilation, ITypeSymbol source, ITypeSymbol destination)
 {
     return compilation.ClassifyConversion(source, destination).Exists;
 }
            private bool IsBaseOrIdentity(ITypeSymbol source, ITypeSymbol dest)
            {
                Conversion conversion = _compilation.ClassifyConversion(source, dest);

                return(conversion.IsIdentity || (conversion.IsReference && conversion.IsImplicit));
            }
Beispiel #3
0
 protected override bool DoesConversionExist(Compilation compilation, ITypeSymbol source, ITypeSymbol destination)
 {
     return(compilation.ClassifyConversion(source, destination).Exists);
 }
            protected override bool IsImplicitReferenceConversion(Compilation compilation, ITypeSymbol sourceType, ITypeSymbol targetType)
            {
                var conversion = compilation.ClassifyConversion(sourceType, targetType);

                return(conversion.IsImplicit && conversion.IsReference);
            }
        protected override bool IsAssignableTo(Compilation compilation, ITypeSymbol fromSymbol, ITypeSymbol toSymbol)
        {
            var conversion = compilation.ClassifyConversion(fromSymbol, toSymbol);

            return(conversion.Exists && conversion.IsExplicit == false && conversion.IsNumeric == false);
        }
Beispiel #6
0
 protected override bool IsReferenceConversion(Compilation compilation, ITypeSymbol sourceType, ITypeSymbol targetType)
 {
     return(compilation.ClassifyConversion(sourceType, targetType).IsReference);
 }
Beispiel #7
0
        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));
        }
        private static bool IsAssignable(Compilation compilation, ITypeSymbol fromSymbol, ITypeSymbol toSymbol)
        {
            var conversion = compilation.ClassifyConversion(fromSymbol, toSymbol);

            return(conversion.IsImplicit && !conversion.IsUserDefined);
        }
        protected override bool IsConvertible(Compilation compilation, ITypeSymbol source, ITypeSymbol destination)
        {
            var conversion = compilation.ClassifyConversion(source, destination);

            return(conversion.Exists && conversion.IsImplicit);
        }
Beispiel #10
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));
        }
        /// <summary>
        /// Takes a set of types and returns the most "constrained" type that all of them can be converted to.
        /// 
        /// Worst case, it returns a TypeSyntax for `object`.
        /// 
        /// If the appropriate type is an anonymous one, `replaceType` contains a Tuple of that anonymous type and the 
        /// name of a new one that should be created to take its place.
        /// </summary>
        private static TypeSyntax FindCommonType(IEnumerable<TypeInfo> info, Compilation comp, out Tuple<NamedTypeSymbol, string> replaceType)
        {
            if (info.Any(a => a.Equals(TypeInfo.None)))
            {
                replaceType = null;
                return null;
            }

            var allPossibilities = info.SelectMany(i => i.Type.AllInterfaces).OfType<NamedTypeSymbol>().ToList();

            allPossibilities.AddRange(info.Select(s => s.Type).OfType<NamedTypeSymbol>());

            foreach (var i in info)
            {
                var @base = i.Type.BaseType;
                while (@base != null)
                {
                    allPossibilities.Add(@base);
                    @base = @base.BaseType;
                }
            }

            // Order so that subclasses are before superclasses, classes are before interfaces,
            //   special interfaces first, and generic types are before non-generic ones
            //   with the special case that System.Object is always the *last* option
            //   uses type name as a tie-breaker for ordering
            //
            // Special interfaces are anything that gets special treatment in the language, which for now is IEnumerable<T> and IEnumerable
            allPossibilities.Sort(
                (a, b) =>
                {
                    var aIsNotObject = a.TypeKind != TypeKind.Class || a.BaseType != null;
                    var bIsNotObject = b.TypeKind != TypeKind.Class || b.BaseType != null;

                    var aIsNotInterface = a.TypeKind != TypeKind.Interface;
                    var bIsNotInferface = b.TypeKind != TypeKind.Interface;

                    // Get both IEnumerable && IEnumerable<T>
                    var aIsSpecial = a.Name == "IEnumerable";
                    var bIsSpecial = b.Name == "IEnumerable";

                    var aIsSubclassOfB = IsSubclass(a, b);
                    var bIsSubclassOfA = IsSubclass(b, a);

                    if (aIsNotObject && !bIsNotObject) return -1;
                    if (bIsNotObject && !aIsNotObject) return 1;

                    if (aIsSubclassOfB) return -1;
                    if (bIsSubclassOfA) return 1;

                    if (aIsNotInterface && !bIsNotInferface) return -1;
                    if (bIsNotInferface && !aIsNotInterface) return 1;

                    if (!aIsNotInterface && !bIsNotInferface)
                    {
                        if (aIsSpecial && !bIsSpecial) return -1;
                        if (bIsSpecial && !aIsSpecial) return 1;
                    }

                    if (a.IsGenericType && !b.IsGenericType) return -1;
                    if (b.IsGenericType && !a.IsGenericType) return 1;

                    return a.MetadataName.CompareTo(b.MetadataName);
                }
            );

            var commonType =
                allPossibilities.First(
                    t =>
                    {
                        var conversions = info.Select(a => comp.ClassifyConversion(a.Type, t)).ToList();

                        return conversions.All(a => a.Exists && a.IsImplicit);
                    }
                );

            string fullName;

            // we actually need to *replace* this type so we can put it in the returns
            if (commonType.IsAnonymousType)
            {
                fullName = "__FTI" + Guid.NewGuid().ToString().Replace("-", "");
                replaceType = Tuple.Create(commonType, fullName);
            }
            else
            {
                fullName = commonType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
                replaceType = null;
            }

            return Syntax.ParseTypeName(fullName);
        }
        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));
        }
Beispiel #13
0
        private static bool CanBeSameType(ITypeSymbol actualType, ITypeSymbol expectedType, Compilation compilation)
        {
            var conversion = compilation.ClassifyConversion(actualType, expectedType);

            return(conversion.IsIdentity || conversion.IsReference);
        }
 protected override bool IsConversionImplicit(Compilation compilation, ITypeSymbol sourceType, ITypeSymbol targetType)
 {
     return(compilation.ClassifyConversion(sourceType, targetType).IsImplicit);
 }
 protected override bool CanCast(Compilation compilation, ITypeSymbol sourceSymbol, ITypeSymbol destinationSymbol)
 {
     return(compilation.ClassifyConversion(sourceSymbol, destinationSymbol).Exists);
 }
Beispiel #16
0
 public static bool IsImplicitConversion(Compilation compilation, ITypeSymbol source, ITypeSymbol destination)
 => compilation.ClassifyConversion(source: source, destination: destination).IsImplicit;
        internal static bool AreEquivalent(TypeSymbol a, TypeSymbol b, Compilation comp)
        {
            var aMembers = a.GetMembers().OfType<PropertySymbol>().ToList();
            var bMembers = b.GetMembers().OfType<PropertySymbol>().ToList();

            if (aMembers.Count != bMembers.Count) return false;

            for (var i = 0; i < aMembers.Count; i++)
            {
                var aMember = aMembers[i];
                var bMember = bMembers[i];

                if (aMember.Name != bMember.Name) return false;
                if (aMember.DeclaredAccessibility != bMember.DeclaredAccessibility) return false;

                var aType = aMember.Type;
                var bType = bMember.Type;

                var aName = aType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
                var bName = bType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);

                if (aName == bName) continue;

                var conv = comp.ClassifyConversion(aType, bType);

                if (!conv.IsIdentity) return false;
            }

            return true;
        }