Merge branch 'master' into aeschli/ts-sem

This commit is contained in:
Martin Aeschlimann
2020-01-09 15:41:56 +01:00
112 changed files with 1720 additions and 1020 deletions

View File

@@ -0,0 +1,111 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { ITypeScriptServiceClient } from '../typescriptService';
import * as typeConverters from '../utils/typeConverters';
import API from '../utils/api';
import { VersionDependentRegistration } from '../utils/dependentRegistration';
import * as Proto from '../protocol';
import * as path from 'path';
import * as PConst from '../protocol.const';
class TypeScriptCallHierarchySupport implements vscode.CallHierarchyProvider {
public static readonly minVersion = API.v380;
public constructor(
private readonly client: ITypeScriptServiceClient) { }
public async prepareCallHierarchy(
document: vscode.TextDocument,
position: vscode.Position,
token: vscode.CancellationToken
): Promise<vscode.CallHierarchyItem | vscode.CallHierarchyItem[] | undefined> {
const filepath = this.client.toOpenedFilePath(document);
if (!filepath) {
return undefined;
}
const args = typeConverters.Position.toFileLocationRequestArgs(filepath, position);
const response = await this.client.execute('prepareCallHierarchy', args, token);
if (response.type !== 'response' || !response.body) {
return undefined;
}
return Array.isArray(response.body)
? response.body.map(fromProtocolCallHierarchyItem)
: fromProtocolCallHierarchyItem(response.body);
}
public async provideCallHierarchyIncomingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): Promise<vscode.CallHierarchyIncomingCall[] | undefined> {
const filepath = this.client.toPath(item.uri);
if (!filepath) {
return undefined;
}
const args = typeConverters.Position.toFileLocationRequestArgs(filepath, item.selectionRange.start);
const response = await this.client.execute('provideCallHierarchyIncomingCalls', args, token);
if (response.type !== 'response' || !response.body) {
return undefined;
}
return response.body.map(fromProtocolCallHierchyIncomingCall);
}
public async provideCallHierarchyOutgoingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): Promise<vscode.CallHierarchyOutgoingCall[] | undefined> {
const filepath = this.client.toPath(item.uri);
if (!filepath) {
return undefined;
}
const args = typeConverters.Position.toFileLocationRequestArgs(filepath, item.selectionRange.start);
const response = await this.client.execute('provideCallHierarchyOutgoingCalls', args, token);
if (response.type !== 'response' || !response.body) {
return undefined;
}
return response.body.map(fromProtocolCallHierchyOutgoingCall);
}
}
function isSourceFileItem(item: Proto.CallHierarchyItem) {
return item.kind === PConst.Kind.script || item.kind === PConst.Kind.module && item.selectionSpan.start.line === 0 && item.selectionSpan.start.offset === 0;
}
function fromProtocolCallHierarchyItem(item: Proto.CallHierarchyItem): vscode.CallHierarchyItem {
const useFileName = isSourceFileItem(item);
const name = useFileName ? path.basename(item.file) : item.name;
const detail = useFileName ? vscode.workspace.asRelativePath(path.dirname(item.file)) : '';
return new vscode.CallHierarchyItem(
typeConverters.SymbolKind.fromProtocolScriptElementKind(item.kind),
name,
detail,
vscode.Uri.file(item.file),
typeConverters.Range.fromTextSpan(item.span),
typeConverters.Range.fromTextSpan(item.selectionSpan)
);
}
function fromProtocolCallHierchyIncomingCall(item: Proto.CallHierarchyIncomingCall): vscode.CallHierarchyIncomingCall {
return new vscode.CallHierarchyIncomingCall(
fromProtocolCallHierarchyItem(item.from),
item.fromSpans.map(typeConverters.Range.fromTextSpan)
);
}
function fromProtocolCallHierchyOutgoingCall(item: Proto.CallHierarchyOutgoingCall): vscode.CallHierarchyOutgoingCall {
return new vscode.CallHierarchyOutgoingCall(
fromProtocolCallHierarchyItem(item.to),
item.fromSpans.map(typeConverters.Range.fromTextSpan)
);
}
export function register(
selector: vscode.DocumentSelector,
client: ITypeScriptServiceClient
) {
return new VersionDependentRegistration(client, TypeScriptCallHierarchySupport.minVersion,
() => vscode.languages.registerCallHierarchyProvider(selector,
new TypeScriptCallHierarchySupport(client)));
}

View File

