Skip to content
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
f9f9157
Add initial tests
sandersn May 1, 2018
5fab72f
Add types
sandersn May 1, 2018
37076b3
Half of parsing (builds but does not pass tests)
sandersn May 1, 2018
248cd06
Parsing done; types are uglier; doesn't crash but doesn't pass
sandersn May 1, 2018
2ce53ba
Bind callback tag
sandersn May 1, 2018
8991502
Only bind param tags inside callback tags
sandersn May 1, 2018
7737c7c
Fix binding switch to only handle param tags once
sandersn May 1, 2018
ec7ddf8
Checking is 1/3 done or so.
sandersn May 1, 2018
7d2233a
Rename typeExpression to type (for some jsdoc)
sandersn May 1, 2018
f41a96b
Rename the rest of typeExpressions
sandersn May 1, 2018
64631e5
Few more checker changes
sandersn May 1, 2018
009c411
Revert "Rename the rest of typeExpressions"
sandersn May 1, 2018
0de72c2
Revert "Rename typeExpression to type (for some jsdoc)"
sandersn May 1, 2018
8ae8939
Finish undoing typeExpression rename
sandersn May 1, 2018
a96bdfd
Rename and improve getTypeParametersForAliasSymbol
sandersn May 2, 2018
6a0a5eb
Core checking works, but is flabbergastingly messy
sandersn May 2, 2018
0003c48
Callback return types work now
sandersn May 2, 2018
f4ac992
Fix crash in services
sandersn May 2, 2018
ad7fb64
Make github diff smaller
sandersn May 2, 2018
2410bee
Try to make github diff even smaller
sandersn May 2, 2018
0ae190b
Fix rename for callback tag
sandersn May 2, 2018
3ca5bf0
Fix nav bar for callback tag
sandersn May 3, 2018
819f19d
Handle ooorder callback tags
sandersn May 3, 2018
c2d7db7
Add ooorder callback tag test
sandersn May 3, 2018
7c6d66e
Parse comments for typedef/callback+display param comments
sandersn May 3, 2018
5e02518
Always export callbacks
sandersn May 3, 2018
12bd83d
Update baselines
sandersn May 3, 2018
dafb67d
Fix support for nested namespaced callbacks
sandersn May 3, 2018
9600db7
Callbacks support type parameters
sandersn May 4, 2018
0c28218
Template tags are now bound correctly
sandersn May 7, 2018
07cd96d
Test oorder template tags
sandersn May 7, 2018
1986b4d
Merge branch 'master' into jsdoc/callback
sandersn May 7, 2018
eb61b8b
Parser cleanup
sandersn May 7, 2018
e6e8ebf
Cleanup types and utilities
sandersn May 7, 2018
91d95f7
Handle callback more often in services
sandersn May 7, 2018
57fa3a5
Merge branch 'master' into jsdoc/callback
sandersn May 7, 2018
6973c5d
Cleanup of binder and checker
sandersn May 7, 2018
52cd1c7
More checker cleanup
sandersn May 7, 2018
072ae0d
Remove TODOs and one more cleanup
sandersn May 7, 2018
4c01063
Support parameter-less callback tags
sandersn May 7, 2018
831f44f
Remove extra bind call on template type parameters
sandersn May 8, 2018
9ec7f26
Bind template tag containers
sandersn May 8, 2018
3fed87e
Fix fourslash failures
sandersn May 9, 2018
64623f5
Stop pre-binding js type aliases
sandersn May 9, 2018
f44be81
Further cleanup of delayed js type alias binding
sandersn May 9, 2018
e59acbc
Stop prebinding template tags too
sandersn May 9, 2018
7a4ac26
Remove TODO
sandersn May 9, 2018
a073966
Merge branch 'master' into jsdoc/callback
sandersn May 11, 2018
0e13916
Fix lint
sandersn May 11, 2018
f75abe1
Merge branch 'master' into jsdoc/callback
sandersn May 16, 2018
4f61e71
Finish merge with use-jsdoc-aliases
sandersn May 16, 2018
cc011a6
Merge branch 'master' into jsdoc/callback
sandersn May 16, 2018
75d4d95
Update callback tag baselines
sandersn May 16, 2018
fcdc499
Merge branch 'master' into jsdoc/callback
sandersn May 16, 2018
4116fea
Merge branch 'master' into jsdoc/callback
sandersn May 17, 2018
3431563
Rename getTypeParametersForAliasSymbol
sandersn May 17, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 51 additions & 22 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ namespace ts {
let thisParentContainer: Node; // Container one level up
let blockScopeContainer: Node;
let lastContainer: Node;
let delayedTypedefs: { typedef: JSDocTypedefTag, container: Node, lastContainer: Node, blockScopeContainer: Node, parent: Node }[];
let delayedTypedefs: { typeAlias: JSDocTypedefTag | JSDocCallbackTag, container: Node, lastContainer: Node, blockScopeContainer: Node, parent: Node }[];
let seenThisKeyword: boolean;

// state used by control flow analysis
Expand Down Expand Up @@ -273,6 +273,7 @@ namespace ts {
return InternalSymbolName.Constructor;
case SyntaxKind.FunctionType:
case SyntaxKind.CallSignature:
case SyntaxKind.JSDocSignature:
return InternalSymbolName.Call;
case SyntaxKind.ConstructorType:
case SyntaxKind.ConstructSignature:
Expand Down Expand Up @@ -301,9 +302,6 @@ namespace ts {
const functionType = <JSDocFunctionType>node.parent;
const index = functionType.parameters.indexOf(node as ParameterDeclaration);
return "arg" + index as __String;
case SyntaxKind.JSDocTypedefTag:
const name = getNameOfJSDocTypedef(node as JSDocTypedefTag);
return typeof name !== "undefined" ? name.escapedText : undefined;
}
}

Expand Down Expand Up @@ -456,8 +454,8 @@ namespace ts {
// during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation
// and this case is specially handled. Module augmentations should only be merged with original module definition
// and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed.
if (node.kind === SyntaxKind.JSDocTypedefTag) Debug.assert(isInJavaScriptFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypedefTag(node)) {
if (isJSDocTypeAlias(node)) Debug.assert(isInJavaScriptFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypeAlias(node)) {
if (hasModifier(node, ModifierFlags.Default) && !getDeclarationName(node)) {
return declareSymbol(container.symbol.exports, container.symbol, node, symbolFlags, symbolExcludes); // No local symbol for an unnamed default!
}
Expand Down Expand Up @@ -713,7 +711,8 @@ namespace ts {
bindJSDocComment(<JSDoc>node);
break;
case SyntaxKind.JSDocTypedefTag:
bindJSDocTypedefTag(<JSDocTypedefTag>node);
case SyntaxKind.JSDocCallbackTag:
bindJSDocTypeAlias(node as JSDocTypedefTag | JSDocCallbackTag);
break;
// In source files and blocks, bind functions first to match hoisting that occurs at runtime
case SyntaxKind.SourceFile:
Expand Down Expand Up @@ -1381,13 +1380,14 @@ namespace ts {

function bindJSDocComment(node: JSDoc) {
forEachChild(node, n => {
if (n.kind !== SyntaxKind.JSDocTypedefTag) {
// Skip type-alias-related tags, which are bound early.
if (!isJSDocTypeAlias(n) && !getTypeAliasForJSDocTemplateTag(n, node.tags)) {
bind(n);
}
});
}

function bindJSDocTypedefTag(node: JSDocTypedefTag) {
function bindJSDocTypeAlias(node: JSDocTypedefTag | JSDocCallbackTag) {
forEachChild(node, n => {
// if the node has a fullName "A.B.C", that means symbol "C" was already bound
// when we visit "fullName"; so when we visit the name "C" as the next child of
Expand Down Expand Up @@ -1456,6 +1456,7 @@ namespace ts {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.CallSignature:
case SyntaxKind.JSDocSignature:
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructSignature:
Expand Down Expand Up @@ -1545,6 +1546,7 @@ namespace ts {
case SyntaxKind.ConstructorType:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.JSDocSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
Expand All @@ -1555,6 +1557,8 @@ namespace ts {
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.JSDocTypedefTag:
case SyntaxKind.JSDocCallbackTag:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.MappedType:
// All the children of these container types are never visible through another
Expand Down Expand Up @@ -1650,7 +1654,7 @@ namespace ts {
return state;
}

function bindFunctionOrConstructorType(node: SignatureDeclaration): void {
function bindFunctionOrConstructorType(node: SignatureDeclaration | JSDocSignature): void {
// For a given function symbol "<...>(...) => T" we want to generate a symbol identical
// to the one we would get for: { <...>(...): T }
//
Expand Down Expand Up @@ -1761,7 +1765,7 @@ namespace ts {
const saveParent = parent;
for (const delay of delayedTypedefs) {
({ container, lastContainer, blockScopeContainer, parent } = delay);
bindBlockScopedDeclaration(delay.typedef, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
bindBlockScopedDeclaration(delay.typeAlias, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
}
container = saveContainer;
lastContainer = saveLastContainer;
Expand Down Expand Up @@ -1946,7 +1950,7 @@ namespace ts {
// Here the current node is "foo", which is a container, but the scope of "MyType" should
// not be inside "foo". Therefore we always bind @typedef before bind the parent node,
// and skip binding this tag later when binding all the other jsdoc tags.
if (isInJavaScriptFile(node)) bindJSDocTypedefTagIfAny(node);
if (isInJavaScriptFile(node)) bindJSDocTypeAliasTagsIfAny(node);

// First we bind declaration nodes to a symbol if possible. We'll both create a symbol
// and then potentially add the symbol to an appropriate symbol table. Possible
Expand Down Expand Up @@ -1982,7 +1986,7 @@ namespace ts {
inStrictMode = saveInStrictMode;
}

function bindJSDocTypedefTagIfAny(node: Node) {
function bindJSDocTypeAliasTagsIfAny(node: Node) {
if (!hasJSDocNodes(node)) {
return;
}
Expand All @@ -1993,16 +1997,33 @@ namespace ts {
}

for (const tag of jsDoc.tags) {
if (tag.kind === SyntaxKind.JSDocTypedefTag) {
if (isJSDocTypeAlias(tag)) {
const savedParent = parent;
parent = jsDoc;
bind(tag);
parent = savedParent;
}
// Bind template tags that have a typedef or callback tag in the same comment.
// The typedef/callback tag is the container of the template.
const alias = getTypeAliasForJSDocTemplateTag(tag, jsDoc.tags);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we doing this? is not a typeAlais always introducing its own scope? at least for @property and @tempate?

if (alias) {
const savedContainer = container;
const savedParent = parent;
container = alias;
parent = jsDoc;
alias.locals = alias.locals || createSymbolTable();
bind(tag);
container = savedContainer;
parent = savedParent;
}
}
}
}

function getTypeAliasForJSDocTemplateTag(tag: Node, siblings: NodeArray<JSDocTag>) {
return isJSDocTemplateTag(tag) && find(siblings, isJSDocTypeAlias);
}

function updateStrictModeStatementList(statements: NodeArray<Statement>) {
if (!inStrictMode) {
for (const statement of statements) {
Expand Down Expand Up @@ -2036,10 +2057,10 @@ namespace ts {
// current "blockScopeContainer" needs to be set to its immediate namespace parent.
if ((<Identifier>node).isInJSDocNamespace) {
let parentNode = node.parent;
while (parentNode && parentNode.kind !== SyntaxKind.JSDocTypedefTag) {
while (parentNode && !isJSDocTypeAlias(parentNode)) {
parentNode = parentNode.parent;
}
bindBlockScopedDeclaration(<Declaration>parentNode, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
bindBlockScopedDeclaration(parentNode as Declaration, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes);
break;
}
// falls through
Expand Down Expand Up @@ -2141,8 +2162,9 @@ namespace ts {
return bindPropertyOrMethodOrAccessor(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes);
case SyntaxKind.FunctionType:
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.JSDocSignature:
case SyntaxKind.ConstructorType:
return bindFunctionOrConstructorType(<SignatureDeclaration>node);
return bindFunctionOrConstructorType(<SignatureDeclaration | JSDocSignature>node);
case SyntaxKind.TypeLiteral:
case SyntaxKind.JSDocTypeLiteral:
case SyntaxKind.MappedType:
Expand Down Expand Up @@ -2205,6 +2227,9 @@ namespace ts {
return updateStrictModeStatementList((<Block | ModuleBlock>node).statements);

case SyntaxKind.JSDocParameterTag:
if (node.parent.kind === SyntaxKind.JSDocSignature) {
return bindParameter(node as JSDocParameterTag);
}
if (node.parent.kind !== SyntaxKind.JSDocTypeLiteral) {
break;
}
Expand All @@ -2215,10 +2240,11 @@ namespace ts {
SymbolFlags.Property | SymbolFlags.Optional :
SymbolFlags.Property;
return declareSymbolAndAddToSymbolTable(propTag, flags, SymbolFlags.PropertyExcludes);
case SyntaxKind.JSDocTypedefTag: {
case SyntaxKind.JSDocTypedefTag:
case SyntaxKind.JSDocCallbackTag: {
const { fullName } = node as JSDocTypedefTag;
if (!fullName || fullName.kind === SyntaxKind.Identifier) {
(delayedTypedefs || (delayedTypedefs = [])).push({ typedef: node as JSDocTypedefTag, container, lastContainer, blockScopeContainer, parent });
(delayedTypedefs || (delayedTypedefs = [])).push({ typeAlias: node as JSDocTypedefTag | JSDocCallbackTag, container, lastContainer, blockScopeContainer, parent });
}
break;
}
Expand Down Expand Up @@ -2622,15 +2648,18 @@ namespace ts {
}
}

function bindParameter(node: ParameterDeclaration) {
function bindParameter(node: ParameterDeclaration | JSDocParameterTag) {
if (node.kind === SyntaxKind.JSDocParameterTag && container.kind !== SyntaxKind.JSDocSignature) {
return;
}
if (inStrictMode && !(node.flags & NodeFlags.Ambient)) {
// It is a SyntaxError if the identifier eval or arguments appears within a FormalParameterList of a
// strict mode FunctionLikeDeclaration or FunctionExpression(13.1)
checkStrictModeEvalOrArguments(node, node.name);
}

if (isBindingPattern(node.name)) {
bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, "__" + node.parent.parameters.indexOf(node) as __String);
bindAnonymousDeclaration(node, SymbolFlags.FunctionScopedVariable, "__" + (node as ParameterDeclaration).parent.parameters.indexOf(node as ParameterDeclaration) as __String);
}
else {
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes);
Expand Down Expand Up @@ -2701,7 +2730,7 @@ namespace ts {
}

function bindTypeParameter(node: TypeParameterDeclaration) {
if (node.parent.kind === SyntaxKind.InferType) {
if (node.parent && node.parent.kind === SyntaxKind.InferType) {
const container = getInferTypeContainer(node.parent);
if (container) {
if (!container.locals) {
Expand Down
Loading