Initial entrypoint in SourceFile for the LS to call to peform incremental parsing.

Right now the entrypoint just causes a full parse to happen.  But the LS code is
cleaned up to take advantage of it appropriately.
This commit is contained in:
Cyrus Najmabadi 2014-12-10 11:45:33 -08:00
parent aea499e572
commit 5bd49fec1d
14 changed files with 202 additions and 155 deletions

View File

@ -1034,10 +1034,13 @@ module ts {
export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false): SourceFile {
var parsingContext: ParsingContext;
var identifiers: Map<string> = {};
var identifiers: Map<string>;
var identifierCount = 0;
var nodeCount = 0;
var lineStarts: number[];
var syntacticDiagnostics: Diagnostic[];
var scanner: Scanner;
var token: SyntaxKind;
// Flags that dictate what parsing context we're in. For example:
// Whether or not we are in strict parsing mode. All that changes in strict parsing mode is
@ -1085,7 +1088,7 @@ module ts {
// Note: it should not be necessary to save/restore these flags during speculative/lookahead
// parsing. These context flags are naturally stored and restored through normal recursive
// descent parsing and unwinding.
var contextFlags: ParserContextFlags = 0;
var contextFlags: ParserContextFlags;
// Whether or not we've had a parse error since creating the last AST node. If we have
// encountered an error, it will be stored on the next AST node we create. Parse errors
@ -1114,48 +1117,69 @@ module ts {
//
// Note: any errors at the end of the file that do not precede a regular node, should get
// attached to the EOF token.
var parseErrorBeforeNextFinishedNode = false;
var parseErrorBeforeNextFinishedNode: boolean;
var sourceFile = <SourceFile>createNode(SyntaxKind.SourceFile, 0);
if (fileExtensionIs(filename, ".d.ts")) {
sourceFile.flags = NodeFlags.DeclarationFile;
}
sourceFile.end = sourceText.length;
sourceFile.filename = normalizePath(filename);
sourceFile.text = sourceText;
var sourceFile: SourceFile;
sourceFile.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition;
sourceFile.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter;
sourceFile.getLineStarts = getLineStarts;
sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics;
return parseSourceFile(sourceText, /*textChangeRange:*/ undefined, setParentNodes);
sourceFile.referenceDiagnostics = [];
sourceFile.parseDiagnostics = [];
sourceFile.grammarDiagnostics = [];
sourceFile.semanticDiagnostics = [];
function parseSourceFile(text: string, textChangeRange: TextChangeRange, setParentNodes: boolean): SourceFile {
// Set our initial state before parsing.
sourceText = text;
parsingContext = 0;
identifiers = {};
lineStarts = undefined;
syntacticDiagnostics = undefined;
contextFlags = 0;
parseErrorBeforeNextFinishedNode = false;
processReferenceComments();
sourceFile = <SourceFile>createNode(SyntaxKind.SourceFile, 0);
sourceFile.referenceDiagnostics = [];
sourceFile.parseDiagnostics = [];
sourceFile.grammarDiagnostics = [];
sourceFile.semanticDiagnostics = [];
// Create and prime the scanner before parsing the source elements.
var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError);
var token = nextToken();
// Create and prime the scanner before parsing the source elements.
scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError);
token = nextToken();
sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement);
Debug.assert(token === SyntaxKind.EndOfFileToken);
sourceFile.endOfFileToken = parseTokenNode();
sourceFile.flags = fileExtensionIs(filename, ".d.ts") ? NodeFlags.DeclarationFile : 0;
sourceFile.end = sourceText.length;
sourceFile.filename = normalizePath(filename);
sourceFile.text = sourceText;
sourceFile.externalModuleIndicator = getExternalModuleIndicator();
sourceFile.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition;
sourceFile.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter;
sourceFile.getLineStarts = getLineStarts;
sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics;
sourceFile.update = update;
sourceFile.nodeCount = nodeCount;
sourceFile.identifierCount = identifierCount;
sourceFile.languageVersion = languageVersion;
sourceFile.identifiers = identifiers;
processReferenceComments(sourceFile);
if (setParentNodes) {
fixupParentReferences(sourceFile);
sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement);
Debug.assert(token === SyntaxKind.EndOfFileToken);
sourceFile.endOfFileToken = parseTokenNode();
setExternalModuleIndicator(sourceFile);
sourceFile.nodeCount = nodeCount;
sourceFile.identifierCount = identifierCount;
sourceFile.languageVersion = languageVersion;
sourceFile.identifiers = identifiers;
if (setParentNodes) {
fixupParentReferences(sourceFile);
}
return sourceFile;
}
function update(newText: string, textChangeRange: TextChangeRange) {
// Don't pass along the text change range for now. We'll pass it along once incremental
// parsing is enabled.
return parseSourceFile(newText, /*textChangeRange:*/ undefined, /*setNodeParents*/ true);
}
return sourceFile;
function setContextFlag(val: Boolean, flag: ParserContextFlags) {
if (val) {
@ -4467,7 +4491,7 @@ module ts {
: parseStatement();
}
function processReferenceComments(): void {
function processReferenceComments(sourceFile: SourceFile): void {
var triviaScanner = createScanner(languageVersion, /*skipTrivia*/false, sourceText);
var referencedFiles: FileReference[] = [];
var amdDependencies: string[] = [];
@ -4523,16 +4547,15 @@ module ts {
sourceFile.amdModuleName = amdModuleName;
}
function getExternalModuleIndicator() {
return forEach(sourceFile.statements, node =>
function setExternalModuleIndicator(sourceFile: SourceFile) {
sourceFile.externalModuleIndicator = forEach(sourceFile.statements, node =>
node.flags & NodeFlags.Export
|| node.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference
|| node.kind === SyntaxKind.ExportAssignment
? node
: undefined);
? node
: undefined);
}
var syntacticDiagnostics: Diagnostic[];
function getSyntacticDiagnostics() {
if (syntacticDiagnostics === undefined) {
if (sourceFile.parseDiagnostics.length > 0) {

View File

@ -866,9 +866,20 @@ module ts {
filename: string;
text: string;
getLineAndCharacterFromPosition(position: number): LineAndCharacter;
getPositionFromLineAndCharacter(line: number, character: number): number;
getLineStarts(): number[];
// Updates this source file to represent the 'newText' passed in. The 'textChangeRange'
// parameter indicates what changed between the 'text' that this SourceFile has and the
// 'newText'.
//
// Note: this function mutates nodes from this SourceFile. That means any existing nodes
// from this SourceFile that are being held onto may change as a result (including
// becoming detached from any SourceFile).
update(newText: string, textChangeRange: TextChangeRange): SourceFile;
amdDependencies: string[];
amdModuleName: string;
referencedFiles: FileReference[];
@ -1435,7 +1446,6 @@ module ts {
character: number;
}
export const enum ScriptTarget {
ES3,
ES5,
@ -1607,4 +1617,26 @@ module ts {
useCaseSensitiveFileNames(): boolean;
getNewLine(): string;
}
export interface TextChangeRange {
span(): TextSpan;
newLength(): number;
newSpan(): TextSpan;
isUnchanged(): boolean;
}
export interface TextSpan {
start(): number;
length(): number;
end(): number;
isEmpty(): boolean;
containsPosition(position: number): boolean;
containsTextSpan(span: TextSpan): boolean;
overlapsWith(span: TextSpan): boolean;
overlap(span: TextSpan): TextSpan;
intersectsWithTextSpan(span: TextSpan): boolean;
intersectsWith(start: number, length: number): boolean;
intersectsWithPosition(position: number): boolean;
intersection(span: TextSpan): TextSpan;
}
}

View File

@ -1755,14 +1755,14 @@ module FourSlash {
public verifySemanticClassifications(expected: { classificationType: string; text: string }[]) {
var actual = this.languageService.getSemanticClassifications(this.activeFile.fileName,
new ts.TextSpan(0, this.activeFile.content.length));
new ts.TextSpanObject(0, this.activeFile.content.length));
this.verifyClassifications(expected, actual);
}
public verifySyntacticClassifications(expected: { classificationType: string; text: string }[]) {
var actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName,
new ts.TextSpan(0, this.activeFile.content.length));
new ts.TextSpanObject(0, this.activeFile.content.length));
this.verifyClassifications(expected, actual);
}
@ -1796,7 +1796,7 @@ module FourSlash {
for (var i = 0; i < spans.length; i++) {
var expectedSpan = spans[i];
var actualComment = actual[i];
var actualCommentSpan = new ts.TextSpan(actualComment.position, actualComment.message.length);
var actualCommentSpan = new ts.TextSpanObject(actualComment.position, actualComment.message.length);
if (expectedSpan.start !== actualCommentSpan.start() || expectedSpan.end !== actualCommentSpan.end()) {
this.raiseError('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start() + ',' + actualCommentSpan.end() + ')');

View File

@ -32,8 +32,8 @@ module Harness.LanguageService {
// Store edit range + new length of script
this.editRanges.push({
length: this.content.length,
textChangeRange: new ts.TextChangeRange(
ts.TextSpan.fromBounds(minChar, limChar), newText.length)
textChangeRange: new ts.TextChangeRangeObject(
ts.TextSpanObject.fromBounds(minChar, limChar), newText.length)
});
// Update version #
@ -43,14 +43,14 @@ module Harness.LanguageService {
public getTextChangeRangeBetweenVersions(startVersion: number, endVersion: number): ts.TextChangeRange {
if (startVersion === endVersion) {
// No edits!
return ts.TextChangeRange.unchanged;
return ts.TextChangeRangeObject.unchanged;
}
var initialEditRangeIndex = this.editRanges.length - (this.version - startVersion);
var lastEditRangeIndex = this.editRanges.length - (this.version - endVersion);
var entries = this.editRanges.slice(initialEditRangeIndex, lastEditRangeIndex);
return ts.TextChangeRange.collapseChangesAcrossMultipleVersions(entries.map(e => e.textChangeRange));
return ts.TextChangeRangeObject.collapseChangesAcrossMultipleVersions(entries.map(e => e.textChangeRange));
}
}
@ -126,7 +126,7 @@ module Harness.LanguageService {
isOpen: boolean,
textChangeRange: ts.TextChangeRange
): ts.SourceFile {
return document.update(scriptSnapshot, version, isOpen, textChangeRange);
return ts.updateLanguageServiceSourceFile(document, scriptSnapshot, version, isOpen, textChangeRange);
}
public releaseDocument(fileName: string, compilationSettings: ts.CompilerOptions): void {

View File

@ -38,7 +38,7 @@ module ts.BreakpointResolver {
return spanInNode(tokenAtLocation);
function textSpan(startNode: Node, endNode?: Node) {
return TextSpan.fromBounds(startNode.getStart(), (endNode || startNode).getEnd());
return TextSpanObject.fromBounds(startNode.getStart(), (endNode || startNode).getEnd());
}
function spanInNodeIfStartsOnSameLine(node: Node, otherwiseOnNode?: Node): TextSpan {

View File

@ -868,7 +868,7 @@ module ts.formatting {
}
function newTextChange(start: number, len: number, newText: string): TextChange {
return { span: new TextSpan(start, len), newText }
return { span: new TextSpanObject(start, len), newText }
}
function recordDelete(start: number, len: number) {

View File

@ -16,7 +16,7 @@
///<reference path='references.ts' />
module ts.formatting {
export class TokenSpan extends TextSpan {
export class TokenSpan extends TextSpanObject {
constructor(public kind: SyntaxKind, start: number, length: number) {
super(start, length);
}

View File

@ -462,8 +462,8 @@ module ts.NavigationBar {
function getNodeSpan(node: Node) {
return node.kind === SyntaxKind.SourceFile
? TextSpan.fromBounds(node.getFullStart(), node.getEnd())
: TextSpan.fromBounds(node.getStart(), node.getEnd());
? TextSpanObject.fromBounds(node.getFullStart(), node.getEnd())
: TextSpanObject.fromBounds(node.getStart(), node.getEnd());
}
function getTextOfNode(node: Node): string {

View File

@ -38,8 +38,8 @@ module ts {
function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) {
if (hintSpanNode && startElement && endElement) {
var span: OutliningSpan = {
textSpan: TextSpan.fromBounds(startElement.pos, endElement.end),
hintSpan: TextSpan.fromBounds(hintSpanNode.getStart(), hintSpanNode.end),
textSpan: TextSpanObject.fromBounds(startElement.pos, endElement.end),
hintSpan: TextSpanObject.fromBounds(hintSpanNode.getStart(), hintSpanNode.end),
bannerText: collapseText,
autoCollapse: autoCollapse
};
@ -88,7 +88,7 @@ module ts {
else {
// Block was a standalone block. In this case we want to only collapse
// the span of the block, independent of any parent span.
var span = TextSpan.fromBounds(n.getStart(), n.end);
var span = TextSpanObject.fromBounds(n.getStart(), n.end);
elements.push({
textSpan: span,
hintSpan: span,

View File

@ -61,10 +61,9 @@ module ts {
export interface SourceFile {
isOpen: boolean;
version: string;
scriptSnapshot: IScriptSnapshot;
getScriptSnapshot(): IScriptSnapshot;
getNamedDeclarations(): Declaration[];
update(scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TextChangeRange): SourceFile;
}
/**
@ -724,6 +723,7 @@ module ts {
public _declarationBrand: any;
public filename: string;
public text: string;
public scriptSnapshot: IScriptSnapshot;
public statements: NodeArray<Statement>;
public endOfFileToken: Node;
@ -734,6 +734,7 @@ module ts {
public getPositionFromLineAndCharacter: (line: number, character: number) => number;
public getLineStarts: () => number[];
public getSyntacticDiagnostics: () => Diagnostic[];
public update: (newText: string, textChangeRange: TextChangeRange) => SourceFile;
public amdDependencies: string[];
public amdModuleName: string;
@ -754,13 +755,8 @@ module ts {
public languageVersion: ScriptTarget;
public identifiers: Map<string>;
private scriptSnapshot: IScriptSnapshot;
private namedDeclarations: Declaration[];
public getScriptSnapshot(): IScriptSnapshot {
return this.scriptSnapshot;
}
public getNamedDeclarations() {
if (!this.namedDeclarations) {
var sourceFile = this;
@ -846,35 +842,6 @@ module ts {
return this.namedDeclarations;
}
public update(scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TextChangeRange): SourceFile {
if (textChangeRange && Debug.shouldAssert(AssertionLevel.Normal)) {
var oldText = this.scriptSnapshot;
var newText = scriptSnapshot;
Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength());
if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) {
var oldTextPrefix = oldText.getText(0, textChangeRange.span().start());
var newTextPrefix = newText.getText(0, textChangeRange.span().start());
Debug.assert(oldTextPrefix === newTextPrefix);
var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength());
var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength());
Debug.assert(oldTextSuffix === newTextSuffix);
}
}
return SourceFileObject.createSourceFileObject(this.filename, scriptSnapshot, this.languageVersion, version, isOpen);
}
public static createSourceFileObject(filename: string, scriptSnapshot: IScriptSnapshot, languageVersion: ScriptTarget, version: string, isOpen: boolean) {
var newSourceFile = <SourceFileObject><any>createSourceFile(filename, scriptSnapshot.getText(0, scriptSnapshot.getLength()), languageVersion, /*setParentNodes:*/ true);
newSourceFile.version = version;
newSourceFile.isOpen = isOpen;
newSourceFile.scriptSnapshot = scriptSnapshot;
return newSourceFile;
}
}
export interface Logger {
@ -1646,7 +1613,7 @@ module ts {
public getChangeRange(filename: string, lastKnownVersion: string, oldScriptSnapshot: IScriptSnapshot): TextChangeRange {
var currentVersion = this.getVersion(filename);
if (lastKnownVersion === currentVersion) {
return TextChangeRange.unchanged; // "No changes"
return TextChangeRangeObject.unchanged; // "No changes"
}
var scriptSnapshot = this.getScriptSnapshot(filename);
@ -1679,25 +1646,17 @@ module ts {
var scriptSnapshot = this.hostCache.getScriptSnapshot(filename);
var start = new Date().getTime();
sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, getDefaultCompilerOptions(), version, /*isOpen*/ true);
sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, ScriptTarget.Latest, version, /*isOpen*/ true, /*setNodeParents;*/ true);
this.host.log("SyntaxTreeCache.Initialize: createSourceFile: " + (new Date().getTime() - start));
var start = new Date().getTime();
this.host.log("SyntaxTreeCache.Initialize: fixupParentRefs : " + (new Date().getTime() - start));
}
else if (this.currentFileVersion !== version) {
var scriptSnapshot = this.hostCache.getScriptSnapshot(filename);
var editRange = this.hostCache.getChangeRange(filename, this.currentFileVersion, this.currentSourceFile.getScriptSnapshot());
var editRange = this.hostCache.getChangeRange(filename, this.currentFileVersion, this.currentSourceFile.scriptSnapshot);
var start = new Date().getTime();
sourceFile = !editRange
? createLanguageServiceSourceFile(filename, scriptSnapshot, getDefaultCompilerOptions(), version, /*isOpen*/ true)
: this.currentSourceFile.update(scriptSnapshot, version, /*isOpen*/ true, editRange);
sourceFile = updateLanguageServiceSourceFile(this.currentSourceFile, scriptSnapshot, version, /*isOpen*/ true, editRange);
this.host.log("SyntaxTreeCache.Initialize: updateSourceFile: " + (new Date().getTime() - start));
var start = new Date().getTime();
this.host.log("SyntaxTreeCache.Initialize: fixupParentRefs : " + (new Date().getTime() - start));
}
if (sourceFile) {
@ -1714,12 +1673,52 @@ module ts {
}
public getCurrentScriptSnapshot(filename: string): IScriptSnapshot {
return this.getCurrentSourceFile(filename).getScriptSnapshot();
return this.getCurrentSourceFile(filename).scriptSnapshot;
}
}
export function createLanguageServiceSourceFile(filename: string, scriptSnapshot: IScriptSnapshot, settings: CompilerOptions, version: string, isOpen: boolean): SourceFile {
return SourceFileObject.createSourceFileObject(filename, scriptSnapshot, settings.target, version, isOpen);
function setSourceFileFields(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean) {
sourceFile.version = version;
sourceFile.isOpen = isOpen;
sourceFile.scriptSnapshot = scriptSnapshot;
}
export function createLanguageServiceSourceFile(filename: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, isOpen: boolean, setNodeParents: boolean): SourceFile {
var sourceFile = createSourceFile(filename, scriptSnapshot.getText(0, scriptSnapshot.getLength()), scriptTarget, setNodeParents);
setSourceFileFields(sourceFile, scriptSnapshot, version, isOpen);
return sourceFile;
}
export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TextChangeRange): SourceFile {
if (textChangeRange && Debug.shouldAssert(AssertionLevel.Normal)) {
var oldText = sourceFile.scriptSnapshot;
var newText = scriptSnapshot;
Debug.assert((oldText.getLength() - textChangeRange.span().length() + textChangeRange.newLength()) === newText.getLength());
if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) {
var oldTextPrefix = oldText.getText(0, textChangeRange.span().start());
var newTextPrefix = newText.getText(0, textChangeRange.span().start());
Debug.assert(oldTextPrefix === newTextPrefix);
var oldTextSuffix = oldText.getText(textChangeRange.span().end(), oldText.getLength());
var newTextSuffix = newText.getText(textChangeRange.newSpan().end(), newText.getLength());
Debug.assert(oldTextSuffix === newTextSuffix);
}
}
// If we were given a text change range, and our version or open-ness changed, then
// incrementally parse this file.
if (textChangeRange) {
if (version !== sourceFile.version || isOpen != sourceFile.isOpen) {
var newSourceFile = sourceFile.update(scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange);
setSourceFileFields(newSourceFile, scriptSnapshot, version, isOpen);
return newSourceFile;
}
}
// Otherwise, just create a new source file.
return createLanguageServiceSourceFile(sourceFile.filename, scriptSnapshot, sourceFile.languageVersion, version, isOpen, /*setNodeParents:*/ true);
}
export function createDocumentRegistry(): DocumentRegistry {
@ -1769,7 +1768,7 @@ module ts {
var bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true);
var entry = lookUp(bucket, filename);
if (!entry) {
var sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, compilationSettings, version, isOpen);
var sourceFile = createLanguageServiceSourceFile(filename, scriptSnapshot, compilationSettings.target, version, isOpen, /*setNodeParents:*/ false);
bucket[filename] = entry = {
sourceFile: sourceFile,
@ -1797,11 +1796,7 @@ module ts {
var entry = lookUp(bucket, filename);
Debug.assert(entry !== undefined);
if (entry.sourceFile.isOpen === isOpen && entry.sourceFile.version === version) {
return entry.sourceFile;
}
entry.sourceFile = entry.sourceFile.update(scriptSnapshot, version, isOpen, textChangeRange);
entry.sourceFile = updateLanguageServiceSourceFile(entry.sourceFile, scriptSnapshot, version, isOpen, textChangeRange);
return entry.sourceFile;
}
@ -2225,7 +2220,7 @@ module ts {
// new text buffer).
var textChangeRange: TextChangeRange = null;
if (sourceFile.isOpen && isOpen) {
textChangeRange = hostCache.getChangeRange(filename, sourceFile.version, sourceFile.getScriptSnapshot());
textChangeRange = hostCache.getChangeRange(filename, sourceFile.version, sourceFile.scriptSnapshot);
}
sourceFile = documentRegistry.updateDocument(sourceFile, filename, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange);
@ -3223,7 +3218,7 @@ module ts {
return {
kind: ScriptElementKind.unknown,
kindModifiers: ScriptElementKindModifier.none,
textSpan: new TextSpan(node.getStart(), node.getWidth()),
textSpan: new TextSpanObject(node.getStart(), node.getWidth()),
displayParts: typeToDisplayParts(typeInfoResolver, type, getContainerNode(node)),
documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined
};
@ -3237,7 +3232,7 @@ module ts {
return {
kind: displayPartsDocumentationsAndKind.symbolKind,
kindModifiers: getSymbolModifiers(symbol),
textSpan: new TextSpan(node.getStart(), node.getWidth()),
textSpan: new TextSpanObject(node.getStart(), node.getWidth()),
displayParts: displayPartsDocumentationsAndKind.displayParts,
documentation: displayPartsDocumentationsAndKind.documentation
};
@ -3248,7 +3243,7 @@ module ts {
function getDefinitionInfo(node: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo {
return {
fileName: node.getSourceFile().filename,
textSpan: TextSpan.fromBounds(node.getStart(), node.getEnd()),
textSpan: TextSpanObject.fromBounds(node.getStart(), node.getEnd()),
kind: symbolKind,
name: symbolName,
containerKind: undefined,
@ -3325,7 +3320,7 @@ module ts {
if (referenceFile) {
return [{
fileName: referenceFile.filename,
textSpan: TextSpan.fromBounds(0, 0),
textSpan: TextSpanObject.fromBounds(0, 0),
kind: ScriptElementKind.scriptElement,
name: comment.filename,
containerName: undefined,
@ -3516,7 +3511,7 @@ module ts {
if (shouldHighlightNextKeyword) {
result.push({
fileName: filename,
textSpan: TextSpan.fromBounds(elseKeyword.getStart(), ifKeyword.end),
textSpan: TextSpanObject.fromBounds(elseKeyword.getStart(), ifKeyword.end),
isWriteAccess: false
});
i++; // skip the next keyword
@ -4208,7 +4203,7 @@ module ts {
(findInComments && isInComment(position))) {
result.push({
fileName: sourceFile.filename,
textSpan: new TextSpan(position, searchText.length),
textSpan: new TextSpanObject(position, searchText.length),
isWriteAccess: false
});
}
@ -4591,7 +4586,7 @@ module ts {
return {
fileName: node.getSourceFile().filename,
textSpan: TextSpan.fromBounds(start, end),
textSpan: TextSpanObject.fromBounds(start, end),
isWriteAccess: isWriteAccess(node)
};
}
@ -4647,7 +4642,7 @@ module ts {
kindModifiers: getNodeModifiers(declaration),
matchKind: MatchKind[matchKind],
fileName: filename,
textSpan: TextSpan.fromBounds(declaration.getStart(), declaration.getEnd()),
textSpan: TextSpanObject.fromBounds(declaration.getStart(), declaration.getEnd()),
// TODO(jfreeman): What should be the containerName when the container has a computed name?
containerName: container && container.name ? (<Identifier>container.name).text : "",
containerKind: container && container.name ? getNodeKind(container) : ""
@ -4924,7 +4919,7 @@ module ts {
}
}
return TextSpan.fromBounds(nodeForStartPos.getStart(), node.getEnd());
return TextSpanObject.fromBounds(nodeForStartPos.getStart(), node.getEnd());
}
function getBreakpointStatementAtPosition(filename: string, position: number) {
@ -5001,7 +4996,7 @@ module ts {
var type = classifySymbol(symbol, getMeaningFromLocation(node));
if (type) {
result.push({
textSpan: new TextSpan(node.getStart(), node.getWidth()),
textSpan: new TextSpanObject(node.getStart(), node.getWidth()),
classificationType: type
});
}
@ -5027,7 +5022,7 @@ module ts {
var width = comment.end - comment.pos;
if (span.intersectsWith(comment.pos, width)) {
result.push({
textSpan: new TextSpan(comment.pos, width),
textSpan: new TextSpanObject(comment.pos, width),
classificationType: ClassificationTypeNames.comment
});
}
@ -5040,7 +5035,7 @@ module ts {
var type = classifyTokenType(token);
if (type) {
result.push({
textSpan: new TextSpan(token.getStart(), token.getWidth()),
textSpan: new TextSpanObject(token.getStart(), token.getWidth()),
classificationType: type
});
}
@ -5168,8 +5163,8 @@ module ts {
var current = childNodes[i];
if (current.kind === matchKind) {
var range1 = new TextSpan(token.getStart(sourceFile), token.getWidth(sourceFile));
var range2 = new TextSpan(current.getStart(sourceFile), current.getWidth(sourceFile));
var range1 = new TextSpanObject(token.getStart(sourceFile), token.getWidth(sourceFile));
var range2 = new TextSpanObject(current.getStart(sourceFile), current.getWidth(sourceFile));
// We want to order the braces when we return the result.
if (range1.start() < range2.start()) {
@ -5420,7 +5415,7 @@ module ts {
if (kind) {
return getRenameInfo(symbol.name, typeInfoResolver.getFullyQualifiedName(symbol), kind,
getSymbolModifiers(symbol),
new TextSpan(node.getStart(), node.getWidth()));
new TextSpanObject(node.getStart(), node.getWidth()));
}
}
}

View File

@ -328,8 +328,8 @@ module ts {
}
var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded);
return new TextChangeRange(
new TextSpan(decoded.span.start, decoded.span.length), decoded.newLength);
return new TextChangeRangeObject(
new TextSpanObject(decoded.span.start, decoded.span.length), decoded.newLength);
}
}
@ -510,7 +510,7 @@ module ts {
return this.forwardJSONCall(
"getSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")",
() => {
var classifications = this.languageService.getSyntacticClassifications(fileName, new TextSpan(start, length));
var classifications = this.languageService.getSyntacticClassifications(fileName, new TextSpanObject(start, length));
return classifications;
});
}
@ -519,7 +519,7 @@ module ts {
return this.forwardJSONCall(
"getSemanticClassifications('" + fileName + "', " + start + ", " + length + ")",
() => {
var classifications = this.languageService.getSemanticClassifications(fileName, new TextSpan(start, length));
var classifications = this.languageService.getSemanticClassifications(fileName, new TextSpanObject(start, length));
return classifications;
});
}

View File

@ -367,7 +367,7 @@ module ts.SignatureHelp {
// but not including parentheses)
var applicableSpanStart = argumentsList.getFullStart();
var applicableSpanEnd = skipTrivia(sourceFile.text, argumentsList.getEnd(), /*stopAfterLineBreak*/ false);
return new TextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
return new TextSpanObject(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
}
function getApplicableSpanForTaggedTemplate(taggedTemplate: TaggedTemplateExpression): TextSpan {
@ -391,7 +391,7 @@ module ts.SignatureHelp {
}
}
return new TextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
return new TextSpanObject(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
}
function getContainingArgumentInfo(node: Node): ArgumentListInfo {

View File

@ -1,5 +1,5 @@
module ts {
export class TextSpan {
export class TextSpanObject {
private _start: number;
private _length: number;
@ -49,7 +49,7 @@ module ts {
* @param span The span to check.
*/
public containsTextSpan(span: TextSpan): boolean {
return span._start >= this._start && span.end() <= this.end();
return span.start() >= this._start && span.end() <= this.end();
}
/**
@ -59,7 +59,7 @@ module ts {
* @param span The span to check.
*/
public overlapsWith(span: TextSpan): boolean {
var overlapStart = Math.max(this._start, span._start);
var overlapStart = Math.max(this._start, span.start());
var overlapEnd = Math.min(this.end(), span.end());
return overlapStart < overlapEnd;
@ -70,11 +70,11 @@ module ts {
* @param span The span to check.
*/
public overlap(span: TextSpan): TextSpan {
var overlapStart = Math.max(this._start, span._start);
var overlapStart = Math.max(this._start, span.start());
var overlapEnd = Math.min(this.end(), span.end());
if (overlapStart < overlapEnd) {
return TextSpan.fromBounds(overlapStart, overlapEnd);
return TextSpanObject.fromBounds(overlapStart, overlapEnd);
}
return undefined;
@ -87,7 +87,7 @@ module ts {
* @param The span to check.
*/
public intersectsWithTextSpan(span: TextSpan): boolean {
return span._start <= this.end() && span.end() >= this._start;
return span.start() <= this.end() && span.end() >= this._start;
}
public intersectsWith(start: number, length: number): boolean {
@ -110,11 +110,11 @@ module ts {
* @param span The span to check.
*/
public intersection(span: TextSpan): TextSpan {
var intersectStart = Math.max(this._start, span._start);
var intersectStart = Math.max(this._start, span.start());
var intersectEnd = Math.min(this.end(), span.end());
if (intersectStart <= intersectEnd) {
return TextSpan.fromBounds(intersectStart, intersectEnd);
return TextSpanObject.fromBounds(intersectStart, intersectEnd);
}
return undefined;
@ -127,12 +127,12 @@ module ts {
public static fromBounds(start: number, end: number): TextSpan {
Debug.assert(start >= 0);
Debug.assert(end - start >= 0);
return new TextSpan(start, end - start);
return new TextSpanObject(start, end - start);
}
}
export class TextChangeRange {
public static unchanged = new TextChangeRange(new TextSpan(0, 0), 0);
export class TextChangeRangeObject implements TextChangeRange {
public static unchanged = new TextChangeRangeObject(new TextSpanObject(0, 0), 0);
private _span: TextSpan;
private _newLength: number;
@ -162,7 +162,7 @@ module ts {
}
public newSpan(): TextSpan {
return new TextSpan(this.span().start(), this.newLength());
return new TextSpanObject(this.span().start(), this.newLength());
}
public isUnchanged(): boolean {
@ -179,7 +179,7 @@ module ts {
*/
public static collapseChangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
if (changes.length === 0) {
return TextChangeRange.unchanged;
return TextChangeRangeObject.unchanged;
}
if (changes.length === 1) {
@ -290,7 +290,7 @@ module ts {
newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
}
return new TextChangeRange(TextSpan.fromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
return new TextChangeRangeObject(TextSpanObject.fromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
}
}
}

View File

@ -6,7 +6,7 @@ module ts {
var contents = text.getText(0, text.getLength());
var newContents = contents.substr(0, start) + newText + contents.substring(start + length);
return { text: ScriptSnapshot.fromString(newContents), textChangeRange: new TextChangeRange(new TextSpan(start, length), newText.length) }
return { text: ScriptSnapshot.fromString(newContents), textChangeRange: new TextChangeRangeObject(new TextSpanObject(start, length), newText.length) }
}
function withInsert(text: IScriptSnapshot, start: number, newText: string): { text: IScriptSnapshot; textChangeRange: TextChangeRange; } {
@ -18,10 +18,7 @@ module ts {
}
function createTree(text: IScriptSnapshot, version: string) {
var options: CompilerOptions = {};
options.target = ScriptTarget.ES5;
return createLanguageServiceSourceFile(/*fileName:*/ "", text, options, version, /*isOpen:*/ true)
return createLanguageServiceSourceFile(/*fileName:*/ "", text, ScriptTarget.Latest, version, /*isOpen:*/ true, /*setNodeParents:*/ true)
}
// NOTE: 'reusedElements' is the expected count of elements reused from the old tree to the new
@ -38,7 +35,7 @@ module ts {
Utils.assertInvariants(newTree, /*parent:*/ undefined);
// Create a tree for the new text, in an incremental fashion.
var incrementalNewTree = oldTree.update(newText, oldTree.version + ".", /*isOpen:*/ true, textChangeRange);
var incrementalNewTree = updateLanguageServiceSourceFile(oldTree, newText, oldTree.version + ".", /*isOpen:*/ true, textChangeRange);
Utils.assertInvariants(incrementalNewTree, /*parent:*/ undefined);
// We should get the same tree when doign a full or incremental parse.