Skip to content

Commit a4c8b6e

Browse files
committed
Merge branch 'master' into elaborateNeverIntersections
# Conflicts: # tests/baselines/reference/mixinAccessModifiers.types
2 parents a3b90b8 + 6964137 commit a4c8b6e

File tree

691 files changed

+3783
-2504
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

691 files changed

+3783
-2504
lines changed

src/compiler/checker.ts

Lines changed: 213 additions & 165 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticMessages.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5617,6 +5617,31 @@
56175617
"category": "Message",
56185618
"code": 95110
56195619
},
5620+
"Add a return statement": {
5621+
"category": "Message",
5622+
"code": 95111
5623+
},
5624+
"Remove block body braces": {
5625+
"category": "Message",
5626+
"code": 95112
5627+
},
5628+
"Wrap the following body with parentheses which should be an object literal": {
5629+
"category": "Message",
5630+
"code": 95113
5631+
},
5632+
"Add all missing return statement": {
5633+
"category": "Message",
5634+
"code": 95114
5635+
},
5636+
"Remove all incorrect body block braces": {
5637+
"category": "Message",
5638+
"code": 95115
5639+
},
5640+
"Wrap all object literal with parentheses": {
5641+
"category": "Message",
5642+
"code": 95116
5643+
},
5644+
56205645
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
56215646
"category": "Error",
56225647
"code": 18004

src/compiler/factoryPublic.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,6 +2057,26 @@ namespace ts {
20572057
: node;
20582058
}
20592059

