public AttributeDeclaration Visit(AttributeDeclaration attribute)
        {
            if (ParadoxAttributes.AvailableAttributes.Contains(attribute.Name))
                return null;

            return attribute;
        }
        public override Node Visit(AttributeDeclaration attribute)
        {
            if (XenkoAttributes.AvailableAttributes.Contains(attribute.Name))
                return null;

            return attribute;
        }
        public static void Parse(IList<ShaderStreamOutputDeclarationEntry> entries, out int[] strides, AttributeDeclaration streamOutputAttribute, IList<Variable> fields)
        {
            var streamStrings = streamOutputAttribute.Parameters
                .TakeWhile(x => x.Value is string)
                .Select(x => x.Value as string)
                .ToArray();

            Parse(entries, out strides, streamStrings, fields);
        }
        public override void Visit(AttributeDeclaration attributeDeclaration)
        {

        }
        /// <summary>
        /// Rename the links of the variables
        /// </summary>
        /// <param name="mixin">the current mixin</param>
        /// <param name="context">the string to append</param>
        /// <param name="visitedMixins">list of already visited mixin</param>
        private void LinkVariables(ModuleMixin mixin, string context, List<ModuleMixin> visitedMixins)
        {
            if (visitedMixins.Contains(mixin))
                return;
            
            visitedMixins.Add(mixin);

            foreach (var variable in mixin.LocalVirtualTable.Variables.Select(x => x.Variable))
            {
                if (variable.Qualifiers.Contains(XenkoStorageQualifier.Extern))
                {
                    List<ModuleMixin> mixins;
                    if (CompositionsPerVariable.TryGetValue(variable, out mixins))
                    {
                        if (variable.Type is ArrayType)
                        {
                            for (var i = 0; i < mixins.Count; ++i)
                            {
                                var baselink = "." + variable.Name.Text + "[" + i + "]" + context;
                                LinkVariables(mixins[i], baselink, visitedMixins);
                            }
                        }
                        else
                        {
                            var baselink = "." + variable.Name.Text + context;
                            LinkVariables(mixins[0], baselink, visitedMixins);
                        }
                    }
                }

                if (!(variable.Qualifiers.Values.Contains(XenkoStorageQualifier.Stream)
                      || variable.Qualifiers.Values.Contains(XenkoStorageQualifier.PatchStream)
                      || variable.Qualifiers.Values.Contains(XenkoStorageQualifier.Extern)))
                {
                    var attribute = variable.Attributes.OfType<AttributeDeclaration>().FirstOrDefault(x => x.Name == "Link");
                    if (attribute == null)
                    {
                        // Try to get class name before generics
                        //string baseClassName;
                        //if (!genericTypeDefinitions.TryGetValue(baseClass, out baseClassName))
                        //    baseClassName = baseClass.Name;

                        // TODO: class name before renaming if generics
                        string linkName;

                        // Use Map attribute (if it exists)
                        var mapAttribute = variable.Attributes.OfType<AttributeDeclaration>().FirstOrDefault(x => x.Name == "Map");
                        if (mapAttribute != null)
                        {
                            linkName = (string)mapAttribute.Parameters[0].Value;
                            // Remove "Keys" from class name (or maybe we should just include it in key name to avoid issues?)
                            linkName = linkName.Replace("Keys.", ".");
                        }
                        else
                        {
                            linkName = mixin.MixinGenericName + "." + variable.Name.Text;
                        }

                        attribute = new AttributeDeclaration { Name = new Identifier("Link"), Parameters = new List<Literal> { new Literal(linkName) } };
                        variable.Attributes.Add(attribute);
                    }

                    // Append location to key in case it is a local variable
                    if (!variable.Qualifiers.Values.Contains(XenkoStorageQualifier.Stage))
                    {
                        attribute.Parameters[0].SubLiterals = null; // set to null to avoid conflict with the member Value
                        attribute.Parameters[0].Value = (string)attribute.Parameters[0].Value + context;
                    }
                }
            }

            foreach (var variable in mixin.StaticReferences.VariablesReferences.Select(x => x.Key))
            {
                var attribute = variable.Attributes.OfType<AttributeDeclaration>().FirstOrDefault(x => x.Name == "Link");
                if (attribute == null)
                {
                    var baseClassName = (variable.GetTag(XenkoTags.ShaderScope) as ModuleMixin).MixinGenericName;

                    attribute = new AttributeDeclaration { Name = new Identifier("Link"), Parameters = new List<Literal> { new Literal(baseClassName + "." + variable.Name.Text) } };
                    variable.Attributes.Add(attribute);
                }
            }

            mixin.InheritanceList.ForEach(x => LinkVariables(x, context, visitedMixins));
        }
        /// <summary>
        /// Visits the specified attribute declaration.
        /// </summary>
        /// <param name="attributeDeclaration">The attribute declaration.</param>
        public override void Visit(AttributeDeclaration attributeDeclaration)
        {
            Write("[").Write(attributeDeclaration.Name);
            if (attributeDeclaration.Parameters.Count > 0)
            {
                Write("(");
                for (int i = 0; i < attributeDeclaration.Parameters.Count; i++)
                {
                    var parameter = attributeDeclaration.Parameters[i];
                    if (i > 0)
                    {
                        Write(",").WriteSpace();
                    }

                    VisitDynamic(parameter);
                }

                Write(")");
            }

            WriteLine("]");
        }