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