From ff852ca64a584ee5ec86f0dd71d0cccc3d80b4d5 Mon Sep 17 00:00:00 2001 From: Lukas Hanke Date: Wed, 14 May 2014 20:07:29 +0200 Subject: [PATCH] Bug 430818: [1.8][quick fix] Quick fix for "for loop" is not shown for bare local variable/argument/field Signed-off-by: Lukas Hanke --- .../ui/tests/quickfix/AssistQuickFixTest.java | 36 ++++---- .../LocalCorrectionsQuickFixTest.java | 13 ++- .../text/correction/QuickAssistProcessor.java | 83 ++++++++++++++----- .../GenerateForLoopAssistProposal.java | 41 ++++----- 4 files changed, 104 insertions(+), 69 deletions(-) diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java index 7ae4079831..500f32c368 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java @@ -9,6 +9,7 @@ * IBM Corporation - initial API and implementation * Sebastian Davids - testInvertEquals1-23 * Lukas Hanke - Bug 241696 [quick fix] quickfix to iterate over a collection - https://bugs.eclipse.org/bugs/show_bug.cgi?id=241696 + * Lukas Hanke - Bug 430818 [1.8][quick fix] Quick fix for "for loop" is not shown for bare local variable/argument/field - https://bugs.eclipse.org/bugs/show_bug.cgi?id=430818 *******************************************************************************/ package org.eclipse.jdt.ui.tests.quickfix; @@ -8611,7 +8612,7 @@ public void testGenerateForSimple() throws Exception { AssistContext context= getCorrectionContext(cu, buf.toString().lastIndexOf(selection) + selection.length(), 0); List proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 2); + assertNumberOfProposals(proposals, 4); assertCorrectLabels(proposals); String[] expected= new String[2]; @@ -8633,8 +8634,7 @@ public void testGenerateForSimple() throws Exception { buf.append("import java.util.Iterator;\n"); buf.append("public class E {\n"); buf.append(" void foo(Collection collection) {\n"); - buf.append(" for (Iterator iterator = collection.iterator(); iterator\n"); - buf.append(" .hasNext();) {\n"); + buf.append(" for (Iterator iterator = collection.iterator(); iterator.hasNext();) {\n"); buf.append(" String string = iterator.next();\n"); buf.append(" \n"); buf.append(" }\n"); @@ -8672,7 +8672,7 @@ public void testGenerateForWithSemicolon() throws Exception { AssistContext context= getCorrectionContext(cu, buf.toString().lastIndexOf(selection) + selection.length(), 0); List proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 4); + assertNumberOfProposals(proposals, 2); assertCorrectLabels(proposals); String[] expected= new String[2]; @@ -8793,7 +8793,7 @@ public void testGenerateForComplexParametrization() throws Exception { AssistContext context= getCorrectionContext(cu, buf.toString().lastIndexOf(selection) + selection.length(), 0); List proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 3); + assertNumberOfProposals(proposals, 5); assertCorrectLabels(proposals); String[] expected= new String[3]; @@ -8817,8 +8817,7 @@ public void testGenerateForComplexParametrization() throws Exception { buf.append("import java.util.LinkedList;\n"); buf.append("public class E {\n"); buf.append(" void foo(MySecondOwnIterable collection) {\n"); - buf.append(" for (Iterator iterator = collection.iterator(); iterator\n"); - buf.append(" .hasNext();) {\n"); + buf.append(" for (Iterator iterator = collection.iterator(); iterator.hasNext();) {\n"); buf.append(" String string = iterator.next();\n"); buf.append(" \n"); buf.append(" }\n"); @@ -8874,7 +8873,7 @@ public void testGenerateForGenerics() throws Exception { AssistContext context= getCorrectionContext(cu, buf.toString().lastIndexOf(selection) + selection.length(), 0); List proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 2); + assertNumberOfProposals(proposals, 4); assertCorrectLabels(proposals); String[] expected= new String[2]; @@ -8898,8 +8897,7 @@ public void testGenerateForGenerics() throws Exception { buf.append("import java.util.Iterator;\n"); buf.append("public class E {\n"); buf.append(" void foo(Collection collection) {\n"); - buf.append(" for (Iterator iterator = collection.iterator(); iterator\n"); - buf.append(" .hasNext();) {\n"); + buf.append(" for (Iterator iterator = collection.iterator(); iterator.hasNext();) {\n"); buf.append(" T t = iterator.next();\n"); buf.append(" \n"); buf.append(" }\n"); @@ -9005,7 +9003,7 @@ public void testGenerateForUpperboundWildcard() throws Exception { AssistContext context= getCorrectionContext(cu, buf.toString().lastIndexOf(selection) + selection.length(), 0); List proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 3); + assertNumberOfProposals(proposals, 5); assertCorrectLabels(proposals); String[] expected= new String[3]; @@ -9083,7 +9081,7 @@ public void testGenerateForLowerboundWildcard() throws Exception { AssistContext context= getCorrectionContext(cu, buf.toString().lastIndexOf(selection) + selection.length(), 0); List proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 3); + assertNumberOfProposals(proposals, 5); assertCorrectLabels(proposals); String[] expected= new String[3]; @@ -9230,7 +9228,7 @@ public void testGenerateForMissingParametrization() throws Exception { AssistContext context= getCorrectionContext(cu, buf.toString().lastIndexOf(selection) + selection.length(), 0); List proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 2); + assertNumberOfProposals(proposals, 4); assertCorrectLabels(proposals); String[] expected= new String[2]; @@ -9252,8 +9250,7 @@ public void testGenerateForMissingParametrization() throws Exception { buf.append("import java.util.Iterator;\n"); buf.append("public class E {\n"); buf.append(" void foo(Collection collection) {\n"); - buf.append(" for (Iterator iterator = collection.iterator(); iterator\n"); - buf.append(" .hasNext();) {\n"); + buf.append(" for (Iterator iterator = collection.iterator(); iterator.hasNext();) {\n"); buf.append(" Object object = iterator.next();\n"); buf.append(" \n"); buf.append(" }\n"); @@ -9293,7 +9290,7 @@ public void testGenerateForLowVersion() throws Exception { AssistContext context= getCorrectionContext(cu, buf.toString().lastIndexOf(selection) + selection.length(), 0); List proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 1); + assertNumberOfProposals(proposals, 3); assertProposalDoesNotExist(proposals, CorrectionMessages.QuickAssistProcessor_generate_enhanced_for_loop); assertCorrectLabels(proposals); @@ -9306,8 +9303,7 @@ public void testGenerateForLowVersion() throws Exception { buf.append("import java.util.Iterator;\n"); buf.append("public class E {\n"); buf.append(" void foo(Collection collection) {\n"); - buf.append(" for (Iterator iterator = collection.iterator(); iterator\n"); - buf.append(" .hasNext();) {\n"); + buf.append(" for (Iterator iterator = collection.iterator(); iterator.hasNext();) {\n"); buf.append(" Object object = iterator.next();\n"); buf.append(" \n"); buf.append(" }\n"); @@ -9344,7 +9340,7 @@ public void testGenerateForArray() throws Exception { AssistContext context= getCorrectionContext(cu, buf.toString().lastIndexOf(selection) + selection.length(), 0); List proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 2); + assertNumberOfProposals(proposals, 4); assertCorrectLabels(proposals); String[] expected= new String[2]; @@ -9401,7 +9397,7 @@ public void testGenerateForNameClash() throws Exception { AssistContext context= getCorrectionContext(cu, buf.toString().lastIndexOf(selection) + selection.length(), 0); List proposals= collectAssists(context, false); - assertNumberOfProposals(proposals, 2); + assertNumberOfProposals(proposals, 4); assertCorrectLabels(proposals); String[] expected= new String[2]; diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/LocalCorrectionsQuickFixTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/LocalCorrectionsQuickFixTest.java index 07c8b84908..c2ed915d9d 100644 --- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/LocalCorrectionsQuickFixTest.java +++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/LocalCorrectionsQuickFixTest.java @@ -9,6 +9,7 @@ * IBM Corporation - initial API and implementation * Benjamin Muskalla - [quick fix] Shouldn't offer "Add throws declaration" quickfix for overriding signature if result would conflict with overridden signature * Lukas Hanke - Bug 241696 [quick fix] quickfix to iterate over a collection - https://bugs.eclipse.org/bugs/show_bug.cgi?id=241696 + * Lukas Hanke - Bug 430818 [1.8][quick fix] Quick fix for "for loop" is not shown for bare local variable/argument/field - https://bugs.eclipse.org/bugs/show_bug.cgi?id=430818 *******************************************************************************/ package org.eclipse.jdt.ui.tests.quickfix; @@ -55,7 +56,7 @@ public class LocalCorrectionsQuickFixTest extends QuickFixTest { * caused by: * Bug 430336: [1.8][compiler] Bad syntax error recovery: Lonely identifier should be variable name, not type */ - public static final boolean BUG_430818= true; + public static final boolean BUG_430818= false; private IJavaProject fJProject1; private IPackageFragmentRoot fSourceFolder; @@ -9814,7 +9815,7 @@ public void testLoopOverAddedToFixesForVariable() throws Exception { newOptions.put(DefaultCodeFormatterConstants.FORMATTER_PUT_EMPTY_STATEMENT_ON_NEW_LINE, "true"); try { fJProject1.setOptions(newOptions); - List proposals= collectCorrections(cu, getASTRoot(cu), 2, null); + List proposals= collectCorrections(cu, getASTRoot(cu), 3, null); assertNumberOfProposals(proposals, 2); assertCorrectLabels(proposals); @@ -9838,8 +9839,7 @@ public void testLoopOverAddedToFixesForVariable() throws Exception { buf.append("import java.util.Iterator;\n"); buf.append("public class E {\n"); buf.append(" void foo(Collection collection) {\n"); - buf.append(" for (Iterator iterator = collection.iterator(); iterator\n"); - buf.append(" .hasNext();) {\n"); + buf.append(" for (Iterator iterator = collection.iterator(); iterator.hasNext();) {\n"); buf.append(" String string = iterator.next();\n"); buf.append(" \n"); buf.append(" }\n"); @@ -9942,7 +9942,7 @@ public void testGenerateForeachNotAddedForLowVersion() throws Exception { newOptions.put(DefaultCodeFormatterConstants.FORMATTER_PUT_EMPTY_STATEMENT_ON_NEW_LINE, "true"); try { fJProject1.setOptions(newOptions); - List proposals= collectCorrections(cu, getASTRoot(cu), 2, null); + List proposals= collectCorrections(cu, getASTRoot(cu), 3, null); assertNumberOfProposals(proposals, 1); assertCorrectLabels(proposals); @@ -9957,8 +9957,7 @@ public void testGenerateForeachNotAddedForLowVersion() throws Exception { buf.append("import java.util.Iterator;\n"); buf.append("public class E {\n"); buf.append(" void foo(Collection collection) {\n"); - buf.append(" for (Iterator iterator = collection.iterator(); iterator\n"); - buf.append(" .hasNext();) {\n"); + buf.append(" for (Iterator iterator = collection.iterator(); iterator.hasNext();) {\n"); buf.append(" Object object = iterator.next();\n"); buf.append(" \n"); buf.append(" }\n"); diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java index 66edbf335a..ddf6d18414 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java @@ -12,6 +12,7 @@ * Chris West (Faux) - [quick assist] "Use 'StringBuilder' for string concatenation" could fix existing misuses - https://bugs.eclipse.org/bugs/show_bug.cgi?id=282755 * Lukas Hanke - Bug 241696 [quick fix] quickfix to iterate over a collection - https://bugs.eclipse.org/bugs/show_bug.cgi?id=241696 * Eugene Lucash - [quick assist] Add key binding for Extract method Quick Assist - https://bugs.eclipse.org/424166 + * Lukas Hanke - Bug 430818 [1.8][quick fix] Quick fix for "for loop" is not shown for bare local variable/argument/field - https://bugs.eclipse.org/bugs/show_bug.cgi?id=430818 *******************************************************************************/ package org.eclipse.jdt.internal.ui.text.correction; @@ -67,7 +68,6 @@ import org.eclipse.jdt.core.dom.EnhancedForStatement; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.ExpressionStatement; -import org.eclipse.jdt.core.dom.FieldAccess; import org.eclipse.jdt.core.dom.ForStatement; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IMethodBinding; @@ -90,6 +90,7 @@ import org.eclipse.jdt.core.dom.PrefixExpression; import org.eclipse.jdt.core.dom.PrefixExpression.Operator; import org.eclipse.jdt.core.dom.PrimitiveType; +import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.ReturnStatement; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; @@ -124,6 +125,7 @@ import org.eclipse.jdt.internal.corext.dom.DimensionRewrite; import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder; import org.eclipse.jdt.internal.corext.dom.ModifierRewrite; +import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer; import org.eclipse.jdt.internal.corext.dom.Selection; import org.eclipse.jdt.internal.corext.dom.SelectionAnalyzer; import org.eclipse.jdt.internal.corext.dom.TokenScanner; @@ -2741,26 +2743,31 @@ private static boolean getConvertIterableLoopProposal(IInvocationContext context } public static boolean getGenerateForLoopProposals(IInvocationContext context, ASTNode coveringNode, IProblemLocation[] locations, Collection resultingCollections) { - Statement statement= ASTResolving.findParentStatement(coveringNode); - if (!(statement instanceof ExpressionStatement)) { - return false; - } - if (containsMatchingProblem(locations, IProblem.ParsingErrorInsertToComplete)) return false; - Expression expression= ((ExpressionStatement) statement).getExpression(); + Statement statement= ASTResolving.findParentStatement(coveringNode); ICompilationUnit cu= context.getCompilationUnit(); ITypeBinding expressionType= null; + Expression expression= null; + int relevanceBoost= 0; - if (expression instanceof MethodInvocation - || expression instanceof SimpleName - || expression instanceof FieldAccess) { - expressionType= expression.resolveTypeBinding(); - } else if (expression instanceof Assignment - && ((Assignment) expression).getRightHandSide().resolveTypeBinding() == null - && ((Assignment) expression).getLeftHandSide().resolveTypeBinding() != null) { - expressionType= ((Assignment) expression).getLeftHandSide().resolveTypeBinding(); + if (statement instanceof ExpressionStatement) { + expressionType= extractExpressionType((ExpressionStatement) statement); + expression= ((ExpressionStatement) statement).getExpression(); + + } else if (statement instanceof VariableDeclarationStatement && ((VariableDeclarationStatement) statement).fragments().size() == 1 + && ((VariableDeclarationStatement) statement).fragments().get(0).toString().equals("$missing$")) { //$NON-NLS-1$ + // variable name is resolved to the type in a variable declaration statement, see https://bugs.eclipse.org/430336 + Type type= ((VariableDeclarationStatement) statement).getType(); + if (type instanceof SimpleType) { + SimpleType simpleType= (SimpleType) type; + expressionType= extractExpressionType(simpleType); + expression= simpleType.getName(); + relevanceBoost+= 6; // need to overrule the bad UnresolvedElementsSubProcessor#addNewTypeProposals(..) + } + } else { + return false; } if (expressionType == null) @@ -2769,25 +2776,63 @@ public static boolean getGenerateForLoopProposals(IInvocationContext context, AS if (Bindings.findTypeInHierarchy(expressionType, "java.lang.Iterable") != null) { //$NON-NLS-1$ if (resultingCollections == null) return true; - resultingCollections.add(new GenerateForLoopAssistProposal(cu, statement, expression, GenerateForLoopAssistProposal.GENERATE_ITERATOR_FOR)); + GenerateForLoopAssistProposal proposal= new GenerateForLoopAssistProposal(cu, expressionType, statement, expression, GenerateForLoopAssistProposal.GENERATE_ITERATOR_FOR); + proposal.setRelevance(proposal.getRelevance() + relevanceBoost); + resultingCollections.add(proposal); if (Bindings.findTypeInHierarchy(expressionType, "java.util.List") != null) { //$NON-NLS-1$ - resultingCollections.add(new GenerateForLoopAssistProposal(cu, statement, expression, GenerateForLoopAssistProposal.GENERATE_ITERATE_LIST)); + proposal= new GenerateForLoopAssistProposal(cu, expressionType, statement, expression, GenerateForLoopAssistProposal.GENERATE_ITERATE_LIST); + proposal.setRelevance(proposal.getRelevance() + relevanceBoost); + resultingCollections.add(proposal); } } else if (expressionType.isArray()) { if (resultingCollections == null) return true; - resultingCollections.add(new GenerateForLoopAssistProposal(cu, statement, expression, GenerateForLoopAssistProposal.GENERATE_ITERATE_ARRAY)); + GenerateForLoopAssistProposal proposal= new GenerateForLoopAssistProposal(cu, expressionType, statement, expression, GenerateForLoopAssistProposal.GENERATE_ITERATE_ARRAY); + proposal.setRelevance(proposal.getRelevance() + relevanceBoost); + resultingCollections.add(proposal); } else { return false; } if (JavaModelUtil.is50OrHigher(cu.getJavaProject())) { - resultingCollections.add(new GenerateForLoopAssistProposal(cu, statement, expression, GenerateForLoopAssistProposal.GENERATE_FOREACH)); + GenerateForLoopAssistProposal proposal= new GenerateForLoopAssistProposal(cu, expressionType, statement, expression, GenerateForLoopAssistProposal.GENERATE_FOREACH); + proposal.setRelevance(proposal.getRelevance() + relevanceBoost); + resultingCollections.add(proposal); } return true; } + private static ITypeBinding extractExpressionType(ExpressionStatement statement) { + Expression expression= statement.getExpression(); + if (expression.getNodeType() == ASTNode.METHOD_INVOCATION + || expression.getNodeType() == ASTNode.FIELD_ACCESS) { + return expression.resolveTypeBinding(); + } + return null; + } + + private static ITypeBinding extractExpressionType(SimpleType variableIdentifier) { + ScopeAnalyzer analyzer= new ScopeAnalyzer((CompilationUnit) variableIdentifier.getRoot()); + // get the name of the variable to search the type for + Name name= null; + if (variableIdentifier.getName() instanceof SimpleName) { + name= variableIdentifier.getName(); + } else if (variableIdentifier.getName() instanceof QualifiedName) { + name= ((QualifiedName) variableIdentifier.getName()).getName(); + } + + // analyze variables which are available in the scope at the position of the quick assist invokation + IBinding[] declarationsInScope= analyzer.getDeclarationsInScope(name.getStartPosition(), ScopeAnalyzer.VARIABLES); + for (int i= 0; i < declarationsInScope.length; i++) { + IBinding currentVariable= declarationsInScope[i]; + if (((IVariableBinding) currentVariable).getName().equals(name.getFullyQualifiedName())) { + return ((IVariableBinding) currentVariable).getType(); + } + } + return null; + } + private static ForStatement getEnclosingForStatementHeader(ASTNode node) { return getEnclosingHeader(node, ForStatement.class, ForStatement.INITIALIZERS_PROPERTY, ForStatement.EXPRESSION_PROPERTY, ForStatement.UPDATERS_PROPERTY); } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/GenerateForLoopAssistProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/GenerateForLoopAssistProposal.java index 50e87d0e9e..cf8105c227 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/GenerateForLoopAssistProposal.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/GenerateForLoopAssistProposal.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013 Yatta Solutions GmbH and others. + * Copyright (c) 2014 Yatta Solutions GmbH and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,6 +7,7 @@ * * Contributors: * Lukas Hanke - Bug 241696 [quick fix] quickfix to iterate over a collection - https://bugs.eclipse.org/bugs/show_bug.cgi?id=241696 + * Lukas Hanke - Bug 430818 [1.8][quick fix] Quick fix for "for loop" is not shown for bare local variable/argument/field - https://bugs.eclipse.org/bugs/show_bug.cgi?id=430818 *******************************************************************************/ package org.eclipse.jdt.internal.ui.text.correction.proposals; @@ -71,7 +72,7 @@ public class GenerateForLoopAssistProposal extends LinkedCorrectionProposal { private Expression fCurrentExpression; - private Expression fSubExpression; + private ITypeBinding fExpressionType; private int fLoopTypeToGenerate= -1; @@ -79,6 +80,7 @@ public class GenerateForLoopAssistProposal extends LinkedCorrectionProposal { * Creates an instance of a {@link GenerateForLoopAssistProposal}. * * @param cu the current {@link ICompilationUnit} + * @param expressionType the {@link ITypeBinding} of the element to iterate over * @param currentNode the {@link ASTNode} instance representing the statement on which the * assist was called * @param currentExpression the {@link Expression} contained in the currentNode @@ -87,11 +89,12 @@ public class GenerateForLoopAssistProposal extends LinkedCorrectionProposal { * {@link GenerateForLoopAssistProposal#GENERATE_ITERATOR_FOR} or * {@link GenerateForLoopAssistProposal#GENERATE_ITERATE_ARRAY} */ - public GenerateForLoopAssistProposal(ICompilationUnit cu, ASTNode currentNode, Expression currentExpression, int loopTypeToGenerate) { + public GenerateForLoopAssistProposal(ICompilationUnit cu, ITypeBinding expressionType, ASTNode currentNode, Expression currentExpression, int loopTypeToGenerate) { super("", cu, null, IProposalRelevance.GENERATE_FOR_LOOP, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE)); //$NON-NLS-1$ fCurrentNode= currentNode; fCurrentExpression= currentExpression; fLoopTypeToGenerate= loopTypeToGenerate; + fExpressionType= expressionType; switch (loopTypeToGenerate) { case GenerateForLoopAssistProposal.GENERATE_FOREACH: @@ -122,13 +125,6 @@ protected ASTRewrite getRewrite() throws CoreException { AST ast= fCurrentNode.getAST(); createImportRewrite((CompilationUnit) fCurrentExpression.getRoot()); - // generate the subexpression which represents the expression to iterate over - if (fCurrentExpression instanceof Assignment) { - this.fSubExpression= ((Assignment) fCurrentExpression).getLeftHandSide(); - } else { - this.fSubExpression= fCurrentExpression; - } - switch (fLoopTypeToGenerate) { case GenerateForLoopAssistProposal.GENERATE_FOREACH: return generateForEachRewrite(ast); @@ -165,7 +161,7 @@ private ASTRewrite generateForEachRewrite(AST ast) { forLoopInitializer.setName(forDeclarationName); loopStatement.setParameter(forLoopInitializer); - loopStatement.setExpression((Expression) rewrite.createCopyTarget(fSubExpression)); + loopStatement.setExpression((Expression) rewrite.createCopyTarget(fCurrentExpression)); Block forLoopBody= ast.newBlock(); forLoopBody.statements().add(createBlankLineStatementWithCursorPosition(rewrite)); @@ -223,7 +219,7 @@ private ASTRewrite generateIteratorBasedForRewrite(AST ast) { */ private VariableDeclarationExpression getIteratorBasedForInitializer(ASTRewrite rewrite, SimpleName loopVariableName) { AST ast= rewrite.getAST(); - IMethodBinding iteratorMethodBinding= Bindings.findMethodInHierarchy(fCurrentExpression.resolveTypeBinding(), "iterator", new ITypeBinding[] {}); //$NON-NLS-1$ + IMethodBinding iteratorMethodBinding= Bindings.findMethodInHierarchy(fExpressionType, "iterator", new ITypeBinding[] {}); //$NON-NLS-1$ // initializing fragment VariableDeclarationFragment varDeclarationFragment= ast.newVariableDeclarationFragment(); varDeclarationFragment.setName(loopVariableName); @@ -289,7 +285,7 @@ private ASTRewrite generateForRewrite(AST ast) { loopStatement.initializers().add(getForInitializer(ast, loopVariableName)); FieldAccess getArrayLengthExpression= ast.newFieldAccess(); - getArrayLengthExpression.setExpression((Expression) rewrite.createCopyTarget(fSubExpression)); + getArrayLengthExpression.setExpression((Expression) rewrite.createCopyTarget(fCurrentExpression)); getArrayLengthExpression.setName(ast.newSimpleName("length")); //$NON-NLS-1$ loopStatement.setExpression(getLinkedInfixExpression(rewrite, loopVariableName.getIdentifier(), getArrayLengthExpression, InfixExpression.Operator.LESS)); @@ -330,7 +326,7 @@ private Assignment getForBodyAssignment(ASTRewrite rewrite, SimpleName loopVaria // right hand side ArrayAccess access= ast.newArrayAccess(); - access.setArray((Expression) rewrite.createCopyTarget(fSubExpression)); + access.setArray((Expression) rewrite.createCopyTarget(fCurrentExpression)); SimpleName indexName= ast.newSimpleName(loopVariableName.getIdentifier()); addLinkedPosition(rewrite.track(indexName), LinkedPositionGroup.NO_STOP, indexName.getIdentifier()); access.setIndex(indexName); @@ -425,7 +421,7 @@ private ASTRewrite generateIndexBasedForRewrite(AST ast) { MethodInvocation listSizeExpression= ast.newMethodInvocation(); listSizeExpression.setName(ast.newSimpleName("size")); //$NON-NLS-1$ - Expression listExpression= (Expression) rewrite.createCopyTarget(fSubExpression); + Expression listExpression= (Expression) rewrite.createCopyTarget(fCurrentExpression); listSizeExpression.setExpression(listExpression); loopStatement.setExpression(getLinkedInfixExpression(rewrite, loopVariableName.getIdentifier(), listSizeExpression, InfixExpression.Operator.LESS)); @@ -470,7 +466,7 @@ private Expression getIndexBasedForBodyAssignment(ASTRewrite rewrite, SimpleName SimpleName indexVariableName= ast.newSimpleName(loopVariableName.getIdentifier()); addLinkedPosition(rewrite.track(indexVariableName), LinkedPositionGroup.NO_STOP, indexVariableName.getIdentifier()); invokeGetExpression.arguments().add(indexVariableName); - invokeGetExpression.setExpression((Expression) rewrite.createCopyTarget(fSubExpression)); + invokeGetExpression.setExpression((Expression) rewrite.createCopyTarget(fCurrentExpression)); assignResolvedVariable.setRightHandSide(invokeGetExpression); assignResolvedVariable.setOperator(Assignment.Operator.ASSIGN); @@ -538,24 +534,23 @@ private String[] getVariableNameProposals(String basename, String excludedName) } /** - * Extracts the type parameter of the variable contained in fSubExpression or the elements type - * to iterate over an array using foreach. + * Extracts the type parameter of the variable contained in fCurrentExpression or the elements + * type to iterate over an array using foreach. * * @param ast the current {@link AST} instance * @return the {@link ITypeBinding} of the elements to iterate over */ private ITypeBinding extractElementType(AST ast) { - ITypeBinding binding= fSubExpression.resolveTypeBinding(); - if (binding.isArray()) { - return Bindings.normalizeForDeclarationUse(binding.getElementType(), ast); + if (fExpressionType.isArray()) { + return Bindings.normalizeForDeclarationUse(fExpressionType.getElementType(), ast); } // extract elements type directly out of the bindings - IMethodBinding iteratorMethodBinding= Bindings.findMethodInHierarchy(fCurrentExpression.resolveTypeBinding(), "iterator", new ITypeBinding[] {}); //$NON-NLS-1$ + IMethodBinding iteratorMethodBinding= Bindings.findMethodInHierarchy(fExpressionType, "iterator", new ITypeBinding[] {}); //$NON-NLS-1$ IMethodBinding iteratorNextMethodBinding= Bindings.findMethodInHierarchy(iteratorMethodBinding.getReturnType(), "next", new ITypeBinding[] {}); //$NON-NLS-1$ ITypeBinding currentElementBinding= iteratorNextMethodBinding.getReturnType(); - + return Bindings.normalizeForDeclarationUse(currentElementBinding, ast); }