Skip to content

Commit 56ba186

Browse files
committed
Merge branch 'master' into improveTypeArgumentInference
2 parents 7dd9e21 + 515a0e8 commit 56ba186

39 files changed

+326
-187
lines changed

src/compiler/binder.ts

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -260,18 +260,9 @@ namespace ts {
260260
case SyntaxKind.ExportAssignment:
261261
return (<ExportAssignment>node).isExportEquals ? "export=" : "default";
262262
case SyntaxKind.BinaryExpression:
263-
switch (getSpecialPropertyAssignmentKind(node as BinaryExpression)) {
264-
case SpecialPropertyAssignmentKind.ModuleExports:
265-
// module.exports = ...
266-
return "export=";
267-
case SpecialPropertyAssignmentKind.ExportsProperty:
268-
case SpecialPropertyAssignmentKind.ThisProperty:
269-
case SpecialPropertyAssignmentKind.Property:
270-
// exports.x = ... or this.y = ...
271-
return ((node as BinaryExpression).left as PropertyAccessExpression).name.text;
272-
case SpecialPropertyAssignmentKind.PrototypeProperty:
273-
// className.prototype.methodName = ...
274-
return (((node as BinaryExpression).left as PropertyAccessExpression).expression as PropertyAccessExpression).name.text;
263+
if (getSpecialPropertyAssignmentKind(node as BinaryExpression) === SpecialPropertyAssignmentKind.ModuleExports) {
264+
// module.exports = ...
265+
return "export=";
275266
}
276267
Debug.fail("Unknown binary declaration kind");
277268
break;
@@ -439,6 +430,7 @@ namespace ts {
439430
// during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation
440431
// and this case is specially handled. Module augmentations should only be merged with original module definition
441432
// and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed.
433+
if (node.kind === SyntaxKind.JSDocTypedefTag) Debug.assert(isInJavaScriptFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
442434
const isJSDocTypedefInJSDocNamespace = node.kind === SyntaxKind.JSDocTypedefTag &&
443435
(node as JSDocTypedefTag).name &&
444436
(node as JSDocTypedefTag).name.kind === SyntaxKind.Identifier &&
@@ -603,9 +595,7 @@ namespace ts {
603595
// Binding of JsDocComment should be done before the current block scope container changes.
604596
// because the scope of JsDocComment should not be affected by whether the current node is a
605597
// container or not.
606-
if (isInJavaScriptFile(node) && node.jsDoc) {
607-
forEach(node.jsDoc, bind);
608-
}
598+
forEach(node.jsDoc, bind);
609599
if (checkUnreachable(node)) {
610600
bindEachChild(node);
611601
return;
@@ -1913,9 +1903,7 @@ namespace ts {
19131903
// Here the current node is "foo", which is a container, but the scope of "MyType" should
19141904
// not be inside "foo". Therefore we always bind @typedef before bind the parent node,
19151905
// and skip binding this tag later when binding all the other jsdoc tags.
1916-
if (isInJavaScriptFile(node)) {
1917-
bindJSDocTypedefTagIfAny(node);
1918-
}
1906+
bindJSDocTypedefTagIfAny(node);
19191907

19201908
// First we bind declaration nodes to a symbol if possible. We'll both create a symbol
19211909
// and then potentially add the symbol to an appropriate symbol table. Possible
@@ -2003,7 +1991,7 @@ namespace ts {
20031991
// for typedef type names with namespaces, bind the new jsdoc type symbol here
20041992
// because it requires all containing namespaces to be in effect, namely the
20051993
// current "blockScopeContainer" needs to be set to its immediate namespace parent.
2006-
if ((<Identifier>node).isInJSDocNamespace) {
1994+
if (isInJavaScriptFile(node) && (<Identifier>node).isInJSDocNamespace) {
20071995
let parentNode = node.parent;
20081996
while (parentNode && parentNode.kind !== SyntaxKind.JSDocTypedefTag) {
20091997
parentNode = parentNode.parent;
@@ -2073,10 +2061,7 @@ namespace ts {
20732061
return bindVariableDeclarationOrBindingElement(<VariableDeclaration | BindingElement>node);
20742062
case SyntaxKind.PropertyDeclaration:
20752063
case SyntaxKind.PropertySignature:
2076-
case SyntaxKind.JSDocRecordMember:
2077-
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.Property | ((<PropertyDeclaration>node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
2078-
case SyntaxKind.JSDocPropertyTag:
2079-
return bindJSDocProperty(<JSDocPropertyTag>node);
2064+
return bindPropertyWorker(node as PropertyDeclaration | PropertySignature);
20802065
case SyntaxKind.PropertyAssignment:
20812066
case SyntaxKind.ShorthandPropertyAssignment:
20822067
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
@@ -2121,13 +2106,10 @@ namespace ts {
21212106
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes);
21222107
case SyntaxKind.FunctionType:
21232108
case SyntaxKind.ConstructorType:
2124-
case SyntaxKind.JSDocFunctionType:
21252109
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
21262110
case SyntaxKind.TypeLiteral:
21272111
case SyntaxKind.MappedType:
2128-
case SyntaxKind.JSDocTypeLiteral:
2129-
case SyntaxKind.JSDocRecordType:
2130-
return bindAnonymousDeclaration(<Declaration>node, SymbolFlags.TypeLiteral, "__type");
2112+
return bindAnonymousTypeWorker(node as TypeLiteralNode | MappedTypeNode);
21312113
case SyntaxKind.ObjectLiteralExpression:
21322114
return bindObjectLiteralExpression(<ObjectLiteralExpression>node);
21332115
case SyntaxKind.FunctionExpression:
@@ -2148,11 +2130,6 @@ namespace ts {
21482130
return bindClassLikeDeclaration(<ClassLikeDeclaration>node);
21492131
case SyntaxKind.InterfaceDeclaration:
21502132
return bindBlockScopedDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes);
2151-
case SyntaxKind.JSDocTypedefTag:
2152-
if (!(<JSDocTypedefTag>node).fullName || (<JSDocTypedefTag>node).fullName.kind === SyntaxKind.Identifier) {
2153-
return bindBlockScopedDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
2154-
}
2155-
break;
21562133
case SyntaxKind.TypeAliasDeclaration:
21572134
return bindBlockScopedDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
21582135
case SyntaxKind.EnumDeclaration:
@@ -2190,9 +2167,41 @@ namespace ts {
21902167
// falls through
21912168
case SyntaxKind.ModuleBlock:
21922169
return updateStrictModeStatementList((<Block | ModuleBlock>node).statements);
2170+
2171+
default:
2172+
if (isInJavaScriptFile(node)) return bindJSDocWorker(node);
2173+
}
2174+
}
2175+
2176+
function bindJSDocWorker(node: Node) {
2177+
switch (node.kind) {
2178+
case SyntaxKind.JSDocRecordMember:
2179+
return bindPropertyWorker(node as JSDocRecordMember);
2180+
case SyntaxKind.JSDocPropertyTag:
2181+
return declareSymbolAndAddToSymbolTable(node as JSDocPropertyTag, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
2182+
case SyntaxKind.JSDocFunctionType:
2183+
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
2184+
case SyntaxKind.JSDocTypeLiteral:
2185+
case SyntaxKind.JSDocRecordType:
2186+
return bindAnonymousTypeWorker(node as JSDocTypeLiteral | JSDocRecordType);
2187+
case SyntaxKind.JSDocTypedefTag: {
2188+
const { fullName } = node as JSDocTypedefTag;
2189+
if (!fullName || fullName.kind === SyntaxKind.Identifier) {
2190+
return bindBlockScopedDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
2191+
}
2192+
break;
2193+
}
21932194
}
21942195
}
21952196

2197+
function bindPropertyWorker(node: PropertyDeclaration | PropertySignature) {
2198+
return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property | (node.questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes);
2199+
}
2200+
2201+
function bindAnonymousTypeWorker(node: TypeLiteralNode | MappedTypeNode | JSDocTypeLiteral | JSDocRecordType) {
2202+
return bindAnonymousDeclaration(<Declaration>node, SymbolFlags.TypeLiteral, "__type");
2203+
}
2204+
21962205
function checkTypePredicate(node: TypePredicateNode) {
21972206
const { parameterName, type } = node;
21982207
if (parameterName && parameterName.kind === SyntaxKind.Identifier) {
@@ -2558,10 +2567,8 @@ namespace ts {
25582567
}
25592568

25602569
function bindPropertyOrMethodOrAccessor(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
2561-
if (!file.isDeclarationFile && !isInAmbientContext(node)) {
2562-
if (isAsyncFunction(node)) {
2563-
emitFlags |= NodeFlags.HasAsyncFunctions;
2564-
}
2570+
if (!file.isDeclarationFile && !isInAmbientContext(node) && isAsyncFunction(node)) {
2571+
emitFlags |= NodeFlags.HasAsyncFunctions;
25652572
}
25662573

25672574
if (currentFlow && isObjectLiteralOrClassExpressionMethod(node)) {
@@ -2573,10 +2580,6 @@ namespace ts {
25732580
: declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes);
25742581
}
25752582

2576-
function bindJSDocProperty(node: JSDocPropertyTag) {
2577-
return declareSymbolAndAddToSymbolTable(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
2578-
}
2579-
25802583
// reachability checks
25812584

25822585
function shouldReportErrorOnModuleDeclaration(node: ModuleDeclaration): boolean {

src/compiler/checker.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22372,6 +22372,11 @@ namespace ts {
2237222372
}
2237322373
}
2237422374

22375+
if (entityName.parent!.kind === SyntaxKind.JSDocParameterTag) {
22376+
const parameter = ts.getParameterFromJSDoc(entityName.parent as JSDocParameterTag);
22377+
return parameter && parameter.symbol;
22378+
}
22379+
2237522380
if (isPartOfExpression(entityName)) {
2237622381
if (nodeIsMissing(entityName)) {
2237722382
// Missing entity name.

src/compiler/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ namespace ts {
5050
// stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
5151
// embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
5252
// a truthy value, iteration stops and that value is returned. Otherwise, undefined is returned.
53-
export function forEachChild<T>(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T | undefined {
53+
export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodeArray?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
5454
if (!node) {
5555
return;
5656
}

src/compiler/utilities.ts

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,7 +1599,7 @@ namespace ts {
15991599

16001600
// Pull parameter comments from declaring function as well
16011601
if (node.kind === SyntaxKind.Parameter) {
1602-
cache = concatenate(cache, getJSDocParameterTags(node));
1602+
cache = concatenate(cache, getJSDocParameterTags(node as ParameterDeclaration));
16031603
}
16041604

16051605
if (isVariableLike(node) && node.initializer) {
@@ -1610,11 +1610,8 @@ namespace ts {
16101610
}
16111611
}
16121612

1613-
export function getJSDocParameterTags(param: Node): JSDocParameterTag[] {
1614-
if (!isParameter(param)) {
1615-
return undefined;
1616-
}
1617-
const func = param.parent as FunctionLikeDeclaration;
1613+
export function getJSDocParameterTags(param: ParameterDeclaration): JSDocParameterTag[] {
1614+
const func = param.parent;
16181615
const tags = getJSDocTags(func, SyntaxKind.JSDocParameterTag) as JSDocParameterTag[];
16191616
if (!param.name) {
16201617
// this is an anonymous jsdoc param from a `function(type1, type2): type3` specification
@@ -1635,10 +1632,22 @@ namespace ts {
16351632
}
16361633
}
16371634

1635+
/** Does the opposite of `getJSDocParameterTags`: given a JSDoc parameter, finds the parameter corresponding to it. */
1636+
export function getParameterFromJSDoc(node: JSDocParameterTag): ParameterDeclaration | undefined {
1637+
const name = node.parameterName.text;
1638+
const grandParent = node.parent!.parent!;
1639+
Debug.assert(node.parent!.kind === SyntaxKind.JSDocComment);
1640+
if (!isFunctionLike(grandParent)) {
1641+
return undefined;
1642+
}
1643+
return find(grandParent.parameters, p =>
1644+
p.name.kind === SyntaxKind.Identifier && p.name.text === name);
1645+
}
1646+
16381647
export function getJSDocType(node: Node): JSDocType {
16391648
let tag: JSDocTypeTag | JSDocParameterTag = getFirstJSDocTag(node, SyntaxKind.JSDocTypeTag) as JSDocTypeTag;
16401649
if (!tag && node.kind === SyntaxKind.Parameter) {
1641-
const paramTags = getJSDocParameterTags(node);
1650+
const paramTags = getJSDocParameterTags(node as ParameterDeclaration);
16421651
if (paramTags) {
16431652
tag = find(paramTags, tag => !!tag.typeExpression);
16441653
}
@@ -1776,36 +1785,6 @@ namespace ts {
17761785
}
17771786
}
17781787

1779-
export function getNameOfDeclaration(declaration: Declaration): DeclarationName {
1780-
if (!declaration) {
1781-
return undefined;
1782-
}
1783-
if (declaration.kind === SyntaxKind.BinaryExpression) {
1784-
const kind = getSpecialPropertyAssignmentKind(declaration as BinaryExpression);
1785-
const lhs = (declaration as BinaryExpression).left;
1786-
switch (kind) {
1787-
case SpecialPropertyAssignmentKind.None:
1788-
case SpecialPropertyAssignmentKind.ModuleExports:
1789-
return undefined;
1790-
case SpecialPropertyAssignmentKind.ExportsProperty:
1791-
if (lhs.kind === SyntaxKind.Identifier) {
1792-
return (lhs as PropertyAccessExpression).name;
1793-
}
1794-
else {
1795-
return ((lhs as PropertyAccessExpression).expression as PropertyAccessExpression).name;
1796-
}
1797-
case SpecialPropertyAssignmentKind.ThisProperty:
1798-
case SpecialPropertyAssignmentKind.Property:
1799-
return (lhs as PropertyAccessExpression).name;
1800-
case SpecialPropertyAssignmentKind.PrototypeProperty:
1801-
return ((lhs as PropertyAccessExpression).expression as PropertyAccessExpression).name;
1802-
}
1803-
}
1804-
else {
1805-
return (declaration as NamedDeclaration).name;
1806-
}
1807-
}
1808-
18091788
export function isLiteralComputedPropertyDeclarationName(node: Node) {
18101789
return (node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NumericLiteral) &&
18111790
node.parent.kind === SyntaxKind.ComputedPropertyName &&
@@ -4729,4 +4708,25 @@ namespace ts {
47294708
export function unescapeIdentifier(identifier: string): string {
47304709
return identifier.length >= 3 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ && identifier.charCodeAt(2) === CharacterCodes._ ? identifier.substr(1) : identifier;
47314710
}
4711+
4712+
export function getNameOfDeclaration(declaration: Declaration): DeclarationName | undefined {
4713+
if (!declaration) {
4714+
return undefined;
4715+
}
4716+
if (declaration.kind === SyntaxKind.BinaryExpression) {
4717+
const expr = declaration as BinaryExpression;
4718+
switch (getSpecialPropertyAssignmentKind(expr)) {
4719+
case SpecialPropertyAssignmentKind.ExportsProperty:
4720+
case SpecialPropertyAssignmentKind.ThisProperty:
4721+
case SpecialPropertyAssignmentKind.Property:
4722+
case SpecialPropertyAssignmentKind.PrototypeProperty:
4723+
return (expr.left as PropertyAccessExpression).name;
4724+
default:
4725+
return undefined;
4726+
}
4727+
}
4728+
else {
4729+
return (declaration as NamedDeclaration).name;
4730+
}
4731+
}
47324732
}

src/harness/fourslash.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,7 @@ namespace FourSlash {
916916
}
917917

918918
private getNode(): ts.Node {
919-
return ts.getTouchingPropertyName(this.getSourceFile(), this.currentCaretPosition);
919+
return ts.getTouchingPropertyName(this.getSourceFile(), this.currentCaretPosition, /*includeJsDocComment*/ false);
920920
}
921921

922922
private goToAndGetNode(range: Range): ts.Node {
@@ -994,12 +994,11 @@ namespace FourSlash {
994994
}
995995

996996
public verifyReferenceGroups(startRanges: Range | Range[], parts: Array<{ definition: string, ranges: Range[] }>): void {
997-
interface ReferenceJson { definition: string; ranges: ts.ReferenceEntry[]; }
998997
const fullExpected = ts.map(parts, ({ definition, ranges }) => ({ definition, ranges: ranges.map(rangeToReferenceEntry) }));
999998

1000999
for (const startRange of toArray(startRanges)) {
10011000
this.goToRangeStart(startRange);
1002-
const fullActual = ts.map<ts.ReferencedSymbol, ReferenceJson>(this.findReferencesAtCaret(), ({ definition, references }) => ({
1001+
const fullActual = ts.map(this.findReferencesAtCaret(), ({ definition, references }) => ({
10031002
definition: definition.displayParts.map(d => d.text).join(""),
10041003
ranges: references
10051004
}));
@@ -1046,6 +1045,10 @@ namespace FourSlash {
10461045
this.raiseError(`${msgPrefix}At ${path}: ${msg}`);
10471046
};
10481047

1048+
if ((actual === undefined) !== (expected === undefined)) {
1049+
fail(`Expected ${expected}, got ${actual}`);
1050+
}
1051+
10491052
for (const key in actual) if (ts.hasProperty(actual as any, key)) {
10501053
const ak = actual[key], ek = expected[key];
10511054
if (typeof ak === "object" && typeof ek === "object") {

src/harness/harness.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ namespace Utils {
172172
assert.isFalse(child.pos < currentPos, "child.pos < currentPos");
173173
currentPos = child.end;
174174
},
175-
(array: ts.NodeArray<ts.Node>) => {
175+
array => {
176176
assert.isFalse(array.pos < node.pos, "array.pos < node.pos");
177177
assert.isFalse(array.end > node.end, "array.end > node.end");
178178
assert.isFalse(array.pos < currentPos, "array.pos < currentPos");
@@ -383,7 +383,7 @@ namespace Utils {
383383

384384
assertStructuralEquals(child1, child2);
385385
},
386-
(array1: ts.NodeArray<ts.Node>) => {
386+
array1 => {
387387
const childName = findChildName(node1, array1);
388388
const array2: ts.NodeArray<ts.Node> = (<any>node2)[childName];
389389

0 commit comments

Comments
 (0)