/* * Copyright (c) 2013, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.engine.services.internal.refactoring; import com.google.dart.engine.ast.CompilationUnit; import com.google.dart.engine.context.AnalysisContextHelper; import com.google.dart.engine.services.change.Change; import com.google.dart.engine.services.change.SourceChange; import com.google.dart.engine.services.status.RefactoringStatusSeverity; import com.google.dart.engine.source.FileBasedSource; import com.google.dart.engine.source.Source; import java.io.File; /** * Test for {@link RenameClassMemberRefactoringImpl}. */ public class RenameClassMemberRefactoringImplTest extends RenameRefactoringImplTest { public void test_checkFinalConditions_hasMember_MethodElement() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " test() {}", " newName() {} // existing", "}"); createRenameRefactoring("test() {}"); // check status refactoring.checkInitialConditions(pm); refactoring.setNewName("newName"); assertRefactoringStatus( refactoring.checkFinalConditions(pm), RefactoringStatusSeverity.ERROR, "Class 'A' already declares method with name 'newName'.", findRangeIdentifier("newName() {} // existing")); } public void test_checkFinalConditions_ignoredSdkElements() throws Exception { verifyNoTestUnitErrors = false; indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A extends List<int> {", " add(x) {}", "}"); createRenameRefactoring("add(x) {}"); // check status refactoring.checkInitialConditions(pm); refactoring.setNewName("newName"); assertRefactoringStatus( refactoring.checkFinalConditions(pm), RefactoringStatusSeverity.WARNING, "Elements and references in SDK and external packages will not be renamed."); } public void test_checkFinalConditions_OK_noShadow() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int newName; // marker", "}", "class B {", " test() {}", "}", "class C extends A {", " main() {", " print(newName);", " }", "}"); createRenameRefactoring("test() {}"); // check status refactoring.checkInitialConditions(pm); refactoring.setNewName("newName"); assertRefactoringStatusOK(refactoring.checkFinalConditions(pm)); } public void test_checkFinalConditions_shadowed_byLocal_inSameClass() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " test() {}", " main() {", " var newName;", " test(); // marker", " }", "}"); createRenameRefactoring("test() {}"); // check status refactoring.checkInitialConditions(pm); refactoring.setNewName("newName"); assertRefactoringStatus( refactoring.checkFinalConditions(pm), RefactoringStatusSeverity.ERROR, "Usage of renamed method will be shadowed by local variable 'newName'.", findRangeIdentifier("test(); // marker")); } public void test_checkFinalConditions_shadowed_byLocal_inSubClass() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " test() {}", "}", "class B extends A {", " main() {", " var newName;", " test(); // marker", " }", "}", ""); createRenameRefactoring("test() {}"); // check status refactoring.checkInitialConditions(pm); refactoring.setNewName("newName"); assertRefactoringStatus( refactoring.checkFinalConditions(pm), RefactoringStatusSeverity.ERROR, "Usage of renamed method will be shadowed by local variable 'newName'.", findRangeIdentifier("test(); // marker")); } public void test_checkFinalConditions_shadowed_byLocal_OK_qualifiedReference() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " test() {}", " main() {", " var newName;", " }", "}"); createRenameRefactoring("test() {}"); // check status refactoring.checkInitialConditions(pm); refactoring.setNewName("newName"); assertRefactoringStatusOK(refactoring.checkFinalConditions(pm)); } public void test_checkFinalConditions_shadowed_byLocal_OK_renamedNotUsed() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " test() {}", " main() {", " var newName;", " this.test(); // marker", " }", "}"); createRenameRefactoring("test() {}"); // check status refactoring.checkInitialConditions(pm); refactoring.setNewName("newName"); assertRefactoringStatusOK(refactoring.checkFinalConditions(pm)); } public void test_checkFinalConditions_shadowed_byParameter_inSameClass() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " test() {}", " A(newName) {", " test(); // marker", " }", "}"); createRenameRefactoring("test() {}"); // check status refactoring.checkInitialConditions(pm); refactoring.setNewName("newName"); assertRefactoringStatus( refactoring.checkFinalConditions(pm), RefactoringStatusSeverity.ERROR, "Usage of renamed method will be shadowed by parameter 'newName'.", findRangeIdentifier("test(); // marker")); } public void test_checkFinalConditions_shadowed_inSubClass() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " test() {}", "}", "class B extends A {", " newName() {} // marker", " main() {", " test();", " }", "}"); createRenameRefactoring("test() {}"); // check status refactoring.checkInitialConditions(pm); refactoring.setNewName("newName"); assertRefactoringStatus( refactoring.checkFinalConditions(pm), RefactoringStatusSeverity.ERROR, "Renamed method will be shadowed by method 'B.newName'.", findRangeIdentifier("newName() {} // marker")); } public void test_checkFinalConditions_shadowsSuper_inSubClass_FieldElement() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int newName; // marker", "}", "class B extends A {", " test() {}", "}", "class C extends B {", " main() {", " print(newName);", " }", "}"); createRenameRefactoring("test() {}"); // check status refactoring.checkInitialConditions(pm); refactoring.setNewName("newName"); assertRefactoringStatus( refactoring.checkFinalConditions(pm), RefactoringStatusSeverity.ERROR, "Renamed method will shadow field 'A.newName'.", findRangeIdentifier("newName; // marker")); } public void test_checkFinalConditions_shadowsSuper_MethodElement() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " newName() {} // marker", "}", "class B extends A {", " test() {}", " main() {", " newName();", " }", "}"); createRenameRefactoring("test() {}"); // check status refactoring.checkInitialConditions(pm); refactoring.setNewName("newName"); assertRefactoringStatus( refactoring.checkFinalConditions(pm), RefactoringStatusSeverity.ERROR, "Renamed method will shadow method 'A.newName'.", findRangeIdentifier("newName() {} // marker")); } public void test_checkInitialConditions_operator() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " operator -(other) => this;", "}"); createRenameRefactoring("-(other)"); // check status assertRefactoringStatus( refactoring.checkInitialConditions(pm), RefactoringStatusSeverity.FATAL, "Cannot rename operator."); } public void test_checkNewName_FieldElement() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int test;", "}"); createRenameRefactoring("test;"); // null assertRefactoringStatus( refactoring.checkNewName(null), RefactoringStatusSeverity.ERROR, "Field name must not be null."); // empty assertRefactoringStatus( refactoring.checkNewName(""), RefactoringStatusSeverity.ERROR, "Field name must not be empty."); // same name assertRefactoringStatus( refactoring.checkNewName("test"), RefactoringStatusSeverity.FATAL, "Choose another name."); } public void test_checkNewName_MethodElement() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " test() {}", "}"); createRenameRefactoring("test() {}"); // null assertRefactoringStatus( refactoring.checkNewName(null), RefactoringStatusSeverity.ERROR, "Method name must not be null."); // empty assertRefactoringStatus( refactoring.checkNewName(""), RefactoringStatusSeverity.ERROR, "Method name must not be empty."); // same name assertRefactoringStatus( refactoring.checkNewName("test"), RefactoringStatusSeverity.FATAL, "Choose another name."); } public void test_createChange_FieldElement() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int test;", " main() {", " print(test);", " test = 1;", " test += 2;", " }", "}", "main() {", " A a = new A();", " print(a.test);", " a.test = 1;", " a.test += 2;", "}"); // configure refactoring createRenameRefactoring("test;"); assertEquals("Rename Field", refactoring.getRefactoringName()); refactoring.setNewName("newName"); // validate change assertSuccessfulRename( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int newName;", " main() {", " print(newName);", " newName = 1;", " newName += 2;", " }", "}", "main() {", " A a = new A();", " print(a.newName);", " a.newName = 1;", " a.newName += 2;", "}"); } public void test_createChange_FieldElement_constructorFieldInitializer() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " final test;", " A() : test = 5;", "}"); // configure refactoring createRenameRefactoring("test;"); assertEquals("Rename Field", refactoring.getRefactoringName()); refactoring.setNewName("newName"); // validate change assertSuccessfulRename( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " final newName;", " A() : newName = 5;", "}"); } public void test_createChange_FieldElement_fieldFormalParameter() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int test;", " A(this.test) {}", "}"); // configure refactoring createRenameRefactoring("test;"); assertEquals("Rename Field", refactoring.getRefactoringName()); refactoring.setNewName("newName"); // validate change assertSuccessfulRename( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int newName;", " A(this.newName) {}", "}"); } public void test_createChange_FieldElement_invocation() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "typedef F(a);", "class A {", " F test;", " main() {", " test(1);", " }", "}", "main() {", " A a = new A();", " a.test(2);", "}"); // configure refactoring createRenameRefactoring("test;"); assertEquals("Rename Field", refactoring.getRefactoringName()); refactoring.setNewName("newName"); // validate change assertSuccessfulRename( "// filler filler filler filler filler filler filler filler filler filler", "typedef F(a);", "class A {", " F newName;", " main() {", " newName(1);", " }", "}", "main() {", " A a = new A();", " a.newName(2);", "}"); } public void test_createChange_MethodElement() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " test() {}", "}", "class B extends A {", " test() {} // marker", "}", "class C extends B {", " test() {}", "}", "class D implements A {", " test() {}", "}", "main() {", " A a = new A();", " B b = new B();", " C c = new C();", " D d = new D();", " a.test();", " b.test();", " c.test();", " d.test();", "}"); // configure refactoring createRenameRefactoring("test() {} // marker"); assertEquals("Rename Method", refactoring.getRefactoringName()); refactoring.setNewName("newName"); // validate change assertSuccessfulRename( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " newName() {}", "}", "class B extends A {", " newName() {} // marker", "}", "class C extends B {", " newName() {}", "}", "class D implements A {", " newName() {}", "}", "main() {", " A a = new A();", " B b = new B();", " C c = new C();", " D d = new D();", " a.newName();", " b.newName();", " c.newName();", " d.newName();", "}"); assertFalse(refactoring.requiresPreview()); } public void test_createChange_MethodElement_potential() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " test() {}", "}", "main(var a) {", " a.test();", " new A().test();", "}"); // configure refactoring createRenameRefactoring("test() {}"); assertEquals("Rename Method", refactoring.getRefactoringName()); refactoring.setNewName("newName"); // validate change assertSuccessfulRename( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " newName() {}", "}", "main(var a) {", " a.newName();", " new A().newName();", "}"); assertTrue(refactoring.requiresPreview()); } public void test_createChange_MethodElement_potential_private_otherLibrary() throws Exception { Source lib = addSource( "/lib.dart", makeSource( "// filler filler filler filler filler filler filler filler filler filler", "library lib;", "f(p) {", " p._test();", "}")); indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "import 'lib.dart';", "class A {", " _test() {}", "}", "f(A a) {", " a._test();", "}"); indexUnit(lib); // configure refactoring createRenameRefactoring("_test() {}"); assertEquals("Rename Method", refactoring.getRefactoringName()); refactoring.setNewName("newName"); // validate change assertRefactoringStatusOK(); Change refactoringChange = refactoring.createChange(pm); assertChangeResult( refactoringChange, testSource, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "import 'lib.dart';", "class A {", " newName() {}", "}", "f(A a) {", " a.newName();", "}")); SourceChange noChangeExpected = getSourceChange(refactoringChange, lib); assertNull(noChangeExpected); } public void test_createChange_multipleUnits() throws Exception { testCode = makeSource( "// filler filler filler filler filler filler filler filler filler filler", "library libA;", "class A {", " int test;", " main() {", " print(test);", " test = 1;", " test += 2;", " }", "}", "main() {", " A a = new A();", " print(a.test);", " a.test = 1;", " a.test += 2;", "}"); Source libA = addSource(testCode); Source libB = addSource( "/B.dart", makeSource( "import 'test.dart';", "main() {", " A a = new A();", " print(a.test);", " a.test = 1;", " a.test += 2;", "}")); indexTestUnit(libA); indexUnit(libB); Source sourceB = libB; // configure refactoring createRenameRefactoring("test;"); assertEquals("Rename Field", refactoring.getRefactoringName()); refactoring.setNewName("newName"); // validate change assertRefactoringStatusOK(); Change refactoringChange = refactoring.createChange(pm); assertChangeResult( refactoringChange, testSource, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "library libA;", "class A {", " int newName;", " main() {", " print(newName);", " newName = 1;", " newName += 2;", " }", "}", "main() {", " A a = new A();", " print(a.newName);", " a.newName = 1;", " a.newName += 2;", "}")); assertChangeResult( refactoringChange, sourceB, makeSource( "import 'test.dart';", "main() {", " A a = new A();", " print(a.newName);", " a.newName = 1;", " a.newName += 2;", "}")); } public void test_createChange_oneUnitInTwoContexts() throws Exception { String code = makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " test() {}", "}", "class B extends A {", " test() {} // marker", "}", "class C extends B {", " test() {}", "}", "class D implements B {", " test() {}", "}", "main(var e) {", " A a = new A();", " B b = new B();", " C c = new C();", " D d = new D();", " a.test();", " b.test();", " c.test();", " d.test();", " e.test();", "}"); // index unit in separate context { AnalysisContextHelper helper = new AnalysisContextHelper(); Source source = helper.addSource("/Test.dart", code); CompilationUnit unit = helper.resolveDefiningUnit(source); index.indexUnit(helper.context, unit); } // index same unit as "test" indexTestUnit(code); // configure refactoring createRenameRefactoring("test() {} // marker"); assertEquals("Rename Method", refactoring.getRefactoringName()); refactoring.setNewName("newName"); // validate change assertSuccessfulRename( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " newName() {}", "}", "class B extends A {", " newName() {} // marker", "}", "class C extends B {", " newName() {}", "}", "class D implements B {", " newName() {}", "}", "main(var e) {", " A a = new A();", " B b = new B();", " C c = new C();", " D d = new D();", " a.newName();", " b.newName();", " c.newName();", " d.newName();", " e.newName();", "}"); } public void test_createChange_PropertyAccessorElement_getter() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " get test {} // marker", " set test(x) {}", " main() {", " print(test);", " test = 1;", " }", "}", "class B extends A {", " get test {}", " set test(x) {}", "}", "main() {", " A a = new A();", " print(a.test);", " a.test = 2;", " ", " B b = new B();", " print(b.test);", " b.test = 2;", "}"); // configure refactoring createRenameRefactoring("test {} // marker"); assertEquals("Rename Field", refactoring.getRefactoringName()); refactoring.setNewName("newName"); // validate change assertSuccessfulRename( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " get newName {} // marker", " set newName(x) {}", " main() {", " print(newName);", " newName = 1;", " }", "}", "class B extends A {", " get newName {}", " set newName(x) {}", "}", "main() {", " A a = new A();", " print(a.newName);", " a.newName = 2;", " ", " B b = new B();", " print(b.newName);", " b.newName = 2;", "}"); } public void test_createChange_PropertyAccessorElement_setter() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " get test {}", " set test(x) {}", " main() {", " print(test);", " test = 1;", " }", "}", "main() {", " A a = new A();", " print(a.test);", " a.test = 2;", "}"); // configure refactoring createRenameRefactoring("test(x) {}"); assertEquals("Rename Field", refactoring.getRefactoringName()); refactoring.setNewName("newName"); // validate change assertSuccessfulRename( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " get newName {}", " set newName(x) {}", " main() {", " print(newName);", " newName = 1;", " }", "}", "main() {", " A a = new A();", " print(a.newName);", " a.newName = 2;", "}"); } public void test_createChange_TypeParameterElement() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A<Test> {", " Test f;", " Test m(Test p) => null;", "}"); // configure refactoring createRenameRefactoring("Test>"); assertEquals("Rename Type Parameter", refactoring.getRefactoringName()); refactoring.setNewName("NewName"); // validate change assertSuccessfulRename( "// filler filler filler filler filler filler filler filler filler filler", "class A<NewName> {", " NewName f;", " NewName m(NewName p) => null;", "}"); } public void test_shouldReportUnsafeRefactoringSource() throws Exception { indexTestUnit( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " myPublic() {}", " _myPrivate() {}", "}"); Source externalSource = new FileBasedSource(new File("other.dart")); // check public createRenameRefactoring("myPublic() {}"); assertTrue(refactoring.shouldReportUnsafeRefactoringSource(analysisContext, testSource)); assertTrue(refactoring.shouldReportUnsafeRefactoringSource(analysisContext, externalSource)); assertFalse(refactoring.shouldReportUnsafeRefactoringSource(null, testSource)); // check private createRenameRefactoring("_myPrivate() {}"); assertTrue(refactoring.shouldReportUnsafeRefactoringSource(analysisContext, testSource)); assertFalse(refactoring.shouldReportUnsafeRefactoringSource(analysisContext, externalSource)); } }