From 8bab5860a6817bb73ec3bd12b1ba92739f857755 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 15 Jun 2018 17:47:46 -0700 Subject: [PATCH 1/5] getTokenAtPosition: default includeJsDocComment to true --- src/services/breakpoints.ts | 2 +- .../codefixes/addMissingInvocationForDecorator.ts | 2 +- src/services/codefixes/annotateWithTypeFromJSDoc.ts | 2 +- src/services/codefixes/convertFunctionToEs6Class.ts | 2 +- src/services/codefixes/convertToMappedObjectType.ts | 2 +- .../correctQualifiedNameToIndexedAccessType.ts | 2 +- src/services/codefixes/fixAddMissingMember.ts | 2 +- .../codefixes/fixAddModuleReferTypeMissingTypeof.ts | 2 +- src/services/codefixes/fixAwaitInSyncFunction.ts | 2 +- src/services/codefixes/fixCannotFindModule.ts | 2 +- ...fixClassDoesntImplementInheritedAbstractMember.ts | 2 +- .../fixClassIncorrectlyImplementsInterface.ts | 2 +- .../codefixes/fixClassSuperMustPrecedeThisAccess.ts | 2 +- .../fixConstructorForDerivedNeedSuperCall.ts | 2 +- .../fixExtendsInterfaceBecomesImplements.ts | 2 +- .../codefixes/fixForgottenThisPropertyAccess.ts | 2 +- src/services/codefixes/fixInvalidImportSyntax.ts | 4 ++-- src/services/codefixes/fixJSDocTypes.ts | 2 +- src/services/codefixes/fixSpelling.ts | 2 +- .../codefixes/fixStrictClassInitialization.ts | 2 +- src/services/codefixes/fixUnreachableCode.ts | 2 +- src/services/codefixes/fixUnusedIdentifier.ts | 12 ++++++------ src/services/codefixes/fixUnusedLabel.ts | 2 +- src/services/codefixes/importFixes.ts | 4 ++-- src/services/codefixes/inferFromUsage.ts | 4 ++-- src/services/codefixes/requireInTs.ts | 2 +- src/services/codefixes/useDefaultImport.ts | 2 +- src/services/completions.ts | 2 +- src/services/jsDoc.ts | 2 +- src/services/pathCompletions.ts | 2 +- .../refactors/addOrRemoveBracesToArrowFunction.ts | 2 +- src/services/refactors/convertImport.ts | 2 +- src/services/refactors/extractSymbol.ts | 2 +- .../refactors/generateGetAccessorAndSetAccessor.ts | 2 +- src/services/textChanges.ts | 2 +- src/services/utilities.ts | 4 ++-- 36 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index 812a8a45dd059..404e75db14728 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -9,7 +9,7 @@ namespace ts.BreakpointResolver { return undefined; } - let tokenAtLocation = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); + let tokenAtLocation = getTokenAtPosition(sourceFile, position); const lineOfPosition = sourceFile.getLineAndCharacterOfPosition(position).line; if (sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getStart(sourceFile)).line > lineOfPosition) { // Get previous token if the token is returned starts on new line diff --git a/src/services/codefixes/addMissingInvocationForDecorator.ts b/src/services/codefixes/addMissingInvocationForDecorator.ts index 02b97eec37ebf..25100870623db 100644 --- a/src/services/codefixes/addMissingInvocationForDecorator.ts +++ b/src/services/codefixes/addMissingInvocationForDecorator.ts @@ -13,7 +13,7 @@ namespace ts.codefix { }); function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) { - const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, pos); const decorator = findAncestor(token, isDecorator)!; Debug.assert(!!decorator, "Expected position to be owned by a decorator."); const replacement = createCall(decorator.expression, /*typeArguments*/ undefined, /*argumentsArray*/ undefined); diff --git a/src/services/codefixes/annotateWithTypeFromJSDoc.ts b/src/services/codefixes/annotateWithTypeFromJSDoc.ts index 36664ead4a46f..c31439211069f 100644 --- a/src/services/codefixes/annotateWithTypeFromJSDoc.ts +++ b/src/services/codefixes/annotateWithTypeFromJSDoc.ts @@ -18,7 +18,7 @@ namespace ts.codefix { }); function getDeclaration(file: SourceFile, pos: number): DeclarationWithType | undefined { - const name = getTokenAtPosition(file, pos, /*includeJsDocComment*/ false); + const name = getTokenAtPosition(file, pos); // For an arrow function with no name, 'name' lands on the first parameter. return tryCast(isParameter(name.parent) ? name.parent.parent : name.parent, parameterShouldGetTypeFromJSDoc); } diff --git a/src/services/codefixes/convertFunctionToEs6Class.ts b/src/services/codefixes/convertFunctionToEs6Class.ts index 4c47d3dca7247..b98f2abb708fc 100644 --- a/src/services/codefixes/convertFunctionToEs6Class.ts +++ b/src/services/codefixes/convertFunctionToEs6Class.ts @@ -14,7 +14,7 @@ namespace ts.codefix { function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker): void { const deletedNodes: { node: Node, inList: boolean }[] = []; - const ctorSymbol = checker.getSymbolAtLocation(getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false))!; + const ctorSymbol = checker.getSymbolAtLocation(getTokenAtPosition(sourceFile, position))!; if (!ctorSymbol || !(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable))) { // Bad input diff --git a/src/services/codefixes/convertToMappedObjectType.ts b/src/services/codefixes/convertToMappedObjectType.ts index ff86a9872bb99..0d79d6363c0ae 100644 --- a/src/services/codefixes/convertToMappedObjectType.ts +++ b/src/services/codefixes/convertToMappedObjectType.ts @@ -25,7 +25,7 @@ namespace ts.codefix { interface Info { readonly indexSignature: IndexSignatureDeclaration; readonly container: FixableDeclaration; } function getInfo(sourceFile: SourceFile, pos: number): Info | undefined { - const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, pos); const indexSignature = cast(token.parent.parent, isIndexSignatureDeclaration); if (isClassDeclaration(indexSignature.parent)) return undefined; const container = isInterfaceDeclaration(indexSignature.parent) ? indexSignature.parent : cast(indexSignature.parent.parent, isTypeAliasDeclaration); diff --git a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts index 54fe182386353..02ccbfd1d64cc 100644 --- a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts +++ b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts @@ -21,7 +21,7 @@ namespace ts.codefix { }); function getQualifiedName(sourceFile: SourceFile, pos: number): QualifiedName & { left: Identifier } | undefined { - const qualifiedName = findAncestor(getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ true), isQualifiedName)!; + const qualifiedName = findAncestor(getTokenAtPosition(sourceFile, pos), isQualifiedName)!; Debug.assert(!!qualifiedName, "Expected position to be owned by a qualified name."); return isIdentifier(qualifiedName.left) ? qualifiedName as QualifiedName & { left: Identifier } : undefined; } diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index 534922110428d..e0e01c3999880 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -52,7 +52,7 @@ namespace ts.codefix { // The identifier of the missing property. eg: // this.missing = 1; // ^^^^^^^ - const token = getTokenAtPosition(tokenSourceFile, tokenPos, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(tokenSourceFile, tokenPos); if (!isIdentifier(token)) { return undefined; } diff --git a/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts b/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts index ac79c29fde2a7..b558a270decb1 100644 --- a/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts +++ b/src/services/codefixes/fixAddModuleReferTypeMissingTypeof.ts @@ -17,7 +17,7 @@ namespace ts.codefix { }); function getImportTypeNode(sourceFile: SourceFile, pos: number): ImportTypeNode { - const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, pos); Debug.assert(token.kind === SyntaxKind.ImportKeyword); Debug.assert(token.parent.kind === SyntaxKind.ImportType); return token.parent; diff --git a/src/services/codefixes/fixAwaitInSyncFunction.ts b/src/services/codefixes/fixAwaitInSyncFunction.ts index fd990aebcd4c2..e5b3a24dbea18 100644 --- a/src/services/codefixes/fixAwaitInSyncFunction.ts +++ b/src/services/codefixes/fixAwaitInSyncFunction.ts @@ -34,7 +34,7 @@ namespace ts.codefix { } function getNodes(sourceFile: SourceFile, start: number): { insertBefore: Node, returnType: TypeNode | undefined } | undefined { - const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, start); const containingFunction = getContainingFunction(token); if (!containingFunction) { return; diff --git a/src/services/codefixes/fixCannotFindModule.ts b/src/services/codefixes/fixCannotFindModule.ts index 78532f152723a..68fa3a5c0305b 100644 --- a/src/services/codefixes/fixCannotFindModule.ts +++ b/src/services/codefixes/fixCannotFindModule.ts @@ -28,7 +28,7 @@ namespace ts.codefix { } function getTypesPackageNameToInstall(host: LanguageServiceHost, sourceFile: SourceFile, pos: number, diagCode: number): string | undefined { - const moduleName = cast(getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false), isStringLiteral).text; + const moduleName = cast(getTokenAtPosition(sourceFile, pos), isStringLiteral).text; const { packageName } = getPackageName(moduleName); return diagCode === errorCodeCannotFindModule ? (JsTyping.nodeCoreModules.has(packageName) ? "@types/node" : undefined) diff --git a/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts index 95de8857eb2f8..ed06c86e4f6f9 100644 --- a/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts +++ b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts @@ -28,7 +28,7 @@ namespace ts.codefix { function getClass(sourceFile: SourceFile, pos: number): ClassLikeDeclaration { // Token is the identifier in the case of a class declaration // or the class keyword token in the case of a class expression. - const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, pos); return cast(token.parent, isClassLike); } diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index 781f14566c9a1..6cf6aab735f93 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -29,7 +29,7 @@ namespace ts.codefix { }); function getClass(sourceFile: SourceFile, pos: number): ClassLikeDeclaration { - return Debug.assertDefined(getContainingClass(getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false))); + return Debug.assertDefined(getContainingClass(getTokenAtPosition(sourceFile, pos))); } function symbolPointsToNonPrivateMember (symbol: Symbol) { diff --git a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts index 6a68b9b600488..8ee9b60051f84 100644 --- a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts +++ b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts @@ -33,7 +33,7 @@ namespace ts.codefix { } function getNodes(sourceFile: SourceFile, pos: number): { readonly constructor: ConstructorDeclaration, readonly superCall: ExpressionStatement } | undefined { - const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, pos); if (token.kind !== SyntaxKind.ThisKeyword) return undefined; const constructor = getContainingFunction(token) as ConstructorDeclaration; const superCall = findSuperCall(constructor.body!); diff --git a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts index 605bb660f0623..7d021d5e26097 100644 --- a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts +++ b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts @@ -16,7 +16,7 @@ namespace ts.codefix { }); function getNode(sourceFile: SourceFile, pos: number): ConstructorDeclaration { - const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, pos); Debug.assert(token.kind === SyntaxKind.ConstructorKeyword); return token.parent as ConstructorDeclaration; } diff --git a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts index c2c040b42adf0..78dc6b1ae19d3 100644 --- a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts +++ b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts @@ -20,7 +20,7 @@ namespace ts.codefix { }); function getNodes(sourceFile: SourceFile, pos: number) { - const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, pos); const heritageClauses = getContainingClass(token)!.heritageClauses!; const extendsToken = heritageClauses[0].getFirstToken()!; return extendsToken.kind === SyntaxKind.ExtendsKeyword ? { extendsToken, heritageClauses } : undefined; diff --git a/src/services/codefixes/fixForgottenThisPropertyAccess.ts b/src/services/codefixes/fixForgottenThisPropertyAccess.ts index 82954673d4fe7..e5f58885e1c83 100644 --- a/src/services/codefixes/fixForgottenThisPropertyAccess.ts +++ b/src/services/codefixes/fixForgottenThisPropertyAccess.ts @@ -26,7 +26,7 @@ namespace ts.codefix { interface Info { readonly node: Identifier; readonly className: string | undefined; } function getInfo(sourceFile: SourceFile, pos: number, diagCode: number): Info | undefined { - const node = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const node = getTokenAtPosition(sourceFile, pos); if (!isIdentifier(node)) return undefined; return { node, className: diagCode === didYouMeanStaticMemberCode ? getContainingClass(node)!.name!.text : undefined }; } diff --git a/src/services/codefixes/fixInvalidImportSyntax.ts b/src/services/codefixes/fixInvalidImportSyntax.ts index 906c6f13cd1e0..ab8014bd0b466 100644 --- a/src/services/codefixes/fixInvalidImportSyntax.ts +++ b/src/services/codefixes/fixInvalidImportSyntax.ts @@ -40,7 +40,7 @@ namespace ts.codefix { function getActionsForUsageOfInvalidImport(context: CodeFixContext): CodeFixAction[] | undefined { const sourceFile = context.sourceFile; const targetKind = Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures.code === context.errorCode ? SyntaxKind.CallExpression : SyntaxKind.NewExpression; - const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false), a => a.kind === targetKind && a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length)) as CallExpression | NewExpression; + const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.kind === targetKind && a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length)) as CallExpression | NewExpression; if (!node) { return []; } @@ -69,7 +69,7 @@ namespace ts.codefix { function getActionsForInvalidImportLocation(context: CodeFixContext): CodeFixAction[] | undefined { const sourceFile = context.sourceFile; - const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false), a => a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length)); + const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length)); if (!node) { return []; } diff --git a/src/services/codefixes/fixJSDocTypes.ts b/src/services/codefixes/fixJSDocTypes.ts index 043ed018aa7d8..8769b0339e03c 100644 --- a/src/services/codefixes/fixJSDocTypes.ts +++ b/src/services/codefixes/fixJSDocTypes.ts @@ -44,7 +44,7 @@ namespace ts.codefix { } function getInfo(sourceFile: SourceFile, pos: number, checker: TypeChecker): { readonly typeNode: TypeNode, readonly type: Type } | undefined { - const decl = findAncestor(getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false), isTypeContainer); + const decl = findAncestor(getTokenAtPosition(sourceFile, pos), isTypeContainer); const typeNode = decl && decl.type; return typeNode && { typeNode, type: checker.getTypeFromTypeNode(typeNode) }; } diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index 6986e161f4aa5..fbe3953c1b567 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -29,7 +29,7 @@ namespace ts.codefix { // This is the identifier of the misspelled word. eg: // this.speling = 1; // ^^^^^^^ - const node = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); // TODO: GH#15852 + const node = getTokenAtPosition(sourceFile, pos); const checker = context.program.getTypeChecker(); let suggestion: string | undefined; diff --git a/src/services/codefixes/fixStrictClassInitialization.ts b/src/services/codefixes/fixStrictClassInitialization.ts index f52ebadc851cf..0647a64c36815 100644 --- a/src/services/codefixes/fixStrictClassInitialization.ts +++ b/src/services/codefixes/fixStrictClassInitialization.ts @@ -48,7 +48,7 @@ namespace ts.codefix { }); function getPropertyDeclaration (sourceFile: SourceFile, pos: number): PropertyDeclaration | undefined { - const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, pos); return isIdentifier(token) ? cast(token.parent, isPropertyDeclaration) : undefined; } diff --git a/src/services/codefixes/fixUnreachableCode.ts b/src/services/codefixes/fixUnreachableCode.ts index aed55f96f2ad6..6c279d75ab393 100644 --- a/src/services/codefixes/fixUnreachableCode.ts +++ b/src/services/codefixes/fixUnreachableCode.ts @@ -13,7 +13,7 @@ namespace ts.codefix { }); function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number): void { - const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, start); const statement = findAncestor(token, isStatement)!; Debug.assert(statement.getStart(sourceFile) === token.getStart(sourceFile)); diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index ad3e2e36f5b4b..4df28b85a3267 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -16,7 +16,7 @@ namespace ts.codefix { getCodeActions(context) { const { errorCode, sourceFile, program } = context; const checker = program.getTypeChecker(); - const startToken = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false); + const startToken = getTokenAtPosition(sourceFile, context.span.start); const importDecl = tryGetFullImport(startToken); if (importDecl) { @@ -54,7 +54,7 @@ namespace ts.codefix { const { sourceFile, program } = context; const checker = program.getTypeChecker(); return codeFixAll(context, errorCodes, (changes, diag) => { - const startToken = getTokenAtPosition(sourceFile, diag.start, /*includeJsDocComment*/ false); + const startToken = getTokenAtPosition(sourceFile, diag.start); const token = findPrecedingToken(textSpanEnd(diag), diag.file)!; switch (context.fixId) { case fixIdPrefix: @@ -173,8 +173,8 @@ namespace ts.codefix { const typeParameters = getEffectiveTypeParameterDeclarations(parent.parent); if (typeParameters.length === 1) { const { pos, end } = cast(typeParameters, isNodeArray); - const previousToken = getTokenAtPosition(sourceFile, pos - 1, /*includeJsDocComment*/ false); - const nextToken = getTokenAtPosition(sourceFile, end, /*includeJsDocComment*/ false); + const previousToken = getTokenAtPosition(sourceFile, pos - 1); + const nextToken = getTokenAtPosition(sourceFile, end); Debug.assert(previousToken.kind === SyntaxKind.LessThanToken); Debug.assert(nextToken.kind === SyntaxKind.GreaterThanToken); @@ -251,7 +251,7 @@ namespace ts.codefix { else { // import |d,| * as ns from './file' const start = importClause.name!.getStart(sourceFile); - const nextToken = getTokenAtPosition(sourceFile, importClause.name!.end, /*includeJsDocComment*/ false); + const nextToken = getTokenAtPosition(sourceFile, importClause.name!.end); if (nextToken && nextToken.kind === SyntaxKind.CommaToken) { // shift first non-whitespace position after comma to the start position of the node const end = skipTrivia(sourceFile.text, nextToken.end, /*stopAfterLineBreaks*/ false, /*stopAtComments*/ true); @@ -285,7 +285,7 @@ namespace ts.codefix { // Delete named imports while preserving the default import // import d|, * as ns| from './file' // import d|, { a }| from './file' - const previousToken = getTokenAtPosition(sourceFile, namedBindings.pos - 1, /*includeJsDocComment*/ false); + const previousToken = getTokenAtPosition(sourceFile, namedBindings.pos - 1); if (previousToken && previousToken.kind === SyntaxKind.CommaToken) { changes.deleteRange(sourceFile, { pos: previousToken.getStart(), end: namedBindings.end }); } diff --git a/src/services/codefixes/fixUnusedLabel.ts b/src/services/codefixes/fixUnusedLabel.ts index b99f72d68397e..49f334720ed53 100644 --- a/src/services/codefixes/fixUnusedLabel.ts +++ b/src/services/codefixes/fixUnusedLabel.ts @@ -13,7 +13,7 @@ namespace ts.codefix { }); function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, start: number): void { - const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, start); const labeledStatement = cast(token.parent, isLabeledStatement); const pos = token.getStart(sourceFile); const statementPos = labeledStatement.statement.getStart(sourceFile); diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 86f64a79cf2b5..d2f1095ef4cca 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -326,7 +326,7 @@ namespace ts.codefix { } function getActionsForUMDImport(context: CodeFixContext): CodeFixAction[] | undefined { - const token = getTokenAtPosition(context.sourceFile, context.span.start, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(context.sourceFile, context.span.start); const checker = context.program.getTypeChecker(); let umdSymbol: Symbol | undefined; @@ -385,7 +385,7 @@ namespace ts.codefix { // This will always be an Identifier, since the diagnostics we fix only fail on identifiers. const { sourceFile, span, program, cancellationToken } = context; const checker = program.getTypeChecker(); - const symbolToken = getTokenAtPosition(sourceFile, span.start, /*includeJsDocComment*/ false); + const symbolToken = getTokenAtPosition(sourceFile, span.start); // If we're at ``, we must check if `Foo` is already in scope, and if so, get an import for `React` instead. const symbolName = isJsxOpeningLikeElement(symbolToken.parent) && symbolToken.parent.tagName === symbolToken diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index c58c001b403ee..5843742523e7c 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -30,7 +30,7 @@ namespace ts.codefix { return undefined; // TODO: GH#20113 } - const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, start); let declaration!: Declaration | undefined; const changes = textChanges.ChangeTracker.with(context, changes => { declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken, /*markSeenseen*/ returnTrue); }); return changes.length === 0 ? undefined @@ -41,7 +41,7 @@ namespace ts.codefix { const { sourceFile, program, cancellationToken } = context; const markSeen = nodeSeenTracker(); return codeFixAll(context, errorCodes, (changes, err) => { - doChange(changes, sourceFile, getTokenAtPosition(err.file, err.start, /*includeJsDocComment*/ false), err.code, program, cancellationToken, markSeen); + doChange(changes, sourceFile, getTokenAtPosition(err.file, err.start), err.code, program, cancellationToken, markSeen); }); }, }); diff --git a/src/services/codefixes/requireInTs.ts b/src/services/codefixes/requireInTs.ts index 7efd9bd7fa6fc..ee2a898147d6f 100644 --- a/src/services/codefixes/requireInTs.ts +++ b/src/services/codefixes/requireInTs.ts @@ -21,7 +21,7 @@ namespace ts.codefix { interface Info { readonly statement: VariableStatement; readonly name: Identifier; readonly required: StringLiteralLike; } function getInfo(sourceFile: SourceFile, pos: number): Info { - const { parent } = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const { parent } = getTokenAtPosition(sourceFile, pos); if (!isRequireCall(parent, /*checkArgumentIsStringLiteralLike*/ true)) throw Debug.failBadSyntaxKind(parent); const decl = cast(parent.parent, isVariableDeclaration); return { statement: cast(decl.parent.parent, isVariableStatement), name: cast(decl.name, isIdentifier), required: parent.arguments[0] }; diff --git a/src/services/codefixes/useDefaultImport.ts b/src/services/codefixes/useDefaultImport.ts index 36aa0bb169718..75d4d15bd7e7e 100644 --- a/src/services/codefixes/useDefaultImport.ts +++ b/src/services/codefixes/useDefaultImport.ts @@ -24,7 +24,7 @@ namespace ts.codefix { readonly moduleSpecifier: Expression; } function getInfo(sourceFile: SourceFile, pos: number): Info | undefined { - const name = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + const name = getTokenAtPosition(sourceFile, pos); if (!isIdentifier(name)) return undefined; // bad input const { parent } = name; if (isImportEqualsDeclaration(parent) && isExternalModuleReference(parent.moduleReference)) { diff --git a/src/services/completions.ts b/src/services/completions.ts index e31ac4e81f384..e4a956ce16966 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -849,7 +849,7 @@ namespace ts.Completions { return { kind: CompletionDataKind.JsDocTagName }; } if (isTagWithTypeExpression(tag) && tag.typeExpression && tag.typeExpression.kind === SyntaxKind.JSDocTypeExpression) { - currentToken = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ true); + currentToken = getTokenAtPosition(sourceFile, position); if (!currentToken || (!isDeclarationName(currentToken) && (currentToken.parent.kind !== SyntaxKind.JSDocPropertyTag || diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index bfd371d115414..46a0ad49e3f3e 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -242,7 +242,7 @@ namespace ts.JsDoc { return undefined; } - const tokenAtPos = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); + const tokenAtPos = getTokenAtPosition(sourceFile, position); const tokenStart = tokenAtPos.getStart(sourceFile); if (!tokenAtPos || tokenStart < position) { return undefined; diff --git a/src/services/pathCompletions.ts b/src/services/pathCompletions.ts index 06cc7a718217c..882ab7787487a 100644 --- a/src/services/pathCompletions.ts +++ b/src/services/pathCompletions.ts @@ -304,7 +304,7 @@ namespace ts.Completions.PathCompletions { } export function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number, compilerOptions: CompilerOptions, host: LanguageServiceHost): ReadonlyArray | undefined { - const token = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, position); const commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos); const range = commentRanges && find(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end); if (!range) { diff --git a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts index e982412ed7a49..57e7dbd97a76c 100644 --- a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts +++ b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts @@ -69,7 +69,7 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { } function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number): Info | undefined { - const node = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false); + const node = getTokenAtPosition(file, startPosition); const func = getContainingFunction(node); if (!func || !isArrowFunction(func) || (!rangeContainsRange(func, node) || rangeContainsRange(func.body, node))) return undefined; diff --git a/src/services/refactors/convertImport.ts b/src/services/refactors/convertImport.ts index bdd3e7f4a9684..6db6cd5cd94da 100644 --- a/src/services/refactors/convertImport.ts +++ b/src/services/refactors/convertImport.ts @@ -22,7 +22,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor { function getImportToConvert(context: RefactorContext): NamedImportBindings | undefined { const { file } = context; const span = getRefactorContextSpan(context); - const token = getTokenAtPosition(file, span.start, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(file, span.start); const importDecl = getParentNodeInSpan(token, file, span); if (!importDecl || !isImportDeclaration(importDecl)) return undefined; const { importClause } = importDecl; diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 3f2794e439daf..ade704e36404b 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -194,7 +194,7 @@ namespace ts.refactor.extractSymbol { // Walk up starting from the the start position until we find a non-SourceFile node that subsumes the selected span. // This may fail (e.g. you select two statements in the root of a source file) - const start = getParentNodeInSpan(getTokenAtPosition(sourceFile, span.start, /*includeJsDocComment*/ false), sourceFile, span); + const start = getParentNodeInSpan(getTokenAtPosition(sourceFile, span.start), sourceFile, span); // Do the same for the ending position const end = getParentNodeInSpan(findTokenOnLeftOfPosition(sourceFile, textSpanEnd(span)), sourceFile, span); diff --git a/src/services/refactors/generateGetAccessorAndSetAccessor.ts b/src/services/refactors/generateGetAccessorAndSetAccessor.ts index 2e4f11c4b279f..06019ec57d365 100644 --- a/src/services/refactors/generateGetAccessorAndSetAccessor.ts +++ b/src/services/refactors/generateGetAccessorAndSetAccessor.ts @@ -120,7 +120,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor { function getConvertibleFieldAtPosition(context: RefactorContext, file: SourceFile): Info | undefined { const { startPosition, endPosition } = context; - const node = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false); + const node = getTokenAtPosition(file, startPosition); const declaration = findAncestor(node.parent, isAcceptedDeclaration); // make sure declaration have AccessibilityModifier or Static Modifier or Readonly Modifier const meaning = ModifierFlags.AccessibilityModifier | ModifierFlags.Static | ModifierFlags.Readonly; diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index c37969f19c245..2421e44f49446 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -559,7 +559,7 @@ namespace ts.textChanges { if (index !== containingList.length - 1) { // any element except the last one // use next sibling as an anchor - const nextToken = getTokenAtPosition(sourceFile, after.end, /*includeJsDocComment*/ false); + const nextToken = getTokenAtPosition(sourceFile, after.end); if (nextToken && isSeparator(after, nextToken)) { // for list // a, b, c diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 9715d124d7eee..cea53a6db341e 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -661,8 +661,8 @@ namespace ts { } /** Returns a token if position is in [start-of-leading-trivia, end) */ - export function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includeEndPosition = false): Node { - return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, includeEndPosition, includeJsDocComment); + export function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment = true): Node { + return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, /*includeEndPosition*/ false, includeJsDocComment); } /** Get the token whose text contains the position */ From 35da4ae07c6708e22e40bc510ceecf41932df5a5 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 15 Jun 2018 17:54:56 -0700 Subject: [PATCH 2/5] Update API (#24966) --- tests/baselines/reference/api/tsserverlibrary.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index a9fe9a32556dc..40b1f27fe711b 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -10690,7 +10690,7 @@ declare namespace ts { */ function getTouchingToken(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includePrecedingTokenAtEndPosition?: (n: Node) => boolean): Node; /** Returns a token if position is in [start-of-leading-trivia, end) */ - function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includeEndPosition?: boolean): Node; + function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment?: boolean): Node; /** * The token on the left of the position is the token that strictly includes the position * or sits to the left of the cursor if it is on a boundary. For example From 595b2f424ed4f818e83742552d9edde8f4e06c30 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 22 Jun 2018 11:08:36 -0700 Subject: [PATCH 3/5] Flip meaning of parameter --- src/services/completions.ts | 2 +- src/services/formatting/formatting.ts | 2 +- src/services/utilities.ts | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/services/completions.ts b/src/services/completions.ts index e4a956ce16966..392003cffd673 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -797,7 +797,7 @@ namespace ts.Completions { const typeChecker = program.getTypeChecker(); let start = timestamp(); - let currentToken = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); // TODO: GH#15853 + let currentToken = getTokenAtPosition(sourceFile, position, /*ignoreJsDocComment*/ true); // TODO: GH#15853 // We will check for jsdoc comments with insideComment and getJsDocTagAtPosition. (TODO: that seems rather inefficient to check the same thing so many times.) log("getCompletionData: Get current token: " + (timestamp() - start)); diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index eeec4b15ea7a8..5241f60546905 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -1145,7 +1145,7 @@ namespace ts.formatting { position: number, onlyMultiLine: boolean, precedingToken?: Node | null, // tslint:disable-line:no-null-keyword - tokenAtPosition = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false), + tokenAtPosition = getTokenAtPosition(sourceFile, position, /*ignoreJsDocComment*/ true), predicate?: (c: CommentRange) => boolean): CommentRange | undefined { const tokenStart = tokenAtPosition.getStart(sourceFile); if (tokenStart <= position && position < tokenAtPosition.getEnd()) { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index cea53a6db341e..844dbe677b996 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -661,8 +661,8 @@ namespace ts { } /** Returns a token if position is in [start-of-leading-trivia, end) */ - export function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment = true): Node { - return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, /*includeEndPosition*/ false, includeJsDocComment); + export function getTokenAtPosition(sourceFile: SourceFile, position: number, ignoreJsDocComment?: boolean): Node { + return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, /*includeEndPosition*/ false, /*includeJsDocComment*/ !ignoreJsDocComment); } /** Get the token whose text contains the position */ @@ -714,7 +714,7 @@ namespace ts { export function findTokenOnLeftOfPosition(file: SourceFile, position: number): Node | undefined { // Ideally, getTokenAtPosition should return a token. However, it is currently // broken, so we do a check to make sure the result was indeed a token. - const tokenAtPosition = getTokenAtPosition(file, position, /*includeJsDocComment*/ false); + const tokenAtPosition = getTokenAtPosition(file, position, /*ignoreJsDocComment*/ true); if (isToken(tokenAtPosition) && position > tokenAtPosition.getStart(file) && position < tokenAtPosition.getEnd()) { return tokenAtPosition; } @@ -857,7 +857,7 @@ namespace ts { * returns true if the position is in between the open and close elements of an JSX expression. */ export function isInsideJsxElementOrAttribute(sourceFile: SourceFile, position: number) { - const token = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, position, /*ignoreJsDocComment*/ true); if (!token) { return false; @@ -897,7 +897,7 @@ namespace ts { } export function isInTemplateString(sourceFile: SourceFile, position: number) { - const token = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, position, /*ignoreJsDocComment*/ true); return isTemplateLiteralKind(token.kind) && position > token.getStart(sourceFile); } @@ -1034,7 +1034,7 @@ namespace ts { } export function hasDocComment(sourceFile: SourceFile, position: number) { - const token = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); + const token = getTokenAtPosition(sourceFile, position, /*ignoreJsDocComment*/ true); // First, we have to see if this position actually landed in a comment. const commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos); From 7a837f4c045996ee16888ebfa79f95393612fadc Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 22 Jun 2018 11:31:06 -0700 Subject: [PATCH 4/5] Update API (#24966) --- tests/baselines/reference/api/tsserverlibrary.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 14ef25997864f..619232b7fbea7 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -10707,7 +10707,7 @@ declare namespace ts { */ function getTouchingToken(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includePrecedingTokenAtEndPosition?: (n: Node) => boolean): Node; /** Returns a token if position is in [start-of-leading-trivia, end) */ - function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment?: boolean): Node; + function getTokenAtPosition(sourceFile: SourceFile, position: number, ignoreJsDocComment?: boolean): Node; /** * The token on the left of the position is the token that strictly includes the position * or sits to the left of the cursor if it is on a boundary. For example From 831b17f4f0d69206ed7be74fb26e3d631ae244a9 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 22 Jun 2018 16:39:08 -0700 Subject: [PATCH 5/5] Remove all `ignoreJsDocComment` uses (fixes #25162) --- src/compiler/binder.ts | 6 +++- src/harness/fourslash.ts | 2 +- src/services/completions.ts | 31 ++----------------- src/services/formatting/formatting.ts | 4 ++- src/services/services.ts | 2 +- src/services/utilities.ts | 30 +++++------------- src/testRunner/unittests/tsbuild.ts | 30 +++++++++--------- .../reference/api/tsserverlibrary.d.ts | 4 +-- tests/baselines/reference/callbackTag1.types | 2 +- tests/baselines/reference/callbackTag2.types | 2 +- .../fourslash/completionsTriggerCharacter.ts | 2 +- 11 files changed, 42 insertions(+), 73 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index e6970df6811fc..7d0ef9e6060f5 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -697,10 +697,11 @@ namespace ts { bindJSDocTypeAlias(node as JSDocTypedefTag | JSDocCallbackTag); break; // In source files and blocks, bind functions first to match hoisting that occurs at runtime - case SyntaxKind.SourceFile: + case SyntaxKind.SourceFile: { bindEachFunctionsFirst((node as SourceFile).statements); bind((node as SourceFile).endOfFileToken); break; + } case SyntaxKind.Block: case SyntaxKind.ModuleBlock: bindEachFunctionsFirst((node as Block).statements); @@ -1975,7 +1976,10 @@ namespace ts { } else if (!skipTransformFlagAggregation && (node.transformFlags & TransformFlags.HasComputedFlags) === 0) { subtreeTransformFlags |= computeTransformFlagsForNode(node, 0); + const saveParent = parent; + if (node.kind === SyntaxKind.EndOfFileToken) parent = node; bindJSDoc(node); + parent = saveParent; } inStrictMode = saveInStrictMode; } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 177d98c37ba41..d53ea23408f76 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -850,7 +850,7 @@ namespace FourSlash { private verifyCompletionsWorker(options: FourSlashInterface.VerifyCompletionsOptions): void { const actualCompletions = this.getCompletionListAtCaret({ ...options.preferences, triggerCharacter: options.triggerCharacter })!; if (!actualCompletions) { - if (options.exact === undefined) return; + if ("exact" in options && options.exact === undefined) return; this.raiseError(`No completions at position '${this.currentCaretPosition}'.`); } diff --git a/src/services/completions.ts b/src/services/completions.ts index 22dd3a5cfa87a..e52a34e2faa42 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -797,13 +797,12 @@ namespace ts.Completions { const typeChecker = program.getTypeChecker(); let start = timestamp(); - let currentToken = getTokenAtPosition(sourceFile, position, /*ignoreJsDocComment*/ true); // TODO: GH#15853 + let currentToken = getTokenAtPosition(sourceFile, position); // TODO: GH#15853 // We will check for jsdoc comments with insideComment and getJsDocTagAtPosition. (TODO: that seems rather inefficient to check the same thing so many times.) log("getCompletionData: Get current token: " + (timestamp() - start)); start = timestamp(); - // Completion not allowed inside comments, bail out if this is the case const insideComment = isInComment(sourceFile, position, currentToken); log("getCompletionData: Is inside comment: " + (timestamp() - start)); @@ -2157,32 +2156,8 @@ namespace ts.Completions { /** Get the corresponding JSDocTag node if the position is in a jsDoc comment */ function getJsDocTagAtPosition(node: Node, position: number): JSDocTag | undefined { - const { jsDoc } = getJsDocHavingNode(node) as JSDocContainer; - if (!jsDoc) return undefined; - - for (const { pos, end, tags } of jsDoc) { - if (!tags || position < pos || position > end) continue; - for (let i = tags.length - 1; i >= 0; i--) { - const tag = tags[i]; - if (position >= tag.pos) { - return tag; - } - } - } - } - - function getJsDocHavingNode(node: Node): Node { - if (!isToken(node)) return node; - - switch (node.kind) { - case SyntaxKind.VarKeyword: - case SyntaxKind.LetKeyword: - case SyntaxKind.ConstKeyword: - // if the current token is var, let or const, skip the VariableDeclarationList - return node.parent.parent; - default: - return node.parent; - } + const jsdoc = findAncestor(node, isJSDoc); + return jsdoc && jsdoc.tags && (rangeContainsPosition(jsdoc, position) ? findLast(jsdoc.tags, tag => tag.pos < position) : undefined); } /** diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index cefb1b710f998..0e37672f66da2 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -1148,8 +1148,10 @@ namespace ts.formatting { position: number, onlyMultiLine: boolean, precedingToken?: Node | null, // tslint:disable-line:no-null-keyword - tokenAtPosition = getTokenAtPosition(sourceFile, position, /*ignoreJsDocComment*/ true), + tokenAtPosition = getTokenAtPosition(sourceFile, position), predicate?: (c: CommentRange) => boolean): CommentRange | undefined { + const jsdoc = findAncestor(tokenAtPosition, isJSDoc); + if (jsdoc) tokenAtPosition = jsdoc.parent; const tokenStart = tokenAtPosition.getStart(sourceFile); if (tokenStart <= position && position < tokenAtPosition.getEnd()) { return undefined; diff --git a/src/services/services.ts b/src/services/services.ts index 2e275813585d6..c80cd14d51023 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -261,7 +261,7 @@ namespace ts { } public getChildren(): Node[] { - return emptyArray; + return this.kind === SyntaxKind.EndOfFileToken ? (this as EndOfFileToken).jsDoc || emptyArray : emptyArray; } public getFirstToken(): Node | undefined { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 7a0652591d55f..3af6183781cf6 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -665,19 +665,14 @@ namespace ts { } /** Returns a token if position is in [start-of-leading-trivia, end) */ - export function getTokenAtPosition(sourceFile: SourceFile, position: number, ignoreJsDocComment?: boolean): Node { - return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, /*includeEndPosition*/ false, /*includeJsDocComment*/ !ignoreJsDocComment); + export function getTokenAtPosition(sourceFile: SourceFile, position: number): Node { + return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, /*includeEndPosition*/ false, /*includeJsDocComment*/ true); } /** Get the token whose text contains the position */ function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includePrecedingTokenAtEndPosition: ((n: Node) => boolean) | undefined, includeEndPosition: boolean, includeJsDocComment: boolean): Node { let current: Node = sourceFile; outer: while (true) { - if (isToken(current)) { - // exit early - return current; - } - // find the child that contains 'position' for (const child of current.getChildren()) { if (!includeJsDocComment && isJSDocNode(child)) { @@ -718,7 +713,7 @@ namespace ts { export function findTokenOnLeftOfPosition(file: SourceFile, position: number): Node | undefined { // Ideally, getTokenAtPosition should return a token. However, it is currently // broken, so we do a check to make sure the result was indeed a token. - const tokenAtPosition = getTokenAtPosition(file, position, /*ignoreJsDocComment*/ true); + const tokenAtPosition = getTokenAtPosition(file, position); if (isToken(tokenAtPosition) && position > tokenAtPosition.getStart(file) && position < tokenAtPosition.getEnd()) { return tokenAtPosition; } @@ -861,7 +856,7 @@ namespace ts { * returns true if the position is in between the open and close elements of an JSX expression. */ export function isInsideJsxElementOrAttribute(sourceFile: SourceFile, position: number) { - const token = getTokenAtPosition(sourceFile, position, /*ignoreJsDocComment*/ true); + const token = getTokenAtPosition(sourceFile, position); if (!token) { return false; @@ -901,7 +896,7 @@ namespace ts { } export function isInTemplateString(sourceFile: SourceFile, position: number) { - const token = getTokenAtPosition(sourceFile, position, /*ignoreJsDocComment*/ true); + const token = getTokenAtPosition(sourceFile, position); return isTemplateLiteralKind(token.kind) && position > token.getStart(sourceFile); } @@ -1037,18 +1032,9 @@ namespace ts { return !!formatting.getRangeOfEnclosingComment(sourceFile, position, /*onlyMultiLine*/ false, /*precedingToken*/ undefined, tokenAtPosition, predicate); } - export function hasDocComment(sourceFile: SourceFile, position: number) { - const token = getTokenAtPosition(sourceFile, position, /*ignoreJsDocComment*/ true); - - // First, we have to see if this position actually landed in a comment. - const commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos); - - return forEach(commentRanges, jsDocPrefix); - - function jsDocPrefix(c: CommentRange): boolean { - const text = sourceFile.text; - return text.length >= c.pos + 3 && text[c.pos] === "/" && text[c.pos + 1] === "*" && text[c.pos + 2] === "*"; - } + export function hasDocComment(sourceFile: SourceFile, position: number): boolean { + const token = getTokenAtPosition(sourceFile, position); + return !!findAncestor(token, isJSDoc); } function nodeHasTokens(n: Node, sourceFile: SourceFileLike): boolean { diff --git a/src/testRunner/unittests/tsbuild.ts b/src/testRunner/unittests/tsbuild.ts index bd40c7297d9a3..f9e030ba3ad28 100644 --- a/src/testRunner/unittests/tsbuild.ts +++ b/src/testRunner/unittests/tsbuild.ts @@ -261,20 +261,22 @@ namespace ts { }); describe("tsbuild - downstream prepend projects always get rebuilt", () => { - const fs = outFileFs.shadow(); - const host = new fakes.CompilerHost(fs); - const builder = createSolutionBuilder(host, buildHost, ["/src/third"], { dry: false, force: false, verbose: false }); - clearDiagnostics(); - builder.buildAllProjects(); - assertDiagnosticMessages(/*none*/); - assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "First build timestamp is correct"); - tick(); - replaceText(fs, "src/first/first_PART1.ts", "Hello", "Hola"); - tick(); - builder.resetBuildContext(); - builder.buildAllProjects(); - assertDiagnosticMessages(/*none*/); - assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "Second build timestamp is correct"); + it("", () => { + const fs = outFileFs.shadow(); + const host = new fakes.CompilerHost(fs); + const builder = createSolutionBuilder(host, buildHost, ["/src/third"], { dry: false, force: false, verbose: false }); + clearDiagnostics(); + builder.buildAllProjects(); + assertDiagnosticMessages(/*none*/); + assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "First build timestamp is correct"); + tick(); + replaceText(fs, "src/first/first_PART1.ts", "Hello", "Hola"); + tick(); + builder.resetBuildContext(); + builder.buildAllProjects(); + assertDiagnosticMessages(/*none*/); + assert.equal(fs.statSync("src/third/thirdjs/output/third-output.js").mtimeMs, time(), "Second build timestamp is correct"); + }); }); } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 619232b7fbea7..fb0a81fb5a39a 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -10707,7 +10707,7 @@ declare namespace ts { */ function getTouchingToken(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includePrecedingTokenAtEndPosition?: (n: Node) => boolean): Node; /** Returns a token if position is in [start-of-leading-trivia, end) */ - function getTokenAtPosition(sourceFile: SourceFile, position: number, ignoreJsDocComment?: boolean): Node; + function getTokenAtPosition(sourceFile: SourceFile, position: number): Node; /** * The token on the left of the position is the token that strictly includes the position * or sits to the left of the cursor if it is on a boundary. For example @@ -10742,7 +10742,7 @@ declare namespace ts { * @param predicate Additional predicate to test on the comment range. */ function isInComment(sourceFile: SourceFile, position: number, tokenAtPosition?: Node, predicate?: (c: CommentRange) => boolean): boolean; - function hasDocComment(sourceFile: SourceFile, position: number): boolean | undefined; + function hasDocComment(sourceFile: SourceFile, position: number): boolean; function getNodeModifiers(node: Node): string; function getTypeArgumentOrTypeParameterList(node: Node): NodeArray | undefined; function isComment(kind: SyntaxKind): boolean; diff --git a/tests/baselines/reference/callbackTag1.types b/tests/baselines/reference/callbackTag1.types index 2f1e64c8edcb4..8438da1a6aded 100644 --- a/tests/baselines/reference/callbackTag1.types +++ b/tests/baselines/reference/callbackTag1.types @@ -19,7 +19,7 @@ var sid = s => s + "!"; /** @type {NoReturn} */ var noreturn = obj => void obj.title ->noreturn : (s: { e: number; m: number; title: string; }) => any +>noreturn : NoReturn >obj => void obj.title : (obj: { e: number; m: number; title: string; }) => any >obj : { e: number; m: number; title: string; } >void obj.title : undefined diff --git a/tests/baselines/reference/callbackTag2.types b/tests/baselines/reference/callbackTag2.types index 5a13438ebbe9a..953d7d335ad68 100644 --- a/tests/baselines/reference/callbackTag2.types +++ b/tests/baselines/reference/callbackTag2.types @@ -42,7 +42,7 @@ var outside = n => n + 1; /** @type {Final<{ fantasy }, { heroes }>} */ var noreturn = (barts, tidus, noctis) => "cecil" ->noreturn : (barts: { fantasy: any; }, tidus: { heroes: any; }, noctis: { heroes: any; } & { fantasy: any; }) => "cecil" | "zidane" +>noreturn : Final<{ fantasy: any; }, { heroes: any; }> >(barts, tidus, noctis) => "cecil" : (barts: { fantasy: any; }, tidus: { heroes: any; }, noctis: { heroes: any; } & { fantasy: any; }) => "cecil" >barts : { fantasy: any; } >tidus : { heroes: any; } diff --git a/tests/cases/fourslash/completionsTriggerCharacter.ts b/tests/cases/fourslash/completionsTriggerCharacter.ts index ea1abfdb3e48b..f15c99f1aac69 100644 --- a/tests/cases/fourslash/completionsTriggerCharacter.ts +++ b/tests/cases/fourslash/completionsTriggerCharacter.ts @@ -38,7 +38,7 @@ verify.completions( { marker: "quoteInComment", exact: undefined, triggerCharacter: '"' }, { marker: "lessInComment", exact: undefined, triggerCharacter: "<" }, - { marker: "openTag", includes: "div", triggerCharacter: "<" }, + { marker: "openTag", exact: undefined, triggerCharacter: "<" }, // TODO: `includes: "div"` { marker: "lessThan", exact: undefined, triggerCharacter: "<" }, { marker: "closeTag", exact: "div", triggerCharacter: "/" }, { marker: "path", exact: "importMe", triggerCharacter: "/", isNewIdentifierLocation: true },