/// <summary>
        /// Parses and returns a constructor.
        /// </summary>
        /// <param name="parent">
        /// The parent of the element.
        /// </param>
        /// <param name="elementReference">
        /// A reference to the element being created.
        /// </param>
        /// <param name="unsafeCode">
        /// Indicates whether the code is marked as unsafe.
        /// </param>
        /// <param name="generated">
        /// Indicates whether the code is marked as generated code.
        /// </param>
        /// <param name="xmlHeader">
        /// The element's documentation header.
        /// </param>
        /// <param name="attributes">
        /// The attributes on the element.
        /// </param>
        /// <returns>
        /// Returns the element.
        /// </returns>
        private Constructor ParseConstructor(
            CsElement parent, Reference<ICodePart> elementReference, bool unsafeCode, bool generated, XmlHeader xmlHeader, ICollection<Attribute> attributes)
        {
            Param.AssertNotNull(parent, "parent");
            Param.AssertNotNull(elementReference, "elementReference");
            Param.Ignore(unsafeCode);
            Param.Ignore(generated);
            Param.Ignore(xmlHeader);
            Param.Ignore(attributes);

            Node<CsToken> previousTokenNode = this.tokens.Last;

            // Get the modifiers and access.
            AccessModifierType accessModifier = AccessModifierType.Private;
            Dictionary<CsTokenType, CsToken> modifiers = this.GetElementModifiers(elementReference, ref accessModifier, ConstructorModifiers);

            unsafeCode |= modifiers.ContainsKey(CsTokenType.Unsafe);

            // Get the name of the constructor.
            CsToken name = this.GetElementNameToken(elementReference, unsafeCode);
            this.tokens.Add(name);

            // Get the parameter list.
            IList<Parameter> parameters = this.ParseParameterList(elementReference, unsafeCode, SymbolType.OpenParenthesis);

            // Get the constructor initializer if there is one.
            MethodInvocationExpression constructorInitializer = null;

            Symbol symbol = this.GetNextSymbol(elementReference);
            if (symbol.SymbolType == SymbolType.Colon)
            {
                this.tokens.Add(this.GetToken(CsTokenType.BaseColon, SymbolType.Colon, elementReference));

                // The next symbol must be the keyword base or this.
                symbol = this.GetNextSymbol(elementReference);
                if (symbol.SymbolType != SymbolType.This && symbol.SymbolType != SymbolType.Base)
                {
                    throw this.CreateSyntaxException();
                }

                Reference<ICodePart> initializerNameExpressionReference = new Reference<ICodePart>();
                Node<CsToken> initializerNameTokenNode = this.tokens.InsertLast(this.GetToken(CsTokenType.Other, symbol.SymbolType, initializerNameExpressionReference));

                // Get the name expression.
                LiteralExpression initializerNameExpression = new LiteralExpression(this.tokens, initializerNameTokenNode);
                initializerNameExpressionReference.Target = initializerNameExpression;

                // Get the initializer expression.
                constructorInitializer = this.GetMethodInvocationExpression(initializerNameExpression, ExpressionPrecedence.None, unsafeCode);
            }

            // Create the declaration.
            Node<CsToken> firstTokenNode = previousTokenNode == null ? this.tokens.First : previousTokenNode.Next;
            CsTokenList declarationTokens = new CsTokenList(this.tokens, firstTokenNode, this.tokens.Last);
            Declaration declaration = new Declaration(declarationTokens, name.Text, ElementType.Constructor, accessModifier, modifiers);

            Constructor constructor = new Constructor(
                this.document, parent, xmlHeader, attributes, declaration, parameters, constructorInitializer, unsafeCode, generated);

            elementReference.Target = constructor;

            // If the constructor is extern, it will not have a body.
            if (modifiers.ContainsKey(CsTokenType.Extern))
            {
                // Get the closing semicolon.
                this.tokens.Add(this.GetToken(CsTokenType.Semicolon, SymbolType.Semicolon, elementReference));
            }
            else
            {
                // Get the body.
                this.ParseStatementContainer(constructor, true, unsafeCode);
            }

            return constructor;
        }
Example #2
0
        /// <summary>
        /// Gets the expected summary text <see cref="Regex"/> for a constructor, based on the type of the constructor.
        /// </summary>
        /// <param name="constructor">
        /// The constructor.
        /// </param>
        /// <param name="type">
        /// The type of the element containing the constructor.
        /// </param>
        /// <param name="typeRegex">
        /// The regular expression for matching the type name.
        /// </param>
        /// <returns>
        /// Returns the expected summary text <see cref="Regex"/>.
        /// </returns>
        private static string GetExpectedSummaryTextForConstructorType(Constructor constructor, string type, string typeRegex)
        {
            Param.AssertNotNull(constructor, "constructor");
            Param.AssertValidString(type, "type");
            Param.AssertValidString(typeRegex, "typeRegex");

            if (constructor.Declaration.ContainsModifier(CsTokenType.Static))
            {
                return string.Format(CultureInfo.InvariantCulture, CachedCodeStrings.HeaderSummaryForStaticConstructor, typeRegex, type);
            }

            if (constructor.AccessModifier == AccessModifierType.Private && (constructor.Parameters == null || constructor.Parameters.Count == 0))
            {
                return string.Format(CultureInfo.InvariantCulture, CachedCodeStrings.HeaderSummaryForPrivateInstanceConstructor, typeRegex, type);
            }

            return string.Format(CultureInfo.InvariantCulture, CachedCodeStrings.HeaderSummaryForInstanceConstructor, typeRegex, type);
        }
