/* * 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.correction; import com.google.common.base.CharMatcher; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.dart.engine.ast.CompilationUnit; import com.google.dart.engine.context.AnalysisException; import com.google.dart.engine.context.ChangeSet; import com.google.dart.engine.element.CompilationUnitElement; import com.google.dart.engine.element.LibraryElement; import com.google.dart.engine.error.AnalysisError; import com.google.dart.engine.error.ErrorCode; import com.google.dart.engine.resolver.ResolverErrorCode; import com.google.dart.engine.services.assist.AssistContext; import com.google.dart.engine.services.change.Edit; import com.google.dart.engine.services.change.SourceChange; import com.google.dart.engine.services.correction.AddDependencyCorrectionProposal; import com.google.dart.engine.services.correction.CorrectionKind; import com.google.dart.engine.services.correction.CorrectionProcessors; import com.google.dart.engine.services.correction.CorrectionProposal; import com.google.dart.engine.services.correction.CreateFileCorrectionProposal; import com.google.dart.engine.services.correction.LinkedPositionProposal; import com.google.dart.engine.services.correction.QuickFixProcessor; import com.google.dart.engine.services.correction.SourceCorrectionProposal; import com.google.dart.engine.services.internal.refactoring.RefactoringImplTest; import com.google.dart.engine.source.Source; import com.google.dart.engine.utilities.source.SourceRange; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.List; import java.util.Map; import java.util.Set; public class QuickFixProcessorImplTest extends RefactoringImplTest { protected static final QuickFixProcessor PROCESSOR = CorrectionProcessors.getQuickFixProcessor(); private static CharMatcher NOT_IDENTIFIER_MATCHER = CharMatcher.JAVA_LETTER_OR_DIGIT.negate(); private AnalysisError error; private SourceCorrectionProposal resultProposal; private String resultCode; public void fail_test_importLibrary_withTopLevelVariable() throws Exception { Source libSource = setFileContent( "LibA.dart", makeSource( "// filler filler filler filler filler filler filler filler filler filler", "library A;", "var myTopLevelVariable;", "")); // prepare AnalysisContext ensureAnalysisContext(); // process "libSource" { ChangeSet changeSet = new ChangeSet(); changeSet.addedSource(libSource); analysisContext.applyChanges(changeSet); } // process unit prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " myTopLevelVariable = null;", "}", ""); analysisContext.computeLibraryElement(libSource); assert_runProcessor( CorrectionKind.QF_IMPORT_LIBRARY_PROJECT, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "", "import 'LibA.dart';", "", "main() {", " myTopLevelVariable = null;", "}", "")); } public void test_addPackageDependency() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "import 'package:path/path.dart';", ""); AddDependencyCorrectionProposal proposal = (AddDependencyCorrectionProposal) findProposal(CorrectionKind.QF_ADD_PACKAGE_DEPENDENCY); assertEquals("path", proposal.getPackageName()); } public void test_addPackageDependency_notPackedImport() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:no_such_library';", ""); CorrectionProposal proposal = findProposal(CorrectionKind.QF_ADD_PACKAGE_DEPENDENCY); assertNull(proposal); } public void test_boolean() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " boolean v;", "}"); assert_runProcessor( CorrectionKind.QF_REPLACE_BOOLEAN_WITH_BOOL, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " bool v;", "}")); } public void test_changeToStaticAccess_method_prefixLibrary() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:async' as pref;", "main(pref.Future f) {", " f.wait([]);", "}"); assert_runProcessor( CorrectionKind.QF_CHANGE_TO_STATIC_ACCESS, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:async' as pref;", "main(pref.Future f) {", " pref.Future.wait([]);", "}")); } public void test_changeToStaticAccess_method_thisLibrary() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " static foo() {}", "}", "main(A a) {", " a.foo();", "}"); assert_runProcessor( CorrectionKind.QF_CHANGE_TO_STATIC_ACCESS, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " static foo() {}", "}", "main(A a) {", " A.foo();", "}")); } public void test_changeToStaticAccess_property_thisLibrary() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " static get foo => 42;", "}", "main(A a) {", " a.foo;", "}"); assert_runProcessor( CorrectionKind.QF_CHANGE_TO_STATIC_ACCESS, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " static get foo => 42;", "}", "main(A a) {", " A.foo;", "}")); } public void test_computeProposals_noContext() throws Exception { AnalysisError emptyError = new AnalysisError( testSource, ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART); CorrectionProposal[] proposals = PROCESSOR.computeProposals(null, emptyError); assertThat(proposals).isEmpty(); } public void test_computeProposals_noLibraryElement() throws Exception { // prepare CompilationUnit with CompilationUnitElement, but without LibraryElement CompilationUnit unit = mock(CompilationUnit.class); CompilationUnitElement unitElement = mock(CompilationUnitElement.class); when(unit.getElement()).thenReturn(unitElement); // prepare context AssistContext context = new AssistContext(null, null, null, null, unit, 0, 0); AnalysisError problem = new AnalysisError( testSource, ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART); CorrectionProposal[] proposals = PROCESSOR.computeProposals(context, problem); assertThat(proposals).isEmpty(); } public void test_computeProposals_noProblem() throws Exception { AssistContext emptyContext = new AssistContext(null, null, null, null, null, 0, 0); CorrectionProposal[] proposals = PROCESSOR.computeProposals(emptyContext, null); assertThat(proposals).isEmpty(); } public void test_computeProposals_noUnitElement() throws Exception { Source source = mock(Source.class); // prepare CompilationUnit without CompilationUnitElement CompilationUnit unit = mock(CompilationUnit.class); // prepare context AssistContext context = new AssistContext(null, null, null, source, unit, 0, 0); AnalysisError problem = new AnalysisError( testSource, ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART); CorrectionProposal[] proposals = PROCESSOR.computeProposals(context, problem); assertThat(proposals).isEmpty(); } public void test_createClass() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " Test v = null;", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_CLASS, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " Test v = null;", "}", "", "class Test {", "}")); assertEquals( ImmutableMap.of("NAME", getResultRanges("Test v =", "Test {")), resultProposal.getLinkedPositions()); } public void test_createConstructor_hasNotSyntheticDefault() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A() {}", "}", "main() {", " new A(1, 2.0);", "}", ""); assertNoFix(CorrectionKind.QF_CREATE_CONSTRUCTOR); } public void test_createConstructor_insteadOfSyntheticDefault() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int field;", "", " method() {}", "}", "main() {", " new A(1, 2.0);", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_CONSTRUCTOR, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int field;", "", " A(int i, double d) {", " }", "", " method() {}", "}", "main() {", " new A(1, 2.0);", "}", "")); // linked positions { Map<String, List<SourceRange>> expected = Maps.newHashMap(); expected.put("TYPE0", getResultRanges("int i")); expected.put("ARG0", getResultRanges("i,")); expected.put("TYPE1", getResultRanges("double d")); expected.put("ARG1", getResultRanges("d) {")); assertEquals(expected, resultProposal.getLinkedPositions()); } } public void test_createConstructor_named() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " method() {}", "}", "main() {", " new A.named(1, 2.0);", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_CONSTRUCTOR, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A.named(int i, double d) {", " }", "", " method() {}", "}", "main() {", " new A.named(1, 2.0);", "}", "")); // linked positions { Map<String, List<SourceRange>> expected = Maps.newHashMap(); expected.put("NAME", getResultRanges("named(1, 2.0);", "named(int i")); expected.put("TYPE0", getResultRanges("int i")); expected.put("ARG0", getResultRanges("i,")); expected.put("TYPE1", getResultRanges("double d")); expected.put("ARG1", getResultRanges("d) {")); assertEquals(expected, resultProposal.getLinkedPositions()); } } public void test_createConstructor_named_afterLeadingFields() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int fieldA;", " int fieldB;", "", " method() {}", "", " int fieldC;", "}", "main() {", " new A.named(1, 2.0);", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_CONSTRUCTOR, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int fieldA;", " int fieldB;", "", " A.named(int i, double d) {", " }", "", " method() {}", "", " int fieldC;", "}", "main() {", " new A.named(1, 2.0);", "}", "")); } public void test_createConstructor_named_afterOtherConstructors() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A() {}", "", " method() {}", "}", "main() {", " new A.named(1, 2.0);", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_CONSTRUCTOR, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A() {}", "", " A.named(int i, double d) {", " }", "", " method() {}", "}", "main() {", " new A.named(1, 2.0);", "}", "")); } public void test_createConstructor_named_noOtherMembers() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", "}", "main() {", " new A.named(1, 2.0);", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_CONSTRUCTOR, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A.named(int i, double d) {", " }", "}", "main() {", " new A.named(1, 2.0);", "}", "")); } public void test_createConstructorSuperExplicit() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A(bool p1, int p2, double p3, String p4, {p5});", "}", "class B extends A {", " B() {}", "}"); assert_runProcessor( CorrectionKind.QF_ADD_SUPER_CONSTRUCTOR_INVOCATION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A(bool p1, int p2, double p3, String p4, {p5});", "}", "class B extends A {", " B() : super(false, 0, 0.0, '') {}", "}")); } public void test_createConstructorSuperExplicit_hasInitializers() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A(int p);", "}", "class B extends A {", " int field;", " B() : field = 42 {}", "}"); assert_runProcessor( CorrectionKind.QF_ADD_SUPER_CONSTRUCTOR_INVOCATION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A(int p);", "}", "class B extends A {", " int field;", " B() : field = 42, super(0) {}", "}")); } public void test_createConstructorSuperExplicit_named() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A.named(int p);", "}", "class B extends A {", " B() {}", "}"); assert_runProcessor( CorrectionKind.QF_ADD_SUPER_CONSTRUCTOR_INVOCATION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A.named(int p);", "}", "class B extends A {", " B() : super.named(0) {}", "}")); } public void test_createConstructorSuperExplicit_named_private() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A._named(int p);", "}", "class B extends A {", " B() {}", "}"); assertNoFix(CorrectionKind.QF_ADD_SUPER_CONSTRUCTOR_INVOCATION); } public void test_createConstructorSuperImplicit() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A(p1, int p2, List<String> p3, [int p4]);", "}", "class B extends A {", " int existingField;", "", " int existingMethod() {}", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_CONSTRUCTOR_SUPER, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A(p1, int p2, List<String> p3, [int p4]);", "}", "class B extends A {", " int existingField;", "", " B(p1, int p2, List<String> p3) : super(p1, p2, p3);", "", " int existingMethod() {}", "}")); } public void test_createConstructorSuperImplicit_fieldInitializer() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int _field;", " A(this._field);", "}", "class B extends A {", " int existingField;", "", " int existingMethod() {}", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_CONSTRUCTOR_SUPER, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int _field;", " A(this._field);", "}", "class B extends A {", " int existingField;", "", " B(int field) : super(field);", "", " int existingMethod() {}", "}")); } public void test_createConstructorSuperImplicit_named() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A.named(p1, int p2);", "}", "class B extends A {", " int existingField;", "", " int existingMethod() {}", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_CONSTRUCTOR_SUPER, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A.named(p1, int p2);", "}", "class B extends A {", " int existingField;", "", " B.named(p1, int p2) : super.named(p1, p2);", "", " int existingMethod() {}", "}")); } public void test_createConstructorSuperImplicit_private() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " A._named(int p);", "}", "class B extends A {", "}"); assertNoFix(CorrectionKind.QF_CREATE_CONSTRUCTOR_SUPER); } public void test_createMissingOverrides_functionType() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " forEach(int f(double p1, String p2));", "}", "", "class B extends A {", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_MISSING_OVERRIDES, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " forEach(int f(double p1, String p2));", "}", "", "class B extends A {", " @override", " forEach(int f(double p1, String p2)) {", " // TODO: implement forEach", " }", "}")); } public void test_createMissingOverrides_generics() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:collection';", "class Test extends IterableMixin<int> {", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_MISSING_OVERRIDES, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:collection';", "class Test extends IterableMixin<int> {", " // TODO: implement iterator", " @override", " Iterator<int> get iterator => null;", "}")); } public void test_createMissingOverrides_getter() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " get g1;", " int get g2;", "}", "", "class B extends A {", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_MISSING_OVERRIDES, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " get g1;", " int get g2;", "}", "", "class B extends A {", " // TODO: implement g1", " @override", " get g1 => null;", "", " // TODO: implement g2", " @override", " int get g2 => null;", "}")); } public void test_createMissingOverrides_importPrefix() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:async' as aaa;", "abstract class A {", " Map<aaa.Future, List<aaa.Future>> g(aaa.Future p);", "}", "", "class B extends A {", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_MISSING_OVERRIDES, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:async' as aaa;", "abstract class A {", " Map<aaa.Future, List<aaa.Future>> g(aaa.Future p);", "}", "", "class B extends A {", " @override", " Map<aaa.Future, List<aaa.Future>> g(aaa.Future p) {", " // TODO: implement g", " }", "}")); } public void test_createMissingOverrides_method() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " m1();", " int m2();", " String m3(int p1, double p2, Map<int, List<String>> p3);", " String m4(p1, p2);", " String m5(p1, [int p2 = 2, int p3, p4 = 4]);", " String m6(p1, {int p2: 2, int p3, p4: 4});", "}", "", "class B extends A {", "}"); String expectedSource = makeSource( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " m1();", " int m2();", " String m3(int p1, double p2, Map<int, List<String>> p3);", " String m4(p1, p2);", " String m5(p1, [int p2 = 2, int p3, p4 = 4]);", " String m6(p1, {int p2: 2, int p3, p4: 4});", "}", "", "class B extends A {", " @override", " m1() {", " // TODO: implement m1", " }", "", " @override", " int m2() {", " // TODO: implement m2", " }", "", " @override", " String m3(int p1, double p2, Map<int, List<String>> p3) {", " // TODO: implement m3", " }", "", " @override", " String m4(p1, p2) {", " // TODO: implement m4", " }", "", " @override", " String m5(p1, [int p2 = 2, int p3, p4 = 4]) {", " // TODO: implement m5", " }", "", " @override", " String m6(p1, {int p2: 2, int p3, p4: 4}) {", " // TODO: implement m6", " }", "}"); assert_runProcessor(CorrectionKind.QF_CREATE_MISSING_OVERRIDES, expectedSource); // end position should be on "m1", not on "m2", "m3", etc { SourceRange endRange = resultProposal.getEndRange(); assertNotNull(endRange); int endOffset = endRange.getOffset(); String endString = expectedSource.substring(endOffset, endOffset + 25); assertTrue(endString.contains("m1")); assertFalse(endString.contains("m2")); assertFalse(endString.contains("m3")); assertFalse(endString.contains("m4")); assertFalse(endString.contains("m5")); assertFalse(endString.contains("m6")); } } public void test_createMissingOverrides_operator() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " int operator [](int index);", " void operator []=(int index, String value);", "}", "", "class B extends A {", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_MISSING_OVERRIDES, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " int operator [](int index);", " void operator []=(int index, String value);", "}", "", "class B extends A {", " @override", " int operator [](int index) {", " // TODO: implement []", " }", "", " @override", " void operator []=(int index, String value) {", " // TODO: implement []=", " }", "}")); } public void test_createMissingOverrides_setter() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " set s1(x);", " set s2(int x);", " void set s3(String x);", "}", "", "class B extends A {", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_MISSING_OVERRIDES, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " set s1(x);", " set s2(int x);", " void set s3(String x);", "}", "", "class B extends A {", " @override", " set s1(x) {", " // TODO: implement s1", " }", "", " @override", " set s2(int x) {", " // TODO: implement s2", " }", "", " @override", " void set s3(String x) {", " // TODO: implement s3", " }", "}")); } public void test_createNoSuchMethod() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " m1();", " int m2();", "}", "", "class B extends A {", " existing() {}", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_NO_SUCH_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " m1();", " int m2();", "}", "", "class B extends A {", " existing() {}", "", " noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);", "}")); } public void test_createPart() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "library app;", "part 'my_part.dart';", ""); CreateFileCorrectionProposal proposal = (CreateFileCorrectionProposal) findProposal(CorrectionKind.QF_CREATE_PART); assertThat(proposal.getFile().getPath()).endsWith("my_part.dart"); { String eol = getTestCorrectionUtils().getEndOfLine(); assertEquals("part of app;" + eol + eol, proposal.getContent()); } } public void test_createPart_absoluteUri() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "library app;", "part 'package:my_part.dart';", ""); assertNoFix(CorrectionKind.QF_CREATE_PART); } public void test_creationFunction_forFunctionType_cascadeSecond() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " B ma() {}", "}", "class B {", " useFunction(int g(double a, String b)) {}", "}", "", "main() {", " A a = new A();", " a..ma().useFunction(test);", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_FUNCTION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " B ma() {}", "}", "class B {", " useFunction(int g(double a, String b)) {}", "}", "", "main() {", " A a = new A();", " a..ma().useFunction(test);", "}", "", "int test(double a, String b) {", "}", "")); } public void test_creationFunction_forFunctionType_function() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " useFunction(test);", "}", "", "useFunction(int g(double a, String b)) {}"); assert_runProcessor( CorrectionKind.QF_CREATE_FUNCTION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " useFunction(test);", "}", "", "useFunction(int g(double a, String b)) {}", "", "int test(double a, String b) {", "}", "")); } public void test_creationFunction_forFunctionType_method_enclosingClass_static() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " static foo() {", " useFunction(test);", " }", "}", "", "useFunction(int g(double a, String b)) {}"); assert_runProcessor( CorrectionKind.QF_CREATE_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " static foo() {", " useFunction(test);", " }", " ", " static int test(double a, String b) {", " }", "}", "", "useFunction(int g(double a, String b)) {}")); } public void test_creationFunction_forFunctionType_method_targetClass() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main(A a) {", " useFunction(a.test);", "}", "", "class A {", "}", "", "useFunction(int g(double a, String b)) {}"); assert_runProcessor( CorrectionKind.QF_CREATE_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main(A a) {", " useFunction(a.test);", "}", "", "class A {", " int test(double a, String b) {", " }", "}", "", "useFunction(int g(double a, String b)) {}")); } public void test_creationFunction_forFunctionType_method_targetClass_hasOtherMember() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main(A a) {", " useFunction(a.test);", "}", "", "class A {", " m() {}", "}", "", "useFunction(int g(double a, String b)) {}"); assert_runProcessor( CorrectionKind.QF_CREATE_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main(A a) {", " useFunction(a.test);", "}", "", "class A {", " m() {}", " ", " int test(double a, String b) {", " }", "}", "", "useFunction(int g(double a, String b)) {}")); } public void test_creationFunction_forFunctionType_notFunctionType() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main(A a) {", " useFunction(a.test);", "}", "", "class A {", "}", "", "useFunction(g) {}"); assertNoFix(CorrectionKind.QF_CREATE_METHOD); } public void test_creationFunction_forFunctionType_unknownTarget() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main(A a) {", " useFunction(a.test);", "}", "", "typedef A();", "", "useFunction(int g(double a, String b)) {}"); assertNoFix(CorrectionKind.QF_CREATE_FUNCTION); assertNoFix(CorrectionKind.QF_CREATE_METHOD); } public void test_expectedToken_semicolon() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " print(0)", "}"); assert_runProcessor( CorrectionKind.QF_INSERT_SEMICOLON, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " print(0);", "}")); } public void test_getSourceFile_notFileBasedSource() throws Exception { Source source = mock(Source.class); assertNull(QuickFixProcessorImpl.getSourceFile(source)); } public void test_importLibrary_privateName() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " _PrivateName v = null;", "}", ""); assertNoFix(CorrectionKind.QF_IMPORT_LIBRARY_PREFIX); assertNoFix(CorrectionKind.QF_IMPORT_LIBRARY_PROJECT); assertNoFix(CorrectionKind.QF_IMPORT_LIBRARY_SDK); } public void test_importLibrary_withTopLevelFunction() throws Exception { Source libSource = setFileContent( "LibA.dart", makeSource( "// filler filler filler filler filler filler filler filler filler filler", "library A;", "myFunction() {}", "")); // prepare AnalysisContext ensureAnalysisContext(); // process "libSource" { ChangeSet changeSet = new ChangeSet(); changeSet.addedSource(libSource); analysisContext.applyChanges(changeSet); } // process unit prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " myFunction();", "}", ""); analysisContext.computeLibraryElement(libSource); assert_runProcessor( CorrectionKind.QF_IMPORT_LIBRARY_PROJECT, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "", "import 'LibA.dart';", "", "main() {", " myFunction();", "}", "")); } public void test_importLibrary_withTopLevelFunction_upDownPath() throws Exception { Source libSource = setFileContent( "aaa/lib_a.dart", makeSource( "// filler filler filler filler filler filler filler filler filler filler", "library A;", "class AAA {}")); testSource = setFileContent( "bbb/Test.dart", makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " AAA a = null;", "}")); // prepare AnalysisContext ensureAnalysisContext(); { ChangeSet changeSet = new ChangeSet(); changeSet.addedSource(libSource); changeSet.addedSource(testSource); analysisContext.applyChanges(changeSet); } // fill "test*" fields testLibraryElement = analysisContext.computeLibraryElement(testSource); testUnit = analysisContext.resolveCompilationUnit(testSource, testLibraryElement); // process "libSource" analysisContext.computeLibraryElement(libSource); // prepare proposal prepareProblemWithFix(); SourceCorrectionProposal proposal = (SourceCorrectionProposal) findProposal(CorrectionKind.QF_IMPORT_LIBRARY_PROJECT); assertNotNull(proposal); // we have "fix", note that preview is for library SourceChange appChange = proposal.getChange(); assertSame(testSource, appChange.getSource()); assertChangeResult( analysisContext, appChange, testSource, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "", "import '../aaa/lib_a.dart';", "", "main() {", " AAA a = null;", "}")); } public void test_importLibrary_withType_hasDirectiveImport() throws Exception { Source libSource = setFileContent( "LibA.dart", makeSource( "// filler filler filler filler filler filler filler filler filler filler", "library A;", "class AAA {", "}", "")); Source appSource = setFileContent( "App.dart", makeSource( "// filler filler filler filler filler filler filler filler filler filler", "library App;", "import 'dart:core';", "part 'Test.dart';", "")); Source partSource = setFileContent( "Test.dart", makeSource( "// filler filler filler filler filler filler filler filler filler filler", "part of App;", "main() {", " AAA a = null;", "}", "")); testSource = partSource; // prepare AnalysisContext ensureAnalysisContext(); { ChangeSet changeSet = new ChangeSet(); changeSet.addedSource(libSource); changeSet.addedSource(appSource); changeSet.addedSource(partSource); analysisContext.applyChanges(changeSet); } // fill "test*" fields testLibraryElement = analysisContext.computeLibraryElement(appSource); testUnit = analysisContext.resolveCompilationUnit(partSource, testLibraryElement); // process "libSource" analysisContext.computeLibraryElement(libSource); // prepare proposal prepareProblemWithFix(); SourceCorrectionProposal proposal = (SourceCorrectionProposal) findProposal(CorrectionKind.QF_IMPORT_LIBRARY_PROJECT); assertNotNull(proposal); // we have "fix", note that preview is for library SourceChange appChange = proposal.getChange(); assertSame(appSource, appChange.getSource()); assertChangeResult( analysisContext, appChange, appSource, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "library App;", "import 'dart:core';", "import 'LibA.dart';", "part 'Test.dart';", "")); } public void test_importLibrary_withType_hasImportWithPrefix() throws Exception { ensureSdkLibraryAsync(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:async' as pref;", "main() {", " Future f = null;", " pref.Stream s = null;", "}", ""); assert_runProcessor( CorrectionKind.QF_IMPORT_LIBRARY_PREFIX, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:async' as pref;", "main() {", " pref.Future f = null;", " pref.Stream s = null;", "}", "")); } public void test_importLibrary_withType_hasImportWithShow() throws Exception { ensureSdkLibraryAsync(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:async' show Stream;", "main() {", " Future f = null;", "}", ""); assert_runProcessor( CorrectionKind.QF_IMPORT_LIBRARY_SHOW, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:async' show Future, Stream;", "main() {", " Future f = null;", "}", "")); } public void test_importLibrary_withType_invocationTarget_fromSDK() throws Exception { ensureSdkLibraryAsync(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " Future.wait(null);", "}", ""); assert_runProcessor( CorrectionKind.QF_IMPORT_LIBRARY_SDK, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "", "import 'dart:async';", "", "main() {", " Future.wait(null);", "}", "")); } public void test_importLibrary_withType_typeAnnotation_fromSDK() throws Exception { ensureSdkLibraryAsync(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " Future f = null;", "}", ""); assert_runProcessor( CorrectionKind.QF_IMPORT_LIBRARY_SDK, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "", "import 'dart:async';", "", "main() {", " Future f = null;", "}", "")); } public void test_importLibrary_withType_typeAnnotation_PrefixedIdentifier() throws Exception { ensureSdkLibraryAsync(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " Future.wait;", "}", ""); assert_runProcessor( CorrectionKind.QF_IMPORT_LIBRARY_SDK, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "", "import 'dart:async';", "", "main() {", " Future.wait;", "}", "")); } public void test_isNotNull() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main(p) {", " p is! Null;", "}"); assert_runProcessor( CorrectionKind.QF_USE_NOT_EQ_NULL, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main(p) {", " p != null;", "}")); } public void test_isNull() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main(p) {", " p is Null;", "}"); assert_runProcessor( CorrectionKind.QF_USE_EQ_EQ_NULL, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main(p) {", " p == null;", "}")); } public void test_makeEnclosingClassAbstract_declaresAbstractMethod() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " m();", "}"); assert_runProcessor( CorrectionKind.QF_MAKE_CLASS_ABSTRACT, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " m();", "}")); } public void test_makeEnclosingClassAbstract_inheritsAbstractMethod() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " m();", "}", "class B extends A {", "}"); assert_runProcessor( CorrectionKind.QF_MAKE_CLASS_ABSTRACT, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "abstract class A {", " m();", "}", "abstract class B extends A {", "}")); } public void test_removeParentheses_inGetterDeclaration() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int get foo() => 0;", "}", ""); assert_runProcessor( CorrectionKind.QF_REMOVE_PARAMETERS_IN_GETTER_DECLARATION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int get foo => 0;", "}", "")); } public void test_removeParentheses_inGetterInvocation() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int get foo => 0;", "}", "main() {", " A a = new A();", " a.foo();", "}", ""); assert_runProcessor( CorrectionKind.QF_REMOVE_PARENTHESIS_IN_GETTER_INVOCATION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " int get foo => 0;", "}", "main() {", " A a = new A();", " a.foo;", "}", "")); } public void test_removeUnnecessaryCast_assignment() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main(Object p) {", " if (p is String) {", " String v = ((p as String));", " }", "}", ""); assert_runProcessor( CorrectionKind.QF_REMOVE_UNNECASSARY_CAST, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main(Object p) {", " if (p is String) {", " String v = p;", " }", "}", "")); } public void test_removeUnnecessaryCast_invocationTarget() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main(Object p) {", " if (p is String) {", " (p as String).length;", " }", "}", ""); assert_runProcessor( CorrectionKind.QF_REMOVE_UNNECASSARY_CAST, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main(Object p) {", " if (p is String) {", " p.length;", " }", "}", "")); } public void test_removeUnnecessaryCast_multiplyArgument() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " 3 * ((1 + 2 as int));", "}", ""); assert_runProcessor( CorrectionKind.QF_REMOVE_UNNECASSARY_CAST, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " 3 * (1 + 2);", "}", "")); } public void test_removeUnusedImport() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:math';", "", "main() {", "}"); assert_runProcessor( CorrectionKind.QF_REMOVE_UNUSED_IMPORT, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "", "main() {", "}")); } public void test_removeUnusedImport_anotherImportOnLine() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:math'; import 'dart:async';", "", "main() {", " Future f;", "}"); assert_runProcessor( CorrectionKind.QF_REMOVE_UNUSED_IMPORT, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "import 'dart:async';", "", "main() {", " Future f;", "}")); } public void test_removeUnusedImport_severalLines() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "import ", " 'dart:math';", "", "main() {", "}"); assert_runProcessor( CorrectionKind.QF_REMOVE_UNUSED_IMPORT, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "", "main() {", "}")); } public void test_replaceWithConstInstanceCreation() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " const A();", "}", "const a = new A();"); assert_runProcessor( CorrectionKind.QF_USE_CONST, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " const A();", "}", "const a = const A();")); } public void test_undefinedClass_useSimilar_fromThisLibrary() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class MyClass {}", "main() {", " MyCalss v = null;", "}"); assert_runProcessor( CorrectionKind.QF_CHANGE_TO, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class MyClass {}", "main() {", " MyClass v = null;", "}")); } public void test_undefinedClass_useSimilar_String() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " Stirng s = 'abc';", "}"); assert_runProcessor( CorrectionKind.QF_CHANGE_TO, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " String s = 'abc';", "}")); } public void test_undefinedFunction_create_fromFunction() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " int v = myUndefinedFunction(1, 2.0, '3');", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_FUNCTION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " int v = myUndefinedFunction(1, 2.0, '3');", "}", "", "int myUndefinedFunction(int i, double d, String s) {", "}", "")); } public void test_undefinedFunction_create_fromMethod() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " main() {", " int v = myUndefinedFunction(1, 2.0, '3');", " }", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_FUNCTION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " main() {", " int v = myUndefinedFunction(1, 2.0, '3');", " }", "}", "", "int myUndefinedFunction(int i, double d, String s) {", "}", "")); } public void test_undefinedFunction_create_returnType_bool_expressions() throws Exception { assert_undefinedFunction_create_returnType_bool("!test();"); assert_undefinedFunction_create_returnType_bool("true && test();"); assert_undefinedFunction_create_returnType_bool("test() && true;"); assert_undefinedFunction_create_returnType_bool("true || test();"); assert_undefinedFunction_create_returnType_bool("test() || true;"); } public void test_undefinedFunction_create_returnType_bool_statements() throws Exception { assert_undefinedFunction_create_returnType_bool("assert ( test() );"); assert_undefinedFunction_create_returnType_bool("if ( test() ) {}"); assert_undefinedFunction_create_returnType_bool("while ( test() ) {}"); assert_undefinedFunction_create_returnType_bool("do {} while ( test() );"); } public void test_undefinedFunction_create_returnType_fromAssignment_eq() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " int v;", " v = myUndefinedFunction();", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_FUNCTION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " int v;", " v = myUndefinedFunction();", "}", "", "int myUndefinedFunction() {", "}", "")); } public void test_undefinedFunction_create_returnType_fromAssignment_plusEq() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " int v;", " v += myUndefinedFunction();", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_FUNCTION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " int v;", " v += myUndefinedFunction();", "}", "", "num myUndefinedFunction() {", "}", "")); } public void test_undefinedFunction_create_returnType_fromBinary_right() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " 0 + myUndefinedFunction();", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_FUNCTION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " 0 + myUndefinedFunction();", "}", "", "num myUndefinedFunction() {", "}", "")); } public void test_undefinedFunction_create_returnType_fromInitializer() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " int v = myUndefinedFunction();", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_FUNCTION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " int v = myUndefinedFunction();", "}", "", "int myUndefinedFunction() {", "}", "")); } public void test_undefinedFunction_create_returnType_fromInvocationArgument() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "foo(int p) {}", "main() {", " foo( myUndefinedFunction() );", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_FUNCTION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "foo(int p) {}", "main() {", " foo( myUndefinedFunction() );", "}", "", "int myUndefinedFunction() {", "}", "")); } public void test_undefinedFunction_create_returnType_fromReturn() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "int main() {", " return myUndefinedFunction();", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_FUNCTION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "int main() {", " return myUndefinedFunction();", "}", "", "int myUndefinedFunction() {", "}", "")); } public void test_undefinedFunction_create_returnType_void() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " myUndefinedFunction();", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_FUNCTION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " myUndefinedFunction();", "}", "", "void myUndefinedFunction() {", "}", "")); } public void test_undefinedFunction_useSimilar_fromImport() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " pritn(0);", "}"); assert_runProcessor( CorrectionKind.QF_CHANGE_TO, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " print(0);", "}")); } public void test_undefinedFunction_useSimilar_thisLibrary() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "myFunction() {}", "main() {", " myFuntcion();", "}"); assert_runProcessor( CorrectionKind.QF_CHANGE_TO, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "myFunction() {}", "main() {", " myFunction();", "}")); } public void test_undefinedMethod_createQualified_fromClass() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", "}", "main() {", " A.myUndefinedMethod();", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " static void myUndefinedMethod() {", " }", "}", "main() {", " A.myUndefinedMethod();", "}", "")); } public void test_undefinedMethod_createQualified_fromClass_hasOtherMember() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " foo() {}", "}", "main() {", " A.myUndefinedMethod();", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " foo() {}", " ", " static void myUndefinedMethod() {", " }", "}", "main() {", " A.myUndefinedMethod();", "}", "")); } public void test_undefinedMethod_createQualified_fromClass_unresolved() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " NoSuchClass.myUndefinedMethod();", "}", ""); assertNoFix(CorrectionKind.QF_CREATE_METHOD); } public void test_undefinedMethod_createQualified_fromInstance() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", "}", "main() {", " A a = new A();", " a.myUndefinedMethod();", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " void myUndefinedMethod() {", " }", "}", "main() {", " A a = new A();", " a.myUndefinedMethod();", "}", "")); // linked positions { Map<String, List<SourceRange>> expected = Maps.newHashMap(); expected.put("NAME", getResultRanges("myUndefinedMethod();", "myUndefinedMethod() {")); expected.put("RETURN_TYPE", getResultRanges("void myUndefinedMethod()")); assertEquals(expected, resultProposal.getLinkedPositions()); } } public void test_undefinedMethod_createQualified_targetIsFunctionType() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "typedef A();", "main() {", " A.myUndefinedMethod();", "}", ""); assertNoFix(CorrectionKind.QF_CREATE_METHOD); } public void test_undefinedMethod_createUnqualified_parameters() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " main() {", " myUndefinedMethod(0, 1.0, '3');", " }", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " main() {", " myUndefinedMethod(0, 1.0, '3');", " }", " ", " void myUndefinedMethod(int i, double d, String s) {", " }", "}")); // linked positions { Map<String, List<SourceRange>> expected = Maps.newHashMap(); expected.put("NAME", getResultRanges("myUndefinedMethod(0", "myUndefinedMethod(int")); expected.put("RETURN_TYPE", getResultRanges("void myUndefinedMethod(")); expected.put("TYPE0", getResultRanges("int i")); expected.put("TYPE1", getResultRanges("double d")); expected.put("TYPE2", getResultRanges("String s")); expected.put("ARG0", getResultRanges("i,")); expected.put("ARG1", getResultRanges("d,")); expected.put("ARG2", getResultRanges("s)")); assertEquals(expected, resultProposal.getLinkedPositions()); } // linked proposals assertLinkedProposals("TYPE0", "int", "num", "Comparable", "Object"); assertLinkedProposals("TYPE1", "double", "num", "Comparable", "Object"); assertLinkedProposals("TYPE2", "String", "Comparable", "Object"); } public void test_undefinedMethod_createUnqualified_returnType() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " main() {", " int v = myUndefinedMethod();", " }", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " main() {", " int v = myUndefinedMethod();", " }", " ", " int myUndefinedMethod() {", " }", "}")); // linked positions { Map<String, List<SourceRange>> expected = Maps.newHashMap(); expected.put("NAME", getResultRanges("myUndefinedMethod();", "myUndefinedMethod() {")); expected.put("RETURN_TYPE", getResultRanges("int myUndefinedMethod()")); assertEquals(expected, resultProposal.getLinkedPositions()); } } public void test_undefinedMethod_createUnqualified_staticFromField() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " static var f = myUndefinedMethod();", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " static var f = myUndefinedMethod();", " ", " static myUndefinedMethod() {", " }", "}")); } public void test_undefinedMethod_createUnqualified_staticFromMethod() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " static main() {", " myUndefinedMethod();", " }", "}"); assert_runProcessor( CorrectionKind.QF_CREATE_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " static main() {", " myUndefinedMethod();", " }", " ", " static void myUndefinedMethod() {", " }", "}")); } public void test_undefinedMethod_hint_createQualified_fromInstance() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", "}", "main() {", " var a = new A();", " a.myUndefinedMethod();", "}", ""); assert_runProcessor( CorrectionKind.QF_CREATE_METHOD, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " void myUndefinedMethod() {", " }", "}", "main() {", " var a = new A();", " a.myUndefinedMethod();", "}", "")); // linked positions { Map<String, List<SourceRange>> expected = Maps.newHashMap(); expected.put("NAME", getResultRanges("myUndefinedMethod();", "myUndefinedMethod() {")); expected.put("RETURN_TYPE", getResultRanges("void myUndefinedMethod()")); assertEquals(expected, resultProposal.getLinkedPositions()); } } public void test_undefinedMethod_useSimilar_ignoreOperators() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main(Object object) {", " object.then();", "}"); assertNoFix(CorrectionKind.QF_CHANGE_TO); } public void test_undefinedMethod_useSimilar_qualified() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " myMethod() {}", "}", "main() {", " A a = new A();", " a.myMehtod();", "}", ""); assert_runProcessor( CorrectionKind.QF_CHANGE_TO, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " myMethod() {}", "}", "main() {", " A a = new A();", " a.myMethod();", "}", "")); } public void test_undefinedMethod_useSimilar_unqualified_superClass() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " myMethod() {}", "}", "class B extends A {", " main() {", " myMehtod();", " }", "}"); assert_runProcessor( CorrectionKind.QF_CHANGE_TO, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " myMethod() {}", "}", "class B extends A {", " main() {", " myMethod();", " }", "}")); } public void test_undefinedMethod_useSimilar_unqualified_thisClass() throws Exception { prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " myMethod() {}", " main() {", " myMehtod();", " }", "}"); assert_runProcessor( CorrectionKind.QF_CHANGE_TO, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "class A {", " myMethod() {}", " main() {", " myMethod();", " }", "}")); } public void test_useEffectiveIntegerDivision() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " var a = 5;", " var b = 2;", " print((a / b).toInt());", "}"); assert_runProcessor( CorrectionKind.QF_USE_EFFECTIVE_INTEGER_DIVISION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " var a = 5;", " var b = 2;", " print(a ~/ b);", "}")); } public void test_useEffectiveIntegerDivision_doublePathensesis() throws Exception { enableContextHints(); prepareProblemWithFix( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " var a = 5;", " var b = 2;", " print(((a / b)).toInt());", "}"); assert_runProcessor( CorrectionKind.QF_USE_EFFECTIVE_INTEGER_DIVISION, makeSource( "// filler filler filler filler filler filler filler filler filler filler", "main() {", " var a = 5;", " var b = 2;", " print(a ~/ b);", "}")); } @Override protected void setUp() throws Exception { super.setUp(); verifyNoTestUnitErrors = false; } @Override protected void tearDown() throws Exception { disableContextHints(); super.tearDown(); } /** * @return the result of applying {@link SourceCorrectionProposal} to the {@link #testCode}. */ private String applyProposal(SourceCorrectionProposal proposal) { SourceChange change = proposal.getChange(); List<Edit> edits = change.getEdits(); return CorrectionUtils.applyReplaceEdits(testCode, edits); } /** * Asserts that running proposal with given name produces expected source. Fills * {@link #resultProposal} and {@link #resultCode}. */ private void assert_runProcessor(CorrectionKind kind, String expectedSource) throws Exception { resultProposal = (SourceCorrectionProposal) findProposal(kind); assertNotNull(kind.name(), resultProposal); resultCode = applyProposal(resultProposal); assertEquals(expectedSource, resultCode); } private void assert_undefinedFunction_create_returnType_bool(String lineWithTest) throws Exception { prepareProblemWithFix(// "main() {", lineWithTest, "}", ""); assert_runProcessor(CorrectionKind.QF_CREATE_FUNCTION, makeSource(// "main() {", lineWithTest, "}", "", "bool test() {", "}", "")); } private void assertLinkedProposals(String positionName, String... expectedNames) { List<LinkedPositionProposal> proposals = resultProposal.getLinkedPositionProposals().get( positionName); Set<String> actualNames = Sets.newHashSet(); for (LinkedPositionProposal proposal : proposals) { actualNames.add(proposal.getText()); } assertThat(actualNames).contains((Object[]) expectedNames); } private void assertNoFix(CorrectionKind kind) throws Exception { CorrectionProposal proposal = findProposal(kind); assertNull(proposal); } /** * Parse unit with library 'async' to have its {@link LibraryElement} ready. */ private void ensureSdkLibraryAsync() throws Exception { parseTestUnit("import 'dart:async';"); } /** * @return the {@link CorrectionProposal} with the given {@link CorrectionKind}. */ private CorrectionProposal findProposal(CorrectionKind kind) throws Exception { CorrectionProposal[] proposals = getProposals(); // find and apply required proposal for (CorrectionProposal proposal : proposals) { if (proposal.getKind() == kind) { return proposal; } } // not found return null; } private CorrectionProposal[] getProposals() throws Exception { AssistContext context = new AssistContext( null, analysisContext, null, testSource, testUnit, 0, 0); return PROCESSOR.computeProposals(context, error); } /** * @return the {@link SourceRange} of "identPattern" in {@link #resultCode}. */ private SourceRange getResultRange(String identPattern) { int offset = resultCode.indexOf(identPattern); assertThat(offset).describedAs(identPattern + " in " + resultCode).isPositive(); String identifier = identPattern.substring(0, NOT_IDENTIFIER_MATCHER.indexIn(identPattern)); return new SourceRange(offset, identifier.length()); } /** * @return the {@link SourceRange}s of "wordPatterns" in {@link #resultCode}. */ private List<SourceRange> getResultRanges(String... wordPatterns) { List<SourceRange> ranges = Lists.newArrayList(); for (String wordPattern : wordPatterns) { ranges.add(getResultRange(wordPattern)); } return ranges; } /** * Prepares single error to fix and stores to {@link #error}. */ private void prepareProblem() { try { AnalysisError[] errors = getAnalysisContext().computeErrors(testSource); assertThat(errors).hasSize(1); error = errors[0]; } catch (AnalysisException exception) { fail("Could not access errors for " + testSource.getFullName()); } } /** * Analyzes {@link #testUnit} and checks that {@link QuickFixProcessor#hasFix(AnalysisError)}. */ private void prepareProblemWithFix() { prepareProblem(); { boolean hasFix = PROCESSOR.hasFix(error); ErrorCode errorCode = error.getErrorCode(); String errorCodeStr = errorCode.getClass().getSimpleName() + "." + errorCode; assertTrue(errorCodeStr + " " + error.getMessage(), hasFix); } } /** * Prepares {@link #error} and checks that {@link QuickFixProcessor#hasFix(AnalysisError)}. */ private void prepareProblemWithFix(String... lines) throws Exception { parseTestUnit(lines); prepareProblemWithFix(); } }