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

Code before:

function getReplacementExpression(reference: Node, replacement: Expression): Expression {
    // Make sure each reference site gets its own copy of the replacement node.
    replacement = getSynthesizedDeepClone(replacement);
    const { parent } = reference;

    // Logic from binaryOperandNeedsParentheses: "If the operand has lower precedence,
    // then it needs to be parenthesized to preserve the intent of the expression.
    // If the operand has higher precedence, then it does not need to be parenthesized."
    //
    // Note that binaryOperandNeedsParentheses has further logic when the precedences
    // are equal, but for the purposes of this refactor we keep things simple and
    // instead just check for special cases with needsParentheses.
    if (isExpression(parent) && (getExpressionPrecedence(replacement) < getExpressionPrecedence(parent) || needsParentheses(parent))) {
        return factory.createParenthesizedExpression(replacement);
    }

    // Functions also need to be parenthesized.
    // E.g.: const f = () => {}; f(); -> (() => {})();
    if (isFunctionLike(replacement) && (isCallLikeExpression(parent) || isPropertyAccessExpression(parent))) {
        return factory.createParenthesizedExpression(replacement);
    }

    // Property access of literals need parentheses.
    // E.g.: const x = 1; x.toString(); -> (1).toString();
    if (isPropertyAccessExpression(parent) && (isLiteralTypeLikeExpression(replacement) || isObjectLiteralExpression(replacement))) {
        return factory.createParenthesizedExpression(replacement);
    }

    return replacement;
}


Review comment (refactor):
`isLiteralTypeLikeExpression` is not the right helper. Literal type-likes correspond to nodes that can be used in type position that are literals. You are more concerned with nodes in the expression space, and it just so happens that we use the same kinds of nodes in both places.

As far as I remember for property accesses, decimal numeric literals with no exponent or fractional component are really the only literals where you need to parenthesize.

```ts
"hello".toString(); // ✅
true.toString();    // ✅
false.toString();   // ✅
1.0.toString();     // ✅
1e32.toString();    // ✅
0xcafe.toString();  // ✅
```

But you can just say "only parenthesize when the node is a numeric literal" just to make this simpler.

Code after:

function getReplacementExpression(reference: Node, replacement: Expression): Expression {
    // Make sure each reference site gets its own copy of the replacement node.
    replacement = getSynthesizedDeepClone(replacement);
    const { parent } = reference;

    // Logic from binaryOperandNeedsParentheses: "If the operand has lower precedence,
    // then it needs to be parenthesized to preserve the intent of the expression.
    // If the operand has higher precedence, then it does not need to be parenthesized."
    //
    // Note that binaryOperandNeedsParentheses has further logic when the precedences
    // are equal, but for the purposes of this refactor we keep things simple and
    // instead just check for special cases with needsParentheses.
    if (isExpression(parent) && (getExpressionPrecedence(replacement) < getExpressionPrecedence(parent) || needsParentheses(parent))) {
        return factory.createParenthesizedExpression(replacement);
    }

    // Functions also need to be parenthesized.
    // E.g.: const f = () => {}; f(); -> (() => {})();
    if (isFunctionLike(replacement) && (isCallLikeExpression(parent) || isPropertyAccessExpression(parent))) {
        return factory.createParenthesizedExpression(replacement);
    }

    // Property access of numeric literals and objects need parentheses.
    // E.g.: const x = 1; x.toString(); -> (1).toString();
    if (isPropertyAccessExpression(parent) && (isNumericLiteral(replacement) || isObjectLiteralExpression(replacement))) {
        return factory.createParenthesizedExpression(replacement);
    }

    return replacement;
}