diff --git a/core/org.eclipse.cdt.ui.tests/resources/refactoring/ExtractMethodDuplicates.rts b/core/org.eclipse.cdt.ui.tests/resources/refactoring/ExtractMethodDuplicates.rts new file mode 100644 index 00000000000..a3be46e65ad --- /dev/null +++ b/core/org.eclipse.cdt.ui.tests/resources/refactoring/ExtractMethodDuplicates.rts @@ -0,0 +1,1075 @@ +//!ExtractFunctionRefactoringTest with duplicates +//#org.eclipse.cdt.ui.tests.refactoring.extractfunction.ExtractFunctionRefactoringTest +//@.config +replaceduplicates=true +//@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(); + void exp(int & i); +}; + +#endif /*A_H_*/ + +//@A.cpp +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int i = 2; + ++i; + help(); +}int A::foo() +{ + int i = 2; + /*$*/++i; + help();/*$$*/ + return i; +} + +int A::help() +{ + return 42; +} + +//= +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int i = 2; + exp(i); +}void A::exp(int & i) +{ + ++i; + help(); +} + +int A::foo() +{ + int i = 2; + exp(i); + return i; +} + +int A::help() +{ + return 42; +} + +//!ExtractFunctionRefactoringTest duplicates with different Names +//#org.eclipse.cdt.ui.tests.refactoring.extractfunction.ExtractFunctionRefactoringTest +//@.config +replaceduplicates=true +//@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(); + void exp(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; + exp(oo); +}void A::exp(int & i) +{ + ++i; + help(); +} + +int A::foo() +{ + int i = 2; + exp(i); + return i; +} + +int A::help() +{ + return 42; +} + +//!ExtractFunctionRefactoringTest dublicate with field +//#org.eclipse.cdt.ui.tests.refactoring.extractfunction.ExtractFunctionRefactoringTest +//@.config +replaceduplicates=true +returnvalue=true +//@A.h +#ifndef A_H_ +#define A_H_ + +class A +{ +public: + A(); + virtual ~A(); + void foo(); + int i; + +private: + int help(); +}; + +#endif /*A_H_*/ + +//= +#ifndef A_H_ +#define A_H_ + +class A +{ +public: + A(); + virtual ~A(); + void foo(); + int i; + +private: + int help(); + int exp(int j, int & a); +}; + +#endif /*A_H_*/ + +//@A.cpp +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int j = 0; + i++; + j++; + help(); +}void A::foo() +{ + int j = 0; + int a = 1; + /*$*/j++; + a++; + help();/*$$*/ + a++; + j++; +} + +int A::help() +{ + return 42; +} + +//= +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int j = 0; + i = exp(i, j); +}int A::exp(int j, int & a) +{ + j++; + a++; + help(); + return j; +} + +void A::foo() +{ + int j = 0; + int a = 1; + j = exp(j, a); + a++; + j++; +} + +int A::help() +{ + return 42; +} + +//!ExtractFunctionRefactoringTest dublicate with field in marked scope +//#org.eclipse.cdt.ui.tests.refactoring.extractfunction.ExtractFunctionRefactoringTest +//@.config +replaceduplicates=true +returnvalue=true +//@A.h +#ifndef A_H_ +#define A_H_ + +class A +{ +public: + A(); + virtual ~A(); + void foo(); + int i; + int field; + +private: + int help(); +}; + +#endif /*A_H_*/ + +//= +#ifndef A_H_ +#define A_H_ + +class A +{ +public: + A(); + virtual ~A(); + void foo(); + int i; + int field; + +private: + int help(); + int exp(int j); +}; + +#endif /*A_H_*/ + +//@A.cpp +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int j = 0; + int a = 1; + a++; + j++; + help(); +}void A::foo() +{ + int j = 0; + + /*$*/field++; + j++; + help();/*$$*/ + field++; + j++; +} + +int A::help() +{ + return 42; +} + +//= +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int j = 0; + int a = 1; + a++; + j++; + help(); +}int A::exp(int j) +{ + field++; + j++; + help(); + return j; +} + +void A::foo() +{ + int j = 0; + j = exp(j); + field++; + j++; +} + +int A::help() +{ + return 42; +} + +//!ExtractFunctionRefactoringTest duplicates with different Names and return type +//#org.eclipse.cdt.ui.tests.refactoring.extractfunction.ExtractFunctionRefactoringTest +//@.config +replaceduplicates=true +returnvalue=true +//@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 exp(int i, float & j); +}; + +#endif /*A_H_*/ + +//@A.cpp +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int oo = 99; + float blabla = 0; + ++oo; + blabla += 1; + help(); + blabla += 1; +}int A::foo() +{ + int i = 2; + float j = 8989; + /*$*/++i; + j+=1; + help();/*$$*/ + j++; + return i; +} + +int A::help() +{ + return 42; +} + +//= +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int oo = 99; + float blabla = 0; + oo = exp(oo, blabla); + blabla += 1; +}int A::exp(int i, float & j) +{ + ++i; + j += 1; + help(); + return i; +} + +int A::foo() +{ + int i = 2; + float j = 8989; + i = exp(i, j); + j++; + return i; +} + +int A::help() +{ + return 42; +} + +//!ExtractFunctionRefactoringTest duplicates with a lot of different Names an variable not used afterwards in the duplicate +//#org.eclipse.cdt.ui.tests.refactoring.extractfunction.ExtractFunctionRefactoringTest +//@.config +replaceduplicates=true +//@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(); + void exp(int & i, float j); +}; + +#endif /*A_H_*/ + +//@A.cpp +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int oo = 99; + float blabla = 0; + ++oo; + blabla += 1; + help(); +}int A::foo() +{ + int i = 2; + float j = 8989; + /*$*/++i; + j+=1; + help();/*$$*/ + return i; +} + +int A::help() +{ + return 42; +} + +//= +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int oo = 99; + float blabla = 0; + exp(oo, blabla); +}void A::exp(int & i, float j) +{ + ++i; + j += 1; + help(); +} + +int A::foo() +{ + int i = 2; + float j = 8989; + exp(i, j); + return i; +} + +int A::help() +{ + return 42; +} + +//!ExtractFunctionRefactoringTest with duplicates name used afterwards in duplicate but not in original selection this is no dublicate +//#org.eclipse.cdt.ui.tests.refactoring.extractfunction.ExtractFunctionRefactoringTest +//@.config +replaceduplicates=true +//@A.h +#ifndef A_H_ +#define A_H_ + +class A +{ +public: + A(); + virtual ~A(); + void foo(); + +private: + int help(); +}; + +#endif /*A_H_*/ + +//= +#ifndef A_H_ +#define A_H_ + +class A +{ +public: + A(); + virtual ~A(); + void foo(); + +private: + int help(); + void exp(int i); +}; + +#endif /*A_H_*/ + +//@A.cpp +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int i = 2; + ++i;// No Duplicate + help(); + ++i;// this is the reason +}void A::foo() +{ + int i = 2; + /*$*/++i; + help();/*$$*/ +} + +int A::help() +{ + return 42; +} + +//= +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int i = 2; + ++i;// No Duplicate + help(); + ++i;// this is the reason +}void A::exp(int i) +{ + ++i; + help(); +} + +void A::foo() +{ + int i = 2; + exp(i); +} + +int A::help() +{ + return 42; +} + +//!ExtractFunctionRefactoringTest with Return Value and a lot Ref Parameter and a method call +//#org.eclipse.cdt.ui.tests.refactoring.extractfunction.ExtractFunctionRefactoringTest +//@.config +replaceduplicates=true +returnvalue=true +//@A.h +#ifndef A_H_ +#define A_H_ + +#include "B.h" + +class A +{ +public: + A(); + virtual ~A(); + int foo(); + +private: + int help(); +}; + +#endif /*A_H_*/ + +//= +#ifndef A_H_ +#define A_H_ + +#include "B.h" + +class A +{ +public: + A(); + virtual ~A(); + int foo(); + +private: + int help(); + int exp(int i, B *& b, int & y, float & x); +}; + +#endif /*A_H_*/ + +//@A.cpp +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int i = 2; + float x = i; + B* b = new B(); + int y = x + i; + ++i; + b->hello(y); + i = i + x; + help(); + b->hello(y); + ++x; + i++; +}int A::foo() +{ + int i = 2; + float x = i; + B* b = new B(); + int y = x + i; + /*$*/++i; + b->hello(y); + i = i + x; + help();/*$$*/ + b->hello(y); + ++x; + return i; +} + +int A::help() +{ + return 42; +} + +//= +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int i = 2; + float x = i; + B* b = new B(); + int y = x + i; + i = exp(i, b, y, x); + b->hello(y); + ++x; + i++; +}int A::exp(int i, B *& b, int & y, float & x) +{ + ++i; + b->hello(y); + i = i + x; + help(); + return i; +} + +int A::foo() +{ + int i = 2; + float x = i; + B* b = new B(); + int y = x + i; + i = exp(i, b, y, x); + b->hello(y); + ++x; + return i; +} + +int A::help() +{ + return 42; +} + +//@B.h +#ifndef B_H_ +#define B_H_ + +class B +{ +public: + B(); + virtual ~B(); + void hello(float y); +}; + +#endif /*B_H_*/ + +//!ExtractFunctionRefactoringTest with Return Value and a lot Ref Parameter and a method call, duplicate is not similar +//#org.eclipse.cdt.ui.tests.refactoring.extractfunction.ExtractFunctionRefactoringTest +//@.config +replaceduplicates=true +returnvalue=true +//@A.h +#ifndef A_H_ +#define A_H_ + +#include "B.h" + +class A +{ +public: + A(); + virtual ~A(); + int foo(); + +private: + int help(); +}; + +#endif /*A_H_*/ + +//= +#ifndef A_H_ +#define A_H_ + +#include "B.h" + +class A +{ +public: + A(); + virtual ~A(); + int foo(); + +private: + int help(); + int exp(int i, B *& b, int & y, float x); +}; + +#endif /*A_H_*/ + +//@A.cpp +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int i = 2; + float x = i; + B* b = new B(); + int y = x + i; + ++i; + b->hello(y); + i = i + x; + help(); + b->hello(y); + ++x; + i++; +}int A::foo() +{ + int i = 2; + float x = i; + B* b = new B(); + int y = x + i; + /*$*/++i; + b->hello(y); + i = i + x; + help();/*$$*/ + b->hello(y); + return i; +} + +int A::help() +{ + return 42; +} + +//= +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int i = 2; + float x = i; + B* b = new B(); + int y = x + i; + ++i; + b->hello(y); + i = i + x; + help(); + b->hello(y); + ++x; + i++; +}int A::exp(int i, B *& b, int & y, float x) +{ + ++i; + b->hello(y); + i = i + x; + help(); + return i; +} + +int A::foo() +{ + int i = 2; + float x = i; + B* b = new B(); + int y = x + i; + i = exp(i, b, y, x); + b->hello(y); + return i; +} + +int A::help() +{ + return 42; +} + +//@B.h +#ifndef B_H_ +#define B_H_ + +class B +{ +public: + B(); + virtual ~B(); + void hello(float y); +}; + +#endif /*B_H_*/ + +//!ExtractFunctionRefactoringTest with duplicates and comments +//#org.eclipse.cdt.ui.tests.refactoring.extractfunction.ExtractFunctionRefactoringTest +//@.config +replaceduplicates=true +//@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(); + void exp(int & i); +}; + +#endif /*A_H_*/ + +//@A.cpp +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int i = 2; + ++i; + help(); +}int A::foo() +{ + int i = 2; + /*$*/++i; + help();/*$$*/ + return i; +} + +int A::help() +{ + return 42; +} + +//= +#include "A.h" + +A::A() +{ +} + +A::~A() +{ + int i = 2; + exp(i); +}void A::exp(int & i) +{ + ++i; + help(); +} + +int A::foo() +{ + int i = 2; + exp(i); + return i; +} + +int A::help() +{ + return 42; +} + diff --git a/core/org.eclipse.cdt.ui.tests/resources/refactoring/ExtractMethodHistory.rts b/core/org.eclipse.cdt.ui.tests/resources/refactoring/ExtractMethodHistory.rts index d359fd5bcc4..218bbba9ccc 100644 --- a/core/org.eclipse.cdt.ui.tests/resources/refactoring/ExtractMethodHistory.rts +++ b/core/org.eclipse.cdt.ui.tests/resources/refactoring/ExtractMethodHistory.rts @@ -261,3 +261,102 @@ int main(){ flags="4" id="org.eclipse.cdt.internal.ui.refactoring.extractfunction.ExtractFunctionRefactoring" name="exp" project="RegressionTestProject" selection="23,5" visibility="private"/> + +//!ExtractFunctionRefactoringTest duplicates with different Names History Test +//#org.eclipse.cdt.ui.tests.refactoring.RefactoringHistoryTest +//@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(); + void exp(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; + exp(oo); +}void A::exp(int & i) +{ + ++i; + help(); +} + +int A::foo() +{ + int i = 2; + exp(i); + return i; +} + +int A::help() +{ + return 42; +} + +//@refScript.xml + + + + diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionTestSuite.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionTestSuite.java index 816fe41c6d6..562ff556e9a 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionTestSuite.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/extractfunction/ExtractFunctionTestSuite.java @@ -30,6 +30,7 @@ public class ExtractFunctionTestSuite extends TestSuite { suite.addTest(RefactoringTester.suite("ExtractMethodPreprocessorRefactoringTests", "resources/refactoring/ExtractMethodPreprocessor.rts")); suite.addTest(RefactoringTester.suite("Extract Function Templates Tests", "resources/refactoring/ExtractFunctionTemplates.rts")); suite.addTest(RefactoringTester.suite("Extract Method History Test", "resources/refactoring/ExtractMethodHistory.rts")); + suite.addTest(RefactoringTester.suite("Extract Function Dublicates Test", "resources/refactoring/ExtractMethodDuplicates.rts")); return suite; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionComposite.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionComposite.java index e77f5a6100d..9a69a5f1d24 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionComposite.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionComposite.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 Institute for Software, HSR Hochschule fuer Technik + * Copyright (c) 2008, 2009 Institute for Software, HSR Hochschule fuer Technik * Rapperswil, University of applied sciences and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -40,15 +40,13 @@ public class ExtractFunctionComposite extends Composite { Group returnGroup = createReturnGroup(nameVisiComp); createReturnValueChooser(returnGroup, info, ip); - // Disabled for now - //createReplaceCheckBox(nameVisiComp); + createReplaceCheckBox(nameVisiComp); if (info.getMethodContext().getType() == MethodContext.ContextType.METHOD) { visibilityPanelSetVisible(true); }else { visibilityPanelSetVisible(false); } - layout(); } @@ -106,13 +104,13 @@ public class ExtractFunctionComposite extends Composite { } -// private void createReplaceCheckBox(Composite parent) { -// replaceSimilar = new Button(parent, SWT.CHECK | SWT.LEFT); -// GridData buttonLayoutData = new GridData(SWT.None); -// buttonLayoutData.verticalIndent = 5; -// replaceSimilar.setLayoutData(buttonLayoutData); -// replaceSimilar.setText(Messages.ExtractFunctionComposite_ReplaceDuplicates); -// } + private void createReplaceCheckBox(Composite parent) { + replaceSimilar = new Button(parent, SWT.CHECK | SWT.LEFT); + GridData buttonLayoutData = new GridData(SWT.None); + buttonLayoutData.verticalIndent = 5; + replaceSimilar.setLayoutData(buttonLayoutData); + replaceSimilar.setText(Messages.ExtractFunctionComposite_ReplaceDuplicates); + } public ChooserComposite getReturnChooser() { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionInputPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionInputPage.java index d0dc6da41d9..c877b466e11 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionInputPage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionInputPage.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2008 Institute for Software, HSR Hochschule fuer Technik + * Copyright (c) 2008, 2009 Institute for Software, HSR Hochschule fuer Technik * Rapperswil, University of applied sciences and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -17,6 +17,8 @@ import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; @@ -65,9 +67,7 @@ public class ExtractFunctionInputPage extends UserInputWizardPage { }); } - /* Disable until it works again. - * - * comp.getReplaceSimilarButton().addSelectionListener(new SelectionListener(){ + comp.getReplaceSimilarButton().addSelectionListener(new SelectionListener(){ public void widgetDefaultSelected(SelectionEvent e) { info.setReplaceDuplicates(comp.getReplaceSimilarButton().isEnabled()); @@ -77,7 +77,7 @@ public class ExtractFunctionInputPage extends UserInputWizardPage { widgetDefaultSelected(e); } - });*/ + }); setControl(comp); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionRefactoring.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionRefactoring.java index 8f14212aee0..beed263a8fe 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionRefactoring.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionRefactoring.java @@ -13,6 +13,7 @@ package org.eclipse.cdt.internal.ui.refactoring.extractfunction; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Vector; @@ -36,6 +37,7 @@ import org.eclipse.text.edits.TextEditGroup; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; +import org.eclipse.cdt.core.dom.ast.IASTComment; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; @@ -49,6 +51,7 @@ import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTInitializerExpression; import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; @@ -63,11 +66,15 @@ import org.eclipse.cdt.core.dom.ast.INodeFactory; import org.eclipse.cdt.core.dom.ast.IParameter; import org.eclipse.cdt.core.dom.ast.cpp.CPPASTVisitor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTOperatorName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.rewrite.ASTRewrite; @@ -105,6 +112,7 @@ import org.eclipse.cdt.internal.ui.refactoring.NodeContainer; import org.eclipse.cdt.internal.ui.refactoring.MethodContext.ContextType; import org.eclipse.cdt.internal.ui.refactoring.NodeContainer.NameInformation; 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.NodeHelper; import org.eclipse.cdt.internal.ui.refactoring.utils.SelectionHelper; @@ -129,7 +137,7 @@ public class ExtractFunctionRefactoring extends CRefactoring { HashMap nameTrail; private ExtractedFunctionConstructionHelper extractedFunctionConstructionHelper; - private INodeFactory factory = CPPNodeFactory.getDefault(); + private final INodeFactory factory = CPPNodeFactory.getDefault(); public ExtractFunctionRefactoring(IFile file, ISelection selection, ExtractFunctionInformation info, ICProject project) { @@ -340,6 +348,11 @@ public class ExtractFunctionRefactoring extends CRefactoring { methodCall = declarationStatement; } insertCallintoTree(methodCall, container.getNodesToWrite(), rewriter, editGroup); + + if (info.isReplaceDuplicates()) { + replaceSimilar(collector, astMethodName, implementationFile, context.getType()); + } + for (IASTNode node : container.getNodesToWrite()) { if (node != firstNodeToWrite) { rewriter.remove(node, editGroup); @@ -404,6 +417,158 @@ public class ExtractFunctionRefactoring extends CRefactoring { } + private void replaceSimilar(ModificationCollector collector, final IASTName astMethodName, + final IFile implementationFile, + final ContextType contextType) { + // Find similar code + final List nodesToRewriteWithoutComments = new LinkedList(); + + for (IASTNode node : container.getNodesToWrite()) { + if (!(node instanceof IASTComment)) { + nodesToRewriteWithoutComments.add(node); + } + } + + final Vector initTrail = getTrail(nodesToRewriteWithoutComments); + final String title; + if (contextType == MethodContext.ContextType.METHOD) { + title = Messages.ExtractFunctionRefactoring_CreateMethodCall; + } else { + title = Messages.ExtractFunctionRefactoring_CreateFunctionCall; + } + + if (!hasNameResolvingForSimilarError) { + unit.accept(new SimilarFinderVisitor(this, collector, initTrail, implementationFile, + astMethodName, nodesToRewriteWithoutComments, title)); + } + } + + protected Vector getTrail(List stmts) { + final Vector trail = new Vector(); + + nameTrail = new HashMap(); + final Container trailCounter = new Container(NULL_INTEGER); + + for (IASTNode node : stmts) { + node.accept(new CPPASTAllVisitor() { + @Override + public int visitAll(IASTNode node) { + + if (node instanceof IASTComment) { + // Visit Comment, but don't add them to the trail + return super.visitAll(node); + } else if (node instanceof IASTNamedTypeSpecifier) { + // Skip if somewhere is a named Type Specifier + trail.add(node); + return PROCESS_SKIP; + } else if (node instanceof IASTName) { + if (node instanceof ICPPASTConversionName && node instanceof ICPPASTOperatorName + && node instanceof ICPPASTTemplateId) { + trail.add(node); + return super.visitAll(node); + } else { + // Save Name Sequenz Number + IASTName name = (IASTName) node; + TrailName trailName = new TrailName(); + int actCount = trailCounter.getObject().intValue(); + if (nameTrail.containsKey(name.getRawSignature())) { + Integer value = nameTrail.get(name.getRawSignature()); + actCount = value.intValue(); + } else { + trailCounter.setObject(Integer.valueOf(++actCount)); + nameTrail.put(name.getRawSignature(), trailCounter.getObject()); + } + trailName.setNameNumber(actCount); + trailName.setRealName(name); + + if (info.getReturnVariable() != null + && info.getReturnVariable().getName().getRawSignature().equals( + name.getRawSignature())) { + returnNumber.setObject(Integer.valueOf(actCount)); + } + + // Save type informations for the name + IBinding bind = name.resolveBinding(); + IASTName[] declNames = name.getTranslationUnit().getDeclarationsInAST(bind); + if (declNames.length > 0) { + IASTNode tmpNode = ASTHelper.getDeclarationForNode(declNames[0]); + + IBinding declbind = declNames[0].resolveBinding(); + if (declbind instanceof ICPPBinding) { + ICPPBinding cppBind = (ICPPBinding) declbind; + try { + trailName.setGloballyQualified(cppBind.isGloballyQualified()); + } catch (DOMException e) { + ILog logger = CUIPlugin.getDefault().getLog(); + IStatus status = new Status(IStatus.WARNING, CUIPlugin.PLUGIN_ID, + IStatus.OK, e.getMessage(), e); + + logger.log(status); + } + } + + if (tmpNode != null) { + trailName.setDeclaration(tmpNode); + } else { + hasNameResolvingForSimilarError = true; + } + } + + trail.add(trailName); + return PROCESS_SKIP; + } + } else { + trail.add(node); + return super.visitAll(node); + } + } + }); + + } + + return trail; + } + + protected boolean isStatementInTrail(IASTStatement stmt, final Vector trail) { + final Container same = new Container(Boolean.TRUE); + final TrailNodeEqualityChecker equalityChecker = new TrailNodeEqualityChecker(names, namesCounter); + + stmt.accept(new CPPASTAllVisitor() { + @Override + public int visitAll(IASTNode node) { + + int pos = trailPos.getObject().intValue(); + + if (trail.size() <= 0 || pos >= trail.size()) { + same.setObject(Boolean.FALSE); + return PROCESS_ABORT; + } + + if (node instanceof IASTComment) { + // Visit Comment, but they are not in the trail + return super.visitAll(node); + } + + IASTNode trailNode = trail.get(pos); + trailPos.setObject(Integer.valueOf(pos + 1)); + + if (equalityChecker.isEquals(trailNode, node)) { + if (node instanceof ICPPASTQualifiedName || node instanceof IASTNamedTypeSpecifier) { + return PROCESS_SKIP; + } else { + return super.visitAll(node); + } + + } else { + same.setObject(new Boolean(false)); + return PROCESS_ABORT; + } + } + }); + + return same.getObject().booleanValue(); + } + private boolean isMethodAllreadyDefined( IASTSimpleDeclaration methodDeclaration, ICPPASTCompositeTypeSpecifier classDeclaration) { @@ -777,6 +942,7 @@ public class ExtractFunctionRefactoring extends CRefactoring { arguments.put(CRefactoringDescription.SELECTION, region.getOffset() + "," + region.getLength()); //$NON-NLS-1$ arguments.put(ExtractFunctionRefactoringDescription.NAME, info.getMethodName()); arguments.put(ExtractFunctionRefactoringDescription.VISIBILITY, info.getVisibility().toString()); + arguments.put(ExtractFunctionRefactoringDescription.REPLACE_DUBLICATES, Boolean.toString(info.isReplaceDuplicates())); return arguments; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionRefactoringDescription.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionRefactoringDescription.java index 2f034329f75..ab641456027 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionRefactoringDescription.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/ExtractFunctionRefactoringDescription.java @@ -32,6 +32,7 @@ import org.eclipse.cdt.internal.ui.refactoring.utils.VisibilityEnum; public class ExtractFunctionRefactoringDescription extends CRefactoringDescription { protected static final String NAME = "name"; //$NON-NLS-1$ protected static final String VISIBILITY = "visibility"; //$NON-NLS-1$ + protected static final String REPLACE_DUBLICATES = "replaceDuplicates"; //$NON-NLS-1$ public ExtractFunctionRefactoringDescription(String project, String description, String comment, Map arguments) { @@ -46,6 +47,7 @@ public class ExtractFunctionRefactoringDescription extends CRefactoringDescripti info.setMethodName(arguments.get(NAME)); info.setVisibility(VisibilityEnum.getEnumForStringRepresentation(arguments.get(VISIBILITY))); + info.setReplaceDuplicates(Boolean.parseBoolean(arguments.get(REPLACE_DUBLICATES))); proj = getCProject(); file = getFile(); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.java index 4c8b1d95f28..3c9aee0dc3c 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/Messages.java @@ -34,7 +34,7 @@ public final class Messages extends NLS { public static String ExtractFunctionComposite_ReturnValue; public static String ExtractFunctionRefactoring_CreateMethodDef; public static String ExtractFunctionRefactoring_CreateFunctionDef; -// public static String ExtractFunctionComposite_ReplaceDuplicates; + public static String ExtractFunctionComposite_ReplaceDuplicates; public static String ExtractFunctionRefactoring_CreateMethodCall; public static String ExtractFunctionRefactoring_CreateFunctionCall; public static String ChooserComposite_Return; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/SimilarFinderVisitor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/SimilarFinderVisitor.java new file mode 100644 index 00000000000..de2e1382715 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/SimilarFinderVisitor.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2009 Institute for Software, HSR Hochschule fuer Technik + * Rapperswil, University of applied sciences 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Institute for Software - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.refactoring.extractfunction; + +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; +import java.util.Map.Entry; + +import org.eclipse.core.resources.IFile; +import org.eclipse.text.edits.TextEditGroup; + +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTStatement; +import org.eclipse.cdt.core.dom.ast.cpp.CPPASTVisitor; +import org.eclipse.cdt.core.dom.rewrite.ASTRewrite; + +import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector; +import org.eclipse.cdt.internal.ui.refactoring.NodeContainer; +import org.eclipse.cdt.internal.ui.refactoring.NodeContainer.NameInformation; + +final class SimilarFinderVisitor extends CPPASTVisitor { + + private final ExtractFunctionRefactoring refactoring; + + private final Vector trail; + private final IASTName name; + private final List stmts; + private int i = 0; + private NodeContainer similarContainer; + private final List stmtToReplace = new ArrayList(); + + private final ModificationCollector collector; + + SimilarFinderVisitor(ExtractFunctionRefactoring refactoring, + ModificationCollector collector, Vector trail, IFile file, IASTName name, + List stmts, String title) { + this.refactoring = refactoring; + this.trail = trail; + this.name = name; + this.stmts = stmts; + this.collector = collector; + this.similarContainer = new NodeContainer(); + } + + { + shouldVisitStatements = true; + } + + @Override + public int visit(IASTStatement stmt) { + + boolean isAllreadyInMainRefactoring = isInSelection(stmt); + + if( (!isAllreadyInMainRefactoring) + && this.refactoring.isStatementInTrail(stmt, trail)){ + stmtToReplace.add(stmt); + similarContainer.add(stmt); + ++i; + + if(i==stmts.size()){ + //found similar code + + boolean similarOnReturnWays = true; + for (NameInformation nameInfo : similarContainer.getAllAfterUsedNames()) { + if(this.refactoring.names.containsKey(nameInfo.getDeclaration().getRawSignature())){ + Integer nameOrderNumber = this.refactoring.names.get(nameInfo.getDeclaration().getRawSignature()); + if(this.refactoring.nameTrail.containsValue(nameOrderNumber)){ + String orgName = null; + boolean found = false; + for (Entry entry : this.refactoring.nameTrail.entrySet()) { + if(entry.getValue().equals(nameOrderNumber)){ + orgName = entry.getKey(); + } + } + if(orgName != null){ + for (NameInformation orgNameInfo : this.refactoring.container.getAllAfterUsedNamesChoosenByUser()) { + if( orgName.equals(orgNameInfo.getDeclaration().getRawSignature()) ){ + found = true; + } + } + } + + if(!found){ + similarOnReturnWays = false; + } + } + } + } + + if(similarOnReturnWays){ + System.out.println(6); + IASTNode call = refactoring.getMethodCall(name, + this.refactoring.nameTrail, this.refactoring.names, + this.refactoring.container, similarContainer); + ASTRewrite rewrite = collector.rewriterForTranslationUnit(stmtToReplace.get(0) + .getTranslationUnit()); + TextEditGroup editGroup = new TextEditGroup("Replace Dublicated Code"); + rewrite.replace(stmtToReplace.get(0), call, editGroup); + if (stmtToReplace.size() > 1) { + for (int i = 1; i < stmtToReplace.size(); ++i) { + rewrite.remove(stmtToReplace.get(i), editGroup); + } + } + } + + clear(); + } + + return PROCESS_SKIP; + } else { + clear(); + return super.visit(stmt); + } + + } + + private boolean isInSelection(IASTStatement stmt) { + Listnodes = this.refactoring.container.getNodesToWrite(); + for (IASTNode node : nodes) { + if(node.equals(stmt)) { + return true; + } + } + return false; + } + + private void clear() { + i = 0; + this.refactoring.names.clear(); + similarContainer = new NodeContainer(); + this.refactoring.namesCounter.setObject(ExtractFunctionRefactoring.NULL_INTEGER); + this.refactoring.trailPos.setObject(ExtractFunctionRefactoring.NULL_INTEGER); + stmtToReplace.clear(); + } + } \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/messages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/messages.properties index 19b02e9be22..a1612196e4c 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/messages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/extractfunction/messages.properties @@ -22,7 +22,7 @@ ExtractFunctionInputPage_1=is used after the extracted block - it needs to be pa ExtractFunctionComposite_ReturnValue=Return value: ExtractFunctionRefactoring_CreateMethodDef=Create Method Definition ExtractFunctionRefactoring_CreateFunctionDef=Create Function Definition -#ExtractFunctionComposite_ReplaceDuplicates=Replace all occurrences of statements with method. +ExtractFunctionComposite_ReplaceDuplicates=Replace all occurrences of statements with method. ExtractFunctionRefactoring_CreateMethodCall=Create Method Call ExtractFunctionRefactoring_CreateFunctionCall=Create Function Call ChooserComposite_Return=Return