Combine getTouchingWord and getTouchingPropertyName (#22127)

This commit is contained in:
Andy
2018-04-12 11:56:40 -07:00
committed by GitHub
parent afcced6839
commit abbb79f972
6 changed files with 43 additions and 83 deletions

View File

@@ -844,7 +844,7 @@ namespace ts.Completions {
// Check if the caret is at the end of an identifier; this is a partial identifier that we want to complete: e.g. a.toS|
// Skip this partial identifier and adjust the contextToken to the token that precedes it.
if (contextToken && position <= contextToken.end && isWord(contextToken.kind)) {
if (contextToken && position <= contextToken.end && (isIdentifier(contextToken) || isKeyword(contextToken.kind))) {
const start = timestamp();
contextToken = findPrecedingToken(contextToken.getFullStart(), sourceFile, /*startNode*/ undefined, insideJsDocTagTypeExpression);
log("getCompletionData: Get previous token 2: " + (timestamp() - start));

View File

@@ -1,7 +1,7 @@
/* @internal */
namespace ts.DocumentHighlights {
export function getDocumentHighlights(program: Program, cancellationToken: CancellationToken, sourceFile: SourceFile, position: number, sourceFilesToSearch: ReadonlyArray<SourceFile>): DocumentHighlights[] | undefined {
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true);
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
if (node.parent && (isJsxOpeningElement(node.parent) && node.parent.tagName === node || isJsxClosingElement(node.parent))) {
// For a JSX element, just highlight the matching tag, not all references.

View File

@@ -716,6 +716,10 @@ namespace ts.FindAllReferences.Core {
});
}
function getPossibleSymbolReferenceNodes(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): ReadonlyArray<Node> {
return getPossibleSymbolReferencePositions(sourceFile, symbolName, container).map(pos => getTouchingPropertyName(sourceFile, pos, /*includeJsDocComment*/ true));
}
function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): ReadonlyArray<number> {
const positions: number[] = [];
@@ -754,11 +758,9 @@ namespace ts.FindAllReferences.Core {
function getLabelReferencesInNode(container: Node, targetLabel: Identifier): SymbolAndEntries[] {
const sourceFile = container.getSourceFile();
const labelName = targetLabel.text;
const references = mapDefined(getPossibleSymbolReferencePositions(sourceFile, labelName, container), position => {
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ false);
const references = mapDefined(getPossibleSymbolReferenceNodes(sourceFile, labelName, container), node =>
// Only pick labels that are either the target label, or have a target that is the target label
return node && (node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel)) ? nodeEntry(node) : undefined;
});
node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel) ? nodeEntry(node) : undefined);
return [{ definition: { type: "label", node: targetLabel }, references }];
}
@@ -788,10 +790,8 @@ namespace ts.FindAllReferences.Core {
function getAllReferencesForKeyword(sourceFiles: ReadonlyArray<SourceFile>, keywordKind: SyntaxKind, cancellationToken: CancellationToken): SymbolAndEntries[] {
const references = flatMap(sourceFiles, sourceFile => {
cancellationToken.throwIfCancellationRequested();
return mapDefined(getPossibleSymbolReferencePositions(sourceFile, tokenToString(keywordKind), sourceFile), position => {
const referenceLocation = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
return referenceLocation.kind === keywordKind ? nodeEntry(referenceLocation) : undefined;
});
return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, tokenToString(keywordKind), sourceFile), referenceLocation =>
referenceLocation.kind === keywordKind ? nodeEntry(referenceLocation) : undefined);
});
return references.length ? [{ definition: { type: "keyword", node: references[0].node }, references }] : undefined;
}
@@ -1255,9 +1255,8 @@ namespace ts.FindAllReferences.Core {
}
const sourceFile = searchSpaceNode.getSourceFile();
const references = mapDefined(getPossibleSymbolReferencePositions(sourceFile, "super", searchSpaceNode), position => {
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ false);
if (!node || node.kind !== SyntaxKind.SuperKeyword) {
const references = mapDefined(getPossibleSymbolReferenceNodes(sourceFile, "super", searchSpaceNode), node => {
if (node.kind !== SyntaxKind.SuperKeyword) {
return;
}
@@ -1307,12 +1306,30 @@ namespace ts.FindAllReferences.Core {
return undefined;
}
const references: Entry[] = [];
for (const sourceFile of searchSpaceNode.kind === SyntaxKind.SourceFile ? sourceFiles : [searchSpaceNode.getSourceFile()]) {
const references = flatMap(searchSpaceNode.kind === SyntaxKind.SourceFile ? sourceFiles : [searchSpaceNode.getSourceFile()], sourceFile => {
cancellationToken.throwIfCancellationRequested();
const positions = getPossibleSymbolReferencePositions(sourceFile, "this", isSourceFile(searchSpaceNode) ? sourceFile : searchSpaceNode);
getThisReferencesInFile(sourceFile, searchSpaceNode.kind === SyntaxKind.SourceFile ? sourceFile : searchSpaceNode, positions, staticFlag, references);
}
return getPossibleSymbolReferenceNodes(sourceFile, "this", isSourceFile(searchSpaceNode) ? sourceFile : searchSpaceNode).filter(node => {
if (!isThis(node)) {
return false;
}
const container = getThisContainer(node, /* includeArrowFunctions */ false);
switch (searchSpaceNode.kind) {
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
return searchSpaceNode.symbol === container.symbol;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
return isObjectLiteralMethod(searchSpaceNode) && searchSpaceNode.symbol === container.symbol;
case SyntaxKind.ClassExpression:
case SyntaxKind.ClassDeclaration:
// Make sure the container belongs to the same class
// and has the appropriate static modifier from the original container.
return container.parent && searchSpaceNode.symbol === container.parent.symbol && (getModifierFlags(container) & ModifierFlags.Static) === staticFlag;
case SyntaxKind.SourceFile:
return container.kind === SyntaxKind.SourceFile && !isExternalModule(<SourceFile>container);
}
});
}).map(n => nodeEntry(n));
return [{
definition: { type: "this", node: thisOrSuperKeyword },
@@ -1320,52 +1337,11 @@ namespace ts.FindAllReferences.Core {
}];
}
function getThisReferencesInFile(sourceFile: SourceFile, searchSpaceNode: Node, possiblePositions: ReadonlyArray<number>, staticFlag: ModifierFlags, result: Push<Entry>): void {
forEach(possiblePositions, position => {
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ false);
if (!node || !isThis(node)) {
return;
}
const container = getThisContainer(node, /* includeArrowFunctions */ false);
switch (searchSpaceNode.kind) {
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
if (searchSpaceNode.symbol === container.symbol) {
result.push(nodeEntry(node));
}
break;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
if (isObjectLiteralMethod(searchSpaceNode) && searchSpaceNode.symbol === container.symbol) {
result.push(nodeEntry(node));
}
break;
case SyntaxKind.ClassExpression:
case SyntaxKind.ClassDeclaration:
// Make sure the container belongs to the same class
// and has the appropriate static modifier from the original container.
if (container.parent && searchSpaceNode.symbol === container.parent.symbol && (getModifierFlags(container) & ModifierFlags.Static) === staticFlag) {
result.push(nodeEntry(node));
}
break;
case SyntaxKind.SourceFile:
if (container.kind === SyntaxKind.SourceFile && !isExternalModule(<SourceFile>container)) {
result.push(nodeEntry(node));
}
break;
}
});
}
function getReferencesForStringLiteral(node: StringLiteral, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken): SymbolAndEntries[] {
const references = flatMap(sourceFiles, sourceFile => {
cancellationToken.throwIfCancellationRequested();
return mapDefined(getPossibleSymbolReferencePositions(sourceFile, node.text), position => {
const ref = tryCast(getTouchingWord(sourceFile, position, /*includeJsDocComment*/ false), isStringLiteral);
return ref && ref.text === node.text ? nodeEntry(ref, /*isInString*/ true) : undefined;
});
return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, node.text), ref =>
isStringLiteral(ref) && ref.text === node.text ? nodeEntry(ref, /*isInString*/ true) : undefined);
});
return [{

View File

@@ -131,9 +131,7 @@ namespace ts.OrganizeImports {
}
function getExternalModuleName(specifier: Expression) {
return isStringLiteral(specifier) || isNoSubstitutionTemplateLiteral(specifier)
? specifier.text
: undefined;
return isStringLiteralLike(specifier) ? specifier.text : undefined;
}
/* @internal */ // Internal for testing

View File

@@ -2,7 +2,7 @@
namespace ts.Rename {
export function getRenameInfo(typeChecker: TypeChecker, defaultLibFileName: string, getCanonicalFileName: GetCanonicalFileName, sourceFile: SourceFile, position: number): RenameInfo {
const getCanonicalDefaultLibName = memoize(() => getCanonicalFileName(normalizePath(defaultLibFileName)));
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true);
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
const renameInfo = node && nodeIsEligibleForRename(node)
? getRenameInfoForNode(node, typeChecker, sourceFile, isDefinedInLibraryFile)
: undefined;

View File

@@ -627,18 +627,12 @@ namespace ts {
return syntaxList;
}
/* Gets the token whose text has range [start, end) and
* position >= start and (position < end or (position === end && token is keyword or identifier))
*/
export function getTouchingWord(sourceFile: SourceFile, position: number, includeJsDocComment: boolean): Node {
return getTouchingToken(sourceFile, position, includeJsDocComment, n => isWord(n.kind));
}
/* Gets the token whose text has range [start, end) and position >= start
* and (position < end or (position === end && token is keyword or identifier or numeric/string literal))
/**
* Gets the token whose text has range [start, end) and
* position >= start and (position < end or (position === end && token is literal or keyword or identifier))
*/
export function getTouchingPropertyName(sourceFile: SourceFile, position: number, includeJsDocComment: boolean): Node {
return getTouchingToken(sourceFile, position, includeJsDocComment, n => isPropertyName(n.kind));
return getTouchingToken(sourceFile, position, includeJsDocComment, n => isPropertyNameLiteral(n) || isKeyword(n.kind));
}
/**
@@ -1059,14 +1053,6 @@ namespace ts {
return undefined;
}
export function isWord(kind: SyntaxKind): boolean {
return kind === SyntaxKind.Identifier || isKeyword(kind);
}
function isPropertyName(kind: SyntaxKind): boolean {
return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NumericLiteral || isWord(kind);
}
export function isComment(kind: SyntaxKind): boolean {
return kind === SyntaxKind.SingleLineCommentTrivia || kind === SyntaxKind.MultiLineCommentTrivia;
}