mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #6905 from Microsoft/portJsDocFixes
Port Salsa fixes
This commit is contained in:
+14
-5
@@ -1384,7 +1384,7 @@ namespace ts {
|
||||
// Export assignment in some sort of block construct
|
||||
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node));
|
||||
}
|
||||
else if (boundExpression.kind === SyntaxKind.Identifier) {
|
||||
else if (boundExpression.kind === SyntaxKind.Identifier && node.kind === SyntaxKind.ExportAssignment) {
|
||||
// An export default clause with an identifier exports all meanings of that identifier
|
||||
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
|
||||
}
|
||||
@@ -1435,7 +1435,8 @@ namespace ts {
|
||||
// Declare a 'member' in case it turns out the container was an ES5 class
|
||||
if (container.kind === SyntaxKind.FunctionExpression || container.kind === SyntaxKind.FunctionDeclaration) {
|
||||
container.symbol.members = container.symbol.members || {};
|
||||
declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
|
||||
// It's acceptable for multiple 'this' assignments of the same identifier to occur
|
||||
declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1444,8 +1445,16 @@ namespace ts {
|
||||
|
||||
// Look up the function in the local scope, since prototype assignments should
|
||||
// follow the function declaration
|
||||
const classId = <Identifier>(<PropertyAccessExpression>(<PropertyAccessExpression>node.left).expression).expression;
|
||||
const funcSymbol = container.locals[classId.text];
|
||||
const leftSideOfAssignment = node.left as PropertyAccessExpression;
|
||||
const classPrototype = leftSideOfAssignment.expression as PropertyAccessExpression;
|
||||
const constructorFunction = classPrototype.expression as Identifier;
|
||||
|
||||
// Fix up parent pointers since we're going to use these nodes before we bind into them
|
||||
leftSideOfAssignment.parent = node;
|
||||
constructorFunction.parent = classPrototype;
|
||||
classPrototype.parent = leftSideOfAssignment;
|
||||
|
||||
const funcSymbol = container.locals[constructorFunction.text];
|
||||
if (!funcSymbol || !(funcSymbol.flags & SymbolFlags.Function)) {
|
||||
return;
|
||||
}
|
||||
@@ -1456,7 +1465,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Declare the method/property
|
||||
declareSymbol(funcSymbol.members, funcSymbol, <PropertyAccessExpression>node.left, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
|
||||
declareSymbol(funcSymbol.members, funcSymbol, leftSideOfAssignment, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
|
||||
}
|
||||
|
||||
function bindCallExpression(node: CallExpression) {
|
||||
|
||||
@@ -2845,7 +2845,7 @@ namespace ts {
|
||||
}
|
||||
// Handle module.exports = expr
|
||||
if (declaration.kind === SyntaxKind.BinaryExpression) {
|
||||
return links.type = checkExpression((<BinaryExpression>declaration).right);
|
||||
return links.type = getUnionType(map(symbol.declarations, (decl: BinaryExpression) => checkExpressionCached(decl.right)));
|
||||
}
|
||||
if (declaration.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
// Declarations only exist for property access expressions for certain
|
||||
@@ -10356,9 +10356,11 @@ namespace ts {
|
||||
|
||||
function getReturnTypeFromJSDocComment(func: SignatureDeclaration | FunctionDeclaration): Type {
|
||||
const returnTag = getJSDocReturnTag(func);
|
||||
if (returnTag) {
|
||||
if (returnTag && returnTag.typeExpression) {
|
||||
return getTypeFromTypeNode(returnTag.typeExpression.type);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function createPromiseType(promisedType: Type): Type {
|
||||
@@ -10433,7 +10435,8 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
error(func, Diagnostics.No_best_common_type_exists_among_return_expressions);
|
||||
return unknownType;
|
||||
// Defer to unioning the return types so we get a) downstream errors earlier and b) better Salsa experience
|
||||
return getUnionType(types);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4051,7 +4051,7 @@ namespace ts {
|
||||
setDecoratorContext(/*val*/ true);
|
||||
}
|
||||
|
||||
return finishNode(node);
|
||||
return addJSDocComment(finishNode(node));
|
||||
}
|
||||
|
||||
function parseOptionalIdentifier() {
|
||||
@@ -4335,13 +4335,13 @@ namespace ts {
|
||||
const labeledStatement = <LabeledStatement>createNode(SyntaxKind.LabeledStatement, fullStart);
|
||||
labeledStatement.label = <Identifier>expression;
|
||||
labeledStatement.statement = parseStatement();
|
||||
return finishNode(labeledStatement);
|
||||
return addJSDocComment(finishNode(labeledStatement));
|
||||
}
|
||||
else {
|
||||
const expressionStatement = <ExpressionStatement>createNode(SyntaxKind.ExpressionStatement, fullStart);
|
||||
expressionStatement.expression = expression;
|
||||
parseSemicolon();
|
||||
return finishNode(expressionStatement);
|
||||
return addJSDocComment(finishNode(expressionStatement));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4778,7 +4778,7 @@ namespace ts {
|
||||
parseExpected(SyntaxKind.ConstructorKeyword);
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node);
|
||||
node.body = parseFunctionBlockOrSemicolon(/*isGenerator*/ false, /*isAsync*/ false, Diagnostics.or_expected);
|
||||
return finishNode(node);
|
||||
return addJSDocComment(finishNode(node));
|
||||
}
|
||||
|
||||
function parseMethodDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray, asteriskToken: Node, name: PropertyName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration {
|
||||
@@ -4792,7 +4792,7 @@ namespace ts {
|
||||
const isAsync = !!(method.flags & NodeFlags.Async);
|
||||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, method);
|
||||
method.body = parseFunctionBlockOrSemicolon(isGenerator, isAsync, diagnosticMessage);
|
||||
return finishNode(method);
|
||||
return addJSDocComment(finishNode(method));
|
||||
}
|
||||
|
||||
function parsePropertyDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray, name: PropertyName, questionToken: Node): ClassElement {
|
||||
|
||||
@@ -1207,7 +1207,19 @@ namespace ts {
|
||||
node.parent.parent.parent.kind === SyntaxKind.VariableStatement;
|
||||
|
||||
const variableStatementNode = isInitializerOfVariableDeclarationInStatement ? node.parent.parent.parent : undefined;
|
||||
return variableStatementNode && variableStatementNode.jsDocComment;
|
||||
if (variableStatementNode) {
|
||||
return variableStatementNode.jsDocComment;
|
||||
}
|
||||
|
||||
// Also recognize when the node is the RHS of an assignment expression
|
||||
const isSourceOfAssignmentExpressionStatement =
|
||||
node.parent && node.parent.parent &&
|
||||
node.parent.kind === SyntaxKind.BinaryExpression &&
|
||||
(node.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
|
||||
node.parent.parent.kind === SyntaxKind.ExpressionStatement;
|
||||
if (isSourceOfAssignmentExpressionStatement) {
|
||||
return node.parent.parent.jsDocComment;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
+14
-11
@@ -62,7 +62,7 @@ namespace ts {
|
||||
export interface SourceFile {
|
||||
/* @internal */ version: string;
|
||||
/* @internal */ scriptSnapshot: IScriptSnapshot;
|
||||
/* @internal */ nameTable: Map<string>;
|
||||
/* @internal */ nameTable: Map<number>;
|
||||
|
||||
/* @internal */ getNamedDeclarations(): Map<Declaration[]>;
|
||||
|
||||
@@ -808,7 +808,7 @@ namespace ts {
|
||||
public languageVersion: ScriptTarget;
|
||||
public languageVariant: LanguageVariant;
|
||||
public identifiers: Map<string>;
|
||||
public nameTable: Map<string>;
|
||||
public nameTable: Map<number>;
|
||||
public resolvedModules: Map<ResolvedModule>;
|
||||
public imports: LiteralExpression[];
|
||||
public moduleAugmentations: LiteralExpression[];
|
||||
@@ -1957,8 +1957,6 @@ namespace ts {
|
||||
const text = scriptSnapshot.getText(0, scriptSnapshot.getLength());
|
||||
const sourceFile = createSourceFile(fileName, text, scriptTarget, setNodeParents);
|
||||
setSourceFileFields(sourceFile, scriptSnapshot, version);
|
||||
// after full parsing we can use table with interned strings as name table
|
||||
sourceFile.nameTable = sourceFile.identifiers;
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
@@ -3834,7 +3832,7 @@ namespace ts {
|
||||
|
||||
if (isRightOfDot && isSourceFileJavaScript(sourceFile)) {
|
||||
const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries);
|
||||
addRange(entries, getJavaScriptCompletionEntries(sourceFile, uniqueNames));
|
||||
addRange(entries, getJavaScriptCompletionEntries(sourceFile, location.pos, uniqueNames));
|
||||
}
|
||||
else {
|
||||
if (!symbols || symbols.length === 0) {
|
||||
@@ -3867,12 +3865,17 @@ namespace ts {
|
||||
|
||||
return { isMemberCompletion, isNewIdentifierLocation, entries };
|
||||
|
||||
function getJavaScriptCompletionEntries(sourceFile: SourceFile, uniqueNames: Map<string>): CompletionEntry[] {
|
||||
function getJavaScriptCompletionEntries(sourceFile: SourceFile, position: number, uniqueNames: Map<string>): CompletionEntry[] {
|
||||
const entries: CompletionEntry[] = [];
|
||||
const target = program.getCompilerOptions().target;
|
||||
|
||||
const nameTable = getNameTable(sourceFile);
|
||||
for (const name in nameTable) {
|
||||
// Skip identifiers produced only from the current location
|
||||
if (nameTable[name] === position) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!uniqueNames[name]) {
|
||||
uniqueNames[name] = name;
|
||||
const displayName = getCompletionEntryDisplayName(name, target, /*performCharacterChecks*/ true);
|
||||
@@ -5487,7 +5490,7 @@ namespace ts {
|
||||
|
||||
const nameTable = getNameTable(sourceFile);
|
||||
|
||||
if (lookUp(nameTable, internedName)) {
|
||||
if (lookUp(nameTable, internedName) !== undefined) {
|
||||
result = result || [];
|
||||
getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex);
|
||||
}
|
||||
@@ -7525,7 +7528,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getNameTable(sourceFile: SourceFile): Map<string> {
|
||||
export function getNameTable(sourceFile: SourceFile): Map<number> {
|
||||
if (!sourceFile.nameTable) {
|
||||
initializeNameTable(sourceFile);
|
||||
}
|
||||
@@ -7534,7 +7537,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function initializeNameTable(sourceFile: SourceFile): void {
|
||||
const nameTable: Map<string> = {};
|
||||
const nameTable: Map<number> = {};
|
||||
|
||||
walk(sourceFile);
|
||||
sourceFile.nameTable = nameTable;
|
||||
@@ -7542,7 +7545,7 @@ namespace ts {
|
||||
function walk(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
nameTable[(<Identifier>node).text] = (<Identifier>node).text;
|
||||
nameTable[(<Identifier>node).text] = nameTable[(<Identifier>node).text] === undefined ? node.pos : -1;
|
||||
break;
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
@@ -7554,7 +7557,7 @@ namespace ts {
|
||||
node.parent.kind === SyntaxKind.ExternalModuleReference ||
|
||||
isArgumentOfElementAccessExpression(node)) {
|
||||
|
||||
nameTable[(<LiteralExpression>node).text] = (<LiteralExpression>node).text;
|
||||
nameTable[(<LiteralExpression>node).text] = nameTable[(<LiteralExpression>node).text] === undefined ? node.pos : -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: file.js
|
||||
//// "use strict";
|
||||
////
|
||||
//// class Something {
|
||||
////
|
||||
//// /**
|
||||
//// * @param {number} a
|
||||
//// */
|
||||
//// constructor(a, b) {
|
||||
//// a/*body*/
|
||||
//// }
|
||||
////
|
||||
//// /**
|
||||
//// * @param {number} a
|
||||
//// */
|
||||
//// method(a) {
|
||||
//// a/*method*/
|
||||
//// }
|
||||
//// }
|
||||
//// let x = new Something(/*sig*/);
|
||||
|
||||
goTo.marker('body');
|
||||
edit.insert('.');
|
||||
verify.completionListContains('toFixed', undefined, undefined, 'method');
|
||||
edit.backspace();
|
||||
|
||||
goTo.marker('sig');
|
||||
verify.currentSignatureHelpIs('Something(a: number, b: any): Something');
|
||||
|
||||
goTo.marker('method');
|
||||
edit.insert('.');
|
||||
verify.completionListContains('toFixed', undefined, undefined, 'method');
|
||||
@@ -0,0 +1,21 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: file.js
|
||||
//// /**
|
||||
//// * @param {number} a
|
||||
//// * @param {string} b
|
||||
//// */
|
||||
//// exports.foo = function(a, b) {
|
||||
//// a/*a*/;
|
||||
//// b/*b*/
|
||||
//// };
|
||||
|
||||
goTo.marker('a');
|
||||
edit.insert('.');
|
||||
verify.completionListContains('toFixed', undefined, undefined, 'method');
|
||||
|
||||
|
||||
goTo.marker('b');
|
||||
edit.insert('.');
|
||||
verify.completionListContains('substr', undefined, undefined, 'method');
|
||||
@@ -0,0 +1,25 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: file.js
|
||||
//// function fn() {
|
||||
//// if (foo) {
|
||||
//// return 0;
|
||||
//// } else {
|
||||
//// return '0';
|
||||
//// }
|
||||
//// }
|
||||
//// let x = fn();
|
||||
//// if(typeof x === 'string') {
|
||||
//// x/*str*/
|
||||
//// } else {
|
||||
//// x/*num*/
|
||||
//// }
|
||||
|
||||
goTo.marker('str');
|
||||
edit.insert('.');
|
||||
verify.completionListContains('substr', undefined, undefined, 'method');
|
||||
|
||||
goTo.marker('num');
|
||||
edit.insert('.');
|
||||
verify.completionListContains('toFixed', undefined, undefined, 'method');
|
||||
@@ -0,0 +1,21 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: file.js
|
||||
//// /**
|
||||
//// * A person
|
||||
//// * @constructor
|
||||
//// * @param {string} name - The name of the person.
|
||||
//// * @param {number} age - The age of the person.
|
||||
//// */
|
||||
//// function Person(name, age) {
|
||||
//// this.name = name;
|
||||
//// this.age = age;
|
||||
//// }
|
||||
////
|
||||
////
|
||||
//// Person.getName = 10;
|
||||
//// Person.getNa/**/ = 10;
|
||||
|
||||
goTo.marker();
|
||||
verify.not.memberListContains('getNa');
|
||||
@@ -0,0 +1,20 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @allowNonTsExtensions: true
|
||||
// @Filename: file.js
|
||||
//// /**
|
||||
//// * This is a very cool function that is very nice.
|
||||
//// * @returns something
|
||||
//// * @param p anotherthing
|
||||
//// */
|
||||
//// function a1(p) {
|
||||
//// try {
|
||||
//// throw new Error('x');
|
||||
//// } catch (x) { x--; }
|
||||
//// return 23;
|
||||
//// }
|
||||
////
|
||||
//// x - /**/a1()
|
||||
|
||||
goTo.marker();
|
||||
verify.quickInfoExists();
|
||||
@@ -0,0 +1,14 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @allowJs: true
|
||||
// @Filename: a.js
|
||||
//// function Person(age) {
|
||||
//// if (age >= 18) {
|
||||
//// this.canVote = true;
|
||||
//// } else {
|
||||
//// this.canVote = false;
|
||||
//// }
|
||||
//// }
|
||||
|
||||
verify.getSyntacticDiagnostics(`[]`);
|
||||
verify.getSemanticDiagnostics(`[]`);
|
||||
@@ -0,0 +1,16 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @allowJs: true
|
||||
// @Filename: a.js
|
||||
//// function Person(age) {
|
||||
//// if (age >= 18) {
|
||||
//// this.canVote = true;
|
||||
//// } else {
|
||||
//// this.canVote = 23;
|
||||
//// }
|
||||
//// }
|
||||
//// let x = new Person(100);
|
||||
//// x.canVote/**/;
|
||||
|
||||
goTo.marker();
|
||||
verify.quickInfoIs('(property) Person.canVote: boolean | number');
|
||||
@@ -23,4 +23,6 @@ verify.completionListContains('y');
|
||||
verify.not.completionListContains('invisible');
|
||||
|
||||
edit.insert('x.');
|
||||
verify.completionListContains('a');
|
||||
verify.memberListContains('a', undefined, undefined, 'property');
|
||||
edit.insert('a.');
|
||||
verify.memberListContains('toFixed', undefined, undefined, 'method');
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
///<reference path="fourslash.ts" />
|
||||
|
||||
// Assignments to 'module.exports' create an external module
|
||||
|
||||
// @allowJs: true
|
||||
// @Filename: myMod.js
|
||||
//// var x = { a: 10 };
|
||||
//// module.exports = x;
|
||||
|
||||
// @Filename: isGlobal.js
|
||||
//// var y = 10;
|
||||
|
||||
// @Filename: consumer.js
|
||||
//// var x = require('myMod');
|
||||
//// /**/;
|
||||
|
||||
goTo.file('consumer.js');
|
||||
goTo.marker();
|
||||
|
||||
verify.completionListContains('y');
|
||||
verify.not.completionListContains('invisible');
|
||||
|
||||
edit.insert('x.');
|
||||
verify.memberListContains('a', undefined, undefined, 'property');
|
||||
edit.insert('a.');
|
||||
verify.memberListContains('toFixed', undefined, undefined, 'method');
|
||||
Reference in New Issue
Block a user