2060+
/* @internal */
2061+
export function updateFunctionLikeBody(declaration: FunctionLikeDeclaration, body: Block): FunctionLikeDeclaration {
2062+
switch (declaration.kind) {
2063+
case SyntaxKind.FunctionDeclaration:
2064+
return createFunctionDeclaration(declaration.decorators, declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.typeParameters, declaration.parameters, declaration.type, body);
2065+
case SyntaxKind.MethodDeclaration:
2066+
return createMethod(declaration.decorators, declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.questionToken, declaration.typeParameters, declaration.parameters, declaration.type, body);
2067+
case SyntaxKind.GetAccessor:
2068+
return createGetAccessor(declaration.decorators, declaration.modifiers, declaration.name, declaration.parameters, declaration.type, body);
2069+
case SyntaxKind.SetAccessor:
2070+
return createSetAccessor(declaration.decorators, declaration.modifiers, declaration.name, declaration.parameters, body);
2071+
case SyntaxKind.Constructor:
2072+
return createConstructor(declaration.decorators, declaration.modifiers, declaration.parameters, body);
2073+
case SyntaxKind.FunctionExpression:
2074+
return createFunctionExpression(declaration.modifiers, declaration.asteriskToken, declaration.name, declaration.typeParameters, declaration.parameters, declaration.type, body);
2075+
case SyntaxKind.ArrowFunction:
2076+
return createArrowFunction(declaration.modifiers, declaration.typeParameters, declaration.parameters, declaration.type, declaration.equalsGreaterThanToken, body);
2077+
}
2078+
}
2079+
20602080
export function createClassDeclaration(
20612081
decorators: readonly Decorator[] | undefined,
20622082
modifiers: readonly Modifier[] | undefined,

src/compiler/utilities.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2114,10 +2114,13 @@ namespace ts {
21142114
return isIdentifier(node) && node.escapedText === "exports";
21152115
}
21162116

2117+
export function isModuleIdentifier(node: Node) {
2118+
return isIdentifier(node) && node.escapedText === "module";
2119+
}
2120+
21172121
export function isModuleExportsAccessExpression(node: Node): node is LiteralLikeElementAccessExpression & { expression: Identifier } {
21182122
return (isPropertyAccessExpression(node) || isLiteralLikeElementAccess(node))
2119-
&& isIdentifier(node.expression)
2120-
&& node.expression.escapedText === "module"
2123+
&& isModuleIdentifier(node.expression)
21212124
&& getElementOrPropertyAccessName(node) === "exports";
21222125
}
21232126

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/* @internal */
2+
namespace ts.codefix {
3+
const fixId = "returnValueCorrect";
4+
const fixIdAddReturnStatement = "fixAddReturnStatement";
5+
const fixIdRemoveBlockBodyBrace = "fixRemoveBlockBodyBrace";
6+
const fixIdWrapTheBlockWithParen = "fixWrapTheBlockWithParen";
7+
const errorCodes = [
8+
Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value.code,
9+
Diagnostics.Type_0_is_not_assignable_to_type_1.code,
10+
Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code
11+
];
12+
13+
enum ProblemKind {
14+
MissingReturnStatement,
15+
MissingParentheses
16+
}
17+
18+
interface MissingReturnInfo {
19+
kind: ProblemKind.MissingReturnStatement;
20+
declaration: FunctionLikeDeclaration;
21+
expression: Expression;
22+
statement: Statement;
23+
commentSource: Node;
24+
}
25+
26+
interface MissingParenInfo {
27+
kind: ProblemKind.MissingParentheses;
28+
declaration: ArrowFunction;
29+
expression: Expression;
30+
statement: Statement;
31+
commentSource: Node;
32+
}
33+
34+
type Info = MissingReturnInfo | MissingParenInfo;
35+
36+
registerCodeFix({
37+
errorCodes,
38+
fixIds: [fixIdAddReturnStatement, fixIdRemoveBlockBodyBrace, fixIdWrapTheBlockWithParen],
39+
getCodeActions: context => {
40+
const { program, sourceFile, span: { start }, errorCode } = context;
41+
const info = getInfo(program.getTypeChecker(), sourceFile, start, errorCode);
42+
if (!info) return undefined;
43+
44+
if (info.kind === ProblemKind.MissingReturnStatement) {
45+
return append(
46+
[getActionForfixAddReturnStatement(context, info.expression, info.statement)],
47+
isArrowFunction(info.declaration) ? getActionForfixRemoveBlockBodyBrace(context, info.declaration, info.expression, info.commentSource): undefined);
48+
}
49+
else {
50+
return [getActionForfixWrapTheBlockWithParen(context, info.declaration, info.expression)];
51+
}
52+
},
53+
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
54+
const info = getInfo(context.program.getTypeChecker(), diag.file, diag.start, diag.code);
55+
if (!info) return undefined;
56+
57+
switch (context.fixId) {
58+
case fixIdAddReturnStatement:
59+
addReturnStatement(changes, diag.file, info.expression, info.statement);
60+
break;
61+
case fixIdRemoveBlockBodyBrace:
62+
if (!isArrowFunction(info.declaration)) return undefined;
63+
removeBlockBodyBrace(changes, diag.file, info.declaration, info.expression, info.commentSource, /* withParen */ false);
64+
break;
65+
case fixIdWrapTheBlockWithParen:
66+
if (!isArrowFunction(info.declaration)) return undefined;
67+
wrapBlockWithParen(changes, diag.file, info.declaration, info.expression);
68+
break;
69+
default:
70+
Debug.fail(JSON.stringify(context.fixId));
71+
}
72+
}),
73+
});
74+
75+
function getFixInfo(checker: TypeChecker, declaration: FunctionLikeDeclaration, expectType: Type, isFunctionType: boolean): Info | undefined {
76+
if (!declaration.body || !isBlock(declaration.body) || length(declaration.body.statements) !== 1) return undefined;
77+
78+
const firstStatement = first(declaration.body.statements);
79+
if (isExpressionStatement(firstStatement) && checkFixedAssignableTo(checker, declaration, firstStatement.expression, expectType, isFunctionType)) {
80+
return {
81+
declaration,
82+
kind: ProblemKind.MissingReturnStatement,
83+
expression: firstStatement.expression,
84+
statement: firstStatement,
85+
commentSource: firstStatement.expression
86+
};
87+
}
88+
else if (isLabeledStatement(firstStatement) && isExpressionStatement(firstStatement.statement)) {
89+
const node = createObjectLiteral([createPropertyAssignment(firstStatement.label, firstStatement.statement.expression)]);
90+
if (checkFixedAssignableTo(checker, declaration, node, expectType, isFunctionType)) {
91+
return isArrowFunction(declaration) ? {
92+
declaration,
93+
kind: ProblemKind.MissingParentheses,
94+
expression: node,
95+
statement: firstStatement,
96+
commentSource: firstStatement.statement.expression
97+
} : {
98+
declaration,
99+
kind: ProblemKind.MissingReturnStatement,
100+
expression: node,
101+
statement: firstStatement,
102+
commentSource: firstStatement.statement.expression
103+
};
104+
}
105+
}
106+
else if (isBlock(firstStatement) && length(firstStatement.statements) === 1) {
107+
const firstBlockStatement = first(firstStatement.statements);
108+
if (isLabeledStatement(firstBlockStatement) && isExpressionStatement(firstBlockStatement.statement)) {
109+
const node = createObjectLiteral([createPropertyAssignment(firstBlockStatement.label, firstBlockStatement.statement.expression)]);
110+
if (checkFixedAssignableTo(checker, declaration, node, expectType, isFunctionType)) {
111+
return {
112+
declaration,
113+
kind: ProblemKind.MissingReturnStatement,
114+
expression: node,
115+
statement: firstStatement,
116+
commentSource: firstBlockStatement
117+
};
118+
}
119+
}
120+
}
121+
122+
return undefined;
123+
}
124+
125+
function checkFixedAssignableTo(checker: TypeChecker, declaration: FunctionLikeDeclaration, expr: Expression, type: Type, isFunctionType: boolean) {
126+
return checker.isTypeAssignableTo(checker.getTypeAtLocation(isFunctionType ? updateFunctionLikeBody(declaration, createBlock([createReturn(expr)])) : expr), type);
127+
}
128+
129+
function getInfo(checker: TypeChecker, sourceFile: SourceFile, position: number, errorCode: number): Info | undefined {
130+
const node = getTokenAtPosition(sourceFile, position);
131+
if (!node.parent) return undefined;
132+
133+
const declaration = findAncestor(node.parent, isFunctionLikeDeclaration);
134+
switch (errorCode) {
135+
case Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value.code:
136+
if (!declaration || !declaration.body || !declaration.type || !rangeContainsRange(declaration.type, node)) return undefined;
137+
return getFixInfo(checker, declaration, checker.getTypeFromTypeNode(declaration.type), /* isFunctionType */ false);
138+
case Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code:
139+
if (!declaration || !isCallExpression(declaration.parent) || !declaration.body) return undefined;
140+
const pos = declaration.parent.arguments.indexOf(<Expression>declaration);
141+
const type = checker.getContextualTypeForArgumentAtIndex(declaration.parent, pos);
142+
if (!type) return undefined;
143+
return getFixInfo(checker, declaration, type, /* isFunctionType */ true);
144+
case Diagnostics.Type_0_is_not_assignable_to_type_1.code:
145+
if (!isDeclarationName(node) || !isVariableLike(node.parent) && !isJsxAttribute(node.parent)) return undefined;
146+
const initializer = getVariableLikeInitializer(node.parent);
147+
if (!initializer || !isFunctionLikeDeclaration(initializer) || !initializer.body) return undefined;
148+
return getFixInfo(checker, initializer, checker.getTypeAtLocation(node.parent), /* isFunctionType */ true);
149+
}
150+
return undefined;
151+
}
152+
153+
function getVariableLikeInitializer(declaration: VariableLikeDeclaration): Expression | undefined {
154+
switch (declaration.kind) {
155+
case SyntaxKind.VariableDeclaration:
156+
case SyntaxKind.Parameter:
157+
case SyntaxKind.BindingElement:
158+
case SyntaxKind.PropertyDeclaration:
159+
case SyntaxKind.PropertyAssignment:
160+
return declaration.initializer;
161+
case SyntaxKind.JsxAttribute:
162+
return declaration.initializer && (isJsxExpression(declaration.initializer) ? declaration.initializer.expression : undefined);
163+
case SyntaxKind.ShorthandPropertyAssignment:
164+
case SyntaxKind.PropertySignature:
165+
case SyntaxKind.EnumMember:
166+
case SyntaxKind.JSDocPropertyTag:
167+
case SyntaxKind.JSDocParameterTag:
168+
return undefined;
169+
}
170+
}
171+
172+
function addReturnStatement(changes: textChanges.ChangeTracker, sourceFile: SourceFile, expression: Expression, statement: Statement) {
173+
suppressLeadingAndTrailingTrivia(expression);
174+
const probablyNeedSemi = probablyUsesSemicolons(sourceFile);
175+
changes.replaceNode(sourceFile, statement, createReturn(expression), {
176+
leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude,
177+
trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude,
178+
suffix: probablyNeedSemi ? ";" : undefined
179+
});
180+
}
181+
182+
function removeBlockBodyBrace(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression, commentSource: Node, withParen: boolean) {
183+
const newBody = (withParen || needsParentheses(expression)) ? createParen(expression) : expression;
184+
suppressLeadingAndTrailingTrivia(commentSource);
185+
copyComments(commentSource, newBody);
186+
187+
changes.replaceNode(sourceFile, declaration.body, newBody);
188+
}
189+
190+
function wrapBlockWithParen(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: ArrowFunction, expression: Expression) {
191+
changes.replaceNode(sourceFile, declaration.body, createParen(expression));
192+
}
193+
194+
function getActionForfixAddReturnStatement(context: CodeFixContext, expression: Expression, statement: Statement) {
195+
const changes = textChanges.ChangeTracker.with(context, t => addReturnStatement(t, context.sourceFile, expression, statement));
196+
return createCodeFixAction(fixId, changes, Diagnostics.Add_a_return_statement, fixIdAddReturnStatement, Diagnostics.Add_all_missing_return_statement);
197+
}
198+
199+
function getActionForfixRemoveBlockBodyBrace(context: CodeFixContext, declaration: ArrowFunction, expression: Expression, commentSource: Node) {
200+
const changes = textChanges.ChangeTracker.with(context, t => removeBlockBodyBrace(t, context.sourceFile, declaration, expression, commentSource, /* withParen */ false));
201+
return createCodeFixAction(fixId, changes, Diagnostics.Remove_block_body_braces, fixIdRemoveBlockBodyBrace, Diagnostics.Remove_all_incorrect_body_block_braces);
202+
}
203+
204+
function getActionForfixWrapTheBlockWithParen(context: CodeFixContext, declaration: ArrowFunction, expression: Expression) {
205+
const changes = textChanges.ChangeTracker.with(context, t => wrapBlockWithParen(t, context.sourceFile, declaration, expression));
206+
return createCodeFixAction(fixId, changes, Diagnostics.Wrap_the_following_body_with_parentheses_which_should_be_an_object_literal, fixIdWrapTheBlockWithParen, Diagnostics.Wrap_all_object_literal_with_parentheses);
207+
}
208+
}

