diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index cf80b9148b0..ceeec7f9b9c 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -536,11 +536,16 @@ namespace FourSlash { Harness.IO.log("Unexpected error(s) found. Error list is:"); } - for (const { start, length, messageText } of errors) { - Harness.IO.log(" minChar: " + start + - ", limChar: " + (start + length) + + for (const { start, length, messageText, file } of errors) { + Harness.IO.log(" from: " + showPosition(file, start) + + ", to: " + showPosition(file, start + length) + ", message: " + ts.flattenDiagnosticMessageText(messageText, Harness.IO.newLine()) + "\n"); } + + function showPosition(file: ts.SourceFile, pos: number) { + const { line, character } = ts.getLineAndCharacterOfPosition(file, pos); + return `${line}:${character}`; + } } public verifyNoErrors() { @@ -2671,6 +2676,13 @@ namespace FourSlash { this.rangesByText().forEach(ranges => this.verifyRangesAreDocumentHighlights(ranges)); } + public verifyDocumentHighlightsOf(startRange: Range, ranges: Range[]) { + ts.Debug.assert(ts.contains(ranges, startRange)); + const fileNames = unique(ranges, range => range.fileName); + this.goToRangeStart(startRange); + this.verifyDocumentHighlights(ranges, fileNames); + } + public verifyRangesAreDocumentHighlights(ranges?: Range[]) { ranges = ranges || this.getRanges(); const fileNames = unique(ranges, range => range.fileName); @@ -3885,6 +3897,10 @@ namespace FourSlashInterface { this.state.verifyRangesWithSameTextAreDocumentHighlights(); } + public documentHighlightsOf(startRange: FourSlash.Range, ranges: FourSlash.Range[]) { + this.state.verifyDocumentHighlightsOf(startRange, ranges); + } + public completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string, tags?: ts.JSDocTagInfo[]) { this.state.verifyCompletionEntryDetails(entryName, text, documentation, kind, tags); } diff --git a/src/services/documentHighlights.ts b/src/services/documentHighlights.ts index 36b72ecfa78..7ea8c519646 100644 --- a/src/services/documentHighlights.ts +++ b/src/services/documentHighlights.ts @@ -1,17 +1,23 @@ /* @internal */ namespace ts.DocumentHighlights { - export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] { + export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] | undefined { const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true); - return node && (getSemanticDocumentHighlights(node, program, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile)); + if (!node) return undefined; + + if (isJsxOpeningElement(node.parent) && node.parent.tagName === node || isJsxClosingElement(node.parent)) { + // For a JSX element, just highlight the matching tag, not all references. + const { openingElement, closingElement } = node.parent.parent; + const highlightSpans = [openingElement, closingElement].map(({ tagName }) => getHighlightSpanForNode(tagName, sourceFile)); + return [{ fileName: sourceFile.fileName, highlightSpans }]; + } + + return getSemanticDocumentHighlights(node, program, cancellationToken, sourceFilesToSearch) || getSyntacticDocumentHighlights(node, sourceFile); } function getHighlightSpanForNode(node: Node, sourceFile: SourceFile): HighlightSpan { - const start = node.getStart(sourceFile); - const end = node.getEnd(); - return { fileName: sourceFile.fileName, - textSpan: createTextSpanFromBounds(start, end), + textSpan: createTextSpanFromNode(node, sourceFile), kind: HighlightSpanKind.none }; } diff --git a/tests/cases/fourslash/findReferencesJSXTagName.ts b/tests/cases/fourslash/findReferencesJSXTagName.ts index 740eb395b3c..39031051f1b 100644 --- a/tests/cases/fourslash/findReferencesJSXTagName.ts +++ b/tests/cases/fourslash/findReferencesJSXTagName.ts @@ -11,8 +11,7 @@ ////export const [|{| "isWriteAccess": true, "isDefinition": true |}SubmissionComp|] = (submission: SubmissionProps) => ////
; -const ranges = test.ranges(); -const [r0, r1, r2] = ranges; +const [r0, r1, r2] = test.ranges(); const imports = { definition: "import SubmissionComp", ranges: [r0, r1] }; const def = { definition: "const SubmissionComp: (submission: any) => any", ranges: [r2] }; verify.referenceGroups([r0, r1], [imports, def]); diff --git a/tests/cases/fourslash/findReferencesJSXTagName3.ts b/tests/cases/fourslash/findReferencesJSXTagName3.ts new file mode 100644 index 00000000000..0d5d74b6e2e --- /dev/null +++ b/tests/cases/fourslash/findReferencesJSXTagName3.ts @@ -0,0 +1,38 @@ +///