src/vs/workbench/contrib/debug/browser/debugHover.ts/DebugHoverComputer/doCompute
class DebugHoverComputer:	private async doCompute(model: ITextModel, position: Position, token: CancellationToken): Promise<{ range: IRange; matchingExpression: string } | null> {
		if (this.languageFeaturesService.evaluatableExpressionProvider.has(model)) {
			const supports = this.languageFeaturesService.evaluatableExpressionProvider.ordered(model);

			const results = coalesce(await Promise.all(supports.map(async support => {
				try {
					return await support.provideEvaluatableExpression(model, position, token);
				} catch (err) {
					return undefined;
				}
			})));

			if (results.length > 0) {
				let matchingExpression = results[0].expression;
				const range = results[0].range;

				if (!matchingExpression) {
					const lineContent = model.getLineContent(position.lineNumber);
					matchingExpression = lineContent.substring(range.startColumn - 1, range.endColumn - 1);
				}

				return { range, matchingExpression };
			}
		} else { // old one-size-fits-all strategy
			const lineContent = model.getLineContent(position.lineNumber);
			const { start, end } = getExactExpressionStartAndEnd(lineContent, position.column, position.column);

			// use regex to extract the sub-expression #9821
			const matchingExpression = lineContent.substring(start - 1, end);
			return {
				matchingExpression,
				range: new Range(position.lineNumber, start, position.lineNumber, start + matchingExpression.length)
			};
		}

		return null;
	}