@@ -16,7 +16,7 @@ import { ConfigurationDependentRegistration } from '../utils/dependentRegistrati
import { memoize } from '../utils/memoize';
import * as Previewer from '../utils/previewer';
import { snippetForFunctionCall } from '../utils/snippetForFunctionCall';
import TelemetryReporter from '../utils/telemetry';
import { TelemetryReporter } from '../utils/telemetry';
import * as typeConverters from '../utils/typeConverters';
import TypingsStatus from '../utils/typingsStatus';
import FileConfigurationManager from './fileConfigurationManager';
@@ -405,15 +405,17 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider
"duration" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
"type" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
"count" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
"updateGraphDurationMs" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
"${include}": [
"${TypeScriptCommonProperties}"
]
}
*/
this.telemetryReporter.logTelemetry('completions.execute', {
duration: duration + '',
type: response ? response.type : 'unknown',
count: (response && response.type === 'response' && response.body ? response.body.entries.length : 0) + ''
duration: duration,
type: response?.type ?? 'unknown',
count: response?.type === 'response' && response.body ? response.body.entries.length : 0,
updateGraphDurationMs: response?.type === 'response' ? response.performanceData?.updateGraphDurationMs : undefined,
});
}

View File

@@ -12,7 +12,7 @@ import { Command, CommandManager } from '../utils/commandManager';
import { VersionDependentRegistration } from '../utils/dependentRegistration';
import * as typeconverts from '../utils/typeConverters';
import FileConfigurationManager from './fileConfigurationManager';
import TelemetryReporter from '../utils/telemetry';
import { TelemetryReporter } from '../utils/telemetry';
import { nulToken } from '../utils/cancellation';
const localize = nls.loadMessageBundle();

View File

@@ -12,7 +12,7 @@ import { nulToken } from '../utils/cancellation';
import { applyCodeActionCommands, getEditForCodeAction } from '../utils/codeAction';
import { Command, CommandManager } from '../utils/commandManager';
import { memoize } from '../utils/memoize';
import TelemetryReporter from '../utils/telemetry';
import { TelemetryReporter } from '../utils/telemetry';
import * as typeConverters from '../utils/typeConverters';
import { DiagnosticsManager } from './diagnostics';
import FileConfigurationManager from './fileConfigurationManager';

View File

@@ -11,7 +11,7 @@ import API from '../utils/api';
import { nulToken } from '../utils/cancellation';
import { Command, CommandManager } from '../utils/commandManager';
import { VersionDependentRegistration } from '../utils/dependentRegistration';
import TelemetryReporter from '../utils/telemetry';
import { TelemetryReporter } from '../utils/telemetry';
import * as typeConverters from '../utils/typeConverters';
import FormattingOptionsManager from './fileConfigurationManager';
import * as fileSchemes from '../utils/fileSchemes';

View File

@@ -14,7 +14,7 @@ import { Disposable } from './utils/dispose';
import * as fileSchemes from './utils/fileSchemes';
import { LanguageDescription } from './utils/languageDescription';
import { memoize } from './utils/memoize';
import TelemetryReporter from './utils/telemetry';
import { TelemetryReporter } from './utils/telemetry';
import TypingsStatus from './utils/typingsStatus';
@@ -79,6 +79,7 @@ export default class LanguageProvider extends Disposable {
import('./features/tagClosing').then(provider => this._register(provider.register(selector, this.description.id, this.client))),
import('./features/typeDefinitions').then(provider => this._register(provider.register(selector, this.client))),
import('./features/semanticColoring').then(provider => this._register(provider.register(selector, this.client))),
import('./features/callHierarchy').then(provider => this._register(provider.register(selector, this.client))),
]);
}

View File

@@ -33,6 +33,7 @@ export class Kind {
public static readonly warning = 'warning';
public static readonly string = 'string';
public static readonly parameter = 'parameter';
public static readonly typeParameter = 'type parameter';
}

View File

@@ -1,2 +1,61 @@
import * as Proto from 'typescript/lib/protocol';
export = Proto;
declare module "typescript/lib/protocol" {
// TODO: Remove this hardcoded type once we update to TS 3.8+ that brings in the proper types
interface Response {
performanceData?: {
updateGraphDurationMs?: number;
}
}
const enum CommandTypes {
PrepareCallHierarchy = "prepareCallHierarchy",
ProvideCallHierarchyIncomingCalls = "provideCallHierarchyIncomingCalls",
ProvideCallHierarchyOutgoingCalls = "provideCallHierarchyOutgoingCalls",
}
interface CallHierarchyItem {
name: string;
kind: ScriptElementKind;
file: string;
span: TextSpan;
selectionSpan: TextSpan;
}
interface CallHierarchyIncomingCall {
from: CallHierarchyItem;
fromSpans: TextSpan[];
}
interface CallHierarchyOutgoingCall {
to: CallHierarchyItem;
fromSpans: TextSpan[];
}
interface PrepareCallHierarchyRequest extends FileLocationRequest {
command: CommandTypes.PrepareCallHierarchy;
}
interface PrepareCallHierarchyResponse extends Response {
readonly body: CallHierarchyItem | CallHierarchyItem[];
}
interface ProvideCallHierarchyIncomingCallsRequest extends FileLocationRequest {
command: CommandTypes.ProvideCallHierarchyIncomingCalls;
kind: ScriptElementKind;
}
interface ProvideCallHierarchyIncomingCallsResponse extends Response {
readonly body: CallHierarchyIncomingCall[];
}
interface ProvideCallHierarchyOutgoingCallsRequest extends FileLocationRequest {
command: CommandTypes.ProvideCallHierarchyOutgoingCalls;
kind: ScriptElementKind;
}
interface ProvideCallHierarchyOutgoingCallsResponse extends Response {
readonly body: CallHierarchyOutgoingCall[];
}
}

View File

@@ -9,7 +9,7 @@ import * as stream from 'stream';
import { PipeRequestCanceller, TsServerProcess, ProcessBasedTsServer } from '../tsServer/server';
import { nulToken } from '../utils/cancellation';
import Logger from '../utils/logger';
import TelemetryReporter from '../utils/telemetry';
import { TelemetryReporter } from '../utils/telemetry';
import Tracer from '../utils/tracer';
import * as Proto from '../protocol';

View File

@@ -9,7 +9,7 @@ import * as vscode from 'vscode';
import * as Proto from '../protocol';
import { ServerResponse, TypeScriptRequests } from '../typescriptService';
import { Disposable } from '../utils/dispose';
import TelemetryReporter from '../utils/telemetry';
import { TelemetryReporter } from '../utils/telemetry';
import Tracer from '../utils/tracer';
import { TypeScriptVersion } from '../utils/versionProvider';
import { Reader } from '../utils/wireProtocol';

View File

@@ -15,7 +15,7 @@ import LogDirectoryProvider from '../utils/logDirectoryProvider';
import Logger from '../utils/logger';
import { TypeScriptPluginPathsProvider } from '../utils/pluginPathsProvider';
import { PluginManager } from '../utils/plugins';
import TelemetryReporter from '../utils/telemetry';
import { TelemetryReporter } from '../utils/telemetry';
import Tracer from '../utils/tracer';
import { TypeScriptVersion, TypeScriptVersionProvider } from '../utils/versionProvider';
import { ITypeScriptServer, PipeRequestCanceller, ProcessBasedTsServer, SyntaxRoutingTsServer, TsServerProcess, TsServerDelegate } from './server';

View File

@@ -58,6 +58,9 @@ interface StandardTsServerRequests {
'signatureHelp': [Proto.SignatureHelpRequestArgs, Proto.SignatureHelpResponse];
'typeDefinition': [Proto.FileLocationRequestArgs, Proto.TypeDefinitionResponse];
'updateOpen': [Proto.UpdateOpenRequestArgs, Proto.Response];
'prepareCallHierarchy': [Proto.FileLocationRequestArgs, Proto.PrepareCallHierarchyResponse];
'provideCallHierarchyIncomingCalls': [Proto.FileLocationRequestArgs, Proto.ProvideCallHierarchyIncomingCallsResponse];
'provideCallHierarchyOutgoingCalls': [Proto.FileLocationRequestArgs, Proto.ProvideCallHierarchyOutgoingCallsResponse];
}
interface NoResponseTsServerRequests {

View File

@@ -22,7 +22,7 @@ import LogDirectoryProvider from './utils/logDirectoryProvider';
import Logger from './utils/logger';
import { TypeScriptPluginPathsProvider } from './utils/pluginPathsProvider';
import { PluginManager } from './utils/plugins';
import TelemetryReporter, { VSCodeTelemetryReporter } from './utils/telemetry';
import { TelemetryReporter, VSCodeTelemetryReporter, TelemetryProperties } from './utils/telemetry';
import Tracer from './utils/tracer';
import { inferredProjectCompilerOptions } from './utils/tsconfig';
import { TypeScriptVersionPicker } from './utils/versionPicker';
@@ -271,7 +271,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
this.logger.error(message, data);
}
private logTelemetry(eventName: string, properties?: { readonly [prop: string]: string }) {
private logTelemetry(eventName: string, properties?: TelemetryProperties) {
this.telemetryReporter.logTelemetry(eventName, properties);
}
@@ -711,7 +711,8 @@ export default class TypeScriptServiceClient extends Disposable implements IType
"${include}": [
"${TypeScriptCommonProperties}",
"${TypeScriptRequestErrorProperties}"
]
],
"command" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
}
*/
this.logTelemetry('fatalError', { command, ...(error instanceof TypeScriptServerError ? error.telemetry : {}) });

View File

@@ -31,6 +31,7 @@ export default class API {
public static readonly v340 = API.fromSimpleString('3.4.0');
public static readonly v345 = API.fromSimpleString('3.4.5');
public static readonly v350 = API.fromSimpleString('3.5.0');
public static readonly v380 = API.fromSimpleString('3.8.0');
public static fromVersionString(versionString: string): API {
let version = semver.valid(versionString);

View File

@@ -6,7 +6,7 @@
import * as vscode from 'vscode';
import { loadMessageBundle } from 'vscode-nls';
import { ITypeScriptServiceClient } from '../typescriptService';
import TelemetryReporter from './telemetry';
import { TelemetryReporter } from './telemetry';
import { isImplicitProjectConfigFile, openOrCreateConfigFile } from './tsconfig';
const localize = loadMessageBundle();

View File

@@ -13,8 +13,12 @@ interface PackageInfo {
readonly aiKey: string;
}
export default interface TelemetryReporter {
logTelemetry(eventName: string, properties?: { readonly [prop: string]: string }): void;
export interface TelemetryProperties {
readonly [prop: string]: string | number | undefined;
}
export interface TelemetryReporter {
logTelemetry(eventName: string, properties?: TelemetryProperties): void;
dispose(): void;
}

View File

@@ -9,12 +9,18 @@
import * as vscode from 'vscode';
import * as Proto from '../protocol';
import * as PConst from '../protocol.const';
import { ITypeScriptServiceClient } from '../typescriptService';
export namespace Range {
export const fromTextSpan = (span: Proto.TextSpan): vscode.Range =>
fromLocations(span.start, span.end);
export const toTextSpan = (range: vscode.Range): Proto.TextSpan => ({
start: Position.toLocation(range.start),
end: Position.toLocation(range.end)
});
export const fromLocations = (start: Proto.Location, end: Proto.Location): vscode.Range =>
new vscode.Range(
Math.max(0, start.line - 1), Math.max(start.offset - 1, 0),
@@ -90,3 +96,33 @@ export namespace WorkspaceEdit {
return workspaceEdit;
}
}
export namespace SymbolKind {
export function fromProtocolScriptElementKind(kind: Proto.ScriptElementKind) {
switch (kind) {
case PConst.Kind.module: return vscode.SymbolKind.Module;
case PConst.Kind.class: return vscode.SymbolKind.Class;
case PConst.Kind.enum: return vscode.SymbolKind.Enum;
case PConst.Kind.enumMember: return vscode.SymbolKind.EnumMember;
case PConst.Kind.interface: return vscode.SymbolKind.Interface;
case PConst.Kind.indexSignature: return vscode.SymbolKind.Method;
case PConst.Kind.callSignature: return vscode.SymbolKind.Method;
case PConst.Kind.memberFunction: return vscode.SymbolKind.Method;
case PConst.Kind.memberVariable: return vscode.SymbolKind.Property;
case PConst.Kind.memberGetAccessor: return vscode.SymbolKind.Property;
case PConst.Kind.memberSetAccessor: return vscode.SymbolKind.Property;
case PConst.Kind.variable: return vscode.SymbolKind.Variable;
case PConst.Kind.let: return vscode.SymbolKind.Variable;
case PConst.Kind.const: return vscode.SymbolKind.Variable;
case PConst.Kind.localVariable: return vscode.SymbolKind.Variable;
case PConst.Kind.alias: return vscode.SymbolKind.Variable;
case PConst.Kind.function: return vscode.SymbolKind.Function;
case PConst.Kind.localFunction: return vscode.SymbolKind.Function;
case PConst.Kind.constructSignature: return vscode.SymbolKind.Constructor;
case PConst.Kind.constructorImplementation: return vscode.SymbolKind.Constructor;
case PConst.Kind.typeParameter: return vscode.SymbolKind.TypeParameter;
case PConst.Kind.string: return vscode.SymbolKind.String;
default: return vscode.SymbolKind.Variable;
}
}
}