src/services/findAllReferences.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,32 @@ namespace ts.FindAllReferences {
216216

217217
export function getImplementationsAtPosition(program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], sourceFile: SourceFile, position: number): ImplementationLocation[] | undefined {
218218
const node = getTouchingPropertyName(sourceFile, position);
219-
const referenceEntries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, node, position);
219+
let referenceEntries: Entry[] | undefined;
220+
const entries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, node, position);
221+
222+
if (
223+
node.parent.kind === SyntaxKind.PropertyAccessExpression
224+
|| node.parent.kind === SyntaxKind.BindingElement
225+
|| node.parent.kind === SyntaxKind.ElementAccessExpression
226+
|| node.kind === SyntaxKind.SuperKeyword
227+
) {
228+
referenceEntries = entries && [...entries];
229+
}
230+
else {
231+
const queue = entries && [...entries];
232+
const seenNodes = createMap<true>();
233+
while (queue && queue.length) {
234+
const entry = queue.shift() as NodeEntry;
235+
if (!addToSeen(seenNodes, getNodeId(entry.node))) {
236+
continue;
237+
}
238+
referenceEntries = append(referenceEntries, entry);
239+
const entries = getImplementationReferenceEntries(program, cancellationToken, sourceFiles, entry.node, entry.node.pos);
240+
if (entries) {
241+
queue.push(...entries);
242+
}
243+
}
244+
}
220245
const checker = program.getTypeChecker();
221246
return map(referenceEntries, entry => toImplementationLocation(entry, checker));
222247
}

