/// <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 ? "struct" : "class";

                // 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>
        /// 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();
                }

                var 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;
        }
        /// <summary>
        /// Gets the expected summary text 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 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);
            }
            else if (constructor.AccessModifier == AccessModifierType.Private &&
                (constructor.Parameters == null || constructor.Parameters.Count == 0))
            {
                return string.Format(
                    CultureInfo.InvariantCulture,
                    CachedCodeStrings.HeaderSummaryForPrivateInstanceConstructor,
                    typeRegex,
                    type);
            }
            else
            {
                return string.Format(
                    CultureInfo.InvariantCulture,
                    CachedCodeStrings.HeaderSummaryForInstanceConstructor,
                    typeRegex,
                    type);
            }
        }
Example #4
0
 private Constructor ParseConstructor(CsElement parent, bool unsafeCode, bool generated, XmlHeader xmlHeader, ICollection<Microsoft.StyleCop.CSharp.Attribute> attributes)
 {
     Microsoft.StyleCop.Node<CsToken> last = this.tokens.Last;
     AccessModifierType @private = AccessModifierType.Private;
     Dictionary<CsTokenType, CsToken> elementModifiers = this.GetElementModifiers(ref @private, ConstructorModifiers);
     unsafeCode |= elementModifiers.ContainsKey(CsTokenType.Unsafe);
     CsToken elementNameToken = this.GetElementNameToken(unsafeCode);
     this.tokens.Add(elementNameToken);
     IList<Parameter> parameters = this.ParseParameterList(unsafeCode, SymbolType.OpenParenthesis);
     MethodInvocationExpression initializerExpression = null;
     if (this.GetNextSymbol().SymbolType == SymbolType.Colon)
     {
         this.tokens.Add(this.GetToken(CsTokenType.BaseColon, SymbolType.Colon));
         Symbol nextSymbol = this.GetNextSymbol();
         if ((nextSymbol.SymbolType != SymbolType.This) && (nextSymbol.SymbolType != SymbolType.Base))
         {
             throw this.CreateSyntaxException();
         }
         Microsoft.StyleCop.Node<CsToken> tokenNode = this.tokens.InsertLast(this.GetToken(CsTokenType.Other, nextSymbol.SymbolType));
         LiteralExpression methodName = new LiteralExpression(this.tokens, tokenNode);
         initializerExpression = this.GetMethodInvocationExpression(methodName, ExpressionPrecedence.None, unsafeCode);
     }
     Microsoft.StyleCop.Node<CsToken> firstItemNode = (last == null) ? this.tokens.First : last.Next;
     CsTokenList tokens = new CsTokenList(this.tokens, firstItemNode, this.tokens.Last);
     Declaration declaration = new Declaration(tokens, elementNameToken.Text, ElementType.Constructor, @private, elementModifiers);
     Constructor element = new Constructor(this.document, parent, xmlHeader, attributes, declaration, parameters, initializerExpression, unsafeCode, generated);
     if (elementModifiers.ContainsKey(CsTokenType.Extern))
     {
         this.tokens.Add(this.GetToken(CsTokenType.Semicolon, SymbolType.Semicolon));
         return element;
     }
     this.ParseStatementContainer(element, true, unsafeCode);
     return element;
 }