Merge branch 'master' of https://github.com/microsoft/TypeScript into bug/38463

This commit is contained in:
Alexander T
2020-05-20 11:04:55 +03:00
275 changed files with 6207 additions and 1598 deletions
+3 -3
View File
@@ -392,7 +392,7 @@ namespace ts.BreakpointResolver {
// Breakpoint is possible in variableDeclaration only if there is initialization
// or its declaration from 'for of'
if (variableDeclaration.initializer ||
hasModifier(variableDeclaration, ModifierFlags.Export) ||
hasSyntacticModifier(variableDeclaration, ModifierFlags.Export) ||
parent.parent.kind === SyntaxKind.ForOfStatement) {
return textSpanFromVariableDeclaration(variableDeclaration);
}
@@ -410,7 +410,7 @@ namespace ts.BreakpointResolver {
function canHaveSpanInParameterDeclaration(parameter: ParameterDeclaration): boolean {
// Breakpoint is possible on parameter only if it has initializer, is a rest parameter, or has public or private modifier
return !!parameter.initializer || parameter.dotDotDotToken !== undefined ||
hasModifier(parameter, ModifierFlags.Public | ModifierFlags.Private);
hasSyntacticModifier(parameter, ModifierFlags.Public | ModifierFlags.Private);
}
function spanInParameterDeclaration(parameter: ParameterDeclaration): TextSpan | undefined {
@@ -437,7 +437,7 @@ namespace ts.BreakpointResolver {
}
function canFunctionHaveSpanInWholeDeclaration(functionDeclaration: FunctionLikeDeclaration) {
return hasModifier(functionDeclaration, ModifierFlags.Export) ||
return hasSyntacticModifier(functionDeclaration, ModifierFlags.Export) ||
(functionDeclaration.parent.kind === SyntaxKind.ClassDeclaration && functionDeclaration.kind !== SyntaxKind.Constructor);
}
+1 -1
View File
@@ -410,7 +410,7 @@ namespace ts.CallHierarchy {
}
function collectCallSitesOfModuleDeclaration(node: ModuleDeclaration, collect: (node: Node | undefined) => void) {
if (!hasModifier(node, ModifierFlags.Ambient) && node.body && isModuleBlock(node.body)) {
if (!hasSyntacticModifier(node, ModifierFlags.Ambient) && node.body && isModuleBlock(node.body)) {
forEach(node.body.statements, collect);
}
}
+1 -1
View File
@@ -53,7 +53,7 @@ namespace ts.codefix {
}
fixedDeclarations?.set(getNodeId(insertionSite).toString(), true);
const cloneWithModifier = getSynthesizedDeepClone(insertionSite, /*includeTrivia*/ true);
cloneWithModifier.modifiers = createNodeArray(createModifiersFromModifierFlags(getModifierFlags(insertionSite) | ModifierFlags.Async));
cloneWithModifier.modifiers = createNodeArray(createModifiersFromModifierFlags(getSyntacticModifierFlags(insertionSite) | ModifierFlags.Async));
cloneWithModifier.modifierFlagsCache = 0;
changeTracker.replaceNode(
sourceFile,
+1 -1
View File
@@ -148,7 +148,7 @@ namespace ts.codefix {
declaration.type ||
!declaration.initializer ||
variableStatement.getSourceFile() !== sourceFile ||
hasModifier(variableStatement, ModifierFlags.Export) ||
hasSyntacticModifier(variableStatement, ModifierFlags.Export) ||
!variableName ||
!isInsideAwaitableBody(declaration.initializer)) {
isCompleteFix = false;
@@ -42,7 +42,7 @@ namespace ts.codefix {
const parameter = first(indexSignature.parameters);
const mappedTypeParameter = createTypeParameterDeclaration(cast(parameter.name, isIdentifier), parameter.type);
const mappedIntersectionType = createMappedTypeNode(
hasReadonlyModifier(indexSignature) ? createModifier(SyntaxKind.ReadonlyKeyword) : undefined,
hasEffectiveReadonlyModifier(indexSignature) ? createModifier(SyntaxKind.ReadonlyKeyword) : undefined,
mappedTypeParameter,
indexSignature.questionToken,
indexSignature.type);
@@ -49,7 +49,7 @@ namespace ts.codefix {
function symbolPointsToNonPrivateAndAbstractMember(symbol: Symbol): boolean {
// See `codeFixClassExtendAbstractProtectedProperty.ts` in https://github.com/Microsoft/TypeScript/pull/11547/files
// (now named `codeFixClassExtendAbstractPrivateProperty.ts`)
const flags = getModifierFlags(first(symbol.getDeclarations()!));
const flags = getSyntacticModifierFlags(first(symbol.getDeclarations()!));
return !(flags & ModifierFlags.Private) && !!(flags & ModifierFlags.Abstract);
}
}
@@ -34,7 +34,7 @@ namespace ts.codefix {
}
function symbolPointsToNonPrivateMember(symbol: Symbol) {
return !symbol.valueDeclaration || !(getModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private);
return !symbol.valueDeclaration || !(getEffectiveModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private);
}
function addMissingDeclarations(
@@ -0,0 +1,52 @@
/* @internal */
namespace ts.codefix {
const fixId = "fixIncorrectNamedTupleSyntax";
const errorCodes = [
Diagnostics.A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type.code,
Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type.code
];
registerCodeFix({
errorCodes,
getCodeActions: context => {
const { sourceFile, span } = context;
const namedTupleMember = getNamedTupleMember(sourceFile, span.start);
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, namedTupleMember));
return [createCodeFixAction(fixId, changes, Diagnostics.Move_labeled_tuple_element_modifiers_to_labels, fixId, Diagnostics.Move_labeled_tuple_element_modifiers_to_labels)];
},
fixIds: [fixId]
});
function getNamedTupleMember(sourceFile: SourceFile, pos: number) {
const token = getTokenAtPosition(sourceFile, pos);
return findAncestor(token, t => t.kind === SyntaxKind.NamedTupleMember) as NamedTupleMember | undefined;
}
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, namedTupleMember?: NamedTupleMember) {
if (!namedTupleMember) {
return;
}
let unwrappedType = namedTupleMember.type;
let sawOptional = false;
let sawRest = false;
while (unwrappedType.kind === SyntaxKind.OptionalType || unwrappedType.kind === SyntaxKind.RestType || unwrappedType.kind === SyntaxKind.ParenthesizedType) {
if (unwrappedType.kind === SyntaxKind.OptionalType) {
sawOptional = true;
}
else if (unwrappedType.kind === SyntaxKind.RestType) {
sawRest = true;
}
unwrappedType = (unwrappedType as OptionalTypeNode | RestTypeNode | ParenthesizedTypeNode).type;
}
const updated = updateNamedTupleMember(
namedTupleMember,
namedTupleMember.dotDotDotToken || (sawRest ? createToken(SyntaxKind.DotDotDotToken) : undefined),
namedTupleMember.name,
namedTupleMember.questionToken || (sawOptional ? createToken(SyntaxKind.QuestionToken) : undefined),
unwrappedType
);
if (updated === namedTupleMember) {
return;
}
changes.replaceNode(sourceFile, namedTupleMember, updated);
}
}
@@ -120,7 +120,7 @@ namespace ts.codefix {
}
else if (type.isClass()) {
const classDeclaration = getClassLikeDeclarationOfSymbol(type.symbol);
if (!classDeclaration || hasModifier(classDeclaration, ModifierFlags.Abstract)) return undefined;
if (!classDeclaration || hasSyntacticModifier(classDeclaration, ModifierFlags.Abstract)) return undefined;
const constructorDeclaration = getFirstConstructorWithBody(classDeclaration);
if (constructorDeclaration && constructorDeclaration.parameters.length) return undefined;
+1 -1
View File
@@ -40,7 +40,7 @@ namespace ts.codefix {
const scriptTarget = getEmitScriptTarget(context.program.getCompilerOptions());
const declaration = declarations[0];
const name = getSynthesizedDeepClone(getNameOfDeclaration(declaration), /*includeTrivia*/ false) as PropertyName;
const visibilityModifier = createVisibilityModifier(getModifierFlags(declaration));
const visibilityModifier = createVisibilityModifier(getEffectiveModifierFlags(declaration));
const modifiers = visibilityModifier ? createNodeArray([visibilityModifier]) : undefined;
const type = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration));
const optional = !!(symbol.flags & SymbolFlags.Optional);
+6 -6
View File
@@ -2,7 +2,7 @@
namespace ts.codefix {
const fixId = "returnValueCorrect";
const fixIdAddReturnStatement = "fixAddReturnStatement";
const fixIdRemoveBlockBodyBrace = "fixRemoveBlockBodyBrace";
const fixRemoveBracesFromArrowFunctionBody = "fixRemoveBracesFromArrowFunctionBody";
const fixIdWrapTheBlockWithParen = "fixWrapTheBlockWithParen";
const errorCodes = [
Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value.code,
@@ -35,7 +35,7 @@ namespace ts.codefix {
registerCodeFix({
errorCodes,
fixIds: [fixIdAddReturnStatement, fixIdRemoveBlockBodyBrace, fixIdWrapTheBlockWithParen],
fixIds: [fixIdAddReturnStatement, fixRemoveBracesFromArrowFunctionBody, fixIdWrapTheBlockWithParen],
getCodeActions: context => {
const { program, sourceFile, span: { start }, errorCode } = context;
const info = getInfo(program.getTypeChecker(), sourceFile, start, errorCode);
@@ -44,7 +44,7 @@ namespace ts.codefix {
if (info.kind === ProblemKind.MissingReturnStatement) {
return append(
[getActionForfixAddReturnStatement(context, info.expression, info.statement)],
isArrowFunction(info.declaration) ? getActionForfixRemoveBlockBodyBrace(context, info.declaration, info.expression, info.commentSource): undefined);
isArrowFunction(info.declaration) ? getActionForFixRemoveBracesFromArrowFunctionBody(context, info.declaration, info.expression, info.commentSource): undefined);
}
else {
return [getActionForfixWrapTheBlockWithParen(context, info.declaration, info.expression)];
@@ -58,7 +58,7 @@ namespace ts.codefix {
case fixIdAddReturnStatement:
addReturnStatement(changes, diag.file, info.expression, info.statement);
break;
case fixIdRemoveBlockBodyBrace:
case fixRemoveBracesFromArrowFunctionBody:
if (!isArrowFunction(info.declaration)) return undefined;
removeBlockBodyBrace(changes, diag.file, info.declaration, info.expression, info.commentSource, /* withParen */ false);
break;
@@ -196,9 +196,9 @@ namespace ts.codefix {
return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Add_all_missing_return_statement);
}
function getActionForfixRemoveBlockBodyBrace(context: CodeFixContext, declaration: ArrowFunction, expression: Expression, commentSource: Node) {
function getActionForFixRemoveBracesFromArrowFunctionBody(context: CodeFixContext, declaration: ArrowFunction, expression: Expression, commentSource: Node) {
const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, commentSource, /* withParen */ false));
return createCodeFixAction(fixId, changes, Diagnostics.Remove_block_body_braces, fixIdRemoveBlockBodyBrace, Diagnostics.Remove_all_incorrect_body_block_braces);
return createCodeFixAction(fixId, changes, Diagnostics.Remove_braces_from_arrow_function_body, fixRemoveBracesFromArrowFunctionBody, Diagnostics.Remove_braces_from_all_arrow_function_bodies_with_relevant_issues);
}
function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) {
+4 -4
View File
@@ -875,7 +875,7 @@ namespace ts.Completions {
// * |c|
// */
const lineStart = getLineStartPositionForPosition(position, sourceFile);
if (!(sourceFile.text.substring(lineStart, position).match(/[^\*|\s|(/\*\*)]/))) {
if (!/[^\*|\s(/)]/.test(sourceFile.text.substring(lineStart, position))) {
return { kind: CompletionDataKind.JsDocTag };
}
}
@@ -1990,7 +1990,7 @@ namespace ts.Completions {
if (!isClassLike(decl)) return GlobalsSearch.Success;
const classElement = contextToken.kind === SyntaxKind.SemicolonToken ? contextToken.parent.parent : contextToken.parent;
let classElementModifierFlags = isClassElement(classElement) ? getModifierFlags(classElement) : ModifierFlags.None;
let classElementModifierFlags = isClassElement(classElement) ? getEffectiveModifierFlags(classElement) : ModifierFlags.None;
// If this is context token is not something we are editing now, consider if this would lead to be modifier
if (contextToken.kind === SyntaxKind.Identifier && !isCurrentlyEditingNode(contextToken)) {
switch (contextToken.getText()) {
@@ -2409,12 +2409,12 @@ namespace ts.Completions {
}
// Dont filter member even if the name matches if it is declared private in the list
if (hasModifier(m, ModifierFlags.Private)) {
if (hasEffectiveModifier(m, ModifierFlags.Private)) {
continue;
}
// do not filter it out if the static presence doesnt match
if (hasModifier(m, ModifierFlags.Static) !== !!(currentClassElementModifierFlags & ModifierFlags.Static)) {
if (hasEffectiveModifier(m, ModifierFlags.Static) !== !!(currentClassElementModifierFlags & ModifierFlags.Static)) {
continue;
}
+7 -7
View File
@@ -102,7 +102,7 @@ namespace ts.FindAllReferences {
((isImportOrExportSpecifier(node.parent) || isBindingElement(node.parent))
&& node.parent.propertyName === node) ||
// Is default export
(node.kind === SyntaxKind.DefaultKeyword && hasModifier(node.parent, ModifierFlags.ExportDefault))) {
(node.kind === SyntaxKind.DefaultKeyword && hasSyntacticModifier(node.parent, ModifierFlags.ExportDefault))) {
return getContextNode(node.parent);
}
@@ -1146,7 +1146,7 @@ namespace ts.FindAllReferences {
// If this is private property or method, the scope is the containing class
if (flags & (SymbolFlags.Property | SymbolFlags.Method)) {
const privateDeclaration = find(declarations, d => hasModifier(d, ModifierFlags.Private) || isPrivateIdentifierPropertyDeclaration(d));
const privateDeclaration = find(declarations, d => hasEffectiveModifier(d, ModifierFlags.Private) || isPrivateIdentifierPropertyDeclaration(d));
if (privateDeclaration) {
return getAncestor(privateDeclaration, SyntaxKind.ClassDeclaration);
}
@@ -1561,7 +1561,7 @@ namespace ts.FindAllReferences {
Debug.assert(classLike.name === referenceLocation);
const addRef = state.referenceAdder(search.symbol);
for (const member of classLike.members) {
if (!(isMethodOrAccessor(member) && hasModifier(member, ModifierFlags.Static))) {
if (!(isMethodOrAccessor(member) && hasSyntacticModifier(member, ModifierFlags.Static))) {
continue;
}
if (member.body) {
@@ -1776,7 +1776,7 @@ namespace ts.FindAllReferences {
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
staticFlag &= getModifierFlags(searchSpaceNode);
staticFlag &= getSyntacticModifierFlags(searchSpaceNode);
searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class
break;
default:
@@ -1794,7 +1794,7 @@ namespace ts.FindAllReferences {
// If we have a 'super' container, we must have an enclosing class.
// Now make sure the owning class is the same as the search-space
// and has the same static qualifier as the original 'super's owner.
return container && (ModifierFlags.Static & getModifierFlags(container)) === staticFlag && container.parent.symbol === searchSpaceNode.symbol ? nodeEntry(node) : undefined;
return container && (ModifierFlags.Static & getSyntacticModifierFlags(container)) === staticFlag && container.parent.symbol === searchSpaceNode.symbol ? nodeEntry(node) : undefined;
});
return [{ definition: { type: DefinitionKind.Symbol, symbol: searchSpaceNode.symbol }, references }];
@@ -1822,7 +1822,7 @@ namespace ts.FindAllReferences {
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
staticFlag &= getModifierFlags(searchSpaceNode);
staticFlag &= getSyntacticModifierFlags(searchSpaceNode);
searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class
break;
case SyntaxKind.SourceFile:
@@ -1857,7 +1857,7 @@ namespace ts.FindAllReferences {
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;
return container.parent && searchSpaceNode.symbol === container.parent.symbol && (getSyntacticModifierFlags(container) & ModifierFlags.Static) === staticFlag;
case SyntaxKind.SourceFile:
return container.kind === SyntaxKind.SourceFile && !isExternalModule(<SourceFile>container) && !isParameterName(node);
}
+4 -3
View File
@@ -3,6 +3,7 @@ namespace ts.formatting {
export interface FormatContext {
readonly options: FormatCodeSettings;
readonly getRules: RulesMap;
readonly host: FormattingHost;
}
export interface TextRangeWithKind<T extends SyntaxKind = SyntaxKind> extends TextRange {
@@ -394,7 +395,7 @@ namespace ts.formatting {
initialIndentation: number,
delta: number,
formattingScanner: FormattingScanner,
{ options, getRules }: FormatContext,
{ options, getRules, host }: FormatContext,
requestKind: FormattingRequestKind,
rangeContainsError: (r: TextRange) => boolean,
sourceFile: SourceFileLike): TextChange[] {
@@ -1193,7 +1194,7 @@ namespace ts.formatting {
previousRange: TextRangeWithKind,
previousStartLine: number,
currentRange: TextRangeWithKind,
currentStartLine: number,
currentStartLine: number
): LineAction {
const onLaterLine = currentStartLine !== previousStartLine;
switch (rule.action) {
@@ -1221,7 +1222,7 @@ namespace ts.formatting {
// edit should not be applied if we have one line feed between elements
const lineDelta = currentStartLine - previousStartLine;
if (lineDelta !== 1) {
recordReplace(previousRange.end, currentRange.pos - previousRange.end, options.newLineCharacter!);
recordReplace(previousRange.end, currentRange.pos - previousRange.end, getNewLineOrDefaultFromHost(host, options));
return onLaterLine ? LineAction.None : LineAction.LineAdded;
}
break;
+2 -2
View File
@@ -1,7 +1,7 @@
/* @internal */
namespace ts.formatting {
export function getFormatContext(options: FormatCodeSettings): FormatContext {
return { options, getRules: getRulesMap() };
export function getFormatContext(options: FormatCodeSettings, host: FormattingHost): FormatContext {
return { options, getRules: getRulesMap(), host };
}
let rulesMapCache: RulesMap | undefined;
+1 -1
View File
@@ -574,7 +574,7 @@ namespace ts.formatting {
return childKind !== SyntaxKind.JsxClosingFragment;
case SyntaxKind.IntersectionType:
case SyntaxKind.UnionType:
if (childKind === SyntaxKind.TypeLiteral) {
if (childKind === SyntaxKind.TypeLiteral || childKind === SyntaxKind.TupleType) {
return false;
}
// falls through
+10 -9
View File
@@ -100,10 +100,13 @@ namespace ts.GoToDefinition {
/**
* True if we should not add definitions for both the signature symbol and the definition symbol.
* True for `const |f = |() => 0`, false for `function |f() {} const |g = f;`.
* Also true for any assignment RHS.
*/
function symbolMatchesSignature(s: Symbol, calledDeclaration: SignatureDeclaration) {
return s === calledDeclaration.symbol || s === calledDeclaration.symbol.parent ||
!isCallLikeExpression(calledDeclaration.parent) && s === calledDeclaration.parent.symbol;
return s === calledDeclaration.symbol
|| s === calledDeclaration.symbol.parent
|| isAssignmentExpression(calledDeclaration.parent)
|| (!isCallLikeExpression(calledDeclaration.parent) && s === calledDeclaration.parent.symbol);
}
export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { fileName: string, file: SourceFile } | undefined {
@@ -246,7 +249,9 @@ namespace ts.GoToDefinition {
// There are cases when you extend a function by adding properties to it afterwards,
// we want to strip those extra properties.
// For deduping purposes, we also want to exclude any declarationNodes if provided.
const filteredDeclarations = filter(symbol.declarations, d => d !== declarationNode && (!isAssignmentDeclaration(d) || d === symbol.valueDeclaration)) || undefined;
const filteredDeclarations =
filter(symbol.declarations, d => d !== declarationNode && (!isAssignmentDeclaration(d) || d === symbol.valueDeclaration))
|| undefined;
return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(filteredDeclarations, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node));
function getConstructSignatureDefinition(): DefinitionInfo[] | undefined {
@@ -330,15 +335,11 @@ namespace ts.GoToDefinition {
/** Returns a CallLikeExpression where `node` is the target being invoked. */
function getAncestorCallLikeExpression(node: Node): CallLikeExpression | undefined {
const target = climbPastManyPropertyAccesses(node);
const callLike = target.parent;
const target = findAncestor(node, n => !isRightSideOfPropertyAccess(n));
const callLike = target?.parent;
return callLike && isCallLikeExpression(callLike) && getInvokedExpression(callLike) === target ? callLike : undefined;
}
function climbPastManyPropertyAccesses(node: Node): Node {
return isRightSideOfPropertyAccess(node) ? climbPastManyPropertyAccesses(node.parent) : node;
}
function tryGetSignatureDeclaration(typeChecker: TypeChecker, node: Node): SignatureDeclaration | undefined {
const callLike = getAncestorCallLikeExpression(node);
const signature = callLike && typeChecker.getResolvedSignature(callLike);
+3 -3
View File
@@ -103,7 +103,7 @@ namespace ts.FindAllReferences {
break; // TODO: GH#23879
case SyntaxKind.ImportEqualsDeclaration:
handleNamespaceImport(direct, direct.name, hasModifier(direct, ModifierFlags.Export), /*alreadyAddedDirect*/ false);
handleNamespaceImport(direct, direct.name, hasSyntacticModifier(direct, ModifierFlags.Export), /*alreadyAddedDirect*/ false);
break;
case SyntaxKind.ImportDeclaration:
@@ -463,7 +463,7 @@ namespace ts.FindAllReferences {
}
else {
const exportNode = getExportNode(parent, node);
if (exportNode && hasModifier(exportNode, ModifierFlags.Export)) {
if (exportNode && hasSyntacticModifier(exportNode, ModifierFlags.Export)) {
if (isImportEqualsDeclaration(exportNode) && exportNode.moduleReference === node) {
// We're at `Y` in `export import X = Y`. This is not the exported symbol, the left-hand-side is. So treat this as an import statement.
if (comingFromExport) {
@@ -553,7 +553,7 @@ namespace ts.FindAllReferences {
// Not meant for use with export specifiers or export assignment.
function getExportKindForDeclaration(node: Node): ExportKind {
return hasModifier(node, ModifierFlags.Default) ? ExportKind.Default : ExportKind.Named;
return hasSyntacticModifier(node, ModifierFlags.Default) ? ExportKind.Default : ExportKind.Named;
}
}
+3 -6
View File
@@ -89,17 +89,14 @@ namespace ts.JsDoc {
// Eg. const a: Array<string> | Array<number>; a.length
// The property length will have two declarations of property length coming
// from Array<T> - Array<string> and Array<number>
const documentationComment: SymbolDisplayPart[] = [];
const documentationComment: string[] = [];
forEachUnique(declarations, declaration => {
for (const { comment } of getCommentHavingNodes(declaration)) {
if (comment === undefined) continue;
if (documentationComment.length) {
documentationComment.push(lineBreakPart());
}
documentationComment.push(textPart(comment));
pushIfUnique(documentationComment, comment);
}
});
return documentationComment;
return intersperse(map(documentationComment, textPart), lineBreakPart());
}
function getCommentHavingNodes(declaration: Declaration): readonly (JSDoc | JSDocTag)[] {
+15 -4
View File
@@ -307,7 +307,18 @@ namespace ts.NavigationBar {
addNodeWithRecursiveChild(node, getInteriorModule(<ModuleDeclaration>node).body);
break;
case SyntaxKind.ExportAssignment:
case SyntaxKind.ExportAssignment: {
const expression = (<ExportAssignment>node).expression;
if (isObjectLiteralExpression(expression)) {
startNode(node);
addChildrenRecursively(expression);
endNode();
}
else {
addLeafNode(node);
}
break;
}
case SyntaxKind.ExportSpecifier:
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.IndexSignature:
@@ -590,7 +601,7 @@ namespace ts.NavigationBar {
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return hasModifier(a, ModifierFlags.Static) === hasModifier(b, ModifierFlags.Static);
return hasSyntacticModifier(a, ModifierFlags.Static) === hasSyntacticModifier(b, ModifierFlags.Static);
case SyntaxKind.ModuleDeclaration:
return areSameModule(<ModuleDeclaration>a, <ModuleDeclaration>b);
default:
@@ -690,7 +701,7 @@ namespace ts.NavigationBar {
case SyntaxKind.FunctionExpression:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
if (getModifierFlags(node) & ModifierFlags.Default) {
if (getSyntacticModifierFlags(node) & ModifierFlags.Default) {
return "default";
}
// We may get a string with newlines or other whitespace in the case of an object dereference
@@ -883,7 +894,7 @@ namespace ts.NavigationBar {
return nodeText(parent.name);
}
// Default exports are named "default"
else if (getModifierFlags(node) & ModifierFlags.Default) {
else if (getSyntacticModifierFlags(node) & ModifierFlags.Default) {
return "default";
}
else if (isClassLike(node)) {
+1 -1
View File
@@ -76,7 +76,7 @@ namespace ts.OrganizeImports {
// Delete any subsequent imports.
for (let i = 1; i < oldImportDecls.length; i++) {
changeTracker.delete(sourceFile, oldImportDecls[i]);
changeTracker.deleteNode(sourceFile, oldImportDecls[i]);
}
}
}
@@ -42,6 +42,10 @@ namespace ts.OutliningElementsCollector {
addOutliningForLeadingCommentsForNode(n.parent.parent.parent, sourceFile, cancellationToken, out);
}
if (isFunctionLike(n) && isBinaryExpression(n.parent) && isPropertyAccessExpression(n.parent.left)) {
addOutliningForLeadingCommentsForNode(n.parent.left, sourceFile, cancellationToken, out);
}
const span = getOutliningSpanForNode(n, sourceFile);
if (span) out.push(span);
@@ -200,6 +204,7 @@ namespace ts.OutliningElementsCollector {
case SyntaxKind.EnumDeclaration:
case SyntaxKind.CaseBlock:
case SyntaxKind.TypeLiteral:
case SyntaxKind.ObjectBindingPattern:
return spanForNode(n);
case SyntaxKind.TupleType:
return spanForNode(n, /*autoCollapse*/ false, /*useFullStart*/ !isTupleTypeNode(n.parent), SyntaxKind.OpenBracketToken);
+1 -1
View File
@@ -38,7 +38,7 @@ namespace ts.refactor {
const exportingModuleSymbol = isSourceFile(exportNode.parent) ? exportNode.parent.symbol : exportNode.parent.parent.symbol;
const flags = getModifierFlags(exportNode);
const flags = getSyntacticModifierFlags(exportNode);
const wasDefault = !!(flags & ModifierFlags.Default);
// If source file already has a default export, don't offer refactor.
if (!(flags & ModifierFlags.Export) || !wasDefault && exportingModuleSymbol.exports!.has(InternalSymbolName.Default)) {
@@ -0,0 +1,219 @@
/* @internal */
namespace ts.refactor.addOrRemoveBracesToArrowFunction {
const refactorName = "Convert overload list to single signature";
const refactorDescription = Diagnostics.Convert_overload_list_to_single_signature.message;
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] {
const { file, startPosition, program } = context;
const info = getConvertableOverloadListAtPosition(file, startPosition, program);
if (!info) return emptyArray;
return [{
name: refactorName,
description: refactorDescription,
actions: [{
name: refactorName,
description: refactorDescription
}]
}];
}
function getEditsForAction(context: RefactorContext): RefactorEditInfo | undefined {
const { file, startPosition, program } = context;
const signatureDecls = getConvertableOverloadListAtPosition(file, startPosition, program);
if (!signatureDecls) return undefined;
const checker = program.getTypeChecker();
const lastDeclaration = signatureDecls[signatureDecls.length - 1];
let updated = lastDeclaration;
switch (lastDeclaration.kind) {
case SyntaxKind.MethodSignature: {
updated = updateMethodSignature(
lastDeclaration,
lastDeclaration.typeParameters,
getNewParametersForCombinedSignature(signatureDecls),
lastDeclaration.type,
lastDeclaration.name,
lastDeclaration.questionToken
);
break;
}
case SyntaxKind.MethodDeclaration: {
updated = updateMethod(
lastDeclaration,
lastDeclaration.decorators,
lastDeclaration.modifiers,
lastDeclaration.asteriskToken,
lastDeclaration.name,
lastDeclaration.questionToken,
lastDeclaration.typeParameters,
getNewParametersForCombinedSignature(signatureDecls),
lastDeclaration.type,
lastDeclaration.body
);
break;
}
case SyntaxKind.CallSignature: {
updated = updateCallSignature(
lastDeclaration,
lastDeclaration.typeParameters,
getNewParametersForCombinedSignature(signatureDecls),
lastDeclaration.type,
);
break;
}
case SyntaxKind.Constructor: {
updated = updateConstructor(
lastDeclaration,
lastDeclaration.decorators,
lastDeclaration.modifiers,
getNewParametersForCombinedSignature(signatureDecls),
lastDeclaration.body
);
break;
}
case SyntaxKind.ConstructSignature: {
updated = updateConstructSignature(
lastDeclaration,
lastDeclaration.typeParameters,
getNewParametersForCombinedSignature(signatureDecls),
lastDeclaration.type,
);
break;
}
case SyntaxKind.FunctionDeclaration: {
updated = updateFunctionDeclaration(
lastDeclaration,
lastDeclaration.decorators,
lastDeclaration.modifiers,
lastDeclaration.asteriskToken,
lastDeclaration.name,
lastDeclaration.typeParameters,
getNewParametersForCombinedSignature(signatureDecls),
lastDeclaration.type,
lastDeclaration.body
);
break;
}
default: return Debug.failBadSyntaxKind(lastDeclaration, "Unhandled signature kind in overload list conversion refactoring");
}
if (updated === lastDeclaration) {
return; // No edits to apply, do nothing
}
const edits = textChanges.ChangeTracker.with(context, t => {
t.replaceNodeRange(file, signatureDecls[0], signatureDecls[signatureDecls.length - 1], updated);
});
return { renameFilename: undefined, renameLocation: undefined, edits };
function getNewParametersForCombinedSignature(signatureDeclarations: (MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[]): NodeArray<ParameterDeclaration> {
const lastSig = signatureDeclarations[signatureDeclarations.length - 1];
if (isFunctionLikeDeclaration(lastSig) && lastSig.body) {
// Trim away implementation signature arguments (they should already be compatible with overloads, but are likely less precise to guarantee compatability with the overloads)
signatureDeclarations = signatureDeclarations.slice(0, signatureDeclarations.length - 1);
}
return createNodeArray([
createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createToken(SyntaxKind.DotDotDotToken),
"args",
/*questionToken*/ undefined,
createUnionTypeNode(map(signatureDeclarations, convertSignatureParametersToTuple))
)
]);
}
function convertSignatureParametersToTuple(decl: MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration): TupleTypeNode {
const members = map(decl.parameters, convertParameterToNamedTupleMember);
return setEmitFlags(createTupleTypeNode(members), some(members, m => !!length(getSyntheticLeadingComments(m))) ? EmitFlags.None : EmitFlags.SingleLine);
}
function convertParameterToNamedTupleMember(p: ParameterDeclaration): NamedTupleMember {
Debug.assert(isIdentifier(p.name)); // This is checked during refactoring applicability checking
const result = setTextRange(createNamedTupleMember(
p.dotDotDotToken,
p.name,
p.questionToken,
p.type || createKeywordTypeNode(SyntaxKind.AnyKeyword)
), p);
const parameterDocComment = p.symbol && p.symbol.getDocumentationComment(checker);
if (parameterDocComment) {
const newComment = displayPartsToString(parameterDocComment);
if (newComment.length) {
setSyntheticLeadingComments(result, [{
text: `*
${newComment.split("\n").map(c => ` * ${c}`).join("\n")}
`,
kind: SyntaxKind.MultiLineCommentTrivia,
pos: -1,
end: -1,
hasTrailingNewLine: true,
hasLeadingNewline: true,
}]);
}
}
return result;
}
}
function isConvertableSignatureDeclaration(d: Node): d is MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration {
switch (d.kind) {
case SyntaxKind.MethodSignature:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.CallSignature:
case SyntaxKind.Constructor:
case SyntaxKind.ConstructSignature:
case SyntaxKind.FunctionDeclaration:
return true;
}
return false;
}
function getConvertableOverloadListAtPosition(file: SourceFile, startPosition: number, program: Program) {
const node = getTokenAtPosition(file, startPosition);
const containingDecl = findAncestor(node, isConvertableSignatureDeclaration);
if (!containingDecl) {
return;
}
const checker = program.getTypeChecker();
const signatureSymbol = containingDecl.symbol;
if (!signatureSymbol) {
return;
}
const decls = signatureSymbol.declarations;
if (length(decls) <= 1) {
return;
}
if (!every(decls, d => getSourceFileOfNode(d) === file)) {
return;
}
if (!isConvertableSignatureDeclaration(decls[0])) {
return;
}
const kindOne = decls[0].kind;
if (!every(decls, d => d.kind === kindOne)) {
return;
}
const signatureDecls = decls as (MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[];
if (some(signatureDecls, d => !!d.typeParameters || some(d.parameters, p => !!p.decorators || !!p.modifiers || !isIdentifier(p.name)))) {
return;
}
const signatures = mapDefined(signatureDecls, d => checker.getSignatureFromDeclaration(d));
if (length(signatures) !== length(decls)) {
return;
}
const returnOne = checker.getReturnTypeOfSignature(signatures[0]);
if (!every(signatures, s => checker.getReturnTypeOfSignature(s) === returnOne)) {
return;
}
return signatureDecls;
}
}
+35 -24
View File
@@ -28,7 +28,7 @@ namespace ts.refactor.extractSymbol {
const usedConstantNames: Map<boolean> = createMap();
let i = 0;
for (const {functionExtraction, constantExtraction} of extractions) {
for (const { functionExtraction, constantExtraction } of extractions) {
// Skip these since we don't have a way to report errors yet
if (functionExtraction.errors.length === 0) {
// Don't issue refactorings with duplicated names.
@@ -309,7 +309,7 @@ namespace ts.refactor.extractSymbol {
let current: Node = nodeToCheck;
while (current !== containingClass) {
if (current.kind === SyntaxKind.PropertyDeclaration) {
if (hasModifier(current, ModifierFlags.Static)) {
if (hasSyntacticModifier(current, ModifierFlags.Static)) {
rangeFacts |= RangeFacts.InStaticRegion;
}
break;
@@ -322,7 +322,7 @@ namespace ts.refactor.extractSymbol {
break;
}
else if (current.kind === SyntaxKind.MethodDeclaration) {
if (hasModifier(current, ModifierFlags.Static)) {
if (hasSyntacticModifier(current, ModifierFlags.Static)) {
rangeFacts |= RangeFacts.InStaticRegion;
}
}
@@ -375,7 +375,7 @@ namespace ts.refactor.extractSymbol {
if (isDeclaration(node)) {
const declaringNode = (node.kind === SyntaxKind.VariableDeclaration) ? node.parent.parent : node;
if (hasModifier(declaringNode, ModifierFlags.Export)) {
if (hasSyntacticModifier(declaringNode, ModifierFlags.Export)) {
// TODO: GH#18217 Silly to use `errors ||` since it's definitely not defined (see top of `visit`)
// Also, if we're only pushing one error, just use `let error: Diagnostic | undefined`!
// Also TODO: GH#19956
@@ -405,24 +405,24 @@ namespace ts.refactor.extractSymbol {
rangeFacts |= RangeFacts.UsesThis;
}
break;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.FunctionDeclaration:
if (isSourceFile(node.parent) && node.parent.externalModuleIndicator === undefined) {
// You cannot extract global declarations
(errors || (errors = [] as Diagnostic[])).push(createDiagnosticForNode(node, Messages.functionWillNotBeVisibleInTheNewScope));
}
// falls through
case SyntaxKind.ClassExpression:
case SyntaxKind.FunctionExpression:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
// do not dive into functions (except arrow functions) or classes
return false;
}
if (isFunctionLikeDeclaration(node) || isClassLike(node)) {
switch (node.kind) {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ClassDeclaration:
if (isSourceFile(node.parent) && node.parent.externalModuleIndicator === undefined) {
// You cannot extract global declarations
(errors || (errors = [] as Diagnostic[])).push(createDiagnosticForNode(node, Messages.functionWillNotBeVisibleInTheNewScope));
}
break;
}
// do not dive into functions or classes
return false;
}
const savedPermittedJumps = permittedJumps;
switch (node.kind) {
case SyntaxKind.IfStatement:
permittedJumps = PermittedJumps.None;
@@ -1103,7 +1103,12 @@ namespace ts.refactor.extractSymbol {
changeTracker.delete(context.file, node.parent);
}
else {
const localReference = createIdentifier(localNameText);
let localReference: Expression = createIdentifier(localNameText);
// When extract to a new variable in JSX content, need to wrap a {} out of the new variable
// or it will become a plain text
if (isInJSXContent(node)) {
localReference = createJsxExpression(/*dotDotDotToken*/ undefined, localReference);
}
changeTracker.replaceNode(context.file, node, localReference);
}
}
@@ -1115,6 +1120,12 @@ namespace ts.refactor.extractSymbol {
const renameLocation = getRenameLocation(edits, renameFilename, localNameText, /*isDeclaredBeforeUse*/ true);
return { renameFilename, renameLocation, edits };
function isInJSXContent(node: Node) {
if (!isJsxElement(node)) return false;
if (isJsxElement(node.parent)) return true;
return false;
}
function transformFunctionInitializerAndType(variableType: TypeNode | undefined, initializer: Expression): { variableType: TypeNode | undefined, initializer: Expression } {
// If no contextual type exists there is nothing to transfer to the function signature
if (variableType === undefined) return { variableType, initializer };
@@ -1215,8 +1226,8 @@ namespace ts.refactor.extractSymbol {
}
function compareTypesByDeclarationOrder(
{type: type1, declaration: declaration1}: {type: Type, declaration?: Declaration},
{type: type2, declaration: declaration2}: {type: Type, declaration?: Declaration}) {
{ type: type1, declaration: declaration1 }: { type: Type, declaration?: Declaration },
{ type: type2, declaration: declaration2 }: { type: Type, declaration?: Declaration }) {
return compareProperties(declaration1, declaration2, "pos", compareValues)
|| compareStringsCaseSensitive(
@@ -1584,7 +1595,7 @@ namespace ts.refactor.extractSymbol {
hasWrite = true;
if (value.symbol.flags & SymbolFlags.ClassMember &&
value.symbol.valueDeclaration &&
hasModifier(value.symbol.valueDeclaration, ModifierFlags.Readonly)) {
hasEffectiveModifier(value.symbol.valueDeclaration, ModifierFlags.Readonly)) {
readonlyClassPropertyWrite = value.symbol.valueDeclaration;
}
}
@@ -1621,7 +1632,7 @@ namespace ts.refactor.extractSymbol {
// a lot of properties, each of which the walker will visit. Unfortunately, the
// solution isn't as trivial as filtering to user types because of (e.g.) Array.
const symbolWalker = checker.getSymbolWalker(() => (cancellationToken.throwIfCancellationRequested(), true));
const {visitedTypes} = symbolWalker.walkType(type);
const { visitedTypes } = symbolWalker.walkType(type);
for (const visitedType of visitedTypes) {
if (visitedType.isTypeParameter()) {
+5
View File
@@ -145,6 +145,11 @@ namespace ts.refactor {
}
}
}
if (file && isTupleTypeNode(node) && (getLineAndCharacterOfPosition(file, node.pos).line === getLineAndCharacterOfPosition(file, node.end).line)) {
setEmitFlags(node, EmitFlags.SingleLine);
}
return forEachChild(node, visitor);
}
}
@@ -41,7 +41,6 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
const fieldInfo = getConvertibleFieldAtPosition(context);
if (!fieldInfo) return undefined;
const isJS = isSourceFileJS(file);
const changeTracker = textChanges.ChangeTracker.fromContext(context);
const { isStatic, isReadonly, fieldName, accessorName, originalName, type, container, declaration, renameAccessor } = fieldInfo;
@@ -50,15 +49,20 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
suppressLeadingAndTrailingTrivia(declaration);
suppressLeadingAndTrailingTrivia(container);
const isInClassLike = isClassLike(container);
// avoid Readonly modifier because it will convert to get accessor
const modifierFlags = getModifierFlags(declaration) & ~ModifierFlags.Readonly;
const accessorModifiers = isInClassLike
? !modifierFlags || modifierFlags & ModifierFlags.Private
? getModifiers(isJS, isStatic, SyntaxKind.PublicKeyword)
: createNodeArray(createModifiersFromModifierFlags(modifierFlags))
: undefined;
const fieldModifiers = isInClassLike ? getModifiers(isJS, isStatic, SyntaxKind.PrivateKeyword) : undefined;
let accessorModifiers: ModifiersArray | undefined;
let fieldModifiers: ModifiersArray | undefined;
if (isClassLike(container)) {
const modifierFlags = getEffectiveModifierFlags(declaration);
if (isSourceFileJS(file)) {
const modifiers = createModifiers(modifierFlags);
accessorModifiers = modifiers;
fieldModifiers = modifiers;
}
else {
accessorModifiers = createModifiers(prepareModifierFlagsForAccessor(modifierFlags));
fieldModifiers = createModifiers(prepareModifierFlagsForField(modifierFlags));
}
}
updateFieldDeclaration(changeTracker, file, declaration, fieldName, fieldModifiers);
@@ -105,12 +109,26 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
return isIdentifier(fieldName) ? createPropertyAccess(leftHead, fieldName) : createElementAccess(leftHead, createLiteral(fieldName));
}
function getModifiers(isJS: boolean, isStatic: boolean, accessModifier: SyntaxKind.PublicKeyword | SyntaxKind.PrivateKeyword): NodeArray<Modifier> | undefined {
const modifiers = append<Modifier>(
!isJS ? [createToken(accessModifier) as Token<SyntaxKind.PublicKeyword> | Token<SyntaxKind.PrivateKeyword>] : undefined,
isStatic ? createToken(SyntaxKind.StaticKeyword) : undefined
);
return modifiers && createNodeArray(modifiers);
function createModifiers(modifierFlags: ModifierFlags): ModifiersArray | undefined {
return modifierFlags ? createNodeArray(createModifiersFromModifierFlags(modifierFlags)) : undefined;
}
function prepareModifierFlagsForAccessor(modifierFlags: ModifierFlags): ModifierFlags {
modifierFlags &= ~ModifierFlags.Readonly; // avoid Readonly modifier because it will convert to get accessor
modifierFlags &= ~ModifierFlags.Private;
if (!(modifierFlags & ModifierFlags.Protected)) {
modifierFlags |= ModifierFlags.Public;
}
return modifierFlags;
}
function prepareModifierFlagsForField(modifierFlags: ModifierFlags): ModifierFlags {
modifierFlags &= ~ModifierFlags.Public;
modifierFlags &= ~ModifierFlags.Protected;
modifierFlags |= ModifierFlags.Private;
return modifierFlags;
}
function getConvertibleFieldAtPosition(context: RefactorContext): Info | undefined {
@@ -121,7 +139,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
// make sure declaration have AccessibilityModifier or Static Modifier or Readonly Modifier
const meaning = ModifierFlags.AccessibilityModifier | ModifierFlags.Static | ModifierFlags.Readonly;
if (!declaration || !nodeOverlapsWithStartEnd(declaration.name, file, startPosition, endPosition!) // TODO: GH#18217
|| !isConvertibleName(declaration.name) || (getModifierFlags(declaration) | meaning) !== meaning) return undefined;
|| !isConvertibleName(declaration.name) || (getEffectiveModifierFlags(declaration) | meaning) !== meaning) return undefined;
const name = declaration.name.text;
const startWithUnderscore = startsWithUnderscore(name);
@@ -129,7 +147,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
const accessorName = createPropertyName(startWithUnderscore ? getUniqueName(name.substring(1), file) : name, declaration.name);
return {
isStatic: hasStaticModifier(declaration),
isReadonly: hasReadonlyModifier(declaration),
isReadonly: hasEffectiveReadonlyModifier(declaration),
type: getTypeAnnotationNode(declaration),
container: declaration.kind === SyntaxKind.Parameter ? declaration.parent.parent : declaration.parent,
originalName: (<AcceptedNameType>declaration.name).text,
+3 -3
View File
@@ -84,7 +84,7 @@ namespace ts.refactor {
case SyntaxKind.ImportDeclaration:
return true;
case SyntaxKind.ImportEqualsDeclaration:
return !hasModifier(node, ModifierFlags.Export);
return !hasSyntacticModifier(node, ModifierFlags.Export);
case SyntaxKind.VariableStatement:
return (node as VariableStatement).declarationList.declarations.every(d => !!d.initializer && isRequireCall(d.initializer, /*checkArgumentIsStringLiteralLike*/ true));
default:
@@ -420,7 +420,7 @@ namespace ts.refactor {
if (markSeenTop(top)) {
addExportToChanges(oldFile, top, changes, useEs6ModuleSyntax);
}
if (hasModifier(decl, ModifierFlags.Default)) {
if (hasSyntacticModifier(decl, ModifierFlags.Default)) {
oldFileDefault = name;
}
else {
@@ -737,7 +737,7 @@ namespace ts.refactor {
function isExported(sourceFile: SourceFile, decl: TopLevelDeclarationStatement, useEs6Exports: boolean): boolean {
if (useEs6Exports) {
return !isExpressionStatement(decl) && hasModifier(decl, ModifierFlags.Export);
return !isExpressionStatement(decl) && hasSyntacticModifier(decl, ModifierFlags.Export);
}
else {
return getNamesToExportInCommonJS(decl).some(name => sourceFile.symbol.exports!.has(escapeLeadingUnderscores(name)));
+18 -11
View File
@@ -328,7 +328,14 @@ namespace ts {
getDocumentationComment(checker: TypeChecker | undefined): SymbolDisplayPart[] {
if (!this.documentationComment) {
this.documentationComment = emptyArray; // Set temporarily to avoid an infinite loop finding inherited docs
this.documentationComment = getDocumentationComment(this.declarations, checker);
if (!this.declarations && (this as Symbol as TransientSymbol).target && ((this as Symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration) {
const labelDecl = ((this as Symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration!;
this.documentationComment = getDocumentationComment([labelDecl], checker);
}
else {
this.documentationComment = getDocumentationComment(this.declarations, checker);
}
}
return this.documentationComment;
}
@@ -763,7 +770,7 @@ namespace ts {
case SyntaxKind.Parameter:
// Only consider parameter properties
if (!hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
if (!hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier)) {
break;
}
// falls through
@@ -1502,7 +1509,7 @@ namespace ts {
position,
{ name, source },
host,
(formattingOptions && formatting.getFormatContext(formattingOptions))!, // TODO: GH#18217
(formattingOptions && formatting.getFormatContext(formattingOptions, host))!, // TODO: GH#18217
preferences,
cancellationToken,
);
@@ -1840,16 +1847,16 @@ namespace ts {
function getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions | FormatCodeSettings): TextChange[] {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
return formatting.formatSelection(start, end, sourceFile, formatting.getFormatContext(toEditorSettings(options)));
return formatting.formatSelection(start, end, sourceFile, formatting.getFormatContext(toEditorSettings(options), host));
}
function getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] {
return formatting.formatDocument(syntaxTreeCache.getCurrentSourceFile(fileName), formatting.getFormatContext(toEditorSettings(options)));
return formatting.formatDocument(syntaxTreeCache.getCurrentSourceFile(fileName), formatting.getFormatContext(toEditorSettings(options), host));
}
function getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
const formatContext = formatting.getFormatContext(toEditorSettings(options));
const formatContext = formatting.getFormatContext(toEditorSettings(options), host);
if (!isInComment(sourceFile, position)) {
switch (key) {
@@ -1871,7 +1878,7 @@ namespace ts {
synchronizeHostData();
const sourceFile = getValidSourceFile(fileName);
const span = createTextSpanFromBounds(start, end);
const formatContext = formatting.getFormatContext(formatOptions);
const formatContext = formatting.getFormatContext(formatOptions, host);
return flatMap(deduplicate<number>(errorCodes, equateValues, compareValues), errorCode => {
cancellationToken.throwIfCancellationRequested();
@@ -1883,7 +1890,7 @@ namespace ts {
synchronizeHostData();
Debug.assert(scope.type === "file");
const sourceFile = getValidSourceFile(scope.fileName);
const formatContext = formatting.getFormatContext(formatOptions);
const formatContext = formatting.getFormatContext(formatOptions, host);
return codefix.getAllFixes({ fixId, sourceFile, program, host, cancellationToken, formatContext, preferences });
}
@@ -1892,13 +1899,13 @@ namespace ts {
synchronizeHostData();
Debug.assert(scope.type === "file");
const sourceFile = getValidSourceFile(scope.fileName);
const formatContext = formatting.getFormatContext(formatOptions);
const formatContext = formatting.getFormatContext(formatOptions, host);
return OrganizeImports.organizeImports(sourceFile, formatContext, host, program, preferences);
}
function getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): readonly FileTextChanges[] {
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions), preferences, sourceMapper);
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions, host), preferences, sourceMapper);
}
function applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
@@ -2141,7 +2148,7 @@ namespace ts {
endPosition,
program: getProgram()!,
host,
formatContext: formatting.getFormatContext(formatOptions!), // TODO: GH#18217
formatContext: formatting.getFormatContext(formatOptions!, host), // TODO: GH#18217
cancellationToken,
preferences,
};
+52 -19
View File
@@ -500,16 +500,37 @@ namespace ts.SignatureHelp {
const enclosingDeclaration = getEnclosingDeclarationFromInvocation(invocation);
const callTargetSymbol = invocation.kind === InvocationKind.Contextual ? invocation.symbol : typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation));
const callTargetDisplayParts = callTargetSymbol ? symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined) : emptyArray;
const items = candidates.map(candidateSignature => getSignatureHelpItem(candidateSignature, callTargetDisplayParts, isTypeParameterList, typeChecker, enclosingDeclaration, sourceFile));
const items = map(candidates, candidateSignature => getSignatureHelpItem(candidateSignature, callTargetDisplayParts, isTypeParameterList, typeChecker, enclosingDeclaration, sourceFile));
if (argumentIndex !== 0) {
Debug.assertLessThan(argumentIndex, argumentCount);
}
const selectedItemIndex = candidates.indexOf(resolvedSignature);
let selectedItemIndex = 0;
let itemsSeen = 0;
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (candidates[i] === resolvedSignature) {
selectedItemIndex = itemsSeen;
if (item.length > 1) {
// check to see if any items in the list better match than the first one, as the checker isn't filtering the nested lists
// (those come from tuple parameter expansion)
let count = 0;
for (const i of item) {
if (i.isVariadic || i.parameters.length >= argumentCount) {
selectedItemIndex = itemsSeen + count;
break;
}
count++;
}
}
}
itemsSeen += item.length;
}
Debug.assert(selectedItemIndex !== -1); // If candidates is non-empty it should always include bestSignature. We check for an empty candidates before calling this function.
return { items, applicableSpan, selectedItemIndex, argumentIndex, argumentCount };
return { items: flatMapToMutable(items, identity), applicableSpan, selectedItemIndex, argumentIndex, argumentCount };
}
function createTypeHelpItems(
@@ -538,13 +559,15 @@ namespace ts.SignatureHelp {
const separatorDisplayParts: SymbolDisplayPart[] = [punctuationPart(SyntaxKind.CommaToken), spacePart()];
function getSignatureHelpItem(candidateSignature: Signature, callTargetDisplayParts: readonly SymbolDisplayPart[], isTypeParameterList: boolean, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem {
const { isVariadic, parameters, prefix, suffix } = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)(candidateSignature, checker, enclosingDeclaration, sourceFile);
const prefixDisplayParts = [...callTargetDisplayParts, ...prefix];
const suffixDisplayParts = [...suffix, ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker)];
const documentation = candidateSignature.getDocumentationComment(checker);
const tags = candidateSignature.getJsDocTags();
return { isVariadic, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters, documentation, tags };
function getSignatureHelpItem(candidateSignature: Signature, callTargetDisplayParts: readonly SymbolDisplayPart[], isTypeParameterList: boolean, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem[] {
const infos = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)(candidateSignature, checker, enclosingDeclaration, sourceFile);
return map(infos, ({ isVariadic, parameters, prefix, suffix }) => {
const prefixDisplayParts = [...callTargetDisplayParts, ...prefix];
const suffixDisplayParts = [...suffix, ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker)];
const documentation = candidateSignature.getDocumentationComment(checker);
const tags = candidateSignature.getJsDocTags();
return { isVariadic, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters, documentation, tags };
});
}
function returnTypeToDisplayParts(candidateSignature: Signature, enclosingDeclaration: Node, checker: TypeChecker): readonly SymbolDisplayPart[] {
@@ -563,19 +586,22 @@ namespace ts.SignatureHelp {
interface SignatureHelpItemInfo { readonly isVariadic: boolean; readonly parameters: SignatureHelpParameter[]; readonly prefix: readonly SymbolDisplayPart[]; readonly suffix: readonly SymbolDisplayPart[]; }
function itemInfoForTypeParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo {
function itemInfoForTypeParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] {
const typeParameters = (candidateSignature.target || candidateSignature).typeParameters;
const printer = createPrinter({ removeComments: true });
const parameters = (typeParameters || emptyArray).map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer));
const parameterParts = mapToDisplayParts(writer => {
const thisParameter = candidateSignature.thisParameter ? [checker.symbolToParameterDeclaration(candidateSignature.thisParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!] : [];
const params = createNodeArray([...thisParameter, ...checker.getExpandedParameters(candidateSignature).map(param => checker.symbolToParameterDeclaration(param, enclosingDeclaration, signatureHelpNodeBuilderFlags)!)]);
printer.writeList(ListFormat.CallExpressionArguments, params, sourceFile, writer);
const thisParameter = candidateSignature.thisParameter ? [checker.symbolToParameterDeclaration(candidateSignature.thisParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!] : [];
return checker.getExpandedParameters(candidateSignature).map(paramList => {
const params = createNodeArray([...thisParameter, ...map(paramList, param => checker.symbolToParameterDeclaration(param, enclosingDeclaration, signatureHelpNodeBuilderFlags)!)]);
const parameterParts = mapToDisplayParts(writer => {
printer.writeList(ListFormat.CallExpressionArguments, params, sourceFile, writer);
});
return { isVariadic: false, parameters, prefix: [punctuationPart(SyntaxKind.LessThanToken)], suffix: [punctuationPart(SyntaxKind.GreaterThanToken), ...parameterParts] };
});
return { isVariadic: false, parameters, prefix: [punctuationPart(SyntaxKind.LessThanToken)], suffix: [punctuationPart(SyntaxKind.GreaterThanToken), ...parameterParts] };
}
function itemInfoForParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo {
function itemInfoForParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] {
const isVariadic = checker.hasEffectiveRestParameter(candidateSignature);
const printer = createPrinter({ removeComments: true });
const typeParameterParts = mapToDisplayParts(writer => {
@@ -584,8 +610,15 @@ namespace ts.SignatureHelp {
printer.writeList(ListFormat.TypeParameters, args, sourceFile, writer);
}
});
const parameters = checker.getExpandedParameters(candidateSignature).map(p => createSignatureHelpParameterForParameter(p, checker, enclosingDeclaration, sourceFile, printer));
return { isVariadic, parameters, prefix: [...typeParameterParts, punctuationPart(SyntaxKind.OpenParenToken)], suffix: [punctuationPart(SyntaxKind.CloseParenToken)] };
const lists = checker.getExpandedParameters(candidateSignature);
return lists.map(parameterList => {
return {
isVariadic: isVariadic && (lists.length === 1 || !!((parameterList[parameterList.length - 1] as TransientSymbol).checkFlags & CheckFlags.RestParameter)),
parameters: parameterList.map(p => createSignatureHelpParameterForParameter(p, checker, enclosingDeclaration, sourceFile, printer)),
prefix: [...typeParameterParts, punctuationPart(SyntaxKind.OpenParenToken)],
suffix: [punctuationPart(SyntaxKind.CloseParenToken)]
};
});
}
function createSignatureHelpParameterForParameter(parameter: Symbol, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile, printer: Printer): SignatureHelpParameter {
+9 -1
View File
@@ -389,7 +389,7 @@ namespace ts.SymbolDisplay {
if (declarationName) {
const isExternalModuleDeclaration =
isModuleWithStringLiteralName(resolvedNode) &&
hasModifier(resolvedNode, ModifierFlags.Ambient);
hasSyntacticModifier(resolvedNode, ModifierFlags.Ambient);
const shouldUseAliasName = symbol.name !== "default" && !isExternalModuleDeclaration;
const resolvedInfo = getSymbolDisplayPartsDocumentationAndSymbolKind(
typeChecker,
@@ -481,6 +481,14 @@ namespace ts.SymbolDisplay {
else {
addRange(displayParts, typeToDisplayParts(typeChecker, type, enclosingDeclaration));
}
if ((symbol as TransientSymbol).target && ((symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration) {
const labelDecl = ((symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration!;
Debug.assertNode(labelDecl.name, isIdentifier);
displayParts.push(spacePart());
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
displayParts.push(textPart(idText(labelDecl.name)));
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
}
}
else if (symbolFlags & SymbolFlags.Function ||
symbolFlags & SymbolFlags.Method ||
+4
View File
@@ -286,6 +286,10 @@ namespace ts.textChanges {
this.deletedNodes.push({ sourceFile, node });
}
public deleteNode(sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }): void {
this.deleteRange(sourceFile, getAdjustedRange(sourceFile, node, node, options));
}
public deleteModifier(sourceFile: SourceFile, modifier: Modifier): void {
this.deleteRange(sourceFile, { pos: modifier.getStart(sourceFile), end: skipTrivia(sourceFile.text, modifier.end, /*stopAfterLineBreak*/ true) });
}
+2
View File
@@ -64,6 +64,7 @@
"codefixes/fixClassIncorrectlyImplementsInterface.ts",
"codefixes/importFixes.ts",
"codefixes/fixImplicitThis.ts",
"codefixes/fixIncorrectNamedTupleSyntax.ts",
"codefixes/fixSpelling.ts",
"codefixes/returnValueCorrect.ts",
"codefixes/fixAddMissingMember.ts",
@@ -101,6 +102,7 @@
"codefixes/fixExpectedComma.ts",
"refactors/convertExport.ts",
"refactors/convertImport.ts",
"refactors/convertOverloadListToSingleSignature.ts",
"refactors/extractSymbol.ts",
"refactors/extractType.ts",
"refactors/generateGetAccessorAndSetAccessor.ts",
+5
View File
@@ -203,6 +203,11 @@ namespace ts {
has(dependencyName: string, inGroups?: PackageJsonDependencyGroup): boolean;
}
/** @internal */
export interface FormattingHost {
getNewLine?(): string;
}
//
// Public interface of the host of a language service instance.
//
+4 -4
View File
@@ -407,7 +407,7 @@ namespace ts {
case SyntaxKind.Constructor: return ScriptElementKind.constructorImplementationElement;
case SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement;
case SyntaxKind.EnumMember: return ScriptElementKind.enumMemberElement;
case SyntaxKind.Parameter: return hasModifier(node, ModifierFlags.ParameterPropertyModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement;
case SyntaxKind.Parameter: return hasSyntacticModifier(node, ModifierFlags.ParameterPropertyModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement;
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ExportSpecifier:
@@ -2085,9 +2085,9 @@ namespace ts {
/**
* The default is CRLF.
*/
export function getNewLineOrDefaultFromHost(host: LanguageServiceHost | LanguageServiceShimHost, formatSettings?: FormatCodeSettings) {
return (formatSettings && formatSettings.newLineCharacter) ||
(host.getNewLine && host.getNewLine()) ||
export function getNewLineOrDefaultFromHost(host: FormattingHost, formatSettings?: FormatCodeSettings) {
return formatSettings?.newLineCharacter ||
host.getNewLine?.() ||
carriageReturnLineFeed;
}