static bool GetStringArrayEnumHint(VariantType elementVariantType,
                                               AttributeData exportAttr, out string?hintString)
            {
                var constructorArguments = exportAttr.ConstructorArguments;

                if (constructorArguments.Length > 0)
                {
                    var presetHintValue = exportAttr.ConstructorArguments[0].Value;

                    PropertyHint presetHint = presetHintValue switch
                    {
                        null => PropertyHint.None,
                        int intValue => (PropertyHint)intValue,
                        _ => (PropertyHint)(long)presetHintValue
                    };

                    if (presetHint == PropertyHint.Enum)
                    {
                        string?presetHintString = constructorArguments.Length > 1 ?
                                                  exportAttr.ConstructorArguments[1].Value?.ToString() :
                                                  null;

                        hintString = (int)elementVariantType + "/" + (int)PropertyHint.Enum + ":";

                        if (presetHintString != null)
                        {
                            hintString += presetHintString;
                        }

                        return(true);
                    }
                }

                hintString = null;
                return(false);
            }

            if (!isTypeArgument && variantType == VariantType.Array)
            {
                var elementType = MarshalUtils.GetArrayElementType(type);

                if (elementType == null)
                {
                    return(false); // Non-generic Array, so there's no hint to add
                }
                var elementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementType, typeCache) !.Value;
                var elementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(elementMarshalType) !.Value;

                bool isPresetHint = false;

                if (elementVariantType == VariantType.String)
                {
                    isPresetHint = GetStringArrayEnumHint(elementVariantType, exportAttr, out hintString);
                }

                if (!isPresetHint)
                {
                    bool hintRes = TryGetMemberExportHint(typeCache, elementType,
                                                          exportAttr, elementVariantType, isTypeArgument: true,
                                                          out var elementHint, out var elementHintString);

                    // Format: type/hint:hint_string
                    if (hintRes)
                    {
                        hintString = (int)elementVariantType + "/" + (int)elementHint + ":";

                        if (elementHintString != null)
                        {
                            hintString += elementHintString;
                        }
                    }
                    else
                    {
                        hintString = (int)elementVariantType + "/" + (int)PropertyHint.None + ":";
                    }
                }

                hint = PropertyHint.TypeString;

                return(hintString != null);
            }

            if (!isTypeArgument && variantType == VariantType.PackedStringArray)
            {
                if (GetStringArrayEnumHint(VariantType.String, exportAttr, out hintString))
                {
                    hint = PropertyHint.TypeString;
                    return(true);
                }
            }

            if (!isTypeArgument && variantType == VariantType.Dictionary)
            {
                // TODO: Dictionaries are not supported in the inspector
                return(false);
            }

            return(false);
        }
        private static PropertyInfo?DeterminePropertyInfo(
            GeneratorExecutionContext context,
            MarshalUtils.TypeCache typeCache,
            ISymbol memberSymbol,
            MarshalType marshalType
            )
        {
            var exportAttr = memberSymbol.GetAttributes()
                             .FirstOrDefault(a => a.AttributeClass?.IsGodotExportAttribute() ?? false);

            var propertySymbol = memberSymbol as IPropertySymbol;
            var fieldSymbol    = memberSymbol as IFieldSymbol;

            if (exportAttr != null && propertySymbol != null)
            {
                if (propertySymbol.GetMethod == null)
                {
                    // This should never happen, as we filtered WriteOnly properties, but just in case.
                    Common.ReportExportedMemberIsWriteOnly(context, propertySymbol);
                    return(null);
                }

                if (propertySymbol.SetMethod == null)
                {
                    // This should never happen, as we filtered ReadOnly properties, but just in case.
                    Common.ReportExportedMemberIsReadOnly(context, propertySymbol);
                    return(null);
                }
            }

            var memberType = propertySymbol?.Type ?? fieldSymbol !.Type;

            var    memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType) !.Value;
            string memberName        = memberSymbol.Name;

            if (exportAttr == null)
            {
                return(new PropertyInfo(memberVariantType, memberName, PropertyHint.None,
                                        hintString: null, PropertyUsageFlags.ScriptVariable, exported: false));
            }

            if (!TryGetMemberExportHint(typeCache, memberType, exportAttr, memberVariantType,
                                        isTypeArgument: false, out var hint, out var hintString))
            {
                var constructorArguments = exportAttr.ConstructorArguments;

                if (constructorArguments.Length > 0)
                {
                    var hintValue = exportAttr.ConstructorArguments[0].Value;

                    hint = hintValue switch
                    {
                        null => PropertyHint.None,
                        int intValue => (PropertyHint)intValue,
                        _ => (PropertyHint)(long)hintValue
                    };

                    hintString = constructorArguments.Length > 1 ?
                                 exportAttr.ConstructorArguments[1].Value?.ToString() :
                                 null;
                }
                else
                {
                    hint = PropertyHint.None;
                }
            }

            var propUsage = PropertyUsageFlags.Default | PropertyUsageFlags.ScriptVariable;

            if (memberVariantType == VariantType.Nil)
            {
                propUsage |= PropertyUsageFlags.NilIsVariant;
            }

            return(new PropertyInfo(memberVariantType, memberName,
                                    hint, hintString, propUsage, exported: true));
        }