src/services/formatting/rules.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ namespace ts.formatting {
129129

130130
// Async-await
131131
rule("SpaceBetweenAsyncAndOpenParen", SyntaxKind.AsyncKeyword, SyntaxKind.OpenParenToken, [isArrowFunctionContext, isNonJsxSameLineTokenContext], RuleAction.InsertSpace),
132-
rule("SpaceBetweenAsyncAndFunctionKeyword", SyntaxKind.AsyncKeyword, SyntaxKind.FunctionKeyword, [isNonJsxSameLineTokenContext], RuleAction.InsertSpace),
132+
rule("SpaceBetweenAsyncAndFunctionKeyword", SyntaxKind.AsyncKeyword, [SyntaxKind.FunctionKeyword, SyntaxKind.Identifier], [isNonJsxSameLineTokenContext], RuleAction.InsertSpace),
133133

134134
// Template string
135135
rule("NoSpaceBetweenTagAndTemplateString", [SyntaxKind.Identifier, SyntaxKind.CloseParenToken], [SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead], [isNonJsxSameLineTokenContext], RuleAction.DeleteSpace),

src/services/refactors/addOrRemoveBracesToArrowFunction.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,6 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
6464
return { renameFilename: undefined, renameLocation: undefined, edits };
6565
}
6666

