1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-01 06:05:24 +02:00

Fixed passing parameters by pointer and renaming of parameters in

Extract Function refactoring.
This commit is contained in:
Sergey Prigogin 2012-02-07 14:36:47 -08:00
parent 38803901ec
commit 8dc598a145
14 changed files with 580 additions and 293 deletions

View file

@ -39,6 +39,7 @@ public class ASTComparer extends Assert {
// Can be different in copy // Can be different in copy
"isFrozen", "isFrozen",
"getContainingFilename", "getContainingFilename",
"getOriginalNode",
// These methods are problematic // These methods are problematic
"getProblem", "getProblem",
@ -62,18 +63,16 @@ public class ASTComparer extends Assert {
"isLValue" "isLValue"
)); ));
public static void assertCopy(IASTNode node1, IASTNode node2) { public static void assertCopy(IASTNode node1, IASTNode node2) {
try { try {
assertCopy(node1, node2, 0); assertCopy(node1, node2, 0);
} catch(Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private static void assertCopy(IASTNode node1, IASTNode node2, int n) throws Exception { private static void assertCopy(IASTNode node1, IASTNode node2, int n) throws Exception {
if(node1 == null && node2 == null) if (node1 == null && node2 == null)
return; return;
assertNotNull(node1); assertNotNull(node1);
assertNotNull(node2); assertNotNull(node2);
@ -86,11 +85,11 @@ public class ASTComparer extends Assert {
BeanInfo beanInfo = Introspector.getBeanInfo(klass1); BeanInfo beanInfo = Introspector.getBeanInfo(klass1);
for(PropertyDescriptor property : beanInfo.getPropertyDescriptors()) { for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
Method getter = property.getReadMethod(); Method getter = property.getReadMethod();
if(getter == null) if (getter == null)
continue; continue;
if(methodsToIgnore.contains(getter.getName())) if (methodsToIgnore.contains(getter.getName()))
continue; continue;
if (getter.getAnnotation(Deprecated.class) != null) if (getter.getAnnotation(Deprecated.class) != null)
@ -99,48 +98,43 @@ public class ASTComparer extends Assert {
try { try {
Class returnType = getter.getReturnType(); Class returnType = getter.getReturnType();
if(IASTNode.class.isAssignableFrom(returnType)) { if (IASTNode.class.isAssignableFrom(returnType)) {
//System.out.println(spaces(n) + "Testing1: " + getter.getName()); //System.out.println(spaces(n) + "Testing1: " + getter.getName());
IASTNode result1 = (IASTNode) getter.invoke(node1); IASTNode result1 = (IASTNode) getter.invoke(node1);
IASTNode result2 = (IASTNode) getter.invoke(node2); IASTNode result2 = (IASTNode) getter.invoke(node2);
assertCopy(result1, result2, n+1); // members must be same assertCopy(result1, result2, n + 1); // members must be same
} } else if (returnType.isArray() && IASTNode.class.isAssignableFrom(returnType.getComponentType())) {
else if(returnType.isArray() && IASTNode.class.isAssignableFrom(returnType.getComponentType())) {
//System.out.println(spaces(n) + "Testing2: " + getter.getName()); //System.out.println(spaces(n) + "Testing2: " + getter.getName());
IASTNode[] result1 = (IASTNode[]) getter.invoke(node1); IASTNode[] result1 = (IASTNode[]) getter.invoke(node1);
IASTNode[] result2 = (IASTNode[]) getter.invoke(node2); IASTNode[] result2 = (IASTNode[]) getter.invoke(node2);
if(result1 == null && result2 == null) if (result1 == null && result2 == null)
continue; continue;
assertNotNull(result1); assertNotNull(result1);
assertNotNull(result2); assertNotNull(result2);
assertEquals(result1.length, result2.length); assertEquals(result1.length, result2.length);
for(int i = 0; i < result1.length; i++) for(int i = 0; i < result1.length; i++)
assertCopy(result1[i], result2[i], n+1); assertCopy(result1[i], result2[i], n + 1);
} } else if ((returnType.isPrimitive() || returnType.equals(String.class)) && !returnType.equals(Void.class)) {
else if((returnType.isPrimitive() || returnType.equals(String.class)) && !returnType.equals(Void.class)) {
//System.out.println(spaces(n) + "Testing3: " + getter.getName()); //System.out.println(spaces(n) + "Testing3: " + getter.getName());
Object result1 = getter.invoke(node1); Object result1 = getter.invoke(node1);
Object result2 = getter.invoke(node2); Object result2 = getter.invoke(node2);
assertEquals(result1, result2); assertEquals(result1, result2);
} }
} catch (AssertionFailedError e) {
} catch(AssertionFailedError e) {
System.out.printf("Failure when calling %s.%s() @(%d,%d)\n", System.out.printf("Failure when calling %s.%s() @(%d,%d)\n",
node1.getClass().getSimpleName(), node1.getClass().getSimpleName(),
getter.getName(), getter.getName(),
((ASTNode)node1).getOffset(), ((ASTNode) node1).getOffset(),
((ASTNode)node1).getLength()); ((ASTNode) node1).getLength());
throw e; throw e;
} }
} }
} }
// private static String spaces(int n) { // private static String spaces(int n) {
// char[] spaces = new char[n*2]; // char[] spaces = new char[n*2];
// Arrays.fill(spaces, ' '); // Arrays.fill(spaces, ' ');
// return new String(spaces); // return new String(spaces);
// } // }
} }

View file

@ -18,6 +18,10 @@ package org.eclipse.cdt.core.dom.ast;
* @noimplement This interface is not intended to be implemented by clients. * @noimplement This interface is not intended to be implemented by clients.
*/ */
public interface IASTComment extends IASTNode { public interface IASTComment extends IASTNode {
/**
* @since 5.4
*/
public final IASTComment[] EMPTY_COMMENT_ARRAY = {};
/** /**
* Set the comment. * Set the comment.
@ -39,5 +43,4 @@ public interface IASTComment extends IASTNode {
* @return true if this is a blockcomment * @return true if this is a blockcomment
*/ */
public boolean isBlockComment(); public boolean isBlockComment();
} }

View file

@ -17,7 +17,6 @@ package org.eclipse.cdt.core.dom.ast;
* @noimplement This interface is not intended to be implemented by clients. * @noimplement This interface is not intended to be implemented by clients.
*/ */
public interface IASTIdExpression extends IASTExpression, IASTNameOwner { public interface IASTIdExpression extends IASTExpression, IASTNameOwner {
/** /**
* <code>ID_NAME</code> represents the relationship between an * <code>ID_NAME</code> represents the relationship between an
* <code>IASTIdExpression</code> and a <code>IASTName</code>. * <code>IASTIdExpression</code> and a <code>IASTName</code>.

View file

@ -23,7 +23,6 @@ import org.eclipse.cdt.core.dom.ast.IType;
* @noimplement This interface is not intended to be implemented by clients. * @noimplement This interface is not intended to be implemented by clients.
*/ */
public interface ICPPASTFieldReference extends IASTFieldReference, IASTImplicitNameOwner { public interface ICPPASTFieldReference extends IASTFieldReference, IASTImplicitNameOwner {
/** /**
* Was template keyword used? * Was template keyword used?
* *

View file

@ -14,6 +14,7 @@ package org.eclipse.cdt.internal.core.dom.parser;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.ExpansionOverlapsBoundaryException; import org.eclipse.cdt.core.dom.ast.ExpansionOverlapsBoundaryException;
import org.eclipse.cdt.core.dom.ast.IASTCopyLocation;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation; import org.eclipse.cdt.core.dom.ast.IASTImageLocation;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
@ -373,4 +374,19 @@ public abstract class ASTNode implements IASTNode {
protected void setCopyLocation(IASTNode originalNode) { protected void setCopyLocation(IASTNode originalNode) {
locations = new IASTNodeLocation[] { new ASTCopyLocation(originalNode) }; locations = new IASTNodeLocation[] { new ASTCopyLocation(originalNode) };
} }
/**
* If the node is a copy of some other node, returns the original node.
* Otherwise returns the node itself.
*/
public IASTNode getOriginalNode() {
IASTNode node = this;
while (true) {
IASTNodeLocation[] locations = node.getNodeLocations();
if (locations.length == 0 || !(locations[0] instanceof IASTCopyLocation))
break;
node = ((IASTCopyLocation) locations[0]).getOriginalNode();
}
return node;
}
} }

View file

@ -30,8 +30,8 @@ import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
/** /**
* Field reference in C. * Field reference in C.
*/ */
public class CASTFieldReference extends ASTNode implements IASTFieldReference, IASTAmbiguityParent, IASTCompletionContext { public class CASTFieldReference extends ASTNode
implements IASTFieldReference, IASTAmbiguityParent, IASTCompletionContext {
private IASTExpression owner; private IASTExpression owner;
private IASTName name; private IASTName name;
private boolean ptr; private boolean ptr;
@ -39,12 +39,10 @@ public class CASTFieldReference extends ASTNode implements IASTFieldReference, I
public CASTFieldReference() { public CASTFieldReference() {
} }
public CASTFieldReference(IASTName name, IASTExpression owner) { public CASTFieldReference(IASTName name, IASTExpression owner) {
this(name, owner, false); this(name, owner, false);
} }
public CASTFieldReference(IASTName name, IASTExpression owner, boolean ptr) { public CASTFieldReference(IASTName name, IASTExpression owner, boolean ptr) {
setFieldOwner(owner); setFieldOwner(owner);
setFieldName(name); setFieldName(name);
@ -111,41 +109,40 @@ public class CASTFieldReference extends ASTNode implements IASTFieldReference, I
} }
@Override @Override
public boolean accept( ASTVisitor action ){ public boolean accept(ASTVisitor action) {
if( action.shouldVisitExpressions ){ if (action.shouldVisitExpressions) {
switch( action.visit( this ) ){ switch (action.visit(this)) {
case ASTVisitor.PROCESS_ABORT : return false; case ASTVisitor.PROCESS_ABORT: return false;
case ASTVisitor.PROCESS_SKIP : return true; case ASTVisitor.PROCESS_SKIP: return true;
default : break; default: break;
} }
} }
if( owner != null ) if( !owner.accept( action ) ) return false; if (owner != null && !owner.accept(action)) return false;
if( name != null ) if( !name.accept( action ) ) return false; if (name != null && !name.accept(action)) return false;
if( action.shouldVisitExpressions ){ if (action.shouldVisitExpressions) {
switch( action.leave( this ) ){ switch (action.leave(this)) {
case ASTVisitor.PROCESS_ABORT : return false; case ASTVisitor.PROCESS_ABORT: return false;
case ASTVisitor.PROCESS_SKIP : return true; case ASTVisitor.PROCESS_SKIP: return true;
default : break; default: break;
} }
} }
return true; return true;
} }
@Override @Override
public int getRoleForName(IASTName n ) { public int getRoleForName(IASTName n) {
if( n == this.name ) if (n == this.name)
return r_reference; return r_reference;
return r_unclear; return r_unclear;
} }
@Override @Override
public void replace(IASTNode child, IASTNode other) { public void replace(IASTNode child, IASTNode other) {
if( child == owner) if (child == owner) {
{ other.setPropertyInParent(child.getPropertyInParent());
other.setPropertyInParent( child.getPropertyInParent() ); other.setParent(child.getParent());
other.setParent( child.getParent() );
owner = (IASTExpression) other; owner = (IASTExpression) other;
} }
} }
@ -159,7 +156,6 @@ public class CASTFieldReference extends ASTNode implements IASTFieldReference, I
return new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION); return new ProblemType(ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION);
} }
@Override @Override
public boolean isLValue() { public boolean isLValue() {
if (isPointerDereference()) if (isPointerDereference())

View file

@ -18,7 +18,11 @@ import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.glvalueType; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.glvalueType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.prvalueType; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.prvalueType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.typeFromFunctionCall; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.typeFromFunctionCall;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateTypeUptoPointers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -53,15 +57,13 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
public class CPPASTFieldReference extends ASTNode implements ICPPASTFieldReference, IASTAmbiguityParent, public class CPPASTFieldReference extends ASTNode
ICPPASTCompletionContext { implements ICPPASTFieldReference, IASTAmbiguityParent, ICPPASTCompletionContext {
private boolean isTemplate; private boolean isTemplate;
private IASTExpression owner; private IASTExpression owner;
private IASTName name; private IASTName name;
private boolean isDeref; private boolean isDeref;
private IASTImplicitName[] implicitNames;
private IASTImplicitName[] implicitNames = null;
public CPPASTFieldReference() { public CPPASTFieldReference() {
} }
@ -148,15 +150,15 @@ public class CPPASTFieldReference extends ASTNode implements ICPPASTFieldReferen
if (!isDeref) if (!isDeref)
return implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; return implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY;
// collect the function bindings // Collect the function bindings
List<ICPPFunction> functionBindings = new ArrayList<ICPPFunction>(); List<ICPPFunction> functionBindings = new ArrayList<ICPPFunction>();
getFieldOwnerType(functionBindings); getFieldOwnerType(functionBindings);
if (functionBindings.isEmpty()) if (functionBindings.isEmpty())
return implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; return implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY;
// create a name to wrap each binding // Create a name to wrap each binding
implicitNames = new IASTImplicitName[functionBindings.size()]; implicitNames = new IASTImplicitName[functionBindings.size()];
int i=-1; int i= -1;
for (ICPPFunction op : functionBindings) { for (ICPPFunction op : functionBindings) {
if (op != null && !(op instanceof CPPImplicitFunction)) { if (op != null && !(op instanceof CPPImplicitFunction)) {
CPPASTImplicitName operatorName = new CPPASTImplicitName(OverloadableOperator.ARROW, this); CPPASTImplicitName operatorName = new CPPASTImplicitName(OverloadableOperator.ARROW, this);
@ -281,7 +283,6 @@ public class CPPASTFieldReference extends ASTNode implements ICPPASTFieldReferen
return fieldType; return fieldType;
} }
@Override @Override
public ValueCategory getValueCategory() { public ValueCategory getValueCategory() {
IASTName name= getFieldName(); IASTName name= getFieldName();

View file

@ -12,10 +12,17 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.ui.tests.refactoring.extractfunction; package org.eclipse.cdt.ui.tests.refactoring.extractfunction;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.Test; import junit.framework.Test;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ltk.core.refactoring.Refactoring; import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.PreferenceConstants;
import org.eclipse.cdt.ui.tests.refactoring.RefactoringTestBase; import org.eclipse.cdt.ui.tests.refactoring.RefactoringTestBase;
import org.eclipse.cdt.internal.ui.refactoring.NameInformation; import org.eclipse.cdt.internal.ui.refactoring.NameInformation;
@ -31,6 +38,10 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
private ExtractFunctionInformation refactoringInfo; private ExtractFunctionInformation refactoringInfo;
private String extractedFunctionName = "extracted"; private String extractedFunctionName = "extracted";
private String returnValue; private String returnValue;
// Map from old names to new ones.
private Map<String, String> parameterRename = new HashMap<String, String>();
// New positions of parameters, or null.
private int[] parameterOrder;
private VisibilityEnum visibility = VisibilityEnum.v_private; private VisibilityEnum visibility = VisibilityEnum.v_private;
private boolean virtual; private boolean virtual;
private boolean replaceDuplicates = true; private boolean replaceDuplicates = true;
@ -47,6 +58,26 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
return suite(ExtractFunctionRefactoringTest.class); return suite(ExtractFunctionRefactoringTest.class);
} }
@Override
public void setUp() throws Exception {
super.setUp();
resetPreferences();
}
@Override
public void tearDown() throws Exception {
super.tearDown();
resetPreferences();
}
private void resetPreferences() {
getPreferenceStore().setToDefault(PreferenceConstants.FUNCTION_PASS_OUTPUT_PARAMETERS_BY_POINTER);
}
private IPreferenceStore getPreferenceStore() {
return CUIPlugin.getDefault().getPreferenceStore();
}
@Override @Override
protected Refactoring createRefactoring() { protected Refactoring createRefactoring() {
refactoringInfo = new ExtractFunctionInformation(); refactoringInfo = new ExtractFunctionInformation();
@ -61,14 +92,32 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
if (refactoringInfo.getMandatoryReturnVariable() == null) { if (refactoringInfo.getMandatoryReturnVariable() == null) {
if (returnValue != null) { if (returnValue != null) {
for (NameInformation nameInfo : refactoringInfo.getParameters()) { for (NameInformation nameInfo : refactoringInfo.getParameters()) {
nameInfo.setReturnValue(returnValue.equals(String.valueOf(nameInfo.getName().getSimpleID()))); nameInfo.setReturnValue(returnValue.equals(getName(nameInfo)));
} }
} }
} }
if (!parameterRename.isEmpty()) {
for (NameInformation nameInfo : refactoringInfo.getParameters()) {
String newName = parameterRename.get(getName(nameInfo));
if (newName != null)
nameInfo.setNewName(newName);
}
}
if (parameterOrder != null) {
List<NameInformation> parameters = refactoringInfo.getParameters();
NameInformation[] originalParameters = parameters.toArray(new NameInformation[parameters.size()]);
for (int i = 0; i < parameterOrder.length; i++) {
parameters.set(parameterOrder[i], originalParameters[i]);
}
}
refactoringInfo.setVisibility(visibility); refactoringInfo.setVisibility(visibility);
refactoringInfo.setVirtual(virtual); refactoringInfo.setVirtual(virtual);
} }
private String getName(NameInformation nameInfo) {
return String.valueOf(nameInfo.getName().getSimpleID());
}
//A.h //A.h
//#ifndef A_H_ //#ifndef A_H_
//#define A_H_ //#define A_H_
@ -536,7 +585,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//A.cpp //A.cpp
//#include "A.h" //#include "A.h"
// //
//#define ZWO 2 //#define TWO 2
// //
//A::A() { //A::A() {
//} //}
@ -547,7 +596,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int A::foo() { //int A::foo() {
// int i = 2; // int i = 2;
// /*$*/++i; // /*$*/++i;
// i += ZWO; // i += TWO;
// help();/*$$*/ // help();/*$$*/
// return i; // return i;
//} //}
@ -558,7 +607,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//==================== //====================
//#include "A.h" //#include "A.h"
// //
//#define ZWO 2 //#define TWO 2
// //
//A::A() { //A::A() {
//} //}
@ -568,7 +617,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
// //
//int A::extracted(int i) { //int A::extracted(int i) {
// ++i; // ++i;
// i += ZWO; // i += TWO;
// help(); // help();
// return i; // return i;
//} //}
@ -698,7 +747,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
// //
//private: //private:
// int help(); // int help();
// void extracted(int* i); // void extracted(int* j);
//}; //};
// //
//#endif /*A_H_*/ //#endif /*A_H_*/
@ -731,8 +780,8 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//A::~A() { //A::~A() {
//} //}
// //
//void A::extracted(int* i) { //void A::extracted(int* j) {
// ++*i; // ++*j;
// help(); // help();
//} //}
// //
@ -745,7 +794,94 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int A::help() { //int A::help() {
// return 42; // return 42;
//} //}
public void testPointer() throws Exception { public void testRenamedParameter() throws Exception {
parameterRename.put("i", "j");
assertRefactoringSuccess();
}
//A.c
//struct A {
// int i;
// int j;
//};
//
//int test() {
// struct A a = { 1, 2 };
// return /*$*/a.i + a.j/*$$*/;
//}
//====================
//struct A {
// int i;
// int j;
//};
//
//int extracted(const struct A* a) {
// return a->i + a->j;
//}
//
//int test() {
// struct A a = { 1, 2 };
// return extracted(&a);
//}
public void testInputParameterPassedByPointer() throws Exception {
assertRefactoringSuccess();
}
//A.c
//int test() {
// int i = 0;
// int j = 1;
// /*$*/int k = i;
// i = j;
// j = k;/*$$*/
// return i - j;
//}
//====================
//void swap(int* i, int* j) {
// int k = *i;
// *i = *j;
// *j = k;
//}
//
//int test() {
// int i = 0;
// int j = 1;
// swap(&i, &j);
// return i - j;
//}
public void testOutputParameterPassedByPointer() throws Exception {
extractedFunctionName = "swap";
returnValue = NO_RETURN_VALUE;
assertRefactoringSuccess();
}
//A.h
//class A {
//public:
// int method();
// int const_method() const;
//};
//A.cpp
//#include "A.h"
//
//int test() {
// A a, b;
// return /*$*/a.method() + b.const_method()/*$$*/ + a.const_method();
//}
//====================
//#include "A.h"
//
//int extracted(A b, A* a) {
// return a->method() + b.const_method();
//}
//int test() {
// A a, b;
// return extracted(b, &a) + a.const_method();
//}
public void _testOutputParameterWithMethodCall() throws Exception {
// Currently fails due to http://bugs.eclipse.org/bugs/show_bug.cgi?id=370887
getPreferenceStore().setValue(PreferenceConstants.FUNCTION_PASS_OUTPUT_PARAMETERS_BY_POINTER, true);
assertRefactoringSuccess(); assertRefactoringSuccess();
} }
@ -2562,91 +2698,6 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
public void testDuplicates() throws Exception { public void testDuplicates() throws Exception {
assertRefactoringSuccess(); assertRefactoringSuccess();
} }
//A.h
//#ifndef A_H_
//#define A_H_
//
//class A {
//public:
// A();
// virtual ~A();
// int foo();
//
//private:
// int help();
//};
//
//#endif /*A_H_*/
//====================
//#ifndef A_H_
//#define A_H_
//
//class A {
//public:
// A();
// virtual ~A();
// int foo();
//
//private:
// int help();
// int extracted(int i);
//};
//
//#endif /*A_H_*/
//A.cpp
//#include "A.h"
//
//A::A() {
//}
//
//A::~A() {
// int oo = 99;
// ++oo;
// help();
//}
//
//int A::foo() {
// int i = 2;
// /*$*/++i;
// help();/*$$*/
// return i;
//}
//
//int A::help() {
// return 42;
//}
//====================
//#include "A.h"
//
//A::A() {
//}
//
//A::~A() {
// int oo = 99;
// oo = extracted(oo);
//}
//
//int A::extracted(int i) {
// ++i;
// help();
// return i;
//}
//
//int A::foo() {
// int i = 2;
// i = extracted(i);
// return i;
//}
//
//int A::help() {
// return 42;
//}
public void testDuplicatesWithDifferentNames() throws Exception {
assertRefactoringSuccess();
}
//A.h //A.h
//#ifndef A_H_ //#ifndef A_H_
//#define A_H_ //#define A_H_
@ -2930,7 +2981,96 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int A::help() { //int A::help() {
// return 42; // return 42;
//} //}
public void testDuplicatesWithDifferentNamesAndReturnType() throws Exception { public void testDuplicatesWithDifferentNames() throws Exception {
assertRefactoringSuccess();
}
//A.h
//#ifndef A_H_
//#define A_H_
//
//class A {
//public:
// A();
// virtual ~A();
// int foo();
//
//private:
// int help();
//};
//
//#endif /*A_H_*/
//====================
//#ifndef A_H_
//#define A_H_
//
//class A {
//public:
// A();
// virtual ~A();
// int foo();
//
//private:
// int help();
// int extracted(int j, int i);
//};
//
//#endif /*A_H_*/
//A.cpp
//#include "A.h"
//
//A::A() {
//}
//
//A::~A() {
// int aa = 9;
// int bb = 99;
// aa += bb;
// help();
//}
//
//int A::foo() {
// int i = 2;
// int j = 3;
// /*$*/i += j;
// help();/*$$*/
// return i;
//}
//
//int A::help() {
// return 42;
//}
//====================
//#include "A.h"
//
//A::A() {
//}
//
//A::~A() {
// int aa = 9;
// int bb = 99;
// aa = extracted(bb, aa);
//}
//
//int A::extracted(int j, int i) {
// i += j;
// help();
// return i;
//}
//
//int A::foo() {
// int i = 2;
// int j = 3;
// i = extracted(j, i);
// return i;
//}
//
//int A::help() {
// return 42;
//}
public void testDuplicatesWithDifferentNamesAndReordering() throws Exception {
parameterOrder = new int[] { 1, 0 };
assertRefactoringSuccess(); assertRefactoringSuccess();
} }
@ -3105,7 +3245,7 @@ public class ExtractFunctionRefactoringTest extends RefactoringTestBase {
//int A::help() { //int A::help() {
// return 42; // return 42;
//} //}
public void testDuplicateNameUsedAfterwardsInDuplicateButNotInOriginalSelectionThisIsNoDuplicate() throws Exception { public void testOutputParameterInDuplicateButNotInOriginal() throws Exception {
assertRefactoringSuccess(); assertRefactoringSuccess();
} }

View file

@ -21,7 +21,6 @@ import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier; import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle; import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle;
@ -30,6 +29,7 @@ import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.INodeFactory; import org.eclipse.cdt.core.dom.ast.INodeFactory;
import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNodeFactory; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNodeFactory;
import org.eclipse.cdt.core.dom.rewrite.TypeHelper; import org.eclipse.cdt.core.dom.rewrite.TypeHelper;
import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.ITranslationUnit;
@ -40,13 +40,16 @@ import org.eclipse.cdt.internal.core.dom.rewrite.astwriter.ASTWriterVisitor;
* Additional information about an IASTName in code being refactored. * Additional information about an IASTName in code being refactored.
*/ */
public class NameInformation { public class NameInformation {
public static enum Indirection { NONE, POINTER, REFERENCE }
public static final int INDEX_FOR_ADDED = -1; public static final int INDEX_FOR_ADDED = -1;
private final IASTName name; private final IASTName name;
private IASTName declarationName; private IASTName declarationName;
private final List<IASTName> references; private final List<IASTName> references;
private List<IASTName> referencesAfterCached; private final List<IASTName> referencesBeforeSelection;
private int lastCachedReferencesHash; private final List<IASTName> referencesInSelection;
private final List<IASTName> referencesAfterSelection;
private boolean isOutput; private boolean isOutput;
private boolean mustBeReturnValue; private boolean mustBeReturnValue;
private boolean isWriteAccess; private boolean isWriteAccess;
@ -57,11 +60,15 @@ public class NameInformation {
private boolean isDeleted; private boolean isDeleted;
private String defaultValue; private String defaultValue;
private String newTypeName; private String newTypeName;
private Indirection indirection;
public NameInformation(IASTName name) { public NameInformation(IASTName name) {
this.name = name; this.name = name;
this.newName = String.valueOf(name.getSimpleID()); this.newName = String.valueOf(name.getSimpleID());
references = new ArrayList<IASTName>(); references = new ArrayList<IASTName>();
referencesBeforeSelection = new ArrayList<IASTName>();
referencesInSelection = new ArrayList<IASTName>();
referencesAfterSelection = new ArrayList<IASTName>();
} }
public static NameInformation createInfoForAddedParameter(String type, String name, public static NameInformation createInfoForAddedParameter(String type, String name,
@ -99,6 +106,7 @@ public class NameInformation {
void setOutput(boolean isOutput) { void setOutput(boolean isOutput) {
this.isOutput = isOutput; this.isOutput = isOutput;
indirection = null;
} }
public boolean isOutputParameter() { public boolean isOutputParameter() {
@ -111,6 +119,7 @@ public class NameInformation {
public void setMustBeReturnValue(boolean mustBeReturnValue) { public void setMustBeReturnValue(boolean mustBeReturnValue) {
this.mustBeReturnValue = mustBeReturnValue; this.mustBeReturnValue = mustBeReturnValue;
indirection = null;
} }
public boolean isReturnValue() { public boolean isReturnValue() {
@ -120,6 +129,7 @@ public class NameInformation {
public void setReturnValue(boolean isReturnValue) { public void setReturnValue(boolean isReturnValue) {
Assert.isTrue(isReturnValue || !mustBeReturnValue); Assert.isTrue(isReturnValue || !mustBeReturnValue);
this.isReturnValue = isReturnValue; this.isReturnValue = isReturnValue;
indirection = null;
} }
public String getNewName() { public String getNewName() {
@ -136,6 +146,7 @@ public class NameInformation {
void setWriteAccess(boolean isWriteAceess) { void setWriteAccess(boolean isWriteAceess) {
this.isWriteAccess = isWriteAceess; this.isWriteAccess = isWriteAceess;
indirection = null;
} }
public boolean isDeleted() { public boolean isDeleted() {
@ -182,6 +193,7 @@ public class NameInformation {
void setDeclarationName(IASTName declarationName) { void setDeclarationName(IASTName declarationName) {
Assert.isTrue(declarationName.getParent() instanceof IASTDeclarator); Assert.isTrue(declarationName.getParent() instanceof IASTDeclarator);
this.declarationName = declarationName; this.declarationName = declarationName;
indirection = null;
} }
public IASTName getName() { public IASTName getName() {
@ -189,11 +201,19 @@ public class NameInformation {
} }
public boolean isRenamed() { public boolean isRenamed() {
return name == null ? newName != null : String.valueOf(name.getSimpleID()).equals(name); return name == null ? newName != null : !String.valueOf(name.getSimpleID()).equals(newName);
} }
void addReference(IASTName name) { void addReference(IASTName name, int startOffset, int endOffset) {
references.add(name); references.add(name);
int nodeOffset = name.getFileLocation().getNodeOffset();
if (nodeOffset >= endOffset) {
referencesAfterSelection.add(name);
} else if (nodeOffset >= startOffset) {
referencesInSelection.add(name);
} else {
referencesBeforeSelection.add(name);
}
} }
public String getTypeName() { public String getTypeName() {
@ -224,22 +244,20 @@ public class NameInformation {
return writer.toString(); return writer.toString();
} }
public List<IASTName> getReferencesAfterSelection(int endOffset) { public List<IASTName> getReferencesBeforeSelection() {
if (referencesAfterCached == null || lastCachedReferencesHash != references.hashCode()) { return referencesBeforeSelection;
lastCachedReferencesHash = references.hashCode();
referencesAfterCached = new ArrayList<IASTName>();
for (IASTName ref : references) {
IASTFileLocation loc = ref.getFileLocation();
if (loc.getNodeOffset() >= endOffset) {
referencesAfterCached.add(ref);
}
}
}
return referencesAfterCached;
} }
public boolean isReferencedAfterSelection(int endOffset) { public List<IASTName> getReferencesInSelection() {
return !getReferencesAfterSelection(endOffset).isEmpty(); return referencesInSelection;
}
public List<IASTName> getReferencesAfterSelection() {
return referencesAfterSelection;
}
public boolean isReferencedAfterSelection() {
return !referencesAfterSelection.isEmpty();
} }
public IASTParameterDeclaration getParameterDeclaration(INodeFactory nodeFactory) { public IASTParameterDeclaration getParameterDeclaration(INodeFactory nodeFactory) {
@ -251,29 +269,47 @@ public class NameInformation {
IASTDeclSpecifier declSpec = safeCopy(getDeclSpecifier()); IASTDeclSpecifier declSpec = safeCopy(getDeclSpecifier());
IASTDeclarator declarator = createDeclarator(nodeFactory, sourceDeclarator, paramName); IASTDeclarator declarator = createDeclarator(nodeFactory, sourceDeclarator, paramName);
if (isOutputParameter()) { Indirection indirection = getIndirection();
if (nodeFactory instanceof ICPPNodeFactory && !passOutputByPointer) { if (indirection == Indirection.POINTER) {
declarator.addPointerOperator(((ICPPNodeFactory) nodeFactory).newReferenceOperator(false));
} else {
declarator.addPointerOperator(nodeFactory.newPointer()); declarator.addPointerOperator(nodeFactory.newPointer());
} } else if (indirection == Indirection.REFERENCE) {
} else if (declSpec != null && !isWriteAccess) {
IType type = TypeHelper.createType(sourceDeclarator);
if (TypeHelper.shouldBePassedByReference(type, declarationName.getTranslationUnit())) {
if (nodeFactory instanceof ICPPNodeFactory) {
declarator.addPointerOperator(((ICPPNodeFactory) nodeFactory).newReferenceOperator(false)); declarator.addPointerOperator(((ICPPNodeFactory) nodeFactory).newReferenceOperator(false));
} else {
declarator.addPointerOperator(nodeFactory.newPointer());
} }
if (indirection != Indirection.NONE && !isWriteAccess && declSpec != null) {
declSpec.setConst(true); declSpec.setConst(true);
} }
}
declarator.setNestedDeclarator(sourceDeclarator.getNestedDeclarator()); declarator.setNestedDeclarator(sourceDeclarator.getNestedDeclarator());
return nodeFactory.newParameterDeclaration(declSpec, declarator); return nodeFactory.newParameterDeclaration(declSpec, declarator);
} }
public Indirection getIndirection() {
if (indirection == null) {
indirection = Indirection.NONE;
boolean isCpp = declarationName.getTranslationUnit() instanceof ICPPASTTranslationUnit;
if (isOutputParameter()) {
if (isCpp && !passOutputByPointer) {
indirection = Indirection.REFERENCE;
} else {
indirection = Indirection.POINTER;
}
} else {
IType type = TypeHelper.createType(getDeclarator());
if (TypeHelper.shouldBePassedByReference(type, declarationName.getTranslationUnit())) {
if (isCpp) {
if (!isWriteAccess) {
indirection = Indirection.REFERENCE;
}
} else {
indirection = Indirection.POINTER;
}
}
}
}
return indirection;
}
private IASTDeclarator createDeclarator(INodeFactory nodeFactory, IASTDeclarator sourceDeclarator, private IASTDeclarator createDeclarator(INodeFactory nodeFactory, IASTDeclarator sourceDeclarator,
String name) { String name) {
IASTName astName = name != null ? IASTName astName = name != null ?
@ -311,5 +347,6 @@ public class NameInformation {
public void setPassOutputByPointer(boolean passOutputByPointer) { public void setPassOutputByPointer(boolean passOutputByPointer) {
this.passOutputByPointer = passOutputByPointer; this.passOutputByPointer = passOutputByPointer;
indirection = null;
} }
} }

View file

@ -28,6 +28,7 @@ import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation; import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
@ -73,6 +74,8 @@ public class NodeContainer {
return; return;
} }
names = new ArrayList<NameInformation>(); names = new ArrayList<NameInformation>();
final int startOffset = getStartOffset();
final int endOffset = getEndOffset();
IPreferencesService preferences = Platform.getPreferencesService(); IPreferencesService preferences = Platform.getPreferencesService();
final boolean passOutputByPointer = preferences.getBoolean(CUIPlugin.PLUGIN_ID, final boolean passOutputByPointer = preferences.getBoolean(CUIPlugin.PLUGIN_ID,
@ -87,6 +90,7 @@ public class NodeContainer {
@Override @Override
public int visit(IASTName name) { public int visit(IASTName name) {
if (name.getPropertyInParent() != IASTFieldReference.FIELD_NAME) {
IBinding binding = name.resolveBinding(); IBinding binding = name.resolveBinding();
if (binding instanceof ICPPBinding && !(binding instanceof ICPPTemplateTypeParameter)) { if (binding instanceof ICPPBinding && !(binding instanceof ICPPTemplateTypeParameter)) {
@ -97,14 +101,14 @@ public class NodeContainer {
nameInfo.setPassOutputByPointer(passOutputByPointer); nameInfo.setPassOutputByPointer(passOutputByPointer);
IASTName[] refs = name.getTranslationUnit().getReferences(binding); IASTName[] refs = name.getTranslationUnit().getReferences(binding);
for (IASTName ref : refs) { for (IASTName ref : refs) {
nameInfo.addReference(ref); nameInfo.addReference(ref, startOffset, endOffset);
} }
names.add(nameInfo); names.add(nameInfo);
} }
} catch (DOMException e) { } catch (DOMException e) {
ILog logger = CUIPlugin.getDefault().getLog(); ILog logger = CUIPlugin.getDefault().getLog();
IStatus status = new Status(IStatus.WARNING, IStatus status = new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID,
CUIPlugin.PLUGIN_ID, IStatus.OK, e.getMessage(), e); e.getMessage(), e);
logger.log(status); logger.log(status);
} }
} else if (binding instanceof IVariable) { } else if (binding instanceof IVariable) {
@ -112,10 +116,11 @@ public class NodeContainer {
IASTName[] refs = name.getTranslationUnit().getReferences(binding); IASTName[] refs = name.getTranslationUnit().getReferences(binding);
for (IASTName ref : refs) { for (IASTName ref : refs) {
nameInformation.addReference(ref); nameInformation.addReference(ref, startOffset, endOffset);
} }
names.add(nameInformation); names.add(nameInformation);
} }
}
return super.visit(name); return super.visit(name);
} }
}); });
@ -152,12 +157,11 @@ public class NodeContainer {
Set<IASTName> declarations = new HashSet<IASTName>(); Set<IASTName> declarations = new HashSet<IASTName>();
interfaceNames = new ArrayList<NameInformation>(); interfaceNames = new ArrayList<NameInformation>();
int endOffset = getEndOffset();
for (NameInformation nameInfo : names) { for (NameInformation nameInfo : names) {
IASTName declarationName = nameInfo.getDeclarationName(); IASTName declarationName = nameInfo.getDeclarationName();
if (declarations.add(declarationName)) { if (declarations.add(declarationName)) {
if (isDeclaredInSelection(nameInfo)) { if (isDeclaredInSelection(nameInfo)) {
if (nameInfo.isReferencedAfterSelection(endOffset)) { if (nameInfo.isReferencedAfterSelection()) {
nameInfo.setMustBeReturnValue(true); nameInfo.setMustBeReturnValue(true);
interfaceNames.add(nameInfo); interfaceNames.add(nameInfo);
} }
@ -173,7 +177,7 @@ public class NodeContainer {
} }
} }
} }
if (nameInfo.isWriteAccess() && nameInfo.isReferencedAfterSelection(endOffset)) { if (nameInfo.isWriteAccess() && nameInfo.isReferencedAfterSelection()) {
nameInfo.setOutput(true); nameInfo.setOutput(true);
} }
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2008, 2011 Institute for Software, HSR Hochschule fuer Technik * Copyright (c) 2008, 2012 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences and others * Rapperswil, University of applied sciences and others
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
@ -8,11 +8,13 @@
* *
* Contributors: * Contributors:
* Institute for Software - initial API and implementation * Institute for Software - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.extractfunction; package org.eclipse.cdt.internal.ui.refactoring.extractfunction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import org.eclipse.text.edits.TextEditGroup; import org.eclipse.text.edits.TextEditGroup;
@ -24,7 +26,6 @@ import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle; import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle;
@ -44,7 +45,6 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTBinaryExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionDefinition; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionDefinition;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReturnStatement; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReturnStatement;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclSpecifier; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclaration; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclaration;
@ -58,30 +58,27 @@ import org.eclipse.cdt.internal.ui.refactoring.NameInformation;
* @author Mirko Stocker * @author Mirko Stocker
*/ */
public class ExtractExpression extends ExtractedFunctionConstructionHelper { public class ExtractExpression extends ExtractedFunctionConstructionHelper {
private final static char[] ZERO= { '0' };
@Override @Override
public void constructMethodBody(IASTCompoundStatement compound, List<IASTNode> list, public void constructMethodBody(IASTCompoundStatement compound, List<IASTNode> nodes,
ASTRewrite rewrite, TextEditGroup group) { List<NameInformation> parameters, ASTRewrite rewrite, TextEditGroup group) {
CPPASTReturnStatement statement = new CPPASTReturnStatement(); CPPASTReturnStatement statement = new CPPASTReturnStatement();
IASTExpression nullReturnExp = statement.setReturnValue(getExpression(nodes));
new CPPASTLiteralExpression(IASTLiteralExpression.lk_integer_constant, ZERO); ASTRewrite subRewrite = rewrite.insertBefore(compound, null, statement, group);
statement.setReturnValue(nullReturnExp); Map<IASTName, NameInformation> changedParameters = getChangedParameterReferences(parameters);
ASTRewrite nestedRewrite = rewrite.insertBefore(compound, null, statement, group); INodeFactory nodeFactory = nodes.get(0).getTranslationUnit().getASTNodeFactory();
adjustParameterReferences(statement, changedParameters, nodeFactory, subRewrite, group);
nestedRewrite.replace(nullReturnExp, getExpression(list), group);
} }
private IASTExpression getExpression(List<IASTNode> list) { private IASTExpression getExpression(List<IASTNode> nodes) {
if (list.size() > 1) { if (nodes.size() > 1) {
CPPASTBinaryExpression expression = new CPPASTBinaryExpression(); CPPASTBinaryExpression expression = new CPPASTBinaryExpression();
expression.setParent(list.get(0).getParent()); expression.setParent(nodes.get(0).getParent());
expression.setOperand1((IASTExpression) list.get(0).copy(CopyStyle.withLocations)); expression.setOperand1((IASTExpression) nodes.get(0).copy(CopyStyle.withLocations));
expression.setOperator(((IASTBinaryExpression) list.get(1).getParent()).getOperator()); expression.setOperator(((IASTBinaryExpression) nodes.get(1).getParent()).getOperator());
expression.setOperand2(getExpression(list.subList(1, list.size()))); expression.setOperand2(getExpression(nodes.subList(1, nodes.size())));
return expression; return expression;
} else { } else {
return (IASTExpression) list.get(0).copy(CopyStyle.withLocations); return (IASTExpression) nodes.get(0).copy(CopyStyle.withLocations);
} }
} }

View file

@ -61,6 +61,7 @@ import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IField; import org.eclipse.cdt.core.dom.ast.IField;
@ -101,7 +102,6 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTQualifiedName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReturnStatement; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReturnStatement;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclaration; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTemplateDeclaration; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTemplateDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNodeFactory;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
import org.eclipse.cdt.internal.core.dom.rewrite.astwriter.ASTWriterVisitor; import org.eclipse.cdt.internal.core.dom.rewrite.astwriter.ASTWriterVisitor;
@ -113,6 +113,7 @@ import org.eclipse.cdt.internal.ui.refactoring.MethodContext;
import org.eclipse.cdt.internal.ui.refactoring.MethodContext.ContextType; import org.eclipse.cdt.internal.ui.refactoring.MethodContext.ContextType;
import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector; import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector;
import org.eclipse.cdt.internal.ui.refactoring.NameInformation; import org.eclipse.cdt.internal.ui.refactoring.NameInformation;
import org.eclipse.cdt.internal.ui.refactoring.NameInformation.Indirection;
import org.eclipse.cdt.internal.ui.refactoring.NodeContainer; import org.eclipse.cdt.internal.ui.refactoring.NodeContainer;
import org.eclipse.cdt.internal.ui.refactoring.utils.ASTHelper; import org.eclipse.cdt.internal.ui.refactoring.utils.ASTHelper;
import org.eclipse.cdt.internal.ui.refactoring.utils.CPPASTAllVisitor; import org.eclipse.cdt.internal.ui.refactoring.utils.CPPASTAllVisitor;
@ -138,8 +139,8 @@ public class ExtractFunctionRefactoring extends CRefactoring {
HashMap<String, Integer> nameTrail; HashMap<String, Integer> nameTrail;
private ExtractedFunctionConstructionHelper extractedFunctionConstructionHelper; private ExtractedFunctionConstructionHelper functionConstructionHelper;
private final INodeFactory nodeFactory = CPPNodeFactory.getDefault(); private INodeFactory nodeFactory;
DefaultCodeFormatterOptions formattingOptions; DefaultCodeFormatterOptions formattingOptions;
public ExtractFunctionRefactoring(IFile file, ISelection selection, public ExtractFunctionRefactoring(IFile file, ISelection selection,
@ -167,6 +168,7 @@ public class ExtractFunctionRefactoring extends CRefactoring {
return status; return status;
} }
nodeFactory = ast.getASTNodeFactory();
container = findExtractableNodes(); container = findExtractableNodes();
sm.worked(1); sm.worked(1);
@ -212,7 +214,7 @@ public class ExtractFunctionRefactoring extends CRefactoring {
PreferenceConstants.getPreferenceScopes(project.getProject())); PreferenceConstants.getPreferenceScopes(project.getProject()));
info.sortParameters(outFirst); info.sortParameters(outFirst);
extractedFunctionConstructionHelper = functionConstructionHelper =
ExtractedFunctionConstructionHelper.createFor(container.getNodesToWrite()); ExtractedFunctionConstructionHelper.createFor(container.getNodesToWrite());
boolean isExtractExpression = container.getNodesToWrite().get(0) instanceof IASTExpression; boolean isExtractExpression = container.getNodesToWrite().get(0) instanceof IASTExpression;
@ -354,7 +356,7 @@ public class ExtractFunctionRefactoring extends CRefactoring {
} }
} }
private void createMethodCalls(final IASTName astMethodName, MethodContext context, private void createMethodCalls(IASTName methodName, MethodContext context,
ModificationCollector collector) throws CoreException { ModificationCollector collector) throws CoreException {
String title; String title;
if (context.getType() == MethodContext.ContextType.METHOD) { if (context.getType() == MethodContext.ContextType.METHOD) {
@ -363,7 +365,7 @@ public class ExtractFunctionRefactoring extends CRefactoring {
title = Messages.ExtractFunctionRefactoring_CreateFunctionCall; title = Messages.ExtractFunctionRefactoring_CreateFunctionCall;
} }
IASTNode methodCall = getMethodCall(astMethodName); IASTNode methodCall = getMethodCall(methodName);
IASTNode firstNodeToWrite = container.getNodesToWrite().get(0); IASTNode firstNodeToWrite = container.getNodesToWrite().get(0);
ASTRewrite rewriter = collector.rewriterForTranslationUnit( ASTRewrite rewriter = collector.rewriterForTranslationUnit(
@ -377,7 +379,7 @@ public class ExtractFunctionRefactoring extends CRefactoring {
insertCallIntoTree(methodCall, container.getNodesToWrite(), rewriter, editGroup); insertCallIntoTree(methodCall, container.getNodesToWrite(), rewriter, editGroup);
if (info.isReplaceDuplicates()) { if (info.isReplaceDuplicates()) {
replaceSimilar(collector, astMethodName); replaceSimilar(collector, methodName);
} }
for (IASTNode node : container.getNodesToWrite()) { for (IASTNode node : container.getNodesToWrite()) {
@ -415,7 +417,7 @@ public class ExtractFunctionRefactoring extends CRefactoring {
return binExp; return binExp;
} }
private void createMethodDefinition(final IASTName astMethodName, MethodContext context, private void createMethodDefinition(final IASTName methodName, MethodContext context,
IASTNode firstNode, ModificationCollector collector) { IASTNode firstNode, ModificationCollector collector) {
IASTFunctionDefinition node = NodeHelper.findFunctionDefinitionInAncestors(firstNode); IASTFunctionDefinition node = NodeHelper.findFunctionDefinitionInAncestors(firstNode);
if (node != null) { if (node != null) {
@ -427,7 +429,7 @@ public class ExtractFunctionRefactoring extends CRefactoring {
} }
ASTRewrite rewriter = collector.rewriterForTranslationUnit(node.getTranslationUnit()); ASTRewrite rewriter = collector.rewriterForTranslationUnit(node.getTranslationUnit());
addMethod(astMethodName, context, rewriter, node, new TextEditGroup(title)); addMethod(methodName, context, rewriter, node, new TextEditGroup(title));
} }
} }
@ -618,17 +620,17 @@ public class ExtractFunctionRefactoring extends CRefactoring {
return true; return true;
} }
private void addMethod(IASTName astMethodName, MethodContext context, ASTRewrite rewriter, private void addMethod(IASTName methodName, MethodContext context, ASTRewrite rewrite,
IASTNode insertPoint, TextEditGroup group) { IASTNode insertPoint, TextEditGroup group) {
ICPPASTQualifiedName qname = new CPPASTQualifiedName(); ICPPASTQualifiedName qname = new CPPASTQualifiedName();
if (context.getType() == ContextType.METHOD) { if (context.getType() == ContextType.METHOD) {
if (context.getMethodQName() != null) { if (context.getMethodQName() != null) {
for (int i = 0; i < (context.getMethodQName().getNames().length - 1); i++) { for (int i = 0; i < context.getMethodQName().getNames().length - 1; i++) {
qname.addName(new CPPASTName(context.getMethodQName().getNames()[i].toCharArray())); qname.addName(new CPPASTName(context.getMethodQName().getNames()[i].toCharArray()));
} }
} }
} }
qname.addName(astMethodName); qname.addName(methodName);
IASTFunctionDefinition func = new CPPASTFunctionDefinition(); IASTFunctionDefinition func = new CPPASTFunctionDefinition();
func.setParent(ast); func.setParent(ast);
@ -637,32 +639,33 @@ public class ExtractFunctionRefactoring extends CRefactoring {
func.setDeclSpecifier(returnType); func.setDeclSpecifier(returnType);
IASTStandardFunctionDeclarator createdFunctionDeclarator = IASTStandardFunctionDeclarator createdFunctionDeclarator =
extractedFunctionConstructionHelper.createFunctionDeclarator(qname, functionConstructionHelper.createFunctionDeclarator(qname,
info.getDeclarator(), info.getReturnVariable(), container.getNodesToWrite(), info.getDeclarator(), info.getReturnVariable(), container.getNodesToWrite(),
info.getParameters(), ast.getASTNodeFactory()); info.getParameters(), nodeFactory);
func.setDeclarator(createdFunctionDeclarator); func.setDeclarator(createdFunctionDeclarator);
IASTCompoundStatement compound = new CPPASTCompoundStatement(); IASTCompoundStatement compound = new CPPASTCompoundStatement();
func.setBody(compound); func.setBody(compound);
ASTRewrite subRW; ASTRewrite subRewrite;
if (insertPoint.getParent() instanceof ICPPASTTemplateDeclaration) { IASTNode parent = insertPoint.getParent();
if (parent instanceof ICPPASTTemplateDeclaration) {
ICPPASTTemplateDeclaration parentTemplate = (ICPPASTTemplateDeclaration) parent;
CPPASTTemplateDeclaration templateDeclaration = new CPPASTTemplateDeclaration(); CPPASTTemplateDeclaration templateDeclaration = new CPPASTTemplateDeclaration();
templateDeclaration.setParent(ast); templateDeclaration.setParent(ast);
for (ICPPASTTemplateParameter param : ((ICPPASTTemplateDeclaration) insertPoint.getParent()).getTemplateParameters()) { for (ICPPASTTemplateParameter param : parentTemplate.getTemplateParameters()) {
templateDeclaration.addTemplateParameter(param.copy(CopyStyle.withLocations)); templateDeclaration.addTemplateParameter(param.copy(CopyStyle.withLocations));
} }
templateDeclaration.setDeclaration(func); templateDeclaration.setDeclaration(func);
subRW = rewriter.insertBefore(insertPoint.getParent().getParent(), insertPoint.getParent(), subRewrite = rewrite.insertBefore(parent.getParent(), parent, templateDeclaration, group);
templateDeclaration, group);
} else { } else {
subRW = rewriter.insertBefore(insertPoint.getParent(), insertPoint, func, group); subRewrite = rewrite.insertBefore(parent, insertPoint, func, group);
} }
extractedFunctionConstructionHelper.constructMethodBody(compound, functionConstructionHelper.constructMethodBody(compound, container.getNodesToWrite(),
container.getNodesToWrite(), subRW, group); info.getParameters(), subRewrite, group);
// Set return value // Set return value
NameInformation returnVariable = info.getReturnVariable(); NameInformation returnVariable = info.getReturnVariable();
@ -675,7 +678,7 @@ public class ExtractFunctionRefactoring extends CRefactoring {
expr.setName(new CPPASTName(returnVariable.getNewName().toCharArray())); expr.setName(new CPPASTName(returnVariable.getNewName().toCharArray()));
} }
returnStmt.setReturnValue(expr); returnStmt.setReturnValue(expr);
subRW.insertBefore(compound, null, returnStmt, group); subRewrite.insertBefore(compound, null, returnStmt, group);
} }
} }
@ -686,7 +689,7 @@ public class ExtractFunctionRefactoring extends CRefactoring {
private IASTDeclSpecifier getReturnType() { private IASTDeclSpecifier getReturnType() {
IASTNode firstNodeToWrite = container.getNodesToWrite().get(0); IASTNode firstNodeToWrite = container.getNodesToWrite().get(0);
NameInformation returnVariable = info.getReturnVariable(); NameInformation returnVariable = info.getReturnVariable();
return extractedFunctionConstructionHelper.determineReturnType(firstNodeToWrite, return functionConstructionHelper.determineReturnType(firstNodeToWrite,
returnVariable); returnVariable);
} }
@ -755,28 +758,28 @@ public class ExtractFunctionRefactoring extends CRefactoring {
return getReturnAssignment(stmt, callExpression, retName); return getReturnAssignment(stmt, callExpression, retName);
} }
private IASTNode getMethodCall(IASTName astMethodName) { private IASTNode getMethodCall(IASTName methodName) {
IASTExpressionStatement stmt = new CPPASTExpressionStatement(); IASTExpressionStatement statement = new CPPASTExpressionStatement();
IASTFunctionCallExpression callExpression = new CPPASTFunctionCallExpression(); IASTFunctionCallExpression callExpression = new CPPASTFunctionCallExpression();
IASTIdExpression idExpression = new CPPASTIdExpression(); IASTIdExpression idExpression = new CPPASTIdExpression();
idExpression.setName(new CPPASTName(astMethodName.toCharArray())); idExpression.setName(new CPPASTName(methodName.toCharArray()));
List<IASTInitializerClause> args = getCallParameters(); List<IASTInitializerClause> args = getCallParameters();
callExpression.setArguments(args.toArray(new IASTInitializerClause[args.size()])); callExpression.setArguments(args.toArray(new IASTInitializerClause[args.size()]));
callExpression.setFunctionNameExpression(idExpression); callExpression.setFunctionNameExpression(idExpression);
if (info.getReturnVariable() == null) { if (info.getReturnVariable() == null) {
return getReturnAssignment(stmt, callExpression); return getReturnAssignment(statement, callExpression);
} }
IASTName retname = newName(info.getReturnVariable().getName()); IASTName retName = newName(info.getReturnVariable().getName());
return getReturnAssignment(stmt, callExpression, retname); return getReturnAssignment(statement, callExpression, retName);
} }
private IASTNode getReturnAssignment(IASTExpressionStatement stmt, private IASTNode getReturnAssignment(IASTExpressionStatement stmt,
IASTFunctionCallExpression callExpression, IASTName retname) { IASTFunctionCallExpression callExpression, IASTName retname) {
if (info.getReturnVariable().equals(info.getMandatoryReturnVariable())) { if (info.getReturnVariable().equals(info.getMandatoryReturnVariable())) {
IASTSimpleDeclaration orgDecl = NodeHelper.findSimpleDeclarationInParents(info IASTSimpleDeclaration orgDecl = NodeHelper.findSimpleDeclarationInParents(
.getReturnVariable().getDeclarationName()); info.getReturnVariable().getDeclarationName());
IASTSimpleDeclaration decl = new CPPASTSimpleDeclaration(); IASTSimpleDeclaration decl = new CPPASTSimpleDeclaration();
decl.setDeclSpecifier(orgDecl.getDeclSpecifier().copy(CopyStyle.withLocations)); decl.setDeclSpecifier(orgDecl.getDeclSpecifier().copy(CopyStyle.withLocations));
@ -810,15 +813,15 @@ public class ExtractFunctionRefactoring extends CRefactoring {
private IASTNode getReturnAssignment(IASTExpressionStatement stmt, private IASTNode getReturnAssignment(IASTExpressionStatement stmt,
IASTExpression callExpression) { IASTExpression callExpression) {
IASTNode node = container.getNodesToWrite().get(0); IASTNode node = container.getNodesToWrite().get(0);
return extractedFunctionConstructionHelper.createReturnAssignment(node, stmt, callExpression); return functionConstructionHelper.createReturnAssignment(node, stmt, callExpression);
} }
private IASTSimpleDeclaration getDeclaration(IASTName name) { private IASTSimpleDeclaration getDeclaration(IASTName name) {
IASTSimpleDeclaration simpleDecl = new CPPASTSimpleDeclaration(); IASTSimpleDeclaration simpleDecl = new CPPASTSimpleDeclaration();
IASTStandardFunctionDeclarator declarator = IASTStandardFunctionDeclarator declarator =
extractedFunctionConstructionHelper.createFunctionDeclarator(name, functionConstructionHelper.createFunctionDeclarator(name,
info.getDeclarator(), info.getReturnVariable(), container.getNodesToWrite(), info.getDeclarator(), info.getReturnVariable(), container.getNodesToWrite(),
info.getParameters(), ast.getASTNodeFactory()); info.getParameters(), nodeFactory);
simpleDecl.addDeclarator(declarator); simpleDecl.addDeclarator(declarator);
return simpleDecl; return simpleDecl;
} }
@ -831,9 +834,9 @@ public class ExtractFunctionRefactoring extends CRefactoring {
} }
simpleDecl.setParent(ast); simpleDecl.setParent(ast);
IASTStandardFunctionDeclarator declarator = IASTStandardFunctionDeclarator declarator =
extractedFunctionConstructionHelper.createFunctionDeclarator(name, functionConstructionHelper.createFunctionDeclarator(name,
info.getDeclarator(), info.getReturnVariable(), container.getNodesToWrite(), info.getDeclarator(), info.getReturnVariable(), container.getNodesToWrite(),
info.getParameters(), ast.getASTNodeFactory()); info.getParameters(), nodeFactory);
simpleDecl.addDeclarator(declarator); simpleDecl.addDeclarator(declarator);
return simpleDecl; return simpleDecl;
} }
@ -881,8 +884,10 @@ public class ExtractFunctionRefactoring extends CRefactoring {
if (!container.isDeclaredInSelection(nameInfo)) { if (!container.isDeclaredInSelection(nameInfo)) {
IASTName declaration = nameInfo.getDeclarationName(); IASTName declaration = nameInfo.getDeclarationName();
if (declarations.add(declaration)) { if (declarations.add(declaration)) {
IASTIdExpression expression = new CPPASTIdExpression(); IASTExpression expression = nodeFactory.newIdExpression(newName(declaration));
expression.setName(newName(declaration)); if (nameInfo.getIndirection() == Indirection.POINTER) {
expression = nodeFactory.newUnaryExpression(IASTUnaryExpression.op_amper, expression);
}
args.add(expression); args.add(expression);
} }
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2008 Institute for Software, HSR Hochschule fuer Technik * Copyright (c) 2008, 2012 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences and others * Rapperswil, University of applied sciences and others
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
@ -8,10 +8,12 @@
* *
* Contributors: * Contributors:
* Institute for Software - initial API and implementation * Institute for Software - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.extractfunction; package org.eclipse.cdt.internal.ui.refactoring.extractfunction;
import java.util.List; import java.util.List;
import java.util.Map;
import org.eclipse.text.edits.TextEditGroup; import org.eclipse.text.edits.TextEditGroup;
@ -19,9 +21,11 @@ import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle; import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.INodeFactory;
import org.eclipse.cdt.core.dom.rewrite.ASTRewrite; import org.eclipse.cdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclSpecifier; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclSpecifier;
@ -35,9 +39,12 @@ import org.eclipse.cdt.internal.ui.refactoring.utils.ASTHelper;
public class ExtractStatement extends ExtractedFunctionConstructionHelper { public class ExtractStatement extends ExtractedFunctionConstructionHelper {
@Override @Override
public void constructMethodBody(IASTCompoundStatement compound, List<IASTNode> nodes, public void constructMethodBody(IASTCompoundStatement compound, List<IASTNode> nodes,
ASTRewrite rewrite, TextEditGroup group) { List<NameInformation> parameters, ASTRewrite rewrite, TextEditGroup group) {
Map<IASTName, NameInformation> changedParameters = getChangedParameterReferences(parameters);
INodeFactory nodeFactory = nodes.get(0).getTranslationUnit().getASTNodeFactory();
for (IASTNode node : nodes) { for (IASTNode node : nodes) {
rewrite.insertBefore(compound, null, node, group); ASTRewrite subRewrite = rewrite.insertBefore(compound, null, node, group);
adjustParameterReferences(node, changedParameters, nodeFactory, subRewrite, group);
} }
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2008, 2009 Institute for Software, HSR Hochschule fuer Technik * Copyright (c) 2008, 2012 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences and others * Rapperswil, University of applied sciences and others
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
@ -8,31 +8,41 @@
* *
* Contributors: * Contributors:
* Institute for Software - initial API and implementation * Institute for Software - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.extractfunction; package org.eclipse.cdt.internal.ui.refactoring.extractfunction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.eclipse.text.edits.TextEditGroup; import org.eclipse.text.edits.TextEditGroup;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle; import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.INodeFactory; import org.eclipse.cdt.core.dom.ast.INodeFactory;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.rewrite.ASTRewrite; import org.eclipse.cdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.ui.refactoring.NameInformation; import org.eclipse.cdt.internal.ui.refactoring.NameInformation;
import org.eclipse.cdt.internal.ui.refactoring.NameInformation.Indirection;
/** /**
* @author Mirko Stocker * @author Mirko Stocker
@ -46,8 +56,8 @@ public abstract class ExtractedFunctionConstructionHelper {
return new ExtractStatement(); return new ExtractStatement();
} }
public abstract void constructMethodBody(IASTCompoundStatement compound, List<IASTNode> list, public abstract void constructMethodBody(IASTCompoundStatement compound, List<IASTNode> nodes,
ASTRewrite rewrite, TextEditGroup group); List<NameInformation> parameters, ASTRewrite rewrite, TextEditGroup group);
public abstract IASTDeclSpecifier determineReturnType(IASTNode extractedNode, public abstract IASTDeclSpecifier determineReturnType(IASTNode extractedNode,
NameInformation returnVariable); NameInformation returnVariable);
@ -99,4 +109,83 @@ public abstract class ExtractedFunctionConstructionHelper {
} }
return result; return result;
} }
/**
* Adjusts parameter references under the given node to account for renamed parameters and
* parameters passed by pointer.
*
* @param node the root node of the AST subtree to be adjusted
* @param changedParameters the map from references to changed parameters to parameters
* themselves
* @param rewrite the rewrite for the node
* @param group the edit group to add the changes to
*/
protected static void adjustParameterReferences(IASTNode node,
final Map<IASTName, NameInformation> changedParameters, final INodeFactory nodeFactory,
final ASTRewrite rewrite, final TextEditGroup group) {
if (changedParameters.isEmpty())
return;
node.accept(new ASTVisitor() {
{
shouldVisitNames = true;
}
@Override
public int visit(IASTName name) {
NameInformation param = changedParameters.get(((ASTNode) name).getOriginalNode());
if (param != null) {
IASTName newName = null;
if (param.isRenamed()) {
newName = nodeFactory.newName(param.getNewName().toCharArray());
}
if (param.getIndirection() == Indirection.POINTER &&
name.getPropertyInParent() == IASTIdExpression.ID_NAME) {
IASTIdExpression idExp = (IASTIdExpression) name.getParent();
if (idExp.getPropertyInParent() == IASTFieldReference.FIELD_OWNER &&
!((IASTFieldReference) idExp.getParent()).isPointerDereference()) {
IASTFieldReference dotRef = (IASTFieldReference) idExp.getParent();
IASTFieldReference arrowRef = dotRef.copy(CopyStyle.withLocations);
arrowRef.setIsPointerDereference(true);
if (newName != null) {
idExp = (IASTIdExpression) arrowRef.getFieldOwner();
idExp.setName(newName);
}
rewrite.replace(dotRef, arrowRef, group);
} else {
IASTIdExpression newIdExp = idExp.copy(CopyStyle.withLocations);
IASTUnaryExpression starExp =
nodeFactory.newUnaryExpression(IASTUnaryExpression.op_star, newIdExp);
if (newName != null) {
newIdExp.setName(newName);
}
rewrite.replace(idExp, starExp, group);
}
} else if (newName != null) {
rewrite.replace(name, newName, group);
}
}
return super.visit(name);
}
});
}
/**
* Returns a map from references to parameters inside the body of the extracted function to
* the parameters themselves. The map includes only the parameters that are either renamed,
* or passed by pointer.
*
* @param parameters the function parameters.
* @return a map from references to parameters to parameters themselves.
*/
protected static Map<IASTName, NameInformation> getChangedParameterReferences(List<NameInformation> parameters) {
final Map<IASTName, NameInformation> referenceLookupMap = new HashMap<IASTName, NameInformation>();
for (NameInformation param : parameters) {
if (param.isRenamed() || param.getIndirection() == Indirection.POINTER) {
for (IASTName name : param.getReferencesInSelection()) {
referenceLookupMap.put(name, param);
}
}
}
return referenceLookupMap;
}
} }