Merge branch 'master' into literalTypes

# Conflicts:
#	src/compiler/checker.ts
This commit is contained in:
Anders Hejlsberg
2016-07-24 07:28:11 -07:00
306 changed files with 4481 additions and 3322 deletions

View File

@@ -26,7 +26,8 @@ namespace ts.formatting {
RescanGreaterThanToken,
RescanSlashToken,
RescanTemplateToken,
RescanJsxIdentifier
RescanJsxIdentifier,
RescanJsxText,
}
export function getFormattingScanner(sourceFile: SourceFile, startPos: number, endPos: number): FormattingScanner {
@@ -140,6 +141,10 @@ namespace ts.formatting {
return false;
}
function shouldRescanJsxText(node: Node): boolean {
return node && node.kind === SyntaxKind.JsxText;
}
function shouldRescanSlashToken(container: Node): boolean {
return container.kind === SyntaxKind.RegularExpressionLiteral;
}
@@ -176,6 +181,8 @@ namespace ts.formatting {
? ScanAction.RescanTemplateToken
: shouldRescanJsxIdentifier(n)
? ScanAction.RescanJsxIdentifier
: shouldRescanJsxText(n)
? ScanAction.RescanJsxText
: ScanAction.Scan;
if (lastTokenInfo && expectedScanAction === lastScanAction) {
@@ -215,6 +222,10 @@ namespace ts.formatting {
currentToken = scanner.scanJsxIdentifier();
lastScanAction = ScanAction.RescanJsxIdentifier;
}
else if (expectedScanAction === ScanAction.RescanJsxText) {
currentToken = scanner.reScanJsxToken();
lastScanAction = ScanAction.RescanJsxText;
}
else {
lastScanAction = ScanAction.Scan;
}

View File

@@ -514,16 +514,6 @@ namespace ts {
return str === str.toLowerCase();
}
function startsWith(string: string, search: string) {
for (let i = 0, n = search.length; i < n; i++) {
if (string.charCodeAt(i) !== search.charCodeAt(i)) {
return false;
}
}
return true;
}
// Assumes 'value' is already lowercase.
function indexOfIgnoringCase(string: string, value: string): number {
for (let i = 0, n = string.length - value.length; i <= n; i++) {

View File

@@ -94,7 +94,7 @@ namespace ts {
* change range cannot be determined. However, in that case, incremental parsing will
* not happen and the entire document will be re - parsed.
*/
getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange;
getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange | undefined;
/** Releases all resources held by this script snapshot */
dispose?(): void;
@@ -180,9 +180,10 @@ namespace ts {
];
let jsDocCompletionEntries: CompletionEntry[];
function createNode(kind: SyntaxKind, pos: number, end: number, flags: NodeFlags, parent?: Node): NodeObject {
const node = new NodeObject(kind, pos, end);
node.flags = flags;
function createNode(kind: SyntaxKind, pos: number, end: number, parent?: Node): NodeObject | TokenObject | IdentifierObject {
const node = kind >= SyntaxKind.FirstNode ? new NodeObject(kind, pos, end) :
kind === SyntaxKind.Identifier ? new IdentifierObject(kind, pos, end) :
new TokenObject(kind, pos, end);
node.parent = parent;
return node;
}
@@ -197,11 +198,11 @@ namespace ts {
private _children: Node[];
constructor(kind: SyntaxKind, pos: number, end: number) {
this.kind = kind;
this.pos = pos;
this.end = end;
this.flags = NodeFlags.None;
this.parent = undefined;
this.kind = kind;
}
public getSourceFile(): SourceFile {
@@ -246,7 +247,7 @@ namespace ts {
const token = useJSDocScanner ? scanner.scanJSDocToken() : scanner.scan();
const textPos = scanner.getTextPos();
if (textPos <= end) {
nodes.push(createNode(token, pos, textPos, 0, this));
nodes.push(createNode(token, pos, textPos, this));
}
pos = textPos;
}
@@ -254,7 +255,7 @@ namespace ts {
}
private createSyntaxList(nodes: NodeArray<Node>): Node {
const list = createNode(SyntaxKind.SyntaxList, nodes.pos, nodes.end, 0, this);
const list = <NodeObject>createNode(SyntaxKind.SyntaxList, nodes.pos, nodes.end, this);
list._children = [];
let pos = nodes.pos;
@@ -345,6 +346,95 @@ namespace ts {
}
}
class TokenOrIdentifierObject implements Token {
public kind: SyntaxKind;
public pos: number;
public end: number;
public flags: NodeFlags;
public parent: Node;
public jsDocComments: JSDocComment[];
public __tokenTag: any;
constructor(pos: number, end: number) {
// Set properties in same order as NodeObject
this.pos = pos;
this.end = end;
this.flags = NodeFlags.None;
this.parent = undefined;
}
public getSourceFile(): SourceFile {
return getSourceFileOfNode(this);
}
public getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number {
return getTokenPosOfNode(this, sourceFile, includeJsDocComment);
}
public getFullStart(): number {
return this.pos;
}
public getEnd(): number {
return this.end;
}
public getWidth(sourceFile?: SourceFile): number {
return this.getEnd() - this.getStart(sourceFile);
}
public getFullWidth(): number {
return this.end - this.pos;
}
public getLeadingTriviaWidth(sourceFile?: SourceFile): number {
return this.getStart(sourceFile) - this.pos;
}
public getFullText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end);
}
public getText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd());
}
public getChildCount(sourceFile?: SourceFile): number {
return 0;
}
public getChildAt(index: number, sourceFile?: SourceFile): Node {
return undefined;
}
public getChildren(sourceFile?: SourceFile): Node[] {
return emptyArray;
}
public getFirstToken(sourceFile?: SourceFile): Node {
return undefined;
}
public getLastToken(sourceFile?: SourceFile): Node {
return undefined;
}
}
class TokenObject extends TokenOrIdentifierObject {
public kind: SyntaxKind;
constructor(kind: SyntaxKind, pos: number, end: number) {
super(pos, end);
this.kind = kind;
}
}
class IdentifierObject extends TokenOrIdentifierObject {
constructor(kind: SyntaxKind, pos: number, end: number) {
super(pos, end);
}
}
IdentifierObject.prototype.kind = SyntaxKind.Identifier;
class SymbolObject implements Symbol {
flags: SymbolFlags;
name: string;
@@ -3259,14 +3349,14 @@ namespace ts {
let isJsDocTagName = false;
let start = new Date().getTime();
let start = timestamp();
const currentToken = getTokenAtPosition(sourceFile, position);
log("getCompletionData: Get current token: " + (new Date().getTime() - start));
log("getCompletionData: Get current token: " + (timestamp() - start));
start = new Date().getTime();
start = timestamp();
// Completion not allowed inside comments, bail out if this is the case
const insideComment = isInsideComment(sourceFile, currentToken, position);
log("getCompletionData: Is inside comment: " + (new Date().getTime() - start));
log("getCompletionData: Is inside comment: " + (timestamp() - start));
if (insideComment) {
// The current position is next to the '@' sign, when no tag name being provided yet.
@@ -3309,9 +3399,9 @@ namespace ts {
}
}
start = new Date().getTime();
start = timestamp();
const previousToken = findPrecedingToken(position, sourceFile);
log("getCompletionData: Get previous token 1: " + (new Date().getTime() - start));
log("getCompletionData: Get previous token 1: " + (timestamp() - start));
// The decision to provide completion depends on the contextToken, which is determined through the previousToken.
// Note: 'previousToken' (and thus 'contextToken') can be undefined if we are the beginning of the file
@@ -3320,9 +3410,9 @@ namespace ts {
// Check if the caret is at the end of an identifier; this is a partial identifier that we want to complete: e.g. a.toS|
// Skip this partial identifier and adjust the contextToken to the token that precedes it.
if (contextToken && position <= contextToken.end && isWord(contextToken.kind)) {
const start = new Date().getTime();
const start = timestamp();
contextToken = findPrecedingToken(contextToken.getFullStart(), sourceFile);
log("getCompletionData: Get previous token 2: " + (new Date().getTime() - start));
log("getCompletionData: Get previous token 2: " + (timestamp() - start));
}
// Find the node where completion is requested on.
@@ -3369,7 +3459,7 @@ namespace ts {
}
}
const semanticStart = new Date().getTime();
const semanticStart = timestamp();
let isMemberCompletion: boolean;
let isNewIdentifierLocation: boolean;
let symbols: Symbol[] = [];
@@ -3407,7 +3497,7 @@ namespace ts {
}
}
log("getCompletionData: Semantic work: " + (new Date().getTime() - semanticStart));
log("getCompletionData: Semantic work: " + (timestamp() - semanticStart));
return { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), isJsDocTagName };
@@ -3551,12 +3641,12 @@ namespace ts {
}
function isCompletionListBlocker(contextToken: Node): boolean {
const start = new Date().getTime();
const start = timestamp();
const result = isInStringOrRegularExpressionOrTemplateLiteral(contextToken) ||
isSolelyIdentifierDefinitionLocation(contextToken) ||
isDotOfNumericLiteral(contextToken) ||
isInJsxText(contextToken);
log("getCompletionsAtPosition: isCompletionListBlocker: " + (new Date().getTime() - start));
log("getCompletionsAtPosition: isCompletionListBlocker: " + (timestamp() - start));
return result;
}
@@ -4205,10 +4295,11 @@ namespace ts {
kindModifiers: getSymbolModifiers(symbol),
sortText: "0",
};
}
function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Map<string> {
const start = new Date().getTime();
const start = timestamp();
const uniqueNames: Map<string> = {};
if (symbols) {
for (const symbol of symbols) {
@@ -4223,7 +4314,7 @@ namespace ts {
}
}
log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (new Date().getTime() - start));
log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (timestamp() - start));
return uniqueNames;
}
@@ -4233,22 +4324,58 @@ namespace ts {
return undefined;
}
const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile);
if (argumentInfo) {
// Get string literal completions from specialized signatures of the target
return getStringLiteralCompletionEntriesFromCallExpression(argumentInfo);
if (node.parent.kind === SyntaxKind.PropertyAssignment && node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression) {
// Get quoted name of properties of the object literal expression
// i.e. interface ConfigFiles {
// 'jspm:dev': string
// }
// let files: ConfigFiles = {
// '/*completion position*/'
// }
//
// function foo(c: ConfigFiles) {}
// foo({
// '/*completion position*/'
// });
return getStringLiteralCompletionEntriesFromPropertyAssignment(<ObjectLiteralElement>node.parent);
}
else if (isElementAccessExpression(node.parent) && node.parent.argumentExpression === node) {
// Get all names of properties on the expression
// i.e. interface A {
// 'prop1': string
// }
// let a: A;
// a['/*completion position*/']
return getStringLiteralCompletionEntriesFromElementAccess(node.parent);
}
else {
// Otherwise, get the completions from the contextual type if one exists
const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile);
if (argumentInfo) {
// Get string literal completions from specialized signatures of the target
// i.e. declare function f(a: 'A');
// f("/*completion position*/")
return getStringLiteralCompletionEntriesFromCallExpression(argumentInfo, node);
}
// Get completion for string literal from string literal type
// i.e. var x: "hi" | "hello" = "/*completion position*/"
return getStringLiteralCompletionEntriesFromContextualType(<StringLiteral>node);
}
}
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo) {
function getStringLiteralCompletionEntriesFromPropertyAssignment(element: ObjectLiteralElement) {
const typeChecker = program.getTypeChecker();
const type = typeChecker.getContextualType((<ObjectLiteralExpression>element.parent));
const entries: CompletionEntry[] = [];
if (type) {
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, element, /*performCharacterChecks*/false);
if (entries.length) {
return { isMemberCompletion: true, isNewIdentifierLocation: true, entries };
}
}
}
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo, location: Node) {
const typeChecker = program.getTypeChecker();
const candidates: Signature[] = [];
const entries: CompletionEntry[] = [];
@@ -7643,14 +7770,14 @@ namespace ts {
}
function getIndentationAtPosition(fileName: string, position: number, editorOptions: EditorOptions) {
let start = new Date().getTime();
let start = timestamp();
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
log("getIndentationAtPosition: getCurrentSourceFile: " + (new Date().getTime() - start));
log("getIndentationAtPosition: getCurrentSourceFile: " + (timestamp() - start));
start = new Date().getTime();
start = timestamp();
const result = formatting.SmartIndenter.getIndentation(position, sourceFile, editorOptions);
log("getIndentationAtPosition: computeIndentation : " + (new Date().getTime() - start));
log("getIndentationAtPosition: computeIndentation : " + (timestamp() - start));
return result;
}
@@ -8691,6 +8818,8 @@ namespace ts {
function initializeServices() {
objectAllocator = {
getNodeConstructor: () => NodeObject,
getTokenConstructor: () => TokenObject,
getIdentifierConstructor: () => IdentifierObject,
getSourceFileConstructor: () => SourceFileObject,
getSymbolConstructor: () => SymbolObject,
getTypeConstructor: () => TypeObject,

View File

@@ -16,7 +16,7 @@
/// <reference path='services.ts' />
/* @internal */
let debugObjectHost = (<any>this);
let debugObjectHost = new Function("return this")();
// We need to use 'null' to interface with the managed side.
/* tslint:disable:no-null-keyword */
@@ -61,7 +61,7 @@ namespace ts {
getLocalizedDiagnosticMessages(): string;
getCancellationToken(): HostCancellationToken;
getCurrentDirectory(): string;
getDirectories(path: string): string[];
getDirectories(path: string): string;
getDefaultLibFileName(options: string): string;
getNewLine?(): string;
getProjectVersion?(): string;
@@ -404,7 +404,7 @@ namespace ts {
}
public getDirectories(path: string): string[] {
return this.shimHost.getDirectories(path);
return JSON.parse(this.shimHost.getDirectories(path));
}
public getDefaultLibFileName(options: CompilerOptions): string {
@@ -423,7 +423,7 @@ namespace ts {
}
public isCancellationRequested(): boolean {
const time = Date.now();
const time = timestamp();
const duration = Math.abs(time - this.lastCancellationCheckTime);
if (duration > 10) {
// Check no more than once every 10 ms.
@@ -498,13 +498,13 @@ namespace ts {
let start: number;
if (logPerformance) {
logger.log(actionDescription);
start = Date.now();
start = timestamp();
}
const result = action();
if (logPerformance) {
const end = Date.now();
const end = timestamp();
logger.log(`${actionDescription} completed in ${end - start} msec`);
if (typeof result === "string") {
let str = result;

View File

@@ -1,8 +1,10 @@
{
"compilerOptions": {
"noImplicitAny": true,
"noImplicitThis": true,
"removeComments": false,
"preserveConstEnums": true,
"pretty": true,
"outFile": "../../built/local/typescriptServices.js",
"sourceMap": true,
"stripInternal": true,
@@ -11,6 +13,7 @@
},
"files": [
"../compiler/core.ts",
"../compiler/performance.ts",
"../compiler/sys.ts",
"../compiler/types.ts",
"../compiler/scanner.ts",