Example #3
0
        /// <summary>
        /// Gets the example expected summary text for a constructor, based on the type of the constructor.
        /// </summary>
        /// <param name="constructor">
        /// The constructor.
        /// </param>
        /// <param name="type">
        /// The type of the element containing the constructor.
        /// </param>
        /// <returns>
        /// Returns the example summary text.
        /// </returns>
        private static string GetExampleSummaryTextForConstructorType(Constructor constructor, string type)
        {
            Param.AssertNotNull(constructor, "constructor");
            Param.AssertValidString(type, "type");

            if (constructor.Declaration.ContainsModifier(CsTokenType.Static))
            {
                return string.Format(CultureInfo.InvariantCulture, CachedCodeStrings.ExampleHeaderSummaryForStaticConstructor, constructor.Declaration.Name, type);
            }

            if (constructor.AccessModifier == AccessModifierType.Private && (constructor.Parameters == null || constructor.Parameters.Count == 0))
            {
                return string.Format(
                    CultureInfo.InvariantCulture, CachedCodeStrings.ExampleHeaderSummaryForPrivateInstanceConstructor, constructor.Declaration.Name, type);
            }

            string classDeclarationName = ((ClassBase)constructor.Parent).Declaration.Name;

            string classDeclaration = "{";
            if (classDeclarationName.Contains("<"))
            {
                string genericTypes = classDeclarationName.SubstringAfterLast('<').TrimEnd(new[] { '>' });
                string[] generics = genericTypes.Split(',');

                for (int i = 0; i < generics.Count(); i++)
                {
                    string parameterDeclaration = generics[i];
                    classDeclaration += parameterDeclaration;
                    if (i < generics.Count() - 1)
                    {
                        classDeclaration += ",";
                    }
                }

                classDeclaration += "}";
            }
            else
            {
                classDeclaration = constructor.Declaration.Name;
            }

            return string.Format(CultureInfo.InvariantCulture, CachedCodeStrings.ExampleHeaderSummaryForInstanceConstructor, classDeclaration, type);
        }
Example #4
0
        /// <summary>
        /// Checks a constructor to ensure that the summary text matches the expected text.
        /// </summary>
        /// <param name="constructor">
        /// The constructor to check.
        /// </param>
        /// <param name="formattedDocs">
        /// The formatted header documentation.
        /// </param>
        private void CheckConstructorSummaryText(Constructor constructor, XmlDocument formattedDocs)
        {
            Param.AssertNotNull(constructor, "constructor");
            Param.AssertNotNull(formattedDocs, "formattedDocs");

            XmlNode node = formattedDocs.SelectSingleNode("root/summary");
            if (node != null)
            {
                string summaryText = node.InnerXml.Trim();
                string type = constructor.Parent is Struct ? CachedCodeStrings.StructText : CachedCodeStrings.ClassText;

                // Get a regex to match the type name.
                string typeRegex = BuildCrefValidationStringForType((ClassBase)constructor.FindParentElement());

                // Get the full expected summary text.
                string expectedRegex = GetExpectedSummaryTextForConstructorType(constructor, type, typeRegex);

                if (!Regex.IsMatch(summaryText, expectedRegex, RegexOptions.ExplicitCapture))
                {
                    this.AddViolation(
                        constructor, Rules.ConstructorSummaryDocumentationMustBeginWithStandardText, GetExampleSummaryTextForConstructorType(constructor, type));
                }
            }
        }
        /// <summary>
        /// The save default constructor initializer.
        /// </summary>
        /// <param name="constructor">
        /// The constructor.
        /// </param>
        /// <param name="startedInitilizer">
        /// The started initilizer.
        /// </param>
        private void SaveDefaultConstructorInitializer(Constructor constructor, bool startedInitilizer)
        {
            if (@constructor.Initializer != null)
            {
                this.cppWriter.Indent++;

                if (!startedInitilizer)
                {
                    this.cppWriter.WriteLine(" : ");
                }
                else
                {
                    this.cppWriter.WriteLine(",");
                }

                this.Save(@constructor.Initializer);

                this.cppWriter.Indent--;
            }
        }
        /// <summary>
        /// The save.
        /// </summary>
        /// <param name="constructor">
        /// The constructor.
        /// </param>
        private void Save(Constructor @constructor)
        {
            if (this.HasAnyPointerType(@constructor))
            {
                return;
            }

            // 1 to destHeader
            this.SaveModifiersBefore(@constructor);

            // 1 to destHeader
            this.headerWriter.Write(this.GetNameBase(@constructor.Declaration.Name, this.ClassContext.IsTemplate));

            if (!this.IsCPPInHeader)
            {
                // 2 to Source
                this.cppWriter.Write(this.currentClassNamespace);
                this.cppWriter.Write("::");
                this.cppWriter.Write(@constructor.Declaration.Name);
            }

            var hasParameters = this.SaveParameters(@constructor);
            this.SaveModifiersAfter(@constructor);

            if (!this.IsCPPInHeader)
            {
                this.headerWriter.WriteLine(';');
            }

            this.SaveDefaultConstructorInitializer(constructor, this.SaveFieldInitializersIntoDefaultConstructor(false));

            this.Save((ICodeUnit)@constructor);

            this.cppWriter.WriteLine();
        }