Пример #1
0
            private static XmlNameAttributeSyntax ParseNameAttribute(
                string attributeText,
                string elementName
                )
            {
                // NOTE: Rather than introducing a new code path that will have to be kept in
                // sync with other mode changes distributed throughout Lexer, SyntaxParser, and
                // DocumentationCommentParser, we'll just wrap the text in some lexable syntax
                // and then extract the piece we want.
                string commentText = string.Format(@"/// <{0} {1}/>", elementName, attributeText);

                SyntaxTriviaList leadingTrivia = SyntaxFactory.ParseLeadingTrivia(
                    commentText,
                    CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.Diagnose)
                    );

                Debug.Assert(leadingTrivia.Count == 1);
                SyntaxTrivia trivia = leadingTrivia.ElementAt(0);
                DocumentationCommentTriviaSyntax structure =
                    (DocumentationCommentTriviaSyntax)trivia.GetStructure();

                Debug.Assert(structure.Content.Count == 2);
                XmlEmptyElementSyntax elementSyntax = (XmlEmptyElementSyntax)structure.Content[1];

                Debug.Assert(elementSyntax.Attributes.Count == 1);
                return((XmlNameAttributeSyntax)elementSyntax.Attributes[0]);
            }
Пример #2
0
            /// <summary>
            ///     Visit an <see cref="XmlEmptyElementSyntax"/>.
            /// </summary>
            /// <param name="emptyElement">
            ///     The <see cref="XmlEmptyElementSyntax"/>.
            /// </param>
            /// <returns>
            ///     The <see cref="XmlEmptyElementSyntax"/> (unchanged).
            /// </returns>
            public override SyntaxNode VisitXmlEmptyElement(XmlEmptyElementSyntax emptyElement)
            {
                Range elementRange    = emptyElement.Span.ToNative(_textPositions);
                Range nameRange       = emptyElement.NameNode?.Span.ToNative(_textPositions) ?? elementRange;
                Range attributesRange = emptyElement.AttributesNode?.FullSpan.ToNative(_textPositions) ?? elementRange;

                XSElement xsElement;

                if (String.IsNullOrWhiteSpace(emptyElement.Name))
                {
                    xsElement = new XSInvalidElement(emptyElement, elementRange, nameRange, attributesRange, parent: CurrentElement, hasContent: false);
                }
                else
                {
                    xsElement = new XSEmptyElement(emptyElement, elementRange, nameRange, attributesRange, parent: CurrentElement);
                }

                if (xsElement.ParentElement is XSElementWithContent parentElement)
                {
                    parentElement.Content = parentElement.Content.Add(xsElement);
                }

                PushElement(xsElement);

                foreach (XmlAttributeSyntax attribute in emptyElement.AsSyntaxElement.Attributes)
                {
                    Visit(attribute);
                }

                PopElement();

                return(emptyElement);
            }
Пример #3
0
        private void FormatEmptyElementTag(XmlEmptyElementSyntax node)
        {
            if (node.ContainsSkippedText)
            {
                AddWord(node.Span);
            }
            else
            {
                AddWord(node.LessThanToken.Span);

                EnqueueTrailingTriviaChange(node.LessThanToken, string.Empty);

                EnqueueLeadingTriviaChange(node.Name, string.Empty);

                FormatTagName(node.Name);

                EnqueueTrailingTriviaChange(node.Name, string.Empty);

                foreach (var attribute in node.Attributes)
                {
                    EnqueueLeadingTriviaChange(attribute, " ");

                    FormatTagAttribute(attribute);

                    EnqueueTrailingTriviaChange(attribute, string.Empty);
                }

                EnqueueLeadingTriviaChange(node.SlashGreaterThanToken, string.Empty);

                AddWord(node.SlashGreaterThanToken.Span);
            }
        }
Пример #4
0
        private void FormatXmlEmptyElement(XmlEmptyElementSyntax node)
        {
            string            name = node.Name.ToString();
            ElementFormatting formatting;

            _ = _elements.TryGetValue(name, out formatting);

            if (formatting.HasFlag(ElementFormatting.Block))
            {
                Break(BreakMode.LineBreak);
            }

            if (node.HasLeadingTrivia)
            {
                AddTrivia(node.GetLeadingTrivia());
            }

            FormatEmptyElementTag(node);

            if (node.HasTrailingTrivia)
            {
                AddTrivia(node.GetTrailingTrivia());
            }

            if (formatting.HasFlag(ElementFormatting.Block))
            {
                Break(BreakMode.LineBreak);
            }
        }
Пример #5
0
        public static IEnumerable <XmlNodeSyntax> GetXmlElements(this SyntaxList <XmlNodeSyntax> content, string elementName)
        {
            foreach (XmlNodeSyntax syntax in content)
            {
                XmlEmptyElementSyntax emptyElement = syntax as XmlEmptyElementSyntax;
                if (emptyElement != null)
                {
                    if (string.Equals(elementName, emptyElement.Name.ToString(), StringComparison.Ordinal))
                    {
                        yield return(emptyElement);
                    }

                    continue;
                }

                XmlElementSyntax elementSyntax = syntax as XmlElementSyntax;
                if (elementSyntax != null)
                {
                    if (string.Equals(elementName, elementSyntax.StartTag?.Name?.ToString(), StringComparison.Ordinal))
                    {
                        yield return(elementSyntax);
                    }

                    continue;
                }
            }
        }
        private bool SeeTagIsCorrect(XmlEmptyElementSyntax classReferencePart, BaseMethodDeclarationSyntax constructorDeclarationSyntax)
        {
            if (classReferencePart.Name.ToString() == XmlCommentHelper.SeeXmlTag)
            {
                XmlCrefAttributeSyntax crefAttribute = classReferencePart.Attributes.OfType <XmlCrefAttributeSyntax>().FirstOrDefault();

                if (crefAttribute != null)
                {
                    NameMemberCrefSyntax nameMember = crefAttribute.Cref as NameMemberCrefSyntax;

                    if (nameMember != null && nameMember.Parameters == null)
                    {
                        ClassDeclarationSyntax classDeclarationSyntax = constructorDeclarationSyntax.FirstAncestorOrSelf <ClassDeclarationSyntax>();

                        if (classDeclarationSyntax != null &&
                            classDeclarationSyntax.Identifier.ToString() == this.GetName(nameMember.Name))
                        {
                            // Check if type parameters are called the same
                            if (TypeParameterNamesMatch(classDeclarationSyntax, nameMember.Name))
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }
Пример #7
0
        private static void HandleXmlEmptyElement(SyntaxNodeAnalysisContext context)
        {
            XmlEmptyElementSyntax element = (XmlEmptyElementSyntax)context.Node;

            var name = element.Name;

            HandleElement(context, element, name, element.GetLocation());
        }
        private static void HandleXmlEmptyElement(SyntaxNodeAnalysisContext context)
        {
            XmlEmptyElementSyntax emptyElement = context.Node as XmlEmptyElementSyntax;

            var name = emptyElement?.Name;

            HandleElement(context, emptyElement, name, emptyElement?.GetLocation());
        }
Пример #9
0
        public override void VisitXmlEmptyElement(XmlEmptyElementSyntax node)
        {
            node.Name?.Accept(this);
            foreach (XmlAttributeSyntax syntax in node.Attributes)
            {
                syntax.Accept(this);
            }

            base.VisitXmlEmptyElement(node);
        }
        private static void HandleXmlEmptyElement(SyntaxNodeAnalysisContext context)
        {
            XmlEmptyElementSyntax emptyElement = context.Node as XmlEmptyElementSyntax;

            if (string.Equals(emptyElement?.Name.ToString(), XmlCommentHelper.ReturnsXmlTag))
            {
                // <returns .../> is empty.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, emptyElement.GetLocation()));
            }
        }
Пример #11
0
        public override Evaluation VisitXmlEmptyElement(XmlEmptyElementSyntax node)
        {
            node.Name?.Accept <Evaluation>(this);
            foreach (XmlAttributeSyntax syntax in node.Attributes)
            {
                syntax.Accept <Evaluation>(this);
            }

            return(base.VisitXmlEmptyElement(node));
        }
        private static void HandleXmlEmptyElement(SyntaxNodeAnalysisContext context)
        {
            XmlEmptyElementSyntax emptyElement = (XmlEmptyElementSyntax)context.Node;

            if (string.Equals(emptyElement.Name.ToString(), XmlCommentHelper.TypeParamXmlTag))
            {
                // <typeparam .../> is empty.
                context.ReportDiagnostic(Diagnostic.Create(Descriptor, emptyElement.GetLocation()));
            }
        }
        private void HandleXmlEmptyElement(SyntaxNodeAnalysisContext context)
        {
            XmlEmptyElementSyntax syntax = (XmlEmptyElementSyntax)context.Node;

            if (!string.Equals("placeholder", syntax.Name?.ToString(), StringComparison.Ordinal))
            {
                return;
            }

            context.ReportDiagnostic(Diagnostic.Create(Descriptor, syntax.GetLocation()));
        }
        private void ClassifyXmlEmptyElement(XmlEmptyElementSyntax node)
        {
            AddXmlClassification(node.LessThanToken, ClassificationTypeNames.XmlDocCommentDelimiter);
            ClassifyXmlName(node.Name);

            foreach (var attribute in node.Attributes)
            {
                ClassifyXmlAttribute(attribute);
            }

            AddXmlClassification(node.SlashGreaterThanToken, ClassificationTypeNames.XmlDocCommentDelimiter);
        }
Пример #15
0
        internal static XmlNodeSyntax GetTopLevelElement(DocumentationCommentTriviaSyntax syntax, string tagName)
        {
            XmlElementSyntax elementSyntax = syntax.Content.OfType <XmlElementSyntax>().FirstOrDefault(element => string.Equals(element.StartTag.Name.ToString(), tagName));

            if (elementSyntax != null)
            {
                return(elementSyntax);
            }

            XmlEmptyElementSyntax emptyElementSyntax = syntax.Content.OfType <XmlEmptyElementSyntax>().FirstOrDefault(element => string.Equals(element.Name.ToString(), tagName));

            return(emptyElementSyntax);
        }
Пример #16
0
        private static bool HasXmlCrefAttribute(XmlNodeSyntax inheritDocElement)
        {
            XmlElementSyntax xmlElementSyntax = inheritDocElement as XmlElementSyntax;
            if (xmlElementSyntax?.StartTag?.Attributes.Any(SyntaxKind.XmlCrefAttribute) ?? false)
            {
                return true;
            }

            XmlEmptyElementSyntax xmlEmptyElementSyntax = inheritDocElement as XmlEmptyElementSyntax;
            if (xmlEmptyElementSyntax?.Attributes.Any(SyntaxKind.XmlCrefAttribute) ?? false)
            {
                return true;
            }

            return false;
        }
Пример #17
0
        public override void VisitXmlEmptyElement(XmlEmptyElementSyntax node)
        {
            if (!PreVisit(node))
            {
                return;
            }

            node.Name?.Accept(this);
            foreach (XmlAttributeSyntax syntax in node.Attributes)
            {
                syntax.Accept(this);
            }

            base.VisitXmlEmptyElement(node);

            PostVisit(node);
        }
        private static bool SeeTagIsCorrect(SyntaxNodeAnalysisContext context, XmlEmptyElementSyntax classReferencePart, BaseMethodDeclarationSyntax constructorDeclarationSyntax)
        {
            XmlCrefAttributeSyntax crefAttribute = XmlCommentHelper.GetFirstAttributeOrDefault <XmlCrefAttributeSyntax>(classReferencePart);
            CrefSyntax             crefSyntax    = crefAttribute?.Cref;

            if (crefAttribute == null)
            {
                return(false);
            }

            SemanticModel semanticModel = context.SemanticModel;

            if (!(semanticModel.GetSymbolInfo(crefSyntax, context.CancellationToken).Symbol is INamedTypeSymbol actualSymbol))
            {
                return(false);
            }

            INamedTypeSymbol expectedSymbol = semanticModel.GetDeclaredSymbol(constructorDeclarationSyntax.Parent, context.CancellationToken) as INamedTypeSymbol;

            return(Equals(actualSymbol.OriginalDefinition, expectedSymbol));
        }
Пример #19
0
 internal static string GetName(this XmlEmptyElementSyntax value) => value?.Name.LocalName.ValueText;
        private static async Task <Document> GetTransformedDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
        {
            var documentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode syntax = documentRoot.FindNode(diagnostic.Location.SourceSpan);

            if (syntax == null)
            {
                return(document);
            }

            MethodDeclarationSyntax   methodDeclarationSyntax   = syntax.FirstAncestorOrSelf <MethodDeclarationSyntax>();
            DelegateDeclarationSyntax delegateDeclarationSyntax = syntax.FirstAncestorOrSelf <DelegateDeclarationSyntax>();

            if (methodDeclarationSyntax == null && delegateDeclarationSyntax == null)
            {
                return(document);
            }

            DocumentationCommentTriviaSyntax documentationComment =
                methodDeclarationSyntax?.GetDocumentationCommentTriviaSyntax()
                ?? delegateDeclarationSyntax?.GetDocumentationCommentTriviaSyntax();

            if (documentationComment == null)
            {
                return(document);
            }

            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            bool isTask;
            bool isAsynchronousTestMethod;

            if (methodDeclarationSyntax != null)
            {
                isTask = IsTaskReturningMethod(semanticModel, methodDeclarationSyntax, cancellationToken);
                isAsynchronousTestMethod = isTask && IsAsynchronousTestMethod(semanticModel, methodDeclarationSyntax, cancellationToken);
            }
            else
            {
                isTask = IsTaskReturningMethod(semanticModel, delegateDeclarationSyntax, cancellationToken);
                isAsynchronousTestMethod = false;
            }

            XmlNodeSyntax returnsElement = documentationComment.Content.GetFirstXmlElement(XmlCommentHelper.ReturnsXmlTag) as XmlNodeSyntax;

            if (returnsElement != null && !isTask)
            {
                // This code fix doesn't know how to do anything more than document Task-returning methods.
                return(document);
            }

            SyntaxList <XmlNodeSyntax> content = XmlSyntaxFactory.List();

            if (isTask)
            {
                content = content.Add(XmlSyntaxFactory.Text("A "));
                content = content.Add(XmlSyntaxFactory.SeeElement(SyntaxFactory.TypeCref(SyntaxFactory.ParseTypeName("global::System.Threading.Tasks.Task"))).WithAdditionalAnnotations(Simplifier.Annotation));
                string operationKind = isAsynchronousTestMethod ? "unit test" : "operation";
                content = content.Add(XmlSyntaxFactory.Text($" representing the asynchronous {operationKind}."));

                // wrap the generated content in a <placeholder> element for review.
                content = XmlSyntaxFactory.List(XmlSyntaxFactory.PlaceholderElement(content));
            }

            // Try to replace an existing <returns> element if the comment contains one. Otherwise, add it as a new element.
            SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxNode newRoot;

            if (returnsElement != null)
            {
                XmlEmptyElementSyntax emptyElement = returnsElement as XmlEmptyElementSyntax;
                if (emptyElement != null)
                {
                    XmlElementSyntax updatedReturns = XmlSyntaxFactory.Element(XmlCommentHelper.ReturnsXmlTag, content)
                                                      .WithLeadingTrivia(returnsElement.GetLeadingTrivia())
                                                      .WithTrailingTrivia(returnsElement.GetTrailingTrivia());
                    newRoot = root.ReplaceNode(returnsElement, updatedReturns);
                }
                else
                {
                    XmlElementSyntax updatedReturns = ((XmlElementSyntax)returnsElement).WithContent(content);
                    newRoot = root.ReplaceNode(returnsElement, updatedReturns);
                }
            }
            else
            {
                string newLineText = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.NewLine, LanguageNames.CSharp);

                returnsElement = XmlSyntaxFactory.Element(XmlCommentHelper.ReturnsXmlTag, content);

                XmlNodeSyntax leadingNewLine = XmlSyntaxFactory.NewLine(newLineText);

                // HACK: The formatter isn't working when contents are added to an existing documentation comment, so we
                // manually apply the indentation from the last line of the existing comment to each new line of the
                // generated content.
                SyntaxTrivia exteriorTrivia = GetLastDocumentationCommentExteriorTrivia(documentationComment);
                if (!exteriorTrivia.Token.IsMissing)
                {
                    leadingNewLine = leadingNewLine.ReplaceExteriorTrivia(exteriorTrivia);
                    returnsElement = returnsElement.ReplaceExteriorTrivia(exteriorTrivia);
                }

                DocumentationCommentTriviaSyntax newDocumentationComment = documentationComment.WithContent(
                    documentationComment.Content.InsertRange(
                        documentationComment.Content.Count - 1,
                        XmlSyntaxFactory.List(leadingNewLine, returnsElement)));

                newRoot = root.ReplaceNode(documentationComment, newDocumentationComment);
            }

            return(document.WithSyntaxRoot(newRoot));
        }
Пример #21
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="node"></param>
 public override sealed void VisitXmlEmptyElement(XmlEmptyElementSyntax node)
 {
     this.OnNodeVisited(node);
     if (!this.traverseRootOnly) base.VisitXmlEmptyElement(node);
 }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="node"></param>
 public override sealed void VisitXmlEmptyElement(XmlEmptyElementSyntax node)
 {
     this.OnNodeVisited(node, this.type.IsInstanceOfType(node));
     base.VisitXmlEmptyElement(node);
 }
Пример #23
0
 public override void VisitXmlEmptyElement(XmlEmptyElementSyntax node)
 {
     throw new NotImplementedException();
 }
Пример #24
0
        private static Task <Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, XmlEmptyElementSyntax node)
        {
            var typeDeclaration = node.FirstAncestorOrSelf <BaseTypeDeclarationSyntax>();

            TypeParameterListSyntax typeParameterList;

            if (typeDeclaration is ClassDeclarationSyntax classDeclaration)
            {
                typeParameterList = classDeclaration.TypeParameterList;
            }
            else
            {
                typeParameterList = (typeDeclaration as StructDeclarationSyntax)?.TypeParameterList;
            }

            var newRoot = root.ReplaceNode(node, BuildSeeElement(typeDeclaration.Identifier, typeParameterList));

            var newDocument = document.WithSyntaxRoot(newRoot);

            return(Task.FromResult(newDocument));
        }
        private static bool SeeTagIsCorrect(SyntaxNodeAnalysisContext context, XmlEmptyElementSyntax classReferencePart, BaseMethodDeclarationSyntax constructorDeclarationSyntax)
        {
            XmlCrefAttributeSyntax crefAttribute = XmlCommentHelper.GetFirstAttributeOrDefault<XmlCrefAttributeSyntax>(classReferencePart);
            CrefSyntax crefSyntax = crefAttribute?.Cref;
            if (crefAttribute == null)
            {
                return false;
            }

            SemanticModel semanticModel = context.SemanticModel;
            INamedTypeSymbol actualSymbol = semanticModel.GetSymbolInfo(crefSyntax, context.CancellationToken).Symbol as INamedTypeSymbol;
            if (actualSymbol == null)
            {
                return false;
            }

            INamedTypeSymbol expectedSymbol = semanticModel.GetDeclaredSymbol(constructorDeclarationSyntax.Parent, context.CancellationToken) as INamedTypeSymbol;
            return actualSymbol.OriginalDefinition == expectedSymbol;
        }
Пример #26
0
 private static bool IsBlockLevelElement(XmlEmptyElementSyntax element, bool includePotentialElements)
 {
     return(IsBlockLevelName(element.Name, includePotentialElements));
 }
Пример #27
0
        private static void HandleXmlEmptyElement(SyntaxNodeAnalysisContext context)
        {
            XmlEmptyElementSyntax syntax = (XmlEmptyElementSyntax)context.Node;

            CheckTag(context, syntax.Name?.ToString());
        }
        private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, XmlEmptyElementSyntax node)
        {
            var typeDeclaration = node.FirstAncestorOrSelf<BaseTypeDeclarationSyntax>();
            var declarationSyntax = node.FirstAncestorOrSelf<BaseMethodDeclarationSyntax>();
            bool isStruct = typeDeclaration.IsKind(SyntaxKind.StructDeclaration);

            TypeParameterListSyntax typeParameterList;
            ClassDeclarationSyntax classDeclaration = typeDeclaration as ClassDeclarationSyntax;
            if (classDeclaration != null)
            {
                typeParameterList = classDeclaration.TypeParameterList;
            }
            else
            {
                typeParameterList = (typeDeclaration as StructDeclarationSyntax)?.TypeParameterList;
            }

            var newRoot = root.ReplaceNode(node, BuildSeeElement(typeDeclaration.Identifier, typeParameterList));

            var newDocument = document.WithSyntaxRoot(newRoot);

            return Task.FromResult(newDocument);
        }
 public TameXmlEmptyElementSyntax(XmlEmptyElementSyntax node)
 {
     Node = node;
     AddChildren();
 }
Пример #30
0
 public override void VisitXmlEmptyElement(XmlEmptyElementSyntax node)
 {
 }
Пример #31
0
 public override void VisitXmlEmptyElement(XmlEmptyElementSyntax node)
 {
     Debug.Fail(node.ToString());
     base.VisitXmlEmptyElement(node);
 }
        protected static XmlElementSyntax CommentStartingWith(XmlElementSyntax comment, string commentStart, XmlEmptyElementSyntax seeCref, string commentContinue)
        {
            var content = comment.Content;

            // when necessary adjust beginning text
            // Note: when on new line, then the text is not the 1st one but the 2nd one
            var index = GetIndex(content);

            var startText = SyntaxFactory.XmlText(commentStart).WithLeadingXmlComment();

            XmlTextSyntax continueText;

            if (content[index] is XmlTextSyntax text)
            {
                // we have to remove the element as otherwise we duplicate the comment
                content = content.Remove(content[index]);

                // remove first "\r\n" token and remove '  /// ' trivia of second token
                if (text.TextTokens[0].IsKind(SyntaxKind.XmlTextLiteralNewLineToken))
                {
                    var newTokens = text.TextTokens.RemoveAt(0);
                    text = SyntaxFactory.XmlText(newTokens.Replace(newTokens[0], newTokens[0].WithLeadingTrivia()));
                }

                continueText = text.WithStartText(commentContinue);
            }
            else
            {
                index        = Math.Max(0, index - 1);
                continueText = SyntaxFactory.XmlText(commentContinue);
            }

            return(SyntaxFactory.XmlElement(
                       comment.StartTag,
                       content.Insert(index, startText).Insert(index + 1, seeCref).Insert(index + 2, continueText),
                       comment.EndTag));
        }
Пример #33
0
 /// <summary>
 /// Verifies an empty XmlElement
 /// </summary>
 /// <param name="xmlElement">The XmlElement object to validate</param>
 /// <param name="tagName">The name of the tag the XML element should have</param>
 private void VerifyXmlElement(XmlEmptyElementSyntax xmlElement, string tagName)
 {
     Assert.Equal(tagName, xmlElement.Name.LocalName.Value);
 }
Пример #34
0
 protected override ITagCommentReaderState AcceptXmlEmptyElement(XmlEmptyElementSyntax syntax)
 {
     StateMachine.AddText(syntax.ToString());
     return(new TagCommentReaderInLineState(StateMachine));
 }
Пример #35
0
 private static bool ContainsException(XmlEmptyElementSyntax xmlEmptyElement, INamedTypeSymbol exceptionSymbol, SemanticModel semanticModel, CancellationToken cancellationToken)
 {
     return(ContainsException(xmlEmptyElement.Attributes, exceptionSymbol, semanticModel, cancellationToken));
 }
        private void ClassifyXmlEmptyElement(XmlEmptyElementSyntax node)
        {
            AddXmlClassification(node.LessThanToken, ClassificationTypeNames.XmlDocCommentDelimiter);
            ClassifyXmlName(node.Name);

            foreach (var attribute in node.Attributes)
            {
                ClassifyXmlAttribute(attribute);
            }

            AddXmlClassification(node.SlashGreaterThanToken, ClassificationTypeNames.XmlDocCommentDelimiter);
        }