Skip to content

Commit

Permalink
Merge branch 'master' into cacheUnnormalizedIntersections
Browse files Browse the repository at this point in the history
  • Loading branch information
ahejlsberg committed May 20, 2019
2 parents 309ae22 + 907664c commit 2c34672
Show file tree
Hide file tree
Showing 48 changed files with 1,401 additions and 30 deletions.
38 changes: 22 additions & 16 deletions src/compiler/binder.ts
Expand Up @@ -2581,7 +2581,7 @@ namespace ts {
// Fix up parent pointers since we're going to use these nodes before we bind into them
node.left.parent = node;
node.right.parent = node;
if (isIdentifier(lhs.expression) && container === file && isNameOfExportsOrModuleExportsAliasDeclaration(file, lhs.expression)) {
if (isIdentifier(lhs.expression) && container === file && isExportsOrModuleExportsOrAlias(file, lhs.expression)) {
// This can be an alias for the 'exports' or 'module.exports' names, e.g.
// var util = module.exports;
// util.property = function ...
Expand Down Expand Up @@ -2975,21 +2975,27 @@ namespace ts {
}

export function isExportsOrModuleExportsOrAlias(sourceFile: SourceFile, node: Expression): boolean {
return isExportsIdentifier(node) ||
isModuleExportsPropertyAccessExpression(node) ||
isIdentifier(node) && isNameOfExportsOrModuleExportsAliasDeclaration(sourceFile, node);
}

function isNameOfExportsOrModuleExportsAliasDeclaration(sourceFile: SourceFile, node: Identifier): boolean {
const symbol = lookupSymbolForNameWorker(sourceFile, node.escapedText);
return !!symbol && !!symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) &&
!!symbol.valueDeclaration.initializer && isExportsOrModuleExportsOrAliasOrAssignment(sourceFile, symbol.valueDeclaration.initializer);
}

function isExportsOrModuleExportsOrAliasOrAssignment(sourceFile: SourceFile, node: Expression): boolean {
return isExportsOrModuleExportsOrAlias(sourceFile, node) ||
(isAssignmentExpression(node, /*excludeCompoundAssignment*/ true) && (
isExportsOrModuleExportsOrAliasOrAssignment(sourceFile, node.left) || isExportsOrModuleExportsOrAliasOrAssignment(sourceFile, node.right)));
let i = 0;
const q = [node];
while (q.length && i < 100) {
i++;
node = q.shift()!;
if (isExportsIdentifier(node) || isModuleExportsPropertyAccessExpression(node)) {
return true;
}
else if (isIdentifier(node)) {
const symbol = lookupSymbolForNameWorker(sourceFile, node.escapedText);
if (!!symbol && !!symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && !!symbol.valueDeclaration.initializer) {
const init = symbol.valueDeclaration.initializer;
q.push(init);
if (isAssignmentExpression(init, /*excludeCompoundAssignment*/ true)) {
q.push(init.left);
q.push(init.right);
}
}
}
}
return false;
}

function lookupSymbolForNameWorker(container: Node, name: __String): Symbol | undefined {
Expand Down
4 changes: 4 additions & 0 deletions src/harness/client.ts
Expand Up @@ -424,6 +424,10 @@ namespace ts.server {
return renameInfo;
}

getSmartSelectionRange() {
return notImplemented();
}

findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] {
if (!this.lastRenameEntry ||
this.lastRenameEntry.inputs.fileName !== fileName ||
Expand Down
52 changes: 44 additions & 8 deletions src/harness/fourslash.ts
Expand Up @@ -1417,12 +1417,7 @@ Actual: ${stringify(fullActual)}`);
}

public baselineCurrentFileBreakpointLocations() {
let baselineFile = this.testData.globalOptions[MetadataOptionNames.baselineFile];
if (!baselineFile) {
baselineFile = this.activeFile.fileName.replace(this.basePath + "/breakpointValidation", "bpSpan");
baselineFile = baselineFile.replace(ts.Extension.Ts, ".baseline");

}
const baselineFile = this.getBaselineFileName().replace("breakpointValidation", "bpSpan");
Harness.Baseline.runBaseline(baselineFile, this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos)!));
}

Expand Down Expand Up @@ -1497,8 +1492,7 @@ Actual: ${stringify(fullActual)}`);
}

public baselineQuickInfo() {
const baselineFile = this.testData.globalOptions[MetadataOptionNames.baselineFile] ||
ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ".baseline");
const baselineFile = this.getBaselineFileName();
Harness.Baseline.runBaseline(
baselineFile,
stringify(
Expand All @@ -1508,6 +1502,39 @@ Actual: ${stringify(fullActual)}`);
}))));
}

public baselineSmartSelection() {
const n = "\n";
const baselineFile = this.getBaselineFileName();
const markers = this.getMarkers();
const fileContent = this.activeFile.content;
const text = markers.map(marker => {
const baselineContent = [fileContent.slice(0, marker.position) + "/**/" + fileContent.slice(marker.position) + n];
let selectionRange: ts.SelectionRange | undefined = this.languageService.getSmartSelectionRange(this.activeFile.fileName, marker.position);
while (selectionRange) {
const { textSpan } = selectionRange;
let masked = Array.from(fileContent).map((char, index) => {
const charCode = char.charCodeAt(0);
if (index >= textSpan.start && index < ts.textSpanEnd(textSpan)) {
return char === " " ? "•" : ts.isLineBreak(charCode) ? `↲${n}` : char;
}
return ts.isLineBreak(charCode) ? char : " ";
}).join("");
masked = masked.replace(/^\s*$\r?\n?/gm, ""); // Remove blank lines
const isRealCharacter = (char: string) => char !== "•" && char !== "↲" && !ts.isWhiteSpaceLike(char.charCodeAt(0));
const leadingWidth = Array.from(masked).findIndex(isRealCharacter);
const trailingWidth = ts.findLastIndex(Array.from(masked), isRealCharacter);
masked = masked.slice(0, leadingWidth)
+ masked.slice(leadingWidth, trailingWidth).replace(//g, " ").replace(//g, "")
+ masked.slice(trailingWidth);
baselineContent.push(masked);
selectionRange = selectionRange.parent;
}
return baselineContent.join(fileContent.includes("\n") ? n + n : n);
}).join(n.repeat(2) + "=".repeat(80) + n.repeat(2));

Harness.Baseline.runBaseline(baselineFile, text);
}

public printBreakpointLocation(pos: number) {
Harness.IO.log("\n**Pos: " + pos + " " + this.spanInfoToString(this.getBreakpointStatementLocation(pos)!, " "));
}
Expand Down Expand Up @@ -1562,6 +1589,11 @@ Actual: ${stringify(fullActual)}`);
Harness.IO.log(stringify(help.items[help.selectedItemIndex]));
}

private getBaselineFileName() {
return this.testData.globalOptions[MetadataOptionNames.baselineFile] ||
ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ".baseline");
}

private getSignatureHelp({ triggerReason }: FourSlashInterface.VerifySignatureHelpOptions): ts.SignatureHelpItems | undefined {
return this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition, {
triggerReason
Expand Down Expand Up @@ -3960,6 +3992,10 @@ namespace FourSlashInterface {
this.state.baselineQuickInfo();
}

public baselineSmartSelection() {
this.state.baselineSmartSelection();
}

public nameOrDottedNameSpanTextIs(text: string) {
this.state.verifyCurrentNameOrDottedNameSpanText(text);
}
Expand Down
3 changes: 3 additions & 0 deletions src/harness/harnessLanguageService.ts
Expand Up @@ -472,6 +472,9 @@ namespace Harness.LanguageService {
getRenameInfo(fileName: string, position: number, options?: ts.RenameInfoOptions): ts.RenameInfo {
return unwrapJSONCallResult(this.shim.getRenameInfo(fileName, position, options));
}
getSmartSelectionRange(fileName: string, position: number): ts.SelectionRange {
return unwrapJSONCallResult(this.shim.getSmartSelectionRange(fileName, position));
}
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): ts.RenameLocation[] {
return unwrapJSONCallResult(this.shim.findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename));
}
Expand Down
23 changes: 22 additions & 1 deletion src/server/protocol.ts
Expand Up @@ -130,7 +130,10 @@ namespace ts.server.protocol {
GetEditsForFileRename = "getEditsForFileRename",
/* @internal */
GetEditsForFileRenameFull = "getEditsForFileRename-full",
ConfigurePlugin = "configurePlugin"
ConfigurePlugin = "configurePlugin",
SelectionRange = "selectionRange",
/* @internal */
SelectionRangeFull = "selectionRange-full",

// NOTE: If updating this, be sure to also update `allCommandNames` in `harness/unittests/session.ts`.
}
Expand Down Expand Up @@ -1395,6 +1398,24 @@ namespace ts.server.protocol {
export interface ConfigurePluginResponse extends Response {
}

export interface SelectionRangeRequest extends FileRequest {
command: CommandTypes.SelectionRange;
arguments: SelectionRangeRequestArgs;
}

export interface SelectionRangeRequestArgs extends FileRequestArgs {
locations: Location[];
}

export interface SelectionRangeResponse extends Response {
body?: SelectionRange[];
}

export interface SelectionRange {
textSpan: TextSpan;
parent?: SelectionRange;
}

/**
* Information found in an "open" request.
*/
Expand Down
34 changes: 31 additions & 3 deletions src/server/session.ts
Expand Up @@ -1318,11 +1318,11 @@ namespace ts.server {
this.projectService.openClientFileWithNormalizedPath(fileName, fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath);
}

private getPosition(args: protocol.FileLocationRequestArgs, scriptInfo: ScriptInfo): number {
private getPosition(args: protocol.Location & { position?: number }, scriptInfo: ScriptInfo): number {
return args.position !== undefined ? args.position : scriptInfo.lineOffsetToPosition(args.line, args.offset);
}

private getPositionInFile(args: protocol.FileLocationRequestArgs, file: NormalizedPath): number {
private getPositionInFile(args: protocol.Location & { position?: number }, file: NormalizedPath): number {
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file)!;
return this.getPosition(args, scriptInfo);
}
Expand Down Expand Up @@ -2059,6 +2059,28 @@ namespace ts.server {
this.projectService.configurePlugin(args);
}

private getSmartSelectionRange(args: protocol.SelectionRangeRequestArgs, simplifiedResult: boolean) {
const { locations } = args;
const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args);
const scriptInfo = Debug.assertDefined(this.projectService.getScriptInfo(file));

return map(locations, location => {
const pos = this.getPosition(location, scriptInfo);
const selectionRange = languageService.getSmartSelectionRange(file, pos);
return simplifiedResult ? this.mapSelectionRange(selectionRange, scriptInfo) : selectionRange;
});
}

private mapSelectionRange(selectionRange: SelectionRange, scriptInfo: ScriptInfo): protocol.SelectionRange {
const result: protocol.SelectionRange = {
textSpan: this.toLocationTextSpan(selectionRange.textSpan, scriptInfo),
};
if (selectionRange.parent) {
result.parent = this.mapSelectionRange(selectionRange.parent, scriptInfo);
}
return result;
}

getCanonicalFileName(fileName: string) {
const name = this.host.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
return normalizePath(name);
Expand Down Expand Up @@ -2414,7 +2436,13 @@ namespace ts.server {
this.configurePlugin(request.arguments);
this.doOutput(/*info*/ undefined, CommandNames.ConfigurePlugin, request.seq, /*success*/ true);
return this.notRequired();
}
},
[CommandNames.SelectionRange]: (request: protocol.SelectionRangeRequest) => {
return this.requiredResponse(this.getSmartSelectionRange(request.arguments, /*simplifiedResult*/ true));
},
[CommandNames.SelectionRangeFull]: (request: protocol.SelectionRangeRequest) => {
return this.requiredResponse(this.getSmartSelectionRange(request.arguments, /*simplifiedResult*/ false));
},
});

public addProtocolHandler(command: string, handler: (request: protocol.Request) => HandlerResponse) {
Expand Down
5 changes: 5 additions & 0 deletions src/services/services.ts
Expand Up @@ -2080,6 +2080,10 @@ namespace ts {
};
}

function getSmartSelectionRange(fileName: string, position: number): SelectionRange {
return SmartSelectionRange.getSmartSelectionRange(position, syntaxTreeCache.getCurrentSourceFile(fileName));
}

function getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences = emptyOptions): ApplicableRefactorInfo[] {
synchronizeHostData();
const file = getValidSourceFile(fileName);
Expand Down Expand Up @@ -2127,6 +2131,7 @@ namespace ts {
getBreakpointStatementAtPosition,
getNavigateToItems,
getRenameInfo,
getSmartSelectionRange,
findRenameLocations,
getNavigationBarItems,
getNavigationTree,
Expand Down
8 changes: 8 additions & 0 deletions src/services/shims.ts
Expand Up @@ -165,6 +165,7 @@ namespace ts {
* { canRename: boolean, localizedErrorMessage: string, displayName: string, fullDisplayName: string, kind: string, kindModifiers: string, triggerSpan: { start; length } }
*/
getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): string;
getSmartSelectionRange(fileName: string, position: number): string;

/**
* Returns a JSON-encoded value of the type:
Expand Down Expand Up @@ -838,6 +839,13 @@ namespace ts {
);
}

public getSmartSelectionRange(fileName: string, position: number): string {
return this.forwardJSONCall(
`getSmartSelectionRange('${fileName}', ${position})`,
() => this.languageService.getSmartSelectionRange(fileName, position)
);
}

public findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): string {
return this.forwardJSONCall(
`findRenameLocations('${fileName}', ${position}, ${findInStrings}, ${findInComments}, ${providePrefixAndSuffixTextForRename})`,
Expand Down

0 comments on commit 2c34672

Please sign in to comment.