67-
function needsParentheses(expression: Expression) {
68-
return isBinaryExpression(expression) && expression.operatorToken.kind === SyntaxKind.CommaToken || isObjectLiteralExpression(expression);
69-
}
70-
7167
function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number): Info | undefined {
7268
const node = getTokenAtPosition(file, startPosition);
7369
const func = getContainingFunction(node);

src/services/refactors/convertParamsToDestructuredObject.ts

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -491,27 +491,6 @@ namespace ts.refactor.convertParamsToDestructuredObject {
491491
}
492492
}
493493

494-
function copyComments(sourceNode: Node, targetNode: Node) {
495-
const sourceFile = sourceNode.getSourceFile();
496-
const text = sourceFile.text;
497-
if (hasLeadingLineBreak(sourceNode, text)) {
498-
copyLeadingComments(sourceNode, targetNode, sourceFile);
499-
}
500-
else {
501-
copyTrailingAsLeadingComments(sourceNode, targetNode, sourceFile);
502-
}
503-
copyTrailingComments(sourceNode, targetNode, sourceFile);
504-
}
505-
506-
function hasLeadingLineBreak(node: Node, text: string) {
507-
const start = node.getFullStart();
508-
const end = node.getStart();
509-
for (let i = start; i < end; i++) {
510-
if (text.charCodeAt(i) === CharacterCodes.lineFeed) return true;
511-
}
512-
return false;
513-
}
514-
515494
function getParameterName(paramDeclaration: ValidParameterDeclaration) {
516495
return getTextOfIdentifierOrLiteral(paramDeclaration.name);
517496
}

src/services/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"codefixes/importFixes.ts",
6666
"codefixes/fixImplicitThis.ts",
6767
"codefixes/fixSpelling.ts",
68+
"codefixes/returnValueCorrect.ts",
6869
"codefixes/fixAddMissingMember.ts",
6970
"codefixes/fixAddMissingNewOperator.ts",
7071
"codefixes/fixCannotFindModule.ts",

0 commit comments

Comments
 (0)