Merge branch 'master' into fix-implement-interface-with-extends-class

This commit is contained in:
王文璐
2018-05-30 09:05:56 +08:00
112 changed files with 1302 additions and 762 deletions
+13 -3
View File
@@ -10592,6 +10592,16 @@ namespace ts {
else if (source.symbol && source.flags & TypeFlags.Object && globalObjectType === source) {
reportError(Diagnostics.The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead);
}
else if (getObjectFlags(source) & ObjectFlags.JsxAttributes && target.flags & TypeFlags.Intersection) {
const targetTypes = (target as IntersectionType).types;
const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, errorNode);
const intrinsicClassAttributes = getJsxType(JsxNames.IntrinsicClassAttributes, errorNode);
if (intrinsicAttributes !== unknownType && intrinsicClassAttributes !== unknownType &&
(contains(targetTypes, intrinsicAttributes) || contains(targetTypes, intrinsicClassAttributes))) {
// do not report top error
return result;
}
}
reportRelationError(headMessage, source, target);
}
return result;
@@ -16274,7 +16284,7 @@ namespace ts {
return createJsxAttributesTypeFromAttributesProperty(node.parent, checkMode);
}
function getJsxType(name: __String, location: Node) {
function getJsxType(name: __String, location: Node | undefined) {
const namespace = getJsxNamespaceAt(location);
const exports = namespace && getExportsOfSymbol(namespace);
const typeSymbol = exports && getSymbol(exports, name, SymbolFlags.Type);
@@ -16372,7 +16382,7 @@ namespace ts {
return getSignatureInstantiation(signature, args, isJavascript);
}
function getJsxNamespaceAt(location: Node): Symbol {
function getJsxNamespaceAt(location: Node | undefined): Symbol {
const namespaceName = getJsxNamespace(location);
const resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false);
if (resolvedNamespace) {
@@ -20418,7 +20428,7 @@ namespace ts {
if (propType.symbol && propType.symbol.flags & SymbolFlags.Class) {
const name = prop.escapedName;
const symbol = resolveName(prop.valueDeclaration, name, SymbolFlags.Type, undefined, name, /*isUse*/ false);
if (symbol) {
if (symbol && propType.symbol !== symbol) {
grammarErrorOnNode(symbol.declarations[0], Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name));
return grammarErrorOnNode(prop.valueDeclaration, Diagnostics.Duplicate_identifier_0, unescapeLeadingUnderscores(name));
}
+1 -1
View File
@@ -416,7 +416,7 @@ namespace ts {
createLogicalNot(getDone)
),
/*incrementor*/ undefined,
/*statement*/ convertForOfStatementHead(node, createDownlevelAwait(getValue))
/*statement*/ convertForOfStatementHead(node, getValue)
),
/*location*/ node
),
+2 -2
View File
@@ -3252,8 +3252,8 @@ namespace ts {
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [0, t.value];
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
+1 -1
View File
@@ -868,7 +868,7 @@ namespace FourSlash {
for (const entry of actualCompletions.entries) {
if (actualByName.has(entry.name)) {
// TODO: GH#23587
if (entry.name !== "undefined" && entry.name !== "require") this.raiseError(`Duplicate completions for ${entry.name}`);
if (entry.name !== "undefined" && entry.name !== "require") this.raiseError(`Duplicate (${actualCompletions.entries.filter(a => a.name === entry.name).length}) completions for ${entry.name}`);
}
else {
actualByName.set(entry.name, entry);
@@ -0,0 +1,148 @@
/// <reference path="..\harness.ts" />
namespace ts {
declare var Symbol: SymbolConstructor;
describe("forAwaitOfEvaluation", () => {
const sourceFile = vpath.combine(vfs.srcFolder, "source.ts");
function compile(sourceText: string, options?: CompilerOptions) {
const fs = vfs.createFromFileSystem(Harness.IO, /*ignoreCase*/ false);
fs.writeFileSync(sourceFile, sourceText);
const compilerOptions: CompilerOptions = { target: ScriptTarget.ES5, module: ModuleKind.CommonJS, lib: ["lib.esnext.d.ts"], ...options };
const host = new fakes.CompilerHost(fs, compilerOptions);
return compiler.compileFiles(host, [sourceFile], compilerOptions);
}
function noRequire(id: string) {
throw new Error(`Module '${id}' could not be found.`);
}
// Define a custom "Symbol" constructor to attach missing built-in symbols without
// modifying the global "Symbol" constructor
// tslint:disable-next-line:variable-name
const FakeSymbol: SymbolConstructor = ((description?: string) => Symbol(description)) as any;
(<any>FakeSymbol).prototype = Symbol.prototype;
for (const key of Object.getOwnPropertyNames(Symbol)) {
Object.defineProperty(FakeSymbol, key, Object.getOwnPropertyDescriptor(Symbol, key)!);
}
// Add "asyncIterator" if missing
if (!hasProperty(FakeSymbol, "asyncIterator")) Object.defineProperty(FakeSymbol, "asyncIterator", { value: Symbol.for("Symbol.asyncIterator"), configurable: true });
function evaluate(result: compiler.CompilationResult) {
const output = result.getOutput(sourceFile, "js")!;
assert.isDefined(output);
const evaluateText = `(function (module, exports, require, __dirname, __filename, Symbol) { ${output.text} })`;
const evaluateThunk = eval(evaluateText) as (module: any, exports: any, require: (id: string) => any, dirname: string, filename: string, symbolConstructor: SymbolConstructor) => void;
const module: { exports: any; } = { exports: {} };
evaluateThunk(module, module.exports, noRequire, vpath.dirname(output.file), output.file, FakeSymbol);
return module;
}
it("sync (es5)", async () => {
const module = evaluate(compile(`
let i = 0;
const iterator = {
[Symbol.iterator]() { return this; },
next() {
switch (i++) {
case 0: return { value: 1, done: false };
case 1: return { value: Promise.resolve(2), done: false };
case 2: return { value: new Promise<number>(resolve => setTimeout(resolve, 100, 3)), done: false };
default: return { value: undefined: done: true };
}
}
};
export const output: any[] = [];
export async function main() {
for await (const item of iterator) {
output.push(item);
}
}`));
await module.exports.main();
assert.strictEqual(module.exports.output[0], 1);
assert.strictEqual(module.exports.output[1], 2);
assert.strictEqual(module.exports.output[2], 3);
});
it("sync (es2015)", async () => {
const module = evaluate(compile(`
let i = 0;
const iterator = {
[Symbol.iterator]() { return this; },
next() {
switch (i++) {
case 0: return { value: 1, done: false };
case 1: return { value: Promise.resolve(2), done: false };
case 2: return { value: new Promise<number>(resolve => setTimeout(resolve, 100, 3)), done: false };
default: return { value: undefined: done: true };
}
}
};
export const output: any[] = [];
export async function main() {
for await (const item of iterator) {
output.push(item);
}
}`, { target: ScriptTarget.ES2015 }));
await module.exports.main();
assert.strictEqual(module.exports.output[0], 1);
assert.strictEqual(module.exports.output[1], 2);
assert.strictEqual(module.exports.output[2], 3);
});
it("async (es5)", async () => {
const module = evaluate(compile(`
let i = 0;
const iterator = {
[Symbol.asyncIterator]() { return this; },
async next() {
switch (i++) {
case 0: return { value: 1, done: false };
case 1: return { value: Promise.resolve(2), done: false };
case 2: return { value: new Promise<number>(resolve => setTimeout(resolve, 100, 3)), done: false };
default: return { value: undefined: done: true };
}
}
};
export const output: any[] = [];
export async function main() {
for await (const item of iterator) {
output.push(item);
}
}`));
await module.exports.main();
assert.strictEqual(module.exports.output[0], 1);
assert.instanceOf(module.exports.output[1], Promise);
assert.instanceOf(module.exports.output[2], Promise);
});
it("async (es2015)", async () => {
const module = evaluate(compile(`
let i = 0;
const iterator = {
[Symbol.asyncIterator]() { return this; },
async next() {
switch (i++) {
case 0: return { value: 1, done: false };
case 1: return { value: Promise.resolve(2), done: false };
case 2: return { value: new Promise<number>(resolve => setTimeout(resolve, 100, 3)), done: false };
default: return { value: undefined: done: true };
}
}
};
export const output: any[] = [];
export async function main() {
for await (const item of iterator) {
output.push(item);
}
}`, { target: ScriptTarget.ES2015 }));
await module.exports.main();
assert.strictEqual(module.exports.output[0], 1);
assert.instanceOf(module.exports.output[1], Promise);
assert.instanceOf(module.exports.output[2], Promise);
});
});
}
@@ -2394,6 +2394,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_name_cannot_be_Object_when_targeting_ES5_with_module_0_2725" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class name cannot be 'Object' when targeting ES5 with module {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[使用模块 {0} 将目标设置为 ES5 时,类名称不能为 "Object"。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_static_side_0_incorrectly_extends_base_class_static_side_1_2417" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class static side '{0}' incorrectly extends base class static side '{1}'.]]></Val>
@@ -2559,6 +2568,9 @@
<Item ItemId=";Convert_0_to_mapped_object_type_95055" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert '{0}' to mapped object type]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[将“{0}”转换为映射对象类型]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -2394,6 +2394,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_name_cannot_be_Object_when_targeting_ES5_with_module_0_2725" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class name cannot be 'Object' when targeting ES5 with module {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[當目標為具有模組 {0} 的 ES5 時,類別名稱不可為 'Object'。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_static_side_0_incorrectly_extends_base_class_static_side_1_2417" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class static side '{0}' incorrectly extends base class static side '{1}'.]]></Val>
@@ -2556,6 +2565,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Convert_0_to_mapped_object_type_95055" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert '{0}' to mapped object type]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[將 '{0}' 轉換為對應的物件類型]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Convert_all_constructor_functions_to_classes_95045" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert all constructor functions to classes]]></Val>
@@ -2403,6 +2403,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_name_cannot_be_Object_when_targeting_ES5_with_module_0_2725" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class name cannot be 'Object' when targeting ES5 with module {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Když se cílí na ES5 s modulem {0}, název třídy nemůže být Object.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_static_side_0_incorrectly_extends_base_class_static_side_1_2417" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class static side '{0}' incorrectly extends base class static side '{1}'.]]></Val>
@@ -2568,6 +2577,9 @@
<Item ItemId=";Convert_0_to_mapped_object_type_95055" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert '{0}' to mapped object type]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Převést {0} na typ mapovaného objektu]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -2391,6 +2391,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_name_cannot_be_Object_when_targeting_ES5_with_module_0_2725" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class name cannot be 'Object' when targeting ES5 with module {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Der Klassenname darf nicht "Object" lauten, wenn ES5 mit Modul "{0}" als Ziel verwendet wird.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_static_side_0_incorrectly_extends_base_class_static_side_1_2417" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class static side '{0}' incorrectly extends base class static side '{1}'.]]></Val>
@@ -2556,6 +2565,9 @@
<Item ItemId=";Convert_0_to_mapped_object_type_95055" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert '{0}' to mapped object type]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA["{0}" in zugeordneten Objekttyp konvertieren]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -2406,6 +2406,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_name_cannot_be_Object_when_targeting_ES5_with_module_0_2725" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class name cannot be 'Object' when targeting ES5 with module {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Le nom de la classe ne peut pas être 'Object' quand ES5 est ciblé avec le module {0}.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_static_side_0_incorrectly_extends_base_class_static_side_1_2417" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class static side '{0}' incorrectly extends base class static side '{1}'.]]></Val>
@@ -2568,6 +2577,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Convert_0_to_mapped_object_type_95055" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert '{0}' to mapped object type]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Convertir '{0}' en type d'objet mappé]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Convert_all_constructor_functions_to_classes_95045" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert all constructor functions to classes]]></Val>
@@ -2394,6 +2394,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_name_cannot_be_Object_when_targeting_ES5_with_module_0_2725" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class name cannot be 'Object' when targeting ES5 with module {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Il nome della classe non può essere 'Object' quando la destinazione è ES5 con il modulo {0}.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_static_side_0_incorrectly_extends_base_class_static_side_1_2417" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class static side '{0}' incorrectly extends base class static side '{1}'.]]></Val>
@@ -2559,6 +2568,9 @@
<Item ItemId=";Convert_0_to_mapped_object_type_95055" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert '{0}' to mapped object type]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Convertire '{0}' nel tipo di oggetto con mapping]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -2394,6 +2394,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_name_cannot_be_Object_when_targeting_ES5_with_module_0_2725" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class name cannot be 'Object' when targeting ES5 with module {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[{0} 모듈을 사용하는 ES5를 대상으로 하는 경우 클래스 이름은 'Object'일 수 없습니다.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_static_side_0_incorrectly_extends_base_class_static_side_1_2417" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class static side '{0}' incorrectly extends base class static side '{1}'.]]></Val>
@@ -2559,6 +2568,9 @@
<Item ItemId=";Convert_0_to_mapped_object_type_95055" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert '{0}' to mapped object type]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA['{0}'을(를) 매핑된 개체 형식으로 변환]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -2384,6 +2384,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_name_cannot_be_Object_when_targeting_ES5_with_module_0_2725" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class name cannot be 'Object' when targeting ES5 with module {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Nazwą klasy nie może być słowo „Object”, gdy docelowym językiem jest ES5 z modułem {0}.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_static_side_0_incorrectly_extends_base_class_static_side_1_2417" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class static side '{0}' incorrectly extends base class static side '{1}'.]]></Val>
@@ -2549,6 +2558,9 @@
<Item ItemId=";Convert_0_to_mapped_object_type_95055" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert '{0}' to mapped object type]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Konwertuj element „{0}” na zamapowany typ obiektu]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -2393,6 +2393,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_name_cannot_be_Object_when_targeting_ES5_with_module_0_2725" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class name cannot be 'Object' when targeting ES5 with module {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Класс не может иметь имя "Object" при выборе ES5 с модулем {0} в качестве целевого.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_static_side_0_incorrectly_extends_base_class_static_side_1_2417" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class static side '{0}' incorrectly extends base class static side '{1}'.]]></Val>
@@ -2555,6 +2564,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Convert_0_to_mapped_object_type_95055" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert '{0}' to mapped object type]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Преобразовать "{0}" в тип сопоставленного объекта]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Convert_all_constructor_functions_to_classes_95045" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert all constructor functions to classes]]></Val>
@@ -2387,6 +2387,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_name_cannot_be_Object_when_targeting_ES5_with_module_0_2725" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class name cannot be 'Object' when targeting ES5 with module {0}.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Modül {0} ile ES5 hedeflendiğinde sınıf adı 'Object' olamaz.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Class_static_side_0_incorrectly_extends_base_class_static_side_1_2417" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Class static side '{0}' incorrectly extends base class static side '{1}'.]]></Val>
@@ -2552,6 +2561,9 @@
<Item ItemId=";Convert_0_to_mapped_object_type_95055" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert '{0}' to mapped object type]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA['{0}' öğesini eşlenen nesne türüne dönüştür]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
+46 -14
View File
@@ -14,7 +14,8 @@ namespace ts.codefix {
registerCodeFix({
errorCodes,
getCodeActions(context) {
const { errorCode, sourceFile } = context;
const { errorCode, sourceFile, program } = context;
const checker = program.getTypeChecker();
const startToken = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false);
const importDecl = tryGetFullImport(startToken);
@@ -22,7 +23,7 @@ namespace ts.codefix {
const changes = textChanges.ChangeTracker.with(context, t => t.deleteNode(sourceFile, importDecl));
return [createCodeFixAction(fixName, changes, [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)], fixIdDelete, Diagnostics.Delete_all_unused_declarations)];
}
const delDestructure = textChanges.ChangeTracker.with(context, t => tryDeleteFullDestructure(t, sourceFile, startToken, /*deleted*/ undefined));
const delDestructure = textChanges.ChangeTracker.with(context, t => tryDeleteFullDestructure(t, sourceFile, startToken, /*deleted*/ undefined, checker, /*isFixAll*/ false));
if (delDestructure.length) {
return [createCodeFixAction(fixName, delDestructure, Diagnostics.Remove_destructuring, fixIdDelete, Diagnostics.Delete_all_unused_declarations)];
}
@@ -34,7 +35,7 @@ namespace ts.codefix {
const token = getToken(sourceFile, textSpanEnd(context.span));
const result: CodeFixAction[] = [];
const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(t, sourceFile, token, /*deleted*/ undefined));
const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(t, sourceFile, token, /*deleted*/ undefined, checker, /*isFixAll*/ false));
if (deletion.length) {
result.push(createCodeFixAction(fixName, deletion, [Diagnostics.Remove_declaration_for_Colon_0, token.getText(sourceFile)], fixIdDelete, Diagnostics.Delete_all_unused_declarations));
}
@@ -50,8 +51,9 @@ namespace ts.codefix {
getAllCodeActions: context => {
// Track a set of deleted nodes that may be ancestors of other marked for deletion -- only delete the ancestors.
const deleted = new NodeSet();
const { sourceFile, program } = context;
const checker = program.getTypeChecker();
return codeFixAll(context, errorCodes, (changes, diag) => {
const { sourceFile } = context;
const startToken = getTokenAtPosition(sourceFile, diag.start, /*includeJsDocComment*/ false);
const token = findPrecedingToken(textSpanEnd(diag), diag.file)!;
switch (context.fixId) {
@@ -68,8 +70,9 @@ namespace ts.codefix {
if (importDecl) {
changes.deleteNode(sourceFile, importDecl);
}
else if (!tryDeleteFullDestructure(changes, sourceFile, startToken, deleted) && !tryDeleteFullVariableStatement(changes, sourceFile, startToken, deleted)) {
tryDeleteDeclaration(changes, sourceFile, token, deleted);
else if (!tryDeleteFullDestructure(changes, sourceFile, startToken, deleted, checker, /*isFixAll*/ true) &&
!tryDeleteFullVariableStatement(changes, sourceFile, startToken, deleted)) {
tryDeleteDeclaration(changes, sourceFile, token, deleted, checker, /*isFixAll*/ true);
}
break;
default:
@@ -84,7 +87,7 @@ namespace ts.codefix {
return startToken.kind === SyntaxKind.ImportKeyword ? tryCast(startToken.parent, isImportDeclaration) : undefined;
}
function tryDeleteFullDestructure(changes: textChanges.ChangeTracker, sourceFile: SourceFile, startToken: Node, deletedAncestors: NodeSet | undefined): boolean {
function tryDeleteFullDestructure(changes: textChanges.ChangeTracker, sourceFile: SourceFile, startToken: Node, deletedAncestors: NodeSet | undefined, checker: TypeChecker, isFixAll: boolean): boolean {
if (startToken.kind !== SyntaxKind.OpenBraceToken || !isObjectBindingPattern(startToken.parent)) return false;
const decl = cast(startToken.parent, isObjectBindingPattern).parent;
switch (decl.kind) {
@@ -92,6 +95,7 @@ namespace ts.codefix {
tryDeleteVariableDeclaration(changes, sourceFile, decl, deletedAncestors);
break;
case SyntaxKind.Parameter:
if (!mayDeleteParameter(decl, checker, isFixAll)) break;
if (deletedAncestors) deletedAncestors.add(decl);
changes.deleteNodeInList(sourceFile, decl);
break;
@@ -144,10 +148,10 @@ namespace ts.codefix {
return false;
}
function tryDeleteDeclaration(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, deletedAncestors: NodeSet | undefined): void {
function tryDeleteDeclaration(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, deletedAncestors: NodeSet | undefined, checker: TypeChecker, isFixAll: boolean): void {
switch (token.kind) {
case SyntaxKind.Identifier:
tryDeleteIdentifier(changes, sourceFile, <Identifier>token, deletedAncestors);
tryDeleteIdentifier(changes, sourceFile, <Identifier>token, deletedAncestors, checker, isFixAll);
break;
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.NamespaceImport:
@@ -170,7 +174,7 @@ namespace ts.codefix {
}
}
function tryDeleteIdentifier(changes: textChanges.ChangeTracker, sourceFile: SourceFile, identifier: Identifier, deletedAncestors: NodeSet | undefined): void {
function tryDeleteIdentifier(changes: textChanges.ChangeTracker, sourceFile: SourceFile, identifier: Identifier, deletedAncestors: NodeSet | undefined, checker: TypeChecker, isFixAll: boolean): void {
const parent = identifier.parent;
switch (parent.kind) {
case SyntaxKind.VariableDeclaration:
@@ -194,11 +198,8 @@ namespace ts.codefix {
break;
case SyntaxKind.Parameter:
if (!mayDeleteParameter(parent as ParameterDeclaration, checker, isFixAll)) break;
const oldFunction = parent.parent;
if (isSetAccessor(oldFunction)) {
// Setter must have a parameter
break;
}
if (isArrowFunction(oldFunction) && oldFunction.parameters.length === 1) {
// Lambdas with exactly one parameter are special because, after removal, there
@@ -347,4 +348,35 @@ namespace ts.codefix {
}
}
}
function mayDeleteParameter(p: ParameterDeclaration, checker: TypeChecker, isFixAll: boolean) {
const parent = p.parent;
switch (parent.kind) {
case SyntaxKind.MethodDeclaration:
// Don't remove a parameter if this overrides something
const symbol = checker.getSymbolAtLocation(parent.name)!;
if (isMemberSymbolInBaseType(symbol, checker)) return false;
// falls through
case SyntaxKind.Constructor:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction: {
// Can't remove a non-last parameter. Can remove a parameter in code-fix-all if future parameters are also unused.
const { parameters } = parent;
const index = parameters.indexOf(p);
Debug.assert(index !== -1);
return isFixAll
? parameters.slice(index + 1).every(p => p.name.kind === SyntaxKind.Identifier && !p.symbol.isReferenced)
: index === parameters.length - 1;
}
case SyntaxKind.SetAccessor:
// Setter must have a parameter
return false;
default:
return Debug.failBadSyntaxKind(parent);
}
}
}
+15 -22
View File
@@ -16,15 +16,18 @@ namespace ts.moduleSpecifiers {
const getCanonicalFileName = hostGetCanonicalFileName(host);
const sourceDirectory = getDirectoryPath(importingSourceFile.fileName);
return getAllModulePaths(program, moduleSymbol.valueDeclaration.getSourceFile()).map(moduleFileName => {
const global = tryGetModuleNameFromAmbientModule(moduleSymbol)
|| tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension)
|| tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory)
|| rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName);
if (global) {
return [global];
}
const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol);
if (ambient) return [[ambient]];
const modulePaths = getAllModulePaths(program, moduleSymbol.valueDeclaration.getSourceFile());
const global = mapDefined(modulePaths, moduleFileName =>
tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension) ||
tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory) ||
rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName));
if (global.length) return global.map(g => [g]);
return modulePaths.map(moduleFileName => {
const relativePath = removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), moduleResolutionKind, addJsExtension);
if (!baseUrl || preferences.importModuleSpecifierPreference === "relative") {
return [relativePath];
@@ -191,11 +194,12 @@ namespace ts.moduleSpecifiers {
// Simplify the full file path to something that can be resolved by Node.
// If the module could be imported by a directory name, use that directory's name
let moduleSpecifier = getDirectoryOrExtensionlessFileName(moduleFileName);
const moduleSpecifier = getDirectoryOrExtensionlessFileName(moduleFileName);
// Get a path that's relative to node_modules or the importing file's path
moduleSpecifier = getNodeResolvablePath(moduleSpecifier);
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
if (!startsWith(sourceDirectory, moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex))) return undefined;
// If the module was found in @types, get the actual Node package name
return getPackageNameFromAtTypesDirectory(moduleSpecifier);
return getPackageNameFromAtTypesDirectory(moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1));
function getDirectoryOrExtensionlessFileName(path: string): string {
// If the file is the main module, it can be imported by the package name
@@ -224,17 +228,6 @@ namespace ts.moduleSpecifiers {
return fullModulePathWithoutExtension;
}
function getNodeResolvablePath(path: string): string {
const basePath = path.substring(0, parts.topLevelNodeModulesIndex);
if (sourceDirectory.indexOf(basePath) === 0) {
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
return path.substring(parts.topLevelPackageNameIndex + 1);
}
else {
return ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, path, getCanonicalFileName));
}
}
}
interface NodeModulePathParts {
+9 -1
View File
@@ -1320,12 +1320,20 @@ namespace ts.Completions {
function getSymbolsFromOtherSourceFileExports(symbols: Symbol[], tokenText: string, target: ScriptTarget): void {
const tokenTextLowerCase = tokenText.toLowerCase();
const seenResolvedModules = createMap<true>();
codefix.forEachExternalModuleToImportFrom(typeChecker, sourceFile, program.getSourceFiles(), moduleSymbol => {
// Perf -- ignore other modules if this is a request for details
if (detailsEntryId && detailsEntryId.source && stripQuotes(moduleSymbol.name) !== detailsEntryId.source) {
return;
}
const resolvedModuleSymbol = typeChecker.resolveExternalModuleSymbol(moduleSymbol);
// resolvedModuleSymbol may be a namespace. A namespace may be `export =` by multiple module declarations, but only keep the first one.
if (!addToSeen(seenResolvedModules, getSymbolId(resolvedModuleSymbol))) {
return;
}
for (let symbol of typeChecker.getExportsOfModule(moduleSymbol)) {
// Don't add a completion for a re-export, only for the original.
// The actual import fix might end up coming from a re-export -- we don't compute that until getting completion details.
@@ -1333,7 +1341,7 @@ namespace ts.Completions {
//
// If `symbol.parent !== ...`, this comes from an `export * from "foo"` re-export. Those don't create new symbols.
// If `some(...)`, this comes from an `export { foo } from "foo"` re-export, which creates a new symbol (thus isn't caught by the first check).
if (typeChecker.getMergedSymbol(symbol.parent!) !== typeChecker.resolveExternalModuleSymbol(moduleSymbol)
if (typeChecker.getMergedSymbol(symbol.parent!) !== resolvedModuleSymbol
|| some(symbol.declarations, d => isExportSpecifier(d) && !!d.parent.parent.moduleSpecifier)) {
continue;
}
+1 -1
View File
@@ -180,7 +180,7 @@ namespace ts.DocumentHighlights {
default:
// Don't cross function boundaries.
// TODO: GH#20090
return (isFunctionLike(node) && "quit") as false | "quit";
return isFunctionLike(node) && "quit";
}
});
}
-28
View File
@@ -1399,34 +1399,6 @@ namespace ts.FindAllReferences.Core {
}
}
/**
* Find symbol of the given property-name and add the symbol to the given result array
* @param symbol a symbol to start searching for the given propertyName
* @param propertyName a name of property to search for
* @param result an array of symbol of found property symbols
* @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisiting of the same symbol.
* The value of previousIterationSymbol is undefined when the function is first called.
*/
function getPropertySymbolsFromBaseTypes<T>(symbol: Symbol, propertyName: string, checker: TypeChecker, cb: (symbol: Symbol) => T | undefined): T | undefined {
const seen = createMap<true>();
return recur(symbol);
function recur(symbol: Symbol): T | undefined {
// Use `addToSeen` to ensure we don't infinitely recurse in this situation:
// interface C extends C {
// /*findRef*/propName: string;
// }
if (!(symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) || !addToSeen(seen, getSymbolId(symbol))) return;
return firstDefined(symbol.declarations, declaration => firstDefined(getAllSuperTypeNodes(declaration), typeReference => {
const type = checker.getTypeAtLocation(typeReference);
const propertySymbol = type && type.symbol && checker.getPropertyOfType(type, propertyName);
// Visit the typeReference as well to see if it directly or indirectly uses that property
return propertySymbol && (firstDefined(checker.getRootSymbols(propertySymbol), cb) || recur(type!.symbol));
}));
}
}
function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): Symbol | undefined {
const { checker } = state;
return forEachRelatedSymbol(referenceSymbol, referenceLocation, checker,
+11 -16
View File
@@ -243,7 +243,7 @@ namespace ts.JsDoc {
}
const tokenAtPos = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false);
const tokenStart = tokenAtPos.getStart();
const tokenStart = tokenAtPos.getStart(sourceFile);
if (!tokenAtPos || tokenStart < position) {
return undefined;
}
@@ -253,7 +253,7 @@ namespace ts.JsDoc {
return undefined;
}
const { commentOwner, parameters } = commentOwnerInfo;
if (commentOwner.getStart() < position) {
if (commentOwner.getStart(sourceFile) < position) {
return undefined;
}
@@ -268,19 +268,6 @@ namespace ts.JsDoc {
// replace non-whitespace characters in prefix with spaces.
const indentationStr = sourceFile.text.substr(lineStart, posLineAndChar.character).replace(/\S/i, () => " ");
const isJavaScriptFile = hasJavaScriptFileExtension(sourceFile.fileName);
let docParams = "";
for (let i = 0; i < parameters.length; i++) {
const currentName = parameters[i].name;
const paramName = currentName.kind === SyntaxKind.Identifier ? currentName.escapedText : "param" + i;
if (isJavaScriptFile) {
docParams += `${indentationStr} * @param {any} ${paramName}${newLine}`;
}
else {
docParams += `${indentationStr} * @param ${paramName}${newLine}`;
}
}
// A doc comment consists of the following
// * The opening comment line
@@ -293,13 +280,21 @@ namespace ts.JsDoc {
indentationStr + " * ";
const result =
preamble + newLine +
docParams +
parameterDocComments(parameters, hasJavaScriptFileExtension(sourceFile.fileName), indentationStr, newLine) +
indentationStr + " */" +
(tokenStart === position ? newLine + indentationStr : "");
return { newText: result, caretOffset: preamble.length };
}
function parameterDocComments(parameters: ReadonlyArray<ParameterDeclaration>, isJavaScriptFile: boolean, indentationStr: string, newLine: string): string {
return parameters.map(({ name, dotDotDotToken }, i) => {
const paramName = name.kind === SyntaxKind.Identifier ? name.text : "param" + i;
const type = isJavaScriptFile ? (dotDotDotToken ? "{...any} " : "{any} ") : "";
return `${indentationStr} * @param ${type}${paramName}${newLine}`;
}).join("");
}
interface CommentOwnerInfo {
readonly commentOwner: Node;
readonly parameters?: ReadonlyArray<ParameterDeclaration>;
+3 -11
View File
@@ -1735,17 +1735,9 @@ namespace ts {
synchronizeHostData();
// Exclude default library when renaming as commonly user don't want to change that file.
let sourceFiles: SourceFile[] = [];
if (options && options.isForRename) {
for (const sourceFile of program.getSourceFiles()) {
if (!program.isSourceFileDefaultLibrary(sourceFile)) {
sourceFiles.push(sourceFile);
}
}
}
else {
sourceFiles = program.getSourceFiles().slice();
}
const sourceFiles = options && options.isForRename
? program.getSourceFiles().filter(sourceFile => !program.isSourceFileDefaultLibrary(sourceFile))
: program.getSourceFiles();
return FindAllReferences.findReferencedEntries(program, cancellationToken, sourceFiles, getValidSourceFile(fileName), position, options);
}
+32
View File
@@ -1293,6 +1293,38 @@ namespace ts {
return propSymbol;
}
/**
* Find symbol of the given property-name and add the symbol to the given result array
* @param symbol a symbol to start searching for the given propertyName
* @param propertyName a name of property to search for
* @param result an array of symbol of found property symbols
* @param previousIterationSymbolsCache a cache of symbol from previous iterations of calling this function to prevent infinite revisiting of the same symbol.
* The value of previousIterationSymbol is undefined when the function is first called.
*/
export function getPropertySymbolsFromBaseTypes<T>(symbol: Symbol, propertyName: string, checker: TypeChecker, cb: (symbol: Symbol) => T | undefined): T | undefined {
const seen = createMap<true>();
return recur(symbol);
function recur(symbol: Symbol): T | undefined {
// Use `addToSeen` to ensure we don't infinitely recurse in this situation:
// interface C extends C {
// /*findRef*/propName: string;
// }
if (!(symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) || !addToSeen(seen, getSymbolId(symbol))) return;
return firstDefined(symbol.declarations, declaration => firstDefined(getAllSuperTypeNodes(declaration), typeReference => {
const type = checker.getTypeAtLocation(typeReference);
const propertySymbol = type && type.symbol && checker.getPropertyOfType(type, propertyName);
// Visit the typeReference as well to see if it directly or indirectly uses that property
return type && propertySymbol && (firstDefined(checker.getRootSymbols(propertySymbol), cb) || recur(type.symbol));
}));
}
}
export function isMemberSymbolInBaseType(memberSymbol: Symbol, checker: TypeChecker): boolean {
return getPropertySymbolsFromBaseTypes(memberSymbol.parent!, memberSymbol.name, checker, _ => true) || false;
}
export class NodeSet {
private map = createMap<Node>();