From e9330d49949e64a103cb9f7eb303c4b2cb300b90 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 27 Jul 2017 12:40:48 -0700 Subject: [PATCH 1/5] Add test case for code fixes on qualified names used instead of indexed access types. --- .../codeFixReplaceQualifiedNameWithIndexedAccessType01.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/cases/fourslash/codeFixReplaceQualifiedNameWithIndexedAccessType01.ts diff --git a/tests/cases/fourslash/codeFixReplaceQualifiedNameWithIndexedAccessType01.ts b/tests/cases/fourslash/codeFixReplaceQualifiedNameWithIndexedAccessType01.ts new file mode 100644 index 0000000000..ffcc9ffeac --- /dev/null +++ b/tests/cases/fourslash/codeFixReplaceQualifiedNameWithIndexedAccessType01.ts @@ -0,0 +1,8 @@ +/// + +//// export interface Foo { +//// bar: string; +//// } +//// const x: [|Foo.bar|] = "" + +verify.rangeAfterCodeFix(`Foo["bar"]`); From 0dc74245e2072610d84d0bd03264793bca750315 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 27 Jul 2017 12:42:11 -0700 Subject: [PATCH 2/5] Added codefix for replacing qualified names with indexed access types. --- src/compiler/diagnosticMessages.json | 4 +++ ...correctQualifiedNameToIndexedAccessType.ts | 27 +++++++++++++++++++ src/services/codefixes/fixes.ts | 1 + 3 files changed, 32 insertions(+) create mode 100644 src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 0d9e7a0a6b..1ffc78134c 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3657,6 +3657,10 @@ "category": "Message", "code": 90025 }, + "Rewrite as the indexed access type '{0}'.": { + "category": "Message", + "code": 90026 + }, "Convert function to an ES2015 class": { "category": "Message", diff --git a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts new file mode 100644 index 0000000000..3087d73276 --- /dev/null +++ b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts @@ -0,0 +1,27 @@ +/* @internal */ +namespace ts.codefix { + registerCodeFix({ + errorCodes: [Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1.code], + getCodeActions: (context: CodeFixContext) => { + const sourceFile = context.sourceFile; + const token = getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false); + const qualifiedName = getAncestor(token, SyntaxKind.QualifiedName) as QualifiedName; + Debug.assert(!!qualifiedName, "Expected position to be owned by a qualified name."); + if (!isIdentifier(qualifiedName.left)) { + return undefined; + } + const leftText = qualifiedName.left.getText(sourceFile); + const rightText = qualifiedName.right.getText(sourceFile); + const replacement = createIndexedAccessTypeNode( + createTypeReferenceNode(qualifiedName.left, /*typeArguments*/ undefined), + createLiteralTypeNode(createLiteral(rightText))); + const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context); + changeTracker.replaceNode(sourceFile, qualifiedName, replacement); + + return [{ + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Rewrite_as_the_indexed_access_type_0), [`${leftText}["${rightText}"]`]), + changes: changeTracker.getChanges() + }]; + } + }); +} diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index ef670c81ba..9bc80cad69 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -1,3 +1,4 @@ +/// /// /// /// From 935b895ac11277cf3cfdf70f794d641cbd966007 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 27 Jul 2017 14:55:29 -0700 Subject: [PATCH 3/5] Added/augmented tests. --- .../compiler/errorForUsingPropertyOfTypeAsType01.ts | 9 ++++++++- ...tiveReplaceQualifiedNameWithIndexedAccessType01.ts | 11 +++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/codeFixNegativeReplaceQualifiedNameWithIndexedAccessType01.ts diff --git a/tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts b/tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts index c20102881e..8ce16b6fcd 100644 --- a/tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts +++ b/tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts @@ -4,6 +4,7 @@ namespace Test1 { } var x: Foo.bar = ""; + var y: Test1.Foo.bar = ""; } namespace Test2 { @@ -12,6 +13,7 @@ namespace Test2 { } var x: Foo.bar = ""; + var y: Test2.Foo.bar = ""; } namespace Test3 { @@ -20,6 +22,7 @@ namespace Test3 { } var x: Foo.bar = ""; + var y: Test3.Foo.bar = ""; } namespace Test4 { @@ -27,6 +30,7 @@ namespace Test4 { | { bar: string } var x: Foo.bar = ""; + var y: Test4.Foo.bar = ""; } namespace Test5 { @@ -34,4 +38,7 @@ namespace Test5 { | { wat: string } var x: Foo.bar = ""; -} \ No newline at end of file + var y: Test5.Foo.bar = ""; +} + +import lol = Test5.Foo. \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixNegativeReplaceQualifiedNameWithIndexedAccessType01.ts b/tests/cases/fourslash/codeFixNegativeReplaceQualifiedNameWithIndexedAccessType01.ts new file mode 100644 index 0000000000..683e45f056 --- /dev/null +++ b/tests/cases/fourslash/codeFixNegativeReplaceQualifiedNameWithIndexedAccessType01.ts @@ -0,0 +1,11 @@ +/// + + +//// namespace Container { +//// export interface Foo { +//// bar: string; +//// } +//// } +//// const x: [|Container.Foo.bar|] = "" + +verify.not.codeFixAvailable(); From 3205ca68c07d5bb770e92839ad4706d4c9e248a3 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 27 Jul 2017 14:56:04 -0700 Subject: [PATCH 4/5] Updated baselines. --- ...rForUsingPropertyOfTypeAsType01.errors.txt | 40 ++++++++++++++++--- .../errorForUsingPropertyOfTypeAsType01.js | 15 ++++++- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.errors.txt b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.errors.txt index 0dd9a597e9..0c55ba75f1 100644 --- a/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.errors.txt +++ b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.errors.txt @@ -1,11 +1,18 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(6,12): error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'? -tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(14,12): error TS2503: Cannot find namespace 'Foo'. -tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(22,12): error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'? -tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(29,12): error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'? -tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702: 'Foo' only refers to a type, but is being used as a namespace here. +tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(7,18): error TS2694: Namespace 'Test1' has no exported member 'Foo'. +tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(15,12): error TS2503: Cannot find namespace 'Foo'. +tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(16,18): error TS2694: Namespace 'Test2' has no exported member 'Foo'. +tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(24,12): error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'? +tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(25,18): error TS2694: Namespace 'Test3' has no exported member 'Foo'. +tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(32,12): error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'? +tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(33,18): error TS2694: Namespace 'Test4' has no exported member 'Foo'. +tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(40,12): error TS2702: 'Foo' only refers to a type, but is being used as a namespace here. +tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(41,18): error TS2694: Namespace 'Test5' has no exported member 'Foo'. +tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(44,20): error TS2694: Namespace 'Test5' has no exported member 'Foo'. +tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(44,24): error TS1003: Identifier expected. -==== tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts (5 errors) ==== +==== tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts (12 errors) ==== namespace Test1 { export interface Foo { bar: string; @@ -14,6 +21,9 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702 var x: Foo.bar = ""; ~~~~~~~ !!! error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'? + var y: Test1.Foo.bar = ""; + ~~~ +!!! error TS2694: Namespace 'Test1' has no exported member 'Foo'. } namespace Test2 { @@ -24,6 +34,9 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702 var x: Foo.bar = ""; ~~~ !!! error TS2503: Cannot find namespace 'Foo'. + var y: Test2.Foo.bar = ""; + ~~~ +!!! error TS2694: Namespace 'Test2' has no exported member 'Foo'. } namespace Test3 { @@ -34,6 +47,9 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702 var x: Foo.bar = ""; ~~~~~~~ !!! error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'? + var y: Test3.Foo.bar = ""; + ~~~ +!!! error TS2694: Namespace 'Test3' has no exported member 'Foo'. } namespace Test4 { @@ -43,6 +59,9 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702 var x: Foo.bar = ""; ~~~~~~~ !!! error TS2713: Cannot access 'Foo.bar' because 'Foo' is a type, but not a namespace. Did you mean to retrieve the type of the property 'bar' in 'Foo' with 'Foo["bar"]'? + var y: Test4.Foo.bar = ""; + ~~~ +!!! error TS2694: Namespace 'Test4' has no exported member 'Foo'. } namespace Test5 { @@ -52,4 +71,13 @@ tests/cases/compiler/errorForUsingPropertyOfTypeAsType01.ts(36,12): error TS2702 var x: Foo.bar = ""; ~~~ !!! error TS2702: 'Foo' only refers to a type, but is being used as a namespace here. - } \ No newline at end of file + var y: Test5.Foo.bar = ""; + ~~~ +!!! error TS2694: Namespace 'Test5' has no exported member 'Foo'. + } + + import lol = Test5.Foo. + ~~~ +!!! error TS2694: Namespace 'Test5' has no exported member 'Foo'. + +!!! error TS1003: Identifier expected. \ No newline at end of file diff --git a/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.js b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.js index 8a70396880..26903a9798 100644 --- a/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.js +++ b/tests/baselines/reference/errorForUsingPropertyOfTypeAsType01.js @@ -5,6 +5,7 @@ namespace Test1 { } var x: Foo.bar = ""; + var y: Test1.Foo.bar = ""; } namespace Test2 { @@ -13,6 +14,7 @@ namespace Test2 { } var x: Foo.bar = ""; + var y: Test2.Foo.bar = ""; } namespace Test3 { @@ -21,6 +23,7 @@ namespace Test3 { } var x: Foo.bar = ""; + var y: Test3.Foo.bar = ""; } namespace Test4 { @@ -28,6 +31,7 @@ namespace Test4 { | { bar: string } var x: Foo.bar = ""; + var y: Test4.Foo.bar = ""; } namespace Test5 { @@ -35,12 +39,16 @@ namespace Test5 { | { wat: string } var x: Foo.bar = ""; -} + var y: Test5.Foo.bar = ""; +} + +import lol = Test5.Foo. //// [errorForUsingPropertyOfTypeAsType01.js] var Test1; (function (Test1) { var x = ""; + var y = ""; })(Test1 || (Test1 = {})); var Test2; (function (Test2) { @@ -51,16 +59,21 @@ var Test2; }()); Test2.Foo = Foo; var x = ""; + var y = ""; })(Test2 || (Test2 = {})); var Test3; (function (Test3) { var x = ""; + var y = ""; })(Test3 || (Test3 = {})); var Test4; (function (Test4) { var x = ""; + var y = ""; })(Test4 || (Test4 = {})); var Test5; (function (Test5) { var x = ""; + var y = ""; })(Test5 || (Test5 = {})); +var lol = Test5.Foo.; From c659fe902d28d65cf76451f59a60258f3af2b2db Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 27 Jul 2017 15:06:30 -0700 Subject: [PATCH 5/5] Remove unnecessary references in 'src/harness/tsconfig.json' - they're already referenced in 'src/harness/codefixes/fixes.ts'. --- src/harness/tsconfig.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 8d52791f53..66ca2fc3f4 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -74,11 +74,6 @@ "../services/formatting/tokenRange.ts", "../services/codeFixProvider.ts", "../services/codefixes/fixes.ts", - "../services/codefixes/fixExtendsInterfaceBecomesImplements.ts", - "../services/codefixes/fixClassIncorrectlyImplementsInterface.ts", - "../services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts", - "../services/codefixes/fixClassSuperMustPrecedeThisAccess.ts", - "../services/codefixes/fixConstructorForDerivedNeedSuperCall.ts", "../services/codefixes/helpers.ts", "../services/codefixes/importFixes.ts", "../services/codefixes/fixUnusedIdentifier.ts",