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