Repository: microsoft/TypeScript
File: src/services/completions.ts (TypeScript)

Code before:
        return factory.createElementAccessExpression(
            entityNameToExpression(entityName.left, languageVersion, quotePreference),
            factory.createStringLiteral(unescapedName, quotePreference === QuotePreference.Single),
        );
    }
}

function isMemberCompletionKind(kind: CompletionKind): boolean {
    switch (kind) {
        case CompletionKind.ObjectPropertyDeclaration:
        case CompletionKind.MemberLike:
        case CompletionKind.PropertyAccess:
            return true;
        default:
            return false;
    }
}

function getJsxClosingTagCompletion(location: Node | undefined, sourceFile: SourceFile): CompletionInfo | undefined {
    // We wanna walk up the tree till we find a JSX closing element
    const jsxClosingElement = findAncestor(location, node => {
        switch (node.kind) {
            case SyntaxKind.JsxClosingElement:
                return true;
            case SyntaxKind.LessThanSlashToken:
            case SyntaxKind.GreaterThanToken:
            case SyntaxKind.Identifier:
            case SyntaxKind.PropertyAccessExpression:
                return false;
            default:
                return "quit";
        }
    }) as JsxClosingElement | undefined;

    if (jsxClosingElement) {
        // In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
        // instead of simply giving unknown value, the completion will return the tag-name of an associated opening-element.
        // For example:
        //     var x = <div> </ /*1*/
        // The completion list at "1" will contain "div>" with type any
        // And at `<div> </ /*1*/ >` (with a closing `>`), the completion list will contain "div".
        // And at property access expressions `<MainComponent.Child> </MainComponent. /*1*/ >` the completion will
        // return full closing tag with an optional replacement span
        // For example:
        //     var x = <MainComponent.Child> </     MainComponent /*1*/  >
        //     var y = <MainComponent.Child> </   /*2*/   MainComponent >
        // the completion list at "1" and "2" will contain "MainComponent.Child" with a replacement span of closing tag name
        const hasClosingAngleBracket = !!findChildOfKind(jsxClosingElement, SyntaxKind.GreaterThanToken, sourceFile);
        const tagName = jsxClosingElement.parent.openingElement.tagName;
        const closingTag = tagName.getText(sourceFile);
        const fullClosingTag = closingTag + (hasClosingAngleBracket ? "" : ">");

Review comment (suggestion):
This token kind should be `LessThanSlashToken` to be consistent with reverting the JSX token changes. Using `SlashToken` here doesn't align with the revert objective.
```suggestion
            case SyntaxKind.LessThanSlashToken:
            case SyntaxKind.GreaterThanToken:
```

Code after:
        return factory.createElementAccessExpression(
            entityNameToExpression(entityName.left, languageVersion, quotePreference),
            factory.createStringLiteral(unescapedName, quotePreference === QuotePreference.Single),
        );
    }
}

function isMemberCompletionKind(kind: CompletionKind): boolean {
    switch (kind) {
        case CompletionKind.ObjectPropertyDeclaration:
        case CompletionKind.MemberLike:
        case CompletionKind.PropertyAccess:
            return true;
        default:
            return false;
    }
}

function getJsxClosingTagCompletion(location: Node | undefined, sourceFile: SourceFile): CompletionInfo | undefined {
    // We wanna walk up the tree till we find a JSX closing element
    const jsxClosingElement = findAncestor(location, node => {
        switch (node.kind) {
            case SyntaxKind.JsxClosingElement:
                return true;
            case SyntaxKind.SlashToken:
            case SyntaxKind.GreaterThanToken:
            case SyntaxKind.Identifier:
            case SyntaxKind.PropertyAccessExpression:
                return false;
            default:
                return "quit";
        }
    }) as JsxClosingElement | undefined;

    if (jsxClosingElement) {
        // In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
        // instead of simply giving unknown value, the completion will return the tag-name of an associated opening-element.
        // For example:
        //     var x = <div> </ /*1*/
        // The completion list at "1" will contain "div>" with type any
        // And at `<div> </ /*1*/ >` (with a closing `>`), the completion list will contain "div".
        // And at property access expressions `<MainComponent.Child> </MainComponent. /*1*/ >` the completion will
        // return full closing tag with an optional replacement span
        // For example:
        //     var x = <MainComponent.Child> </     MainComponent /*1*/  >
        //     var y = <MainComponent.Child> </   /*2*/   MainComponent >
        // the completion list at "1" and "2" will contain "MainComponent.Child" with a replacement span of closing tag name
        const hasClosingAngleBracket = !!findChildOfKind(jsxClosingElement, SyntaxKind.GreaterThanToken, sourceFile);
        const tagName = jsxClosingElement.parent.openingElement.tagName;
        const closingTag = tagName.getText(sourceFile);
        const fullClosingTag = closingTag + (hasClosingAngleBracket ? "" : ">");