mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-22 06:02:11 +02:00
Bug 303870 - Add override virtual methods functionality
Added overridemethods package Change-Id: I73a8f0a396336acf7d3bbc8988e629da510ae781 Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com> Signed-off-by: pmarek <pavel.akira.marek@gmail.com>
This commit is contained in:
parent
5edac6e20c
commit
6be494466b
29 changed files with 2223 additions and 25 deletions
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
||||||
Bundle-ManifestVersion: 2
|
Bundle-ManifestVersion: 2
|
||||||
Bundle-Name: %pluginName
|
Bundle-Name: %pluginName
|
||||||
Bundle-SymbolicName: org.eclipse.cdt.core; singleton:=true
|
Bundle-SymbolicName: org.eclipse.cdt.core; singleton:=true
|
||||||
Bundle-Version: 6.7.100.qualifier
|
Bundle-Version: 6.8.0.qualifier
|
||||||
Bundle-Activator: org.eclipse.cdt.core.CCorePlugin
|
Bundle-Activator: org.eclipse.cdt.core.CCorePlugin
|
||||||
Bundle-Vendor: %providerName
|
Bundle-Vendor: %providerName
|
||||||
Bundle-Localization: plugin
|
Bundle-Localization: plugin
|
||||||
|
|
|
@ -368,6 +368,36 @@ public class CCorePreferenceConstants {
|
||||||
*/
|
*/
|
||||||
public static final boolean DEFAULT_PLACE_CONST_RIGHT_OF_TYPE = false;
|
public static final boolean DEFAULT_PLACE_CONST_RIGHT_OF_TYPE = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A named preference that specifies whether the override keyword should be added
|
||||||
|
* to method signature.
|
||||||
|
*
|
||||||
|
* @since 6.8
|
||||||
|
*/
|
||||||
|
public static final String ADD_OVERRIDE_KEYWORD = "astwriter.addOverride"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A named preference that specifies whether the virtual keyword should be added
|
||||||
|
* to method signature.
|
||||||
|
*
|
||||||
|
* @since 6.8
|
||||||
|
*/
|
||||||
|
public static final String PRESERVE_VIRTUAL_KEYWORD = "astwriter.preserveVirtual"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default value for {@link #ADD_OVERRIDE_KEYWORD}.
|
||||||
|
*
|
||||||
|
* @since 6.8
|
||||||
|
*/
|
||||||
|
public static final boolean DEFAULT_ADD_OVERRIDE_KEYWORD = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default value for {@link #PRESERVE_VIRTUAL_KEYWORD}.
|
||||||
|
*
|
||||||
|
* @since 6.8
|
||||||
|
*/
|
||||||
|
public static final boolean DEFAULT_PRESERVE_VIRTUAL_KEYWORD = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the node in the preference in the given context.
|
* Returns the node in the preference in the given context.
|
||||||
*
|
*
|
||||||
|
|
|
@ -94,5 +94,9 @@ public class CCorePreferenceInitializer extends AbstractPreferenceInitializer {
|
||||||
CCorePreferenceConstants.DEFAULT_SCALABILITY_MAXIMUM_TOKENS);
|
CCorePreferenceConstants.DEFAULT_SCALABILITY_MAXIMUM_TOKENS);
|
||||||
defaultPreferences.putBoolean(CCorePreferenceConstants.PLACE_CONST_RIGHT_OF_TYPE,
|
defaultPreferences.putBoolean(CCorePreferenceConstants.PLACE_CONST_RIGHT_OF_TYPE,
|
||||||
CCorePreferenceConstants.DEFAULT_PLACE_CONST_RIGHT_OF_TYPE);
|
CCorePreferenceConstants.DEFAULT_PLACE_CONST_RIGHT_OF_TYPE);
|
||||||
|
defaultPreferences.putBoolean(CCorePreferenceConstants.ADD_OVERRIDE_KEYWORD,
|
||||||
|
CCorePreferenceConstants.DEFAULT_ADD_OVERRIDE_KEYWORD);
|
||||||
|
defaultPreferences.putBoolean(CCorePreferenceConstants.PRESERVE_VIRTUAL_KEYWORD,
|
||||||
|
CCorePreferenceConstants.DEFAULT_PRESERVE_VIRTUAL_KEYWORD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAnd
|
||||||
import org.eclipse.cdt.ui.tests.refactoring.hidemethod.HideMethodRefactoringTest;
|
import org.eclipse.cdt.ui.tests.refactoring.hidemethod.HideMethodRefactoringTest;
|
||||||
import org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest;
|
import org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest;
|
||||||
import org.eclipse.cdt.ui.tests.refactoring.includes.IncludesTestSuite;
|
import org.eclipse.cdt.ui.tests.refactoring.includes.IncludesTestSuite;
|
||||||
|
import org.eclipse.cdt.ui.tests.refactoring.overridemethods.OverrideMethodsRefactoringTest;
|
||||||
import org.eclipse.cdt.ui.tests.refactoring.rename.RenameRegressionTests;
|
import org.eclipse.cdt.ui.tests.refactoring.rename.RenameRegressionTests;
|
||||||
import org.eclipse.cdt.ui.tests.refactoring.togglefunction.ToggleRefactoringTest;
|
import org.eclipse.cdt.ui.tests.refactoring.togglefunction.ToggleRefactoringTest;
|
||||||
import org.eclipse.cdt.ui.tests.refactoring.utils.UtilTestSuite;
|
import org.eclipse.cdt.ui.tests.refactoring.utils.UtilTestSuite;
|
||||||
|
@ -37,7 +38,7 @@ import org.junit.runners.Suite;
|
||||||
@Suite.SuiteClasses({ UtilTestSuite.class, RenameRegressionTests.class, ExtractFunctionRefactoringTest.class,
|
@Suite.SuiteClasses({ UtilTestSuite.class, RenameRegressionTests.class, ExtractFunctionRefactoringTest.class,
|
||||||
ExtractConstantRefactoringTest.class, HideMethodRefactoringTest.class, GenerateGettersAndSettersTest.class,
|
ExtractConstantRefactoringTest.class, HideMethodRefactoringTest.class, GenerateGettersAndSettersTest.class,
|
||||||
ImplementMethodRefactoringTest.class, ExtractLocalVariableRefactoringTest.class, ToggleRefactoringTest.class,
|
ImplementMethodRefactoringTest.class, ExtractLocalVariableRefactoringTest.class, ToggleRefactoringTest.class,
|
||||||
IncludesTestSuite.class,
|
IncludesTestSuite.class, OverrideMethodsRefactoringTest.class
|
||||||
|
|
||||||
})
|
})
|
||||||
public class RefactoringTestSuite {
|
public class RefactoringTestSuite {
|
||||||
|
|
|
@ -0,0 +1,606 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2019 Marco Stornelli
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.ui.tests.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.CRefactoring;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.overridemethods.Method;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.overridemethods.OverrideMethodsRefactoring;
|
||||||
|
import org.eclipse.cdt.ui.tests.refactoring.RefactoringTestBase;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for override methods
|
||||||
|
*/
|
||||||
|
public class OverrideMethodsRefactoringTest extends RefactoringTestBase {
|
||||||
|
|
||||||
|
private String[] selectedMethods;
|
||||||
|
private OverrideMethodsRefactoring refactoring;
|
||||||
|
private boolean addOverride = false;
|
||||||
|
private boolean preserveVirtual = true;
|
||||||
|
|
||||||
|
public OverrideMethodsRefactoringTest() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverrideMethodsRefactoringTest(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Test suite() {
|
||||||
|
return suite(OverrideMethodsRefactoringTest.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CRefactoring createRefactoring() {
|
||||||
|
refactoring = new OverrideMethodsRefactoring(getSelectedTranslationUnit(), getSelection(), getCProject());
|
||||||
|
return refactoring;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void simulateUserInput() {
|
||||||
|
if (selectedMethods != null) {
|
||||||
|
Map<ICPPClassType, List<Method>> map = refactoring.getMethodContainer().getInitialInput();
|
||||||
|
for (Map.Entry<ICPPClassType, List<Method>> entry : map.entrySet()) {
|
||||||
|
List<Method> methods = entry.getValue();
|
||||||
|
for (Method m : methods) {
|
||||||
|
for (String name : selectedMethods) {
|
||||||
|
if (m.toString().equals(name))
|
||||||
|
refactoring.getPrintData().addMethod(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refactoring.getOptions().setAddOverride(addOverride);
|
||||||
|
refactoring.getOptions().setPreserveVirtual(preserveVirtual);
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void baseFunc() const;
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//inline void X::baseFunc() const {
|
||||||
|
//}
|
||||||
|
public void testWithHeaderOnly() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc()const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void baseFunc() const;
|
||||||
|
//};
|
||||||
|
|
||||||
|
//A.cpp
|
||||||
|
//#include "A.h"
|
||||||
|
//====================
|
||||||
|
//#include "A.h"
|
||||||
|
//
|
||||||
|
//void X::baseFunc() const {
|
||||||
|
//}
|
||||||
|
public void testWithHeaderAndSource() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc()const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//namespace FIRST {
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc(Base* ptr) const = 0;
|
||||||
|
//};
|
||||||
|
//};
|
||||||
|
//namespace SECOND {
|
||||||
|
//class X: public FIRST::Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//namespace FIRST {
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc(Base* ptr) const = 0;
|
||||||
|
//};
|
||||||
|
//};
|
||||||
|
//namespace SECOND {
|
||||||
|
//class X: public FIRST::Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void baseFunc(FIRST::Base* ptr) const;
|
||||||
|
//};
|
||||||
|
//};
|
||||||
|
|
||||||
|
//A.cpp
|
||||||
|
//#include "A.h"
|
||||||
|
//====================
|
||||||
|
//#include "A.h"
|
||||||
|
//
|
||||||
|
//void SECOND::X::baseFunc(FIRST::Base* ptr) const {
|
||||||
|
//}
|
||||||
|
public void testWithMixedNamespaceHeaderAndSource() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc(FIRST::Base *)const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// void baseFunc() const;
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//inline void X::baseFunc() const {
|
||||||
|
//}
|
||||||
|
public void testIgnoringVirtual() throws Exception {
|
||||||
|
preserveVirtual = false;
|
||||||
|
selectedMethods = new String[] { "baseFunc()const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void baseFunc() const override;
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//inline void X::baseFunc() const {
|
||||||
|
//}
|
||||||
|
public void testAddingOverrideVirtual() throws Exception {
|
||||||
|
addOverride = true;
|
||||||
|
selectedMethods = new String[] { "baseFunc()const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//template<class T>
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//template<class T>
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void baseFunc() const;
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//template<class T>
|
||||||
|
//inline void X<T>::baseFunc() const {
|
||||||
|
//}
|
||||||
|
public void testWithTemplateClass() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc()const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// class Internal: public Base {
|
||||||
|
// public:
|
||||||
|
// /*$*//*$$*/
|
||||||
|
// };
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// class Internal: public Base {
|
||||||
|
// public:
|
||||||
|
// virtual void baseFunc() const;
|
||||||
|
// };
|
||||||
|
//};
|
||||||
|
|
||||||
|
//A.cpp
|
||||||
|
//#include "A.h"
|
||||||
|
//====================
|
||||||
|
//#include "A.h"
|
||||||
|
//
|
||||||
|
//void X::Internal::baseFunc() const {
|
||||||
|
//}
|
||||||
|
public void testWithNestedClass() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc()const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
//};
|
||||||
|
///*$*//*$$*/
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
//};
|
||||||
|
public void testWithNoSelection() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc()const" };
|
||||||
|
assertRefactoringFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// void baseFunc() const;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
///*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// void baseFunc() const;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
//};
|
||||||
|
public void testWithNoMethods() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc()const" };
|
||||||
|
assertRefactoringFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class X {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
///*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class X {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
//};
|
||||||
|
public void testWithNoBaseClass() throws Exception {
|
||||||
|
assertRefactoringFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const throw (int) = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const throw (int) = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void baseFunc() const throw (int);
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//inline void X::baseFunc() const throw (int) {
|
||||||
|
//}
|
||||||
|
public void testWithThrowNoEmpty() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc()const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const throw () = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const throw () = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void baseFunc() const throw ();
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//inline void X::baseFunc() const throw () {
|
||||||
|
//}
|
||||||
|
public void testWithThrowEmpty() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc()const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const noexcept = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() const noexcept = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void baseFunc() const noexcept;
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//inline void X::baseFunc() const {
|
||||||
|
//}
|
||||||
|
public void testWithNoExcept() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc()const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc1() const = 0;
|
||||||
|
// virtual void baseFunc2() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc1() const = 0;
|
||||||
|
// virtual void baseFunc2() const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void baseFunc2() const;
|
||||||
|
// virtual void baseFunc1() const;
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//inline void X::baseFunc2() const {
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//inline void X::baseFunc1() const {
|
||||||
|
//}
|
||||||
|
public void testWithMultipleMethods() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc1()const", "baseFunc2()const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() && = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void baseFunc() && = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void baseFunc() &&;
|
||||||
|
//};
|
||||||
|
//
|
||||||
|
//inline void X::baseFunc() && {
|
||||||
|
//}
|
||||||
|
public void testWithRefQualifier() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc()&&" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void* baseFunc(void* ptr) const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void* baseFunc(void* ptr) const = 0;
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void* baseFunc(void* ptr) const;
|
||||||
|
//};
|
||||||
|
|
||||||
|
//A.cpp
|
||||||
|
//#include "A.h"
|
||||||
|
//====================
|
||||||
|
//#include "A.h"
|
||||||
|
//
|
||||||
|
//void* X::baseFunc(void* ptr) const {
|
||||||
|
//}
|
||||||
|
public void testWithPointers() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc(void *)const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//A.h
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void* baseFunc(void* ptr) const = 0, method2();
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// /*$*//*$$*/
|
||||||
|
//};
|
||||||
|
//====================
|
||||||
|
//class Base {
|
||||||
|
//public:
|
||||||
|
// virtual ~Base();
|
||||||
|
// virtual void* baseFunc(void* ptr) const = 0, method2();
|
||||||
|
//};
|
||||||
|
//class X: public Base {
|
||||||
|
//public:
|
||||||
|
// X();
|
||||||
|
// virtual void* baseFunc(void* ptr) const;
|
||||||
|
//};
|
||||||
|
|
||||||
|
//A.cpp
|
||||||
|
//#include "A.h"
|
||||||
|
//====================
|
||||||
|
//#include "A.h"
|
||||||
|
//
|
||||||
|
//void* X::baseFunc(void* ptr) const {
|
||||||
|
//}
|
||||||
|
public void testWithMultipleMethodsOnSameLine() throws Exception {
|
||||||
|
selectedMethods = new String[] { "baseFunc(void *)const" };
|
||||||
|
assertRefactoringSuccess();
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,7 @@ Export-Package: org.eclipse.cdt.internal.corext;x-internal:=true,
|
||||||
org.eclipse.cdt.internal.ui.refactoring.hidemethod;x-friends:="org.eclipse.cdt.ui.tests",
|
org.eclipse.cdt.internal.ui.refactoring.hidemethod;x-friends:="org.eclipse.cdt.ui.tests",
|
||||||
org.eclipse.cdt.internal.ui.refactoring.implementmethod;x-friends:="org.eclipse.cdt.ui.tests",
|
org.eclipse.cdt.internal.ui.refactoring.implementmethod;x-friends:="org.eclipse.cdt.ui.tests",
|
||||||
org.eclipse.cdt.internal.ui.refactoring.includes;x-friends:="org.eclipse.cdt.ui.tests",
|
org.eclipse.cdt.internal.ui.refactoring.includes;x-friends:="org.eclipse.cdt.ui.tests",
|
||||||
|
org.eclipse.cdt.internal.ui.refactoring.overridemethods;x-friends:="org.eclipse.cdt.ui.tests",
|
||||||
org.eclipse.cdt.internal.ui.refactoring.rename;x-friends:="org.eclipse.cdt.ui.tests",
|
org.eclipse.cdt.internal.ui.refactoring.rename;x-friends:="org.eclipse.cdt.ui.tests",
|
||||||
org.eclipse.cdt.internal.ui.refactoring.togglefunction;x-friends:="org.eclipse.cdt.ui.tests",
|
org.eclipse.cdt.internal.ui.refactoring.togglefunction;x-friends:="org.eclipse.cdt.ui.tests",
|
||||||
org.eclipse.cdt.internal.ui.refactoring.utils;x-friends:="org.eclipse.cdt.ui.tests",
|
org.eclipse.cdt.internal.ui.refactoring.utils;x-friends:="org.eclipse.cdt.ui.tests",
|
||||||
|
|
|
@ -176,6 +176,8 @@ ActionDefinition.implementMethod.name= Implement Method - Source Generation\u002
|
||||||
ActionDefinition.implementMethod.description= Implements a method for a selected method declaration
|
ActionDefinition.implementMethod.description= Implements a method for a selected method declaration
|
||||||
ActionDefinition.gettersAndSetters.name = Generate Getters and Setters...
|
ActionDefinition.gettersAndSetters.name = Generate Getters and Setters...
|
||||||
ActionDefinition.gettersAndSetters.description = Generates getters and setters for a selected field
|
ActionDefinition.gettersAndSetters.description = Generates getters and setters for a selected field
|
||||||
|
ActionDefinition.overrideMethods.name = Override Methods...
|
||||||
|
ActionDefinition.overrideMethods.description = Generates override methods for a selected class
|
||||||
|
|
||||||
ActionDefinition.surroundWith.quickMenu.name= Surround With Quick Menu
|
ActionDefinition.surroundWith.quickMenu.name= Surround With Quick Menu
|
||||||
ActionDefinition.surroundWith.quickMenu.description= Shows the Surround With quick menu
|
ActionDefinition.surroundWith.quickMenu.description= Shows the Surround With quick menu
|
||||||
|
@ -193,6 +195,7 @@ Refactoring.toggleFunction.label=Toggle Function
|
||||||
Refactoring.hideMethod.label=Hide Method...
|
Refactoring.hideMethod.label=Hide Method...
|
||||||
Refactoring.implementMethod.label=Impl&ement Method...
|
Refactoring.implementMethod.label=Impl&ement Method...
|
||||||
Refactoring.gettersAndSetters.label=Gene&rate Getters and Setters...
|
Refactoring.gettersAndSetters.label=Gene&rate Getters and Setters...
|
||||||
|
Refactoring.overrideMethods.label=Override Methods...
|
||||||
|
|
||||||
Source.menu.label = &Source
|
Source.menu.label = &Source
|
||||||
|
|
||||||
|
|
|
@ -1937,6 +1937,13 @@
|
||||||
id="org.eclipse.cdt.ui.actions.ImplementMethod"
|
id="org.eclipse.cdt.ui.actions.ImplementMethod"
|
||||||
retarget="true">
|
retarget="true">
|
||||||
</action>
|
</action>
|
||||||
|
<action
|
||||||
|
definitionId="org.eclipse.cdt.ui.refactor.override.methods"
|
||||||
|
label="%Refactoring.overrideMethods.label"
|
||||||
|
menubarPath="org.eclipse.jdt.ui.source.menu/generateGroup"
|
||||||
|
id="org.eclipse.cdt.ui.actions.OverrideMethods"
|
||||||
|
retarget="true">
|
||||||
|
</action>
|
||||||
<!-- Import Group -->
|
<!-- Import Group -->
|
||||||
<action
|
<action
|
||||||
definitionId="org.eclipse.cdt.ui.edit.text.c.sort.lines"
|
definitionId="org.eclipse.cdt.ui.edit.text.c.sort.lines"
|
||||||
|
@ -3237,6 +3244,11 @@
|
||||||
description="%ActionDefinition.gettersAndSetters.description"
|
description="%ActionDefinition.gettersAndSetters.description"
|
||||||
categoryId="org.eclipse.cdt.ui.category.source"
|
categoryId="org.eclipse.cdt.ui.category.source"
|
||||||
id="org.eclipse.cdt.ui.refactor.getters.and.setters"/>
|
id="org.eclipse.cdt.ui.refactor.getters.and.setters"/>
|
||||||
|
<command
|
||||||
|
name="%ActionDefinition.overrideMethods.name"
|
||||||
|
description="%ActionDefinition.overrideMethods.description"
|
||||||
|
categoryId="org.eclipse.cdt.ui.category.source"
|
||||||
|
id="org.eclipse.cdt.ui.refactor.override.methods"/>
|
||||||
<command
|
<command
|
||||||
name="%ActionDefinition.surroundWith.quickMenu.name"
|
name="%ActionDefinition.surroundWith.quickMenu.name"
|
||||||
description="%ActionDefinition.surroundWith.quickMenu.description"
|
description="%ActionDefinition.surroundWith.quickMenu.description"
|
||||||
|
|
|
@ -111,6 +111,12 @@ public interface ICEditorActionDefinitionIds extends ITextEditorActionDefinition
|
||||||
*/
|
*/
|
||||||
public static final String EXTRACT_CONSTANT = "org.eclipse.cdt.ui.refactor.extract.constant"; //$NON-NLS-1$
|
public static final String EXTRACT_CONSTANT = "org.eclipse.cdt.ui.refactor.extract.constant"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action definition ID of the refactor -> override methods action
|
||||||
|
* (value <code>"org.eclipse.cdt.ui.refactor.override.methods"</code>).
|
||||||
|
*/
|
||||||
|
public static final String OVERRIDE_METHODS = "org.eclipse.cdt.ui.refactor.override.methods"; //$NON-NLS-1$
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action definition ID of the refactor -> extract local variable action
|
* Action definition ID of the refactor -> extract local variable action
|
||||||
* (value <code>"org.eclipse.cdt.ui.refactor.extract.local.variable"</code>).
|
* (value <code>"org.eclipse.cdt.ui.refactor.extract.local.variable"</code>).
|
||||||
|
|
|
@ -37,10 +37,15 @@ class CodeStyleBlock extends OptionsConfigurationBlock {
|
||||||
PreferenceConstants.FUNCTION_PASS_OUTPUT_PARAMETERS_BY_POINTER);
|
PreferenceConstants.FUNCTION_PASS_OUTPUT_PARAMETERS_BY_POINTER);
|
||||||
private static final Key PLACE_CONST_RIGHT_OF_TYPE = getKey(CCorePlugin.PLUGIN_ID,
|
private static final Key PLACE_CONST_RIGHT_OF_TYPE = getKey(CCorePlugin.PLUGIN_ID,
|
||||||
CCorePreferenceConstants.PLACE_CONST_RIGHT_OF_TYPE);
|
CCorePreferenceConstants.PLACE_CONST_RIGHT_OF_TYPE);
|
||||||
|
private static final Key ADD_OVERRIDE_KEYWORD = getKey(CCorePlugin.PLUGIN_ID,
|
||||||
|
CCorePreferenceConstants.ADD_OVERRIDE_KEYWORD);
|
||||||
|
private static final Key PRESERVE_VIRTUAL_KEYWORD = getKey(CCorePlugin.PLUGIN_ID,
|
||||||
|
CCorePreferenceConstants.PRESERVE_VIRTUAL_KEYWORD);
|
||||||
|
|
||||||
private static Key[] getAllKeys() {
|
private static Key[] getAllKeys() {
|
||||||
return new Key[] { CLASS_MEMBER_ASCENDING_VISIBILITY_ORDER, FUNCTION_OUTPUT_PARAMETERS_BEFORE_INPUT,
|
return new Key[] { CLASS_MEMBER_ASCENDING_VISIBILITY_ORDER, FUNCTION_OUTPUT_PARAMETERS_BEFORE_INPUT,
|
||||||
FUNCTION_PASS_OUTPUT_PARAMETERS_BY_POINTER, PLACE_CONST_RIGHT_OF_TYPE, };
|
FUNCTION_PASS_OUTPUT_PARAMETERS_BY_POINTER, PLACE_CONST_RIGHT_OF_TYPE, ADD_OVERRIDE_KEYWORD,
|
||||||
|
PRESERVE_VIRTUAL_KEYWORD };
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeStyleBlock(IStatusChangeListener context, IProject project, IWorkbenchPreferenceContainer container) {
|
public CodeStyleBlock(IStatusChangeListener context, IProject project, IWorkbenchPreferenceContainer container) {
|
||||||
|
@ -69,6 +74,9 @@ class CodeStyleBlock extends OptionsConfigurationBlock {
|
||||||
composite = addSubsection(control, PreferencesMessages.CodeStyleBlock_const_keyword_placement);
|
composite = addSubsection(control, PreferencesMessages.CodeStyleBlock_const_keyword_placement);
|
||||||
fillConstPlacementsSections(composite);
|
fillConstPlacementsSections(composite);
|
||||||
|
|
||||||
|
composite = addSubsection(control, PreferencesMessages.CodeStyleBlock_function_overridden_methods);
|
||||||
|
fillOverriddenSection(composite);
|
||||||
|
|
||||||
scrolled.setContent(control);
|
scrolled.setContent(control);
|
||||||
final Point size = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);
|
final Point size = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);
|
||||||
scrolled.setMinSize(size.x, size.y);
|
scrolled.setMinSize(size.x, size.y);
|
||||||
|
@ -119,6 +127,17 @@ class CodeStyleBlock extends OptionsConfigurationBlock {
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillOverriddenSection(Composite composite) {
|
||||||
|
GridLayout layout = new GridLayout();
|
||||||
|
layout.numColumns = 3;
|
||||||
|
composite.setLayout(layout);
|
||||||
|
|
||||||
|
addCheckBox(composite, PreferencesMessages.CodeStyleBlock_add_override_keyword, ADD_OVERRIDE_KEYWORD,
|
||||||
|
TRUE_FALSE, 0);
|
||||||
|
addCheckBox(composite, PreferencesMessages.CodeStyleBlock_preserve_virtual, PRESERVE_VIRTUAL_KEYWORD,
|
||||||
|
TRUE_FALSE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void validateSettings(Key changedKey, String oldValue, String newValue) {
|
protected void validateSettings(Key changedKey, String oldValue, String newValue) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,6 +224,9 @@ public final class PreferencesMessages extends NLS {
|
||||||
public static String CodeStyleBlock_const_keyword_placement;
|
public static String CodeStyleBlock_const_keyword_placement;
|
||||||
public static String CodeStyleBlock_const_left;
|
public static String CodeStyleBlock_const_left;
|
||||||
public static String CodeStyleBlock_const_right;
|
public static String CodeStyleBlock_const_right;
|
||||||
|
public static String CodeStyleBlock_function_overridden_methods;
|
||||||
|
public static String CodeStyleBlock_preserve_virtual;
|
||||||
|
public static String CodeStyleBlock_add_override_keyword;
|
||||||
|
|
||||||
public static String TodoTaskPreferencePage_title;
|
public static String TodoTaskPreferencePage_title;
|
||||||
public static String TodoTaskPreferencePage_description;
|
public static String TodoTaskPreferencePage_description;
|
||||||
|
|
|
@ -259,6 +259,9 @@ CodeStyleBlock_pass_by_pointer=Pass by poi&nter
|
||||||
CodeStyleBlock_const_keyword_placement=Placement of the const keyword:
|
CodeStyleBlock_const_keyword_placement=Placement of the const keyword:
|
||||||
CodeStyleBlock_const_left=&Left of type e.g. "const int n{};"
|
CodeStyleBlock_const_left=&Left of type e.g. "const int n{};"
|
||||||
CodeStyleBlock_const_right=&Right of type e.g. "int const n{};"
|
CodeStyleBlock_const_right=&Right of type e.g. "int const n{};"
|
||||||
|
CodeStyleBlock_function_overridden_methods=Overridden methods
|
||||||
|
CodeStyleBlock_preserve_virtual=Add virtual keyword on overridden methods
|
||||||
|
CodeStyleBlock_add_override_keyword=Add override keyword on overridden methods
|
||||||
|
|
||||||
# Task tags.
|
# Task tags.
|
||||||
TodoTaskPreferencePage_title=Task Tags
|
TodoTaskPreferencePage_title=Task Tags
|
||||||
|
|
|
@ -171,12 +171,58 @@ public class ImplementMethodRefactoring extends CRefactoring {
|
||||||
List<MethodToImplementConfig> methodsToImplement = data.getMethodsToImplement();
|
List<MethodToImplementConfig> methodsToImplement = data.getMethodsToImplement();
|
||||||
SubMonitor sm = SubMonitor.convert(pm, 4 * methodsToImplement.size());
|
SubMonitor sm = SubMonitor.convert(pm, 4 * methodsToImplement.size());
|
||||||
for (MethodToImplementConfig config : methodsToImplement) {
|
for (MethodToImplementConfig config : methodsToImplement) {
|
||||||
createDefinition(collector, config, sm.newChild(4));
|
createDefinition(collector, config, sm.newChild(4), -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method to collect modifications from another Refactoring
|
||||||
|
* @param pm The progress monitor
|
||||||
|
* @param collector The collector
|
||||||
|
* @param methods List of methods
|
||||||
|
* @param functionOffset A function offset to determine fully qualified names
|
||||||
|
* @throws CoreException
|
||||||
|
* @throws OperationCanceledException
|
||||||
|
*/
|
||||||
|
public void collectModifications(IProgressMonitor pm, ModificationCollector collector,
|
||||||
|
List<IASTSimpleDeclaration> methods, int functionOffset) throws CoreException, OperationCanceledException {
|
||||||
|
data.setMethodDeclarations(methods);
|
||||||
|
for (MethodToImplementConfig config : data.getMethodDeclarations()) {
|
||||||
|
config.setChecked(true);
|
||||||
|
}
|
||||||
|
List<MethodToImplementConfig> methodsToImplement = data.getMethodsToImplement();
|
||||||
|
SubMonitor sm = SubMonitor.convert(pm, 4 * methodsToImplement.size());
|
||||||
|
for (MethodToImplementConfig config : methodsToImplement) {
|
||||||
|
createDefinition(collector, config, sm.newChild(4), functionOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create definition for a method
|
||||||
|
* @param collector A modification collector
|
||||||
|
* @param config The method to be inserted
|
||||||
|
* @param subMonitor A sub monitor for the progress
|
||||||
|
* @throws CoreException
|
||||||
|
* @throws OperationCanceledException
|
||||||
|
*/
|
||||||
protected void createDefinition(ModificationCollector collector, MethodToImplementConfig config,
|
protected void createDefinition(ModificationCollector collector, MethodToImplementConfig config,
|
||||||
IProgressMonitor subMonitor) throws CoreException, OperationCanceledException {
|
IProgressMonitor subMonitor) throws CoreException, OperationCanceledException {
|
||||||
|
createDefinition(collector, config, subMonitor, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create definition for a method
|
||||||
|
* @param collector A modification collector
|
||||||
|
* @param config The method to be inserted
|
||||||
|
* @param subMonitor A sub monitor for the progress
|
||||||
|
* @param functionOffset The node offset can be explicitly defined with this parameter,
|
||||||
|
* worth when the declarator does not have a valid offset yet. A negative number
|
||||||
|
* can be used to use the node offset of method instead, as returned by getFileLocation().getNodeOffset()
|
||||||
|
* @throws CoreException
|
||||||
|
* @throws OperationCanceledException
|
||||||
|
*/
|
||||||
|
protected void createDefinition(ModificationCollector collector, MethodToImplementConfig config,
|
||||||
|
IProgressMonitor subMonitor, int functionOffset) throws CoreException, OperationCanceledException {
|
||||||
if (subMonitor.isCanceled()) {
|
if (subMonitor.isCanceled()) {
|
||||||
throw new OperationCanceledException();
|
throw new OperationCanceledException();
|
||||||
}
|
}
|
||||||
|
@ -196,7 +242,7 @@ public class ImplementMethodRefactoring extends CRefactoring {
|
||||||
}
|
}
|
||||||
|
|
||||||
IASTNode nodeToInsertBefore = insertLocation.getNodeToInsertBefore();
|
IASTNode nodeToInsertBefore = insertLocation.getNodeToInsertBefore();
|
||||||
IASTNode createdMethodDefinition = createFunctionDefinition(ast, decl, insertLocation);
|
IASTNode createdMethodDefinition = createFunctionDefinition(ast, decl, insertLocation, functionOffset);
|
||||||
subMonitor.worked(1);
|
subMonitor.worked(1);
|
||||||
ASTRewrite methodRewrite = translationUnitRewrite.insertBefore(parent, nodeToInsertBefore,
|
ASTRewrite methodRewrite = translationUnitRewrite.insertBefore(parent, nodeToInsertBefore,
|
||||||
createdMethodDefinition, null);
|
createdMethodDefinition, null);
|
||||||
|
@ -243,8 +289,18 @@ public class ImplementMethodRefactoring extends CRefactoring {
|
||||||
return insertLocation;
|
return insertLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the function definition
|
||||||
|
* @param unit The translation unit
|
||||||
|
* @param methodDeclaration The method to be inserted
|
||||||
|
* @param insertLocation The position for the insert operation
|
||||||
|
* @param functionOffset A function offset to determine fully qualified names. A negative number
|
||||||
|
* can be used to use the node offset of method as returned by getFileLocation().getNodeOffset()
|
||||||
|
* @return
|
||||||
|
* @throws CoreException
|
||||||
|
*/
|
||||||
private IASTDeclaration createFunctionDefinition(IASTTranslationUnit unit, IASTSimpleDeclaration methodDeclaration,
|
private IASTDeclaration createFunctionDefinition(IASTTranslationUnit unit, IASTSimpleDeclaration methodDeclaration,
|
||||||
InsertLocation insertLocation) throws CoreException {
|
InsertLocation insertLocation, int functionOffset) throws CoreException {
|
||||||
IASTDeclSpecifier declSpecifier = methodDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations);
|
IASTDeclSpecifier declSpecifier = methodDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations);
|
||||||
ICPPASTFunctionDeclarator functionDeclarator = (ICPPASTFunctionDeclarator) methodDeclaration
|
ICPPASTFunctionDeclarator functionDeclarator = (ICPPASTFunctionDeclarator) methodDeclaration
|
||||||
.getDeclarators()[0];
|
.getDeclarators()[0];
|
||||||
|
@ -264,7 +320,8 @@ public class ImplementMethodRefactoring extends CRefactoring {
|
||||||
declSpecifier.setStorageClass(IASTDeclSpecifier.sc_unspecified);
|
declSpecifier.setStorageClass(IASTDeclSpecifier.sc_unspecified);
|
||||||
}
|
}
|
||||||
|
|
||||||
ICPPASTQualifiedName qName = createQualifiedNameFor(functionDeclarator, declarationParent, insertLocation);
|
ICPPASTQualifiedName qName = createQualifiedNameFor(functionDeclarator, declarationParent, insertLocation,
|
||||||
|
functionOffset);
|
||||||
|
|
||||||
createdMethodDeclarator = nodeFactory.newFunctionDeclarator(qName);
|
createdMethodDeclarator = nodeFactory.newFunctionDeclarator(qName);
|
||||||
createdMethodDeclarator.setConst(functionDeclarator.isConst());
|
createdMethodDeclarator.setConst(functionDeclarator.isConst());
|
||||||
|
@ -299,12 +356,22 @@ public class ImplementMethodRefactoring extends CRefactoring {
|
||||||
return functionDefinition;
|
return functionDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the fully qualified name for the declaration
|
||||||
|
* @param functionDeclarator The function declaration
|
||||||
|
* @param declarationParent Parent of declaration
|
||||||
|
* @param insertLocation Insert position
|
||||||
|
* @param functionOffset A function offset to determine fully qualified names. A negative number
|
||||||
|
* can be used to use the node offset of method as returned by getFileLocation().getNodeOffset()
|
||||||
|
* @return The fully qualified name
|
||||||
|
* @throws CoreException
|
||||||
|
*/
|
||||||
private ICPPASTQualifiedName createQualifiedNameFor(IASTFunctionDeclarator functionDeclarator,
|
private ICPPASTQualifiedName createQualifiedNameFor(IASTFunctionDeclarator functionDeclarator,
|
||||||
IASTNode declarationParent, InsertLocation insertLocation) throws CoreException {
|
IASTNode declarationParent, InsertLocation insertLocation, int functionOffset) throws CoreException {
|
||||||
int insertOffset = insertLocation.getInsertPosition();
|
int insertOffset = insertLocation.getInsertPosition();
|
||||||
return NameHelper.createQualifiedNameFor(functionDeclarator.getName(), tu,
|
return NameHelper.createQualifiedNameFor(functionDeclarator.getName(), tu,
|
||||||
functionDeclarator.getFileLocation().getNodeOffset(), insertLocation.getTranslationUnit(), insertOffset,
|
functionOffset >= 0 ? functionOffset : functionDeclarator.getFileLocation().getNodeOffset(),
|
||||||
refactoringContext);
|
insertLocation.getTranslationUnit(), insertOffset, refactoringContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImplementMethodData getRefactoringData() {
|
public ImplementMethodData getRefactoringData() {
|
||||||
|
@ -343,10 +410,14 @@ public class ImplementMethodRefactoring extends CRefactoring {
|
||||||
if (isOneOrMoreImplementationInHeader(subProgressMonitor)) {
|
if (isOneOrMoreImplementationInHeader(subProgressMonitor)) {
|
||||||
result.addInfo(Messages.ImplementMethodRefactoring_NoImplFile);
|
result.addInfo(Messages.ImplementMethodRefactoring_NoImplFile);
|
||||||
}
|
}
|
||||||
Checks.addModifiedFilesToChecker(getAllFilesToModify(), checkContext);
|
finalConditions(checkContext);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void finalConditions(CheckConditionsContext checkContext) {
|
||||||
|
Checks.addModifiedFilesToChecker(getAllFilesToModify(), checkContext);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isOneOrMoreImplementationInHeader(IProgressMonitor subProgressMonitor) throws CoreException {
|
private boolean isOneOrMoreImplementationInHeader(IProgressMonitor subProgressMonitor) throws CoreException {
|
||||||
for (MethodToImplementConfig config : data.getMethodsToImplement()) {
|
for (MethodToImplementConfig config : data.getMethodsToImplement()) {
|
||||||
IASTSimpleDeclaration decl = config.getDeclaration();
|
IASTSimpleDeclaration decl = config.getDeclaration();
|
||||||
|
|
|
@ -161,7 +161,8 @@ public class MethodDefinitionInsertLocationFinder {
|
||||||
if (pm != null && pm.isCanceled()) {
|
if (pm != null && pm.isCanceled()) {
|
||||||
return outputDeclarations;
|
return outputDeclarations;
|
||||||
}
|
}
|
||||||
if (decl.getFileLocation().getStartingLineNumber() >= methodPosition.getStartingLineNumber()) {
|
if (methodPosition != null
|
||||||
|
&& decl.getFileLocation().getStartingLineNumber() >= methodPosition.getStartingLineNumber()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (isMemberFunctionDeclaration(decl)) {
|
if (isMemberFunctionDeclaration(decl)) {
|
||||||
|
@ -176,7 +177,8 @@ public class MethodDefinitionInsertLocationFinder {
|
||||||
private static Collection<IASTSimpleDeclaration> getAllFollowingSimpleDeclarationsFromClass(
|
private static Collection<IASTSimpleDeclaration> getAllFollowingSimpleDeclarationsFromClass(
|
||||||
IASTDeclaration[] declarations, IASTFileLocation methodPosition, IProgressMonitor pm) {
|
IASTDeclaration[] declarations, IASTFileLocation methodPosition, IProgressMonitor pm) {
|
||||||
ArrayList<IASTSimpleDeclaration> outputDeclarations = new ArrayList<>();
|
ArrayList<IASTSimpleDeclaration> outputDeclarations = new ArrayList<>();
|
||||||
|
if (methodPosition == null)
|
||||||
|
return outputDeclarations;
|
||||||
if (declarations.length >= 0) {
|
if (declarations.length >= 0) {
|
||||||
for (IASTDeclaration decl : declarations) {
|
for (IASTDeclaration decl : declarations) {
|
||||||
if (pm != null && pm.isCanceled()) {
|
if (pm != null && pm.isCanceled()) {
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Pavel Marek
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Pavel Marek - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import org.eclipse.osgi.util.NLS;
|
||||||
|
|
||||||
|
final class Messages extends NLS {
|
||||||
|
public static String OverrideMethodsInputPage_Name;
|
||||||
|
public static String OverrideMethodsInputPage_Header;
|
||||||
|
public static String OverrideMethodsInputPage_SelectAll;
|
||||||
|
public static String OverrideMethodsInputPage_DeselectAll;
|
||||||
|
public static String OverrideMethodsRefactoring_SelNotInClass;
|
||||||
|
public static String OverrideMethodsRefactoring_NoMethods;
|
||||||
|
public static String OverrideMethodsRefactoring_PreserveVirtual;
|
||||||
|
public static String OverrideMethodsRefactoring_AddOverride;
|
||||||
|
public static String OverrideMethodsRefactoring_LinkDescription;
|
||||||
|
public static String OverrideMethodsRefactoring_LinkTooltip;
|
||||||
|
public static String OverrideMethods_label;
|
||||||
|
|
||||||
|
static {
|
||||||
|
NLS.initializeMessages(Messages.class.getName(), Messages.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not instantiate
|
||||||
|
private Messages() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
###############################################################################
|
||||||
|
# Copyright (c) 2019 Marco Stornelli
|
||||||
|
#
|
||||||
|
# This program and the accompanying materials
|
||||||
|
# are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
# which accompanies this distribution, and is available at
|
||||||
|
# https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: EPL-2.0
|
||||||
|
#
|
||||||
|
###############################################################################
|
||||||
|
OverrideMethodsInputPage_Name=Override Methods
|
||||||
|
OverrideMethodsInputPage_Header=Select methods to override:
|
||||||
|
OverrideMethodsInputPage_SelectAll=Select All
|
||||||
|
OverrideMethodsInputPage_DeselectAll=Deselect All
|
||||||
|
OverrideMethodsRefactoring_SelNotInClass=Selection not inside class.
|
||||||
|
OverrideMethodsRefactoring_NoMethods=No methods to override.
|
||||||
|
OverrideMethodsRefactoring_PreserveVirtual=Preserve 'virtual' keyword
|
||||||
|
OverrideMethodsRefactoring_AddOverride=Add 'override' keyword
|
||||||
|
OverrideMethodsRefactoring_LinkDescription=The options may be configured on the <a>Code Style</a> preference page.
|
||||||
|
OverrideMethodsRefactoring_LinkTooltip=Show the code style preferences.
|
||||||
|
OverrideMethods_label=Override Methods...
|
|
@ -0,0 +1,197 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Pavel Marek
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Pavel Marek - initial API and implementation
|
||||||
|
* Marco Stornelli - Improvements
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.INodeFactory;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVirtSpecifier.SpecifierKind;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNodeFactory;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter;
|
||||||
|
import org.eclipse.cdt.core.dom.rewrite.DeclarationGenerator;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.CRefactoringContext;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.utils.DefinitionFinder;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.OperationCanceledException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for ICPPMethod
|
||||||
|
*/
|
||||||
|
public class Method {
|
||||||
|
private IASTDeclSpecifier fDeclSpecifier;
|
||||||
|
private ICPPMethod fMethod;
|
||||||
|
private OverrideOptions fOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts only methods declared as virtual.
|
||||||
|
* @param method The ICPPMethod to be wrapped
|
||||||
|
* @param declSpecifier The class declaration specifier
|
||||||
|
* @param options Override options
|
||||||
|
*/
|
||||||
|
public Method(ICPPMethod method, IASTDeclSpecifier declSpecifier, OverrideOptions options) {
|
||||||
|
fMethod = method;
|
||||||
|
fOptions = options;
|
||||||
|
fDeclSpecifier = declSpecifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts only methods declared as virtual.
|
||||||
|
* @param method The ICPPMethod to be wrapped
|
||||||
|
* @param options Override options
|
||||||
|
*/
|
||||||
|
public Method(ICPPMethod method, OverrideOptions options) {
|
||||||
|
fMethod = method;
|
||||||
|
fOptions = options;
|
||||||
|
fDeclSpecifier = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two methods are considered equal if they have same signature ie. name
|
||||||
|
* and types of parameters in same order.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
stringBuilder.append(fMethod.getName());
|
||||||
|
for (ICPPParameter parameter : fMethod.getParameters()) {
|
||||||
|
stringBuilder.append(parameter.getType());
|
||||||
|
|
||||||
|
}
|
||||||
|
return stringBuilder.toString().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return this.hashCode() == o.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the wrapped method
|
||||||
|
* @return The method
|
||||||
|
*/
|
||||||
|
public ICPPMethod getMethod() {
|
||||||
|
return fMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts only methods declared as virtual.
|
||||||
|
* @param fMethod
|
||||||
|
*/
|
||||||
|
public void setMethod(ICPPMethod fMethod) {
|
||||||
|
this.fMethod = fMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return fMethod.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the class declaration specifier
|
||||||
|
* @return The class declaration specifier
|
||||||
|
*/
|
||||||
|
public IASTDeclSpecifier getDeclSpecifier() {
|
||||||
|
return fDeclSpecifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a IASTNode for this method
|
||||||
|
* @param context The refactoring context
|
||||||
|
* @return The IASTNode for the method declaration
|
||||||
|
* @throws OperationCanceledException
|
||||||
|
* @throws CoreException
|
||||||
|
*/
|
||||||
|
public IASTNode createNode(CRefactoringContext context) throws OperationCanceledException, CoreException {
|
||||||
|
ICPPFunctionType functionType = fMethod.getDeclaredType();
|
||||||
|
ICPPParameter[] parameters = fMethod.getParameters();
|
||||||
|
IASTName declaration = DefinitionFinder.getMemberDeclaration(fMethod, getDeclSpecifier().getTranslationUnit(),
|
||||||
|
context, null);
|
||||||
|
INodeFactory factory = getDeclSpecifier().getTranslationUnit().getASTNodeFactory();
|
||||||
|
DeclarationGenerator declGen = DeclarationGenerator.create(factory);
|
||||||
|
if (declaration == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
IASTDeclarator declarator = (IASTDeclarator) declaration.getParent();
|
||||||
|
IASTNode parent = declarator.getParent();
|
||||||
|
if (!(parent instanceof IASTSimpleDeclaration))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We can't just copy the original nodes here but we need to create a new node. We can't do it
|
||||||
|
* because the original node could lack some information needed in the clone. Example: the node
|
||||||
|
* in parent has a parameter to an object inside a namespace but namespace miss because the interface
|
||||||
|
* class is declared in the same namespace too, but in this case the new method of child class may needs
|
||||||
|
* of fully qualified name for the parameter, so a plain copy doesn't work.
|
||||||
|
*/
|
||||||
|
IASTStandardFunctionDeclarator newDeclarator = factory.newFunctionDeclarator(declarator.getName().copy());
|
||||||
|
IASTDeclSpecifier newDeclSpec = declGen.createDeclSpecFromType(functionType);
|
||||||
|
if (newDeclSpec instanceof ICPPASTDeclSpecifier && fOptions.preserveVirtual()) {
|
||||||
|
((ICPPASTDeclSpecifier) newDeclSpec).setVirtual(true);
|
||||||
|
}
|
||||||
|
IASTSimpleDeclaration simple = factory.newSimpleDeclaration(newDeclSpec);
|
||||||
|
if (newDeclarator instanceof ICPPASTFunctionDeclarator) {
|
||||||
|
ICPPASTFunctionDeclarator funcDeclarator = (ICPPASTFunctionDeclarator) newDeclarator;
|
||||||
|
funcDeclarator.setPureVirtual(false);
|
||||||
|
funcDeclarator.setConst(functionType.isConst());
|
||||||
|
if (fOptions.addOverride()) {
|
||||||
|
funcDeclarator.addVirtSpecifier(((ICPPNodeFactory) factory).newVirtSpecifier(SpecifierKind.Override));
|
||||||
|
}
|
||||||
|
for (ICPPParameter par : parameters) {
|
||||||
|
IASTDeclarator parDeclarator = declGen.createDeclaratorFromType(par.getType(),
|
||||||
|
par.getName().toCharArray());
|
||||||
|
IASTDeclSpecifier parSpecifier = declGen.createDeclSpecFromType(par.getType());
|
||||||
|
IASTParameterDeclaration parameter = factory.newParameterDeclaration(parSpecifier, parDeclarator);
|
||||||
|
funcDeclarator.addParameterDeclaration(parameter);
|
||||||
|
}
|
||||||
|
for (IASTPointerOperator op : declarator.getPointerOperators())
|
||||||
|
funcDeclarator.addPointerOperator(op.copy());
|
||||||
|
if (declarator instanceof ICPPASTFunctionDeclarator) {
|
||||||
|
ICPPASTFunctionDeclarator orig = (ICPPASTFunctionDeclarator) declarator;
|
||||||
|
funcDeclarator.setRefQualifier(orig.getRefQualifier());
|
||||||
|
IASTTypeId[] typesId = orig.getExceptionSpecification();
|
||||||
|
if (typesId == IASTTypeId.EMPTY_TYPEID_ARRAY)
|
||||||
|
funcDeclarator.setEmptyExceptionSpecification();
|
||||||
|
else {
|
||||||
|
for (IASTTypeId typeId : typesId) {
|
||||||
|
funcDeclarator.addExceptionSpecificationTypeId(typeId == null ? null : typeId.copy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ICPPASTExpression noexceptExpression = orig.getNoexceptExpression();
|
||||||
|
if (noexceptExpression != null) {
|
||||||
|
funcDeclarator.setNoexceptExpression(
|
||||||
|
noexceptExpression == ICPPASTFunctionDeclarator.NOEXCEPT_DEFAULT ? noexceptExpression
|
||||||
|
: (ICPPASTExpression) noexceptExpression.copy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
simple.addDeclarator(newDeclarator);
|
||||||
|
simple.setDeclSpecifier(newDeclSpec);
|
||||||
|
simple.setParent(getDeclSpecifier());
|
||||||
|
return simple;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Pavel Marek
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Pavel Marek - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual method collector invoked from {@link VirtualMethodsASTVisitor}.
|
||||||
|
* @author Pavel Marek
|
||||||
|
*/
|
||||||
|
public class MethodCollector {
|
||||||
|
/**
|
||||||
|
* Ignore virtual destructors.
|
||||||
|
* @param base
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private ICPPMethod[] virtualMethods(ICPPClassType clas) {
|
||||||
|
ArrayList<ICPPMethod> virtualMethods = new ArrayList<>();
|
||||||
|
|
||||||
|
ICPPMethod[] methods = clas.getDeclaredMethods();
|
||||||
|
// Traverse all methods and check for virtuality.
|
||||||
|
for (ICPPMethod method : methods) {
|
||||||
|
if (method.isVirtual() && !method.isDestructor() && !method.isFinal()) {
|
||||||
|
virtualMethods.add(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return virtualMethods.toArray(new ICPPMethod[virtualMethods.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ICPPClassType> getBaseClasses(ICPPClassType classType) {
|
||||||
|
List<ICPPClassType> baseClasses = new ArrayList<>();
|
||||||
|
|
||||||
|
ICPPBase[] bases = classType.getBases();
|
||||||
|
for (int i = 0; i < bases.length; i++) {
|
||||||
|
IBinding binding = bases[i].getBaseClass();
|
||||||
|
if (binding instanceof ICPPClassType) {
|
||||||
|
baseClasses.add((ICPPClassType) binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented with recursion.
|
||||||
|
* @param container
|
||||||
|
* @param classType
|
||||||
|
*/
|
||||||
|
private void fillContainerRecursion(VirtualMethodContainer container, ICPPClassType classType,
|
||||||
|
IASTDeclSpecifier declSpecifier) {
|
||||||
|
List<ICPPClassType> baseClasses = getBaseClasses(classType);
|
||||||
|
// Recursion base (at top base class).
|
||||||
|
if (baseClasses.size() == 0) {
|
||||||
|
container.addMethodsToClass(classType, virtualMethods(classType), declSpecifier);
|
||||||
|
} else {
|
||||||
|
for (ICPPClassType baseClass : baseClasses) {
|
||||||
|
// Recurse.
|
||||||
|
fillContainerRecursion(container, baseClass, declSpecifier);
|
||||||
|
}
|
||||||
|
// Add also virtual methods of this class.
|
||||||
|
container.addMethodsToClass(classType, virtualMethods(classType), declSpecifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just calls private method - this is to avoid storing virtual methods from
|
||||||
|
* the current class eg. the class that the refactoring was invoked from.
|
||||||
|
* @param container
|
||||||
|
* @param classType
|
||||||
|
*/
|
||||||
|
public void fillContainer(VirtualMethodContainer container, ICPPClassType classType,
|
||||||
|
IASTDeclSpecifier declSpecifier) {
|
||||||
|
List<ICPPClassType> baseClasses = getBaseClasses(classType);
|
||||||
|
// Check if there are any base classes.
|
||||||
|
if (baseClasses.size() != 0) {
|
||||||
|
for (ICPPClassType baseClass : baseClasses) {
|
||||||
|
// Recurse.
|
||||||
|
fillContainerRecursion(container, baseClass, declSpecifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Pavel Marek
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Pavel Marek - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.model.ICElement;
|
||||||
|
import org.eclipse.cdt.core.model.IWorkingCopy;
|
||||||
|
import org.eclipse.cdt.ui.refactoring.actions.RefactoringAction;
|
||||||
|
import org.eclipse.jface.text.ITextSelection;
|
||||||
|
import org.eclipse.jface.window.IShellProvider;
|
||||||
|
import org.eclipse.ui.IEditorPart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @noextend This class is not intended to be subclassed by clients.
|
||||||
|
*/
|
||||||
|
public class OverrideMethodsAction extends RefactoringAction {
|
||||||
|
|
||||||
|
public OverrideMethodsAction() {
|
||||||
|
super(Messages.OverrideMethods_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverrideMethodsAction(IEditorPart editor) {
|
||||||
|
this();
|
||||||
|
setEditor(editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(IShellProvider shellProvider, IWorkingCopy wc, ITextSelection selection) {
|
||||||
|
if (wc.getResource() != null) {
|
||||||
|
new OverrideMethodsRefactoringRunner(wc, selection, shellProvider, wc.getCProject()).run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(IShellProvider shellProvider, ICElement elem) {
|
||||||
|
new OverrideMethodsRefactoringRunner(elem, null, shellProvider, elem.getCProject()).run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateSelection(ICElement elem) {
|
||||||
|
super.updateSelection(elem);
|
||||||
|
if (elem != null && elem.getElementType() != ICElement.C_CLASS) {
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Pavel Marek
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Pavel Marek - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
|
import org.eclipse.cdt.internal.ui.preferences.CodeStylePreferencePage;
|
||||||
|
import org.eclipse.jface.viewers.CheckStateChangedEvent;
|
||||||
|
import org.eclipse.jface.viewers.CheckboxTreeViewer;
|
||||||
|
import org.eclipse.jface.viewers.ICheckStateListener;
|
||||||
|
import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
|
||||||
|
import org.eclipse.swt.SWT;
|
||||||
|
import org.eclipse.swt.events.SelectionAdapter;
|
||||||
|
import org.eclipse.swt.events.SelectionEvent;
|
||||||
|
import org.eclipse.swt.layout.FillLayout;
|
||||||
|
import org.eclipse.swt.layout.GridData;
|
||||||
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
|
import org.eclipse.swt.widgets.Button;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Link;
|
||||||
|
import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer;
|
||||||
|
import org.eclipse.ui.dialogs.PreferencesUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents the only InputPage of the wizard for this code generation
|
||||||
|
* @author Pavel Marek
|
||||||
|
*/
|
||||||
|
public class OverrideMethodsInputPage extends UserInputWizardPage {
|
||||||
|
private OverrideMethodsRefactoring fRefactoring;
|
||||||
|
private CheckboxTreeViewer fTree;
|
||||||
|
|
||||||
|
public OverrideMethodsInputPage(OverrideMethodsRefactoring refactoring) {
|
||||||
|
super(Messages.OverrideMethodsInputPage_Name);
|
||||||
|
this.fRefactoring = refactoring;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds "Select All" and "Deselect All" to given Composite.
|
||||||
|
* @param parent
|
||||||
|
*/
|
||||||
|
private Composite createButtons(Composite parent) {
|
||||||
|
Composite buttonComposite = new Composite(parent, SWT.NONE);
|
||||||
|
FillLayout layout = new FillLayout(SWT.VERTICAL);
|
||||||
|
layout.spacing = 4;
|
||||||
|
buttonComposite.setLayout(layout);
|
||||||
|
|
||||||
|
Button selAllButton = new Button(buttonComposite, SWT.PUSH);
|
||||||
|
selAllButton.setText(Messages.OverrideMethodsInputPage_SelectAll);
|
||||||
|
selAllButton.addSelectionListener(new SelectionAdapter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
List<Method> allMethods = fRefactoring.getMethodContainer().getAllMethods();
|
||||||
|
|
||||||
|
// Add all methods from container to PrintData.
|
||||||
|
fTree.setCheckedElements(allMethods.toArray());
|
||||||
|
fRefactoring.getPrintData().addMethods(allMethods);
|
||||||
|
checkPageComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
Button deselAllButton = new Button(buttonComposite, SWT.PUSH);
|
||||||
|
deselAllButton.setText(Messages.OverrideMethodsInputPage_DeselectAll);
|
||||||
|
deselAllButton.addSelectionListener(new SelectionAdapter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
List<Method> allMethods = fRefactoring.getMethodContainer().getAllMethods();
|
||||||
|
|
||||||
|
// Uncheck all methods from tree.
|
||||||
|
for (Method method : allMethods) {
|
||||||
|
fTree.setChecked(method, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fRefactoring.getPrintData().removeMethods(allMethods);
|
||||||
|
checkPageComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
return buttonComposite;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTree(Composite parent) {
|
||||||
|
fTree = new ContainerCheckedTreeViewer(parent);
|
||||||
|
fTree.setContentProvider(fRefactoring.getMethodContainer());
|
||||||
|
fTree.setAutoExpandLevel(3);
|
||||||
|
// Populate the tree.
|
||||||
|
fTree.setInput(fRefactoring.getMethodContainer().getInitialInput());
|
||||||
|
// Horizontal fill.
|
||||||
|
fTree.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
|
||||||
|
|
||||||
|
fTree.addCheckStateListener(new ICheckStateListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkStateChanged(CheckStateChangedEvent event) {
|
||||||
|
VirtualMethodPrintData printData = fRefactoring.getPrintData();
|
||||||
|
|
||||||
|
// ICPPClassType (parent) checked.
|
||||||
|
if (event.getElement() instanceof ICPPClassType) {
|
||||||
|
ICPPClassType parentClass = (ICPPClassType) event.getElement();
|
||||||
|
VirtualMethodContainer methodContainer = fRefactoring.getMethodContainer();
|
||||||
|
List<Method> selectedMethods = methodContainer.getMethods(parentClass);
|
||||||
|
|
||||||
|
// Add (or remove) all methods that are displayed as children in the tree
|
||||||
|
// to PrintData.
|
||||||
|
if (event.getChecked()) {
|
||||||
|
printData.addMethods(selectedMethods);
|
||||||
|
} else {
|
||||||
|
printData.removeMethods(selectedMethods);
|
||||||
|
}
|
||||||
|
} else if (event.getElement() instanceof Method) {
|
||||||
|
Method selectedMethod = (Method) event.getElement();
|
||||||
|
|
||||||
|
if (event.getChecked()) {
|
||||||
|
printData.addMethod(selectedMethod);
|
||||||
|
} else {
|
||||||
|
printData.removeMethod(selectedMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkPageComplete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set all nodes (Methods) in the tree to unchecked.
|
||||||
|
for (Method method : fRefactoring.getMethodContainer().getAllMethods()) {
|
||||||
|
fTree.setChecked(method, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createControl(Composite parent) {
|
||||||
|
setTitle(Messages.OverrideMethodsInputPage_Name);
|
||||||
|
setMessage(Messages.OverrideMethodsInputPage_Header);
|
||||||
|
|
||||||
|
Composite comp = new Composite(parent, SWT.NONE);
|
||||||
|
comp.setLayout(new GridLayout(2, false));
|
||||||
|
createTree(comp);
|
||||||
|
GridData gd = new GridData(GridData.FILL_BOTH);
|
||||||
|
fTree.getTree().setLayoutData(gd);
|
||||||
|
|
||||||
|
Composite buttonContainer = createButtons(comp);
|
||||||
|
gd = new GridData();
|
||||||
|
gd.verticalAlignment = SWT.TOP;
|
||||||
|
buttonContainer.setLayoutData(gd);
|
||||||
|
|
||||||
|
final Button ignoreVirtual = new Button(comp, SWT.CHECK);
|
||||||
|
gd = new GridData();
|
||||||
|
gd.horizontalSpan = 2;
|
||||||
|
gd.heightHint = 20;
|
||||||
|
ignoreVirtual.setLayoutData(gd);
|
||||||
|
ignoreVirtual.setText(Messages.OverrideMethodsRefactoring_PreserveVirtual);
|
||||||
|
ignoreVirtual.setSelection(fRefactoring.getOptions().preserveVirtual());
|
||||||
|
ignoreVirtual.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
fRefactoring.getOptions().setPreserveVirtual(ignoreVirtual.getSelection());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
final Button addOverridden = new Button(comp, SWT.CHECK);
|
||||||
|
gd = new GridData();
|
||||||
|
gd.horizontalSpan = 2;
|
||||||
|
gd.heightHint = 40;
|
||||||
|
addOverridden.setLayoutData(gd);
|
||||||
|
addOverridden.setText(Messages.OverrideMethodsRefactoring_AddOverride);
|
||||||
|
addOverridden.setSelection(fRefactoring.getOptions().addOverride());
|
||||||
|
addOverridden.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
fRefactoring.getOptions().setAddOverride(addOverridden.getSelection());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Link link = new Link(comp, SWT.WRAP);
|
||||||
|
link.setText(Messages.OverrideMethodsRefactoring_LinkDescription);
|
||||||
|
link.addSelectionListener(new SelectionAdapter() {
|
||||||
|
@Override
|
||||||
|
public void widgetSelected(SelectionEvent e) {
|
||||||
|
PreferencesUtil.createPreferenceDialogOn(getShell(), CodeStylePreferencePage.PREF_ID,
|
||||||
|
new String[] { CodeStylePreferencePage.PREF_ID }, null).open();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
link.setToolTipText(Messages.OverrideMethodsRefactoring_LinkTooltip);
|
||||||
|
|
||||||
|
gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||||
|
gd.grabExcessHorizontalSpace = true;
|
||||||
|
link.setLayoutData(gd);
|
||||||
|
|
||||||
|
checkPageComplete();
|
||||||
|
setControl(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets page complete under certain conditions.
|
||||||
|
*
|
||||||
|
* Note that if the page is complete, the "Preview" and "OK" buttons
|
||||||
|
* are enabled.
|
||||||
|
*/
|
||||||
|
private void checkPageComplete() {
|
||||||
|
if (fRefactoring.getPrintData().isEmpty()) {
|
||||||
|
setPageComplete(false);
|
||||||
|
} else {
|
||||||
|
setPageComplete(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Pavel Marek
|
||||||
|
* Copyright (c) 2019 Marco Stornelli
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Pavel Marek - initial API and implementation
|
||||||
|
* Marco Stornelli - Improvements
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.browser.TypeUtil;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
|
import org.eclipse.cdt.core.model.ICElement;
|
||||||
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.CRefactoring;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.implementmethod.ImplementMethodRefactoring;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
|
import org.eclipse.core.runtime.OperationCanceledException;
|
||||||
|
import org.eclipse.core.runtime.SubMonitor;
|
||||||
|
import org.eclipse.jface.text.ITextSelection;
|
||||||
|
import org.eclipse.jface.viewers.ISelection;
|
||||||
|
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
|
||||||
|
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
|
||||||
|
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This adds "Override Methods" functionality to Source context menu
|
||||||
|
* located both in main menu and as a pop-up menu in editor. User can select
|
||||||
|
* which virtual methods overrides from which classes should be generated.
|
||||||
|
* This code generation feature is supposed to be triggered mostly in header
|
||||||
|
* files. Every method is added under corresponding visibility label, in case
|
||||||
|
* when no labels are found, they are generated in order set in preferences.
|
||||||
|
* <p>
|
||||||
|
* Code of this contribution is inspired from "Generate getters and setters"
|
||||||
|
* code generation and "Extract constant" refactoring.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Steps of this refactoring are:
|
||||||
|
* 1) Initial conditions checking.
|
||||||
|
* The initial conditions are satisfied when
|
||||||
|
* the selection (cursor) is located inside a class definition, this class has
|
||||||
|
* some base classes, and there is at least one virtual method to override.
|
||||||
|
* During this step the {@link VirtualMethodASTVisitor} traverses the AST for
|
||||||
|
* the current file and finds the class that is selected. The binding for this
|
||||||
|
* class is resolved and from this binding all the informations about base
|
||||||
|
* classes and their virtual methods are gathered inside {@link VirtualMethodContainer}.
|
||||||
|
*
|
||||||
|
* 2) Method selection (dialog with user).
|
||||||
|
* {@link OverrideMethodsInputPage} represents the only <code>WizardInputPage</code>
|
||||||
|
* that this code generation consists of. This wizard looks similar to the wizard
|
||||||
|
* from "Generate getters and setters" - there is a <code>CheckBoxTreeView</code>
|
||||||
|
* where parent nodes represent base classes and children nodes represent their
|
||||||
|
* virtual methods.
|
||||||
|
* When one of items (virtual methods) is checked, the corresponding method
|
||||||
|
* is saved to {@link VirtualMethodPrintData}.
|
||||||
|
*
|
||||||
|
* 3) Collection of all changes.
|
||||||
|
* This step is handled just by {@link VirtualMethodPrintData} that adds
|
||||||
|
* selected methods inside class (rewrites the corresponding AST with the help
|
||||||
|
* of {@link org.eclipse.cdt.internal.ui.refactoring.ClassMemberInserter}).
|
||||||
|
*
|
||||||
|
* @author Pavel Marek
|
||||||
|
*/
|
||||||
|
public class OverrideMethodsRefactoring extends CRefactoring {
|
||||||
|
private VirtualMethodsASTVisitor fVirtualMethodVisitor;
|
||||||
|
private OverrideOptions fOptions;
|
||||||
|
private VirtualMethodContainer fMethodContainer;
|
||||||
|
private VirtualMethodPrintData fPrintData = new VirtualMethodPrintData();
|
||||||
|
private ImplementMethodRefactoring fImplementMethodRefactoring;
|
||||||
|
|
||||||
|
public VirtualMethodPrintData getPrintData() {
|
||||||
|
return fPrintData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VirtualMethodContainer getMethodContainer() {
|
||||||
|
return fMethodContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverrideMethodsRefactoring(ICElement element, ISelection selection, ICProject project) {
|
||||||
|
super(element, selection, project);
|
||||||
|
|
||||||
|
fOptions = new OverrideOptions(project);
|
||||||
|
fMethodContainer = new VirtualMethodContainer(fOptions);
|
||||||
|
fVirtualMethodVisitor = new VirtualMethodsASTVisitor((ITextSelection) selection, tu.getFile().getName(),
|
||||||
|
fMethodContainer, TypeUtil.getFullyQualifiedName(element).getFullyQualifiedName());
|
||||||
|
fImplementMethodRefactoring = new ImplementMethodRefactoring(element, selection, project);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RefactoringDescriptor getRefactoringDescriptor() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when preview button is pushed, that means that there is at least
|
||||||
|
* one modification.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void collectModifications(IProgressMonitor pm, ModificationCollector collector)
|
||||||
|
throws CoreException, OperationCanceledException {
|
||||||
|
List<IASTSimpleDeclaration> methods = fPrintData.rewriteAST(refactoringContext, collector,
|
||||||
|
fVirtualMethodVisitor);
|
||||||
|
fImplementMethodRefactoring.setContext(refactoringContext);
|
||||||
|
fImplementMethodRefactoring.collectModifications(pm, collector, methods, fPrintData.getParentOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes already overridden methods from VirtualMethodContainer.
|
||||||
|
* This method should be called after fVirtualMethodVisitor visited the ast,
|
||||||
|
* ie. fMethodContainer was filled.
|
||||||
|
*/
|
||||||
|
private void removeOverridenMethods() {
|
||||||
|
ICPPClassType classType = fVirtualMethodVisitor.getClassBinding();
|
||||||
|
|
||||||
|
// Remove all methods that are declared in this class.
|
||||||
|
for (ICPPMethod method : classType.getDeclaredMethods()) {
|
||||||
|
fMethodContainer.remove(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether selection is inside class.
|
||||||
|
* Also initializes fMethodContainer.
|
||||||
|
* @throws CoreException
|
||||||
|
* @throws OperationCanceledException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
|
||||||
|
throws CoreException, OperationCanceledException {
|
||||||
|
SubMonitor subMonitor = SubMonitor.convert(pm, 5);
|
||||||
|
RefactoringStatus status = super.checkInitialConditions(pm);
|
||||||
|
IASTTranslationUnit ast = getAST(tu, subMonitor.split(1));
|
||||||
|
|
||||||
|
// Find the class inside which has selection inside it.
|
||||||
|
fVirtualMethodVisitor.visitAst(ast);
|
||||||
|
subMonitor.worked(3);
|
||||||
|
|
||||||
|
if (fVirtualMethodVisitor.getClassNode() == null) {
|
||||||
|
status.addFatalError(Messages.OverrideMethodsRefactoring_SelNotInClass);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Discard methods that are already overridden from fMethodContainer.
|
||||||
|
removeOverridenMethods();
|
||||||
|
|
||||||
|
if (fMethodContainer.isEmpty()) {
|
||||||
|
status.addFatalError(Messages.OverrideMethodsRefactoring_NoMethods);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RefactoringStatus checkFinalConditions(IProgressMonitor subProgressMonitor,
|
||||||
|
CheckConditionsContext checkContext) throws CoreException, OperationCanceledException {
|
||||||
|
RefactoringStatus result = new RefactoringStatus();
|
||||||
|
fImplementMethodRefactoring.finalConditions(checkContext);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverrideOptions getOptions() {
|
||||||
|
return fOptions;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Pavel Marek
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Pavel Marek - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.model.ICElement;
|
||||||
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.RefactoringRunner;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.RefactoringSaveHelper;
|
||||||
|
import org.eclipse.jface.viewers.ISelection;
|
||||||
|
import org.eclipse.jface.window.IShellProvider;
|
||||||
|
|
||||||
|
public class OverrideMethodsRefactoringRunner extends RefactoringRunner {
|
||||||
|
|
||||||
|
public OverrideMethodsRefactoringRunner(ICElement element, ISelection selection, IShellProvider shellProvider,
|
||||||
|
ICProject cProject) {
|
||||||
|
super(element, selection, shellProvider, cProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
OverrideMethodsRefactoring refactoring = new OverrideMethodsRefactoring(element, selection, project);
|
||||||
|
OverrideMethodsWizard wizard = new OverrideMethodsWizard(refactoring);
|
||||||
|
run(wizard, refactoring, RefactoringSaveHelper.SAVE_REFACTORING);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Pavel Marek
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Pavel Marek - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.ui.CUIPlugin;
|
||||||
|
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
|
||||||
|
|
||||||
|
public class OverrideMethodsWizard extends RefactoringWizard {
|
||||||
|
private OverrideMethodsRefactoring refactoring;
|
||||||
|
|
||||||
|
public OverrideMethodsWizard(OverrideMethodsRefactoring refactoring) {
|
||||||
|
super(refactoring, DIALOG_BASED_USER_INTERFACE | PREVIEW_EXPAND_FIRST_NODE);
|
||||||
|
this.refactoring = refactoring;
|
||||||
|
setDefaultPageTitle(Messages.OverrideMethodsInputPage_Name);
|
||||||
|
setDialogSettings(CUIPlugin.getDefault().getDialogSettings());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addUserInputPages() {
|
||||||
|
addPage(new OverrideMethodsInputPage(refactoring));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2019 Marco Stornelli
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Marco Stornelli - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.CCorePreferenceConstants;
|
||||||
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
|
|
||||||
|
public class OverrideOptions {
|
||||||
|
|
||||||
|
private boolean fpreserveVirtual;
|
||||||
|
private boolean fAddOverride;
|
||||||
|
|
||||||
|
public OverrideOptions(ICProject project) {
|
||||||
|
fAddOverride = CCorePreferenceConstants.getPreference(CCorePreferenceConstants.ADD_OVERRIDE_KEYWORD, project,
|
||||||
|
CCorePreferenceConstants.DEFAULT_ADD_OVERRIDE_KEYWORD);
|
||||||
|
fpreserveVirtual = CCorePreferenceConstants.getPreference(CCorePreferenceConstants.PRESERVE_VIRTUAL_KEYWORD,
|
||||||
|
project, CCorePreferenceConstants.DEFAULT_PRESERVE_VIRTUAL_KEYWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean preserveVirtual() {
|
||||||
|
return fpreserveVirtual;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPreserveVirtual(boolean preserveVirtual) {
|
||||||
|
this.fpreserveVirtual = preserveVirtual;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addOverride() {
|
||||||
|
return fAddOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddOverride(boolean addOverride) {
|
||||||
|
this.fAddOverride = addOverride;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Pavel Marek
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Pavel Marek - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
|
import org.eclipse.jface.viewers.ITreeContentProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container for virtual methods collected by {@link VirtualMethodsASTVisitor}.
|
||||||
|
* Also serves as content provider for <code>CheckBoxTree</code> in wizard.
|
||||||
|
*/
|
||||||
|
public class VirtualMethodContainer implements ITreeContentProvider {
|
||||||
|
private Map<ICPPClassType, List<Method>> fData = new HashMap<>();
|
||||||
|
final private OverrideOptions fOptions;
|
||||||
|
|
||||||
|
public VirtualMethodContainer(OverrideOptions options) {
|
||||||
|
fOptions = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all parents (ICPPClassTypes).
|
||||||
|
* @param inputElement root element.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object[] getElements(Object inputElement) {
|
||||||
|
if (!(inputElement instanceof Map<?, ?>)) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return fData.keySet().toArray(new ICPPClassType[fData.keySet().size()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] getChildren(Object parentElement) {
|
||||||
|
return fData.get(parentElement).toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all virtual methods for given ICPPClassType.
|
||||||
|
* @param classType
|
||||||
|
*/
|
||||||
|
public List<Method> getMethods(ICPPClassType classType) {
|
||||||
|
return fData.get(classType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getParent(Object element) {
|
||||||
|
for (Entry<ICPPClassType, List<Method>> entry : fData.entrySet()) {
|
||||||
|
if (entry.getValue().contains(element)) {
|
||||||
|
return entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasChildren(Object element) {
|
||||||
|
List<Method> list = fData.get(element);
|
||||||
|
if (list == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return !list.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Method> getAllMethods() {
|
||||||
|
List<Method> allMethods = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Entry<ICPPClassType, List<Method>> entry : fData.entrySet()) {
|
||||||
|
allMethods.addAll(entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return allMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called to populate the tree viewer input, thats why
|
||||||
|
* it is not named "getData".
|
||||||
|
*/
|
||||||
|
public Map<ICPPClassType, List<Method>> getInitialInput() {
|
||||||
|
return fData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if given method is already contained in fData.
|
||||||
|
* @param method
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean isDuplicate(Method method) {
|
||||||
|
for (Entry<ICPPClassType, List<Method>> entry : fData.entrySet()) {
|
||||||
|
if (entry.getValue().contains(method)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds one method to a specified ICPPClassType.
|
||||||
|
* @param classType
|
||||||
|
* @param method
|
||||||
|
*/
|
||||||
|
private void addMethodToClass(ICPPClassType classType, Method method) {
|
||||||
|
if (!isDuplicate(method)) {
|
||||||
|
List<Method> methods = fData.get(classType);
|
||||||
|
if (methods == null) {
|
||||||
|
methods = new ArrayList<>();
|
||||||
|
fData.put(classType, methods);
|
||||||
|
}
|
||||||
|
methods.add(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMethodsToClass(ICPPClassType classType, ICPPMethod[] methods, IASTDeclSpecifier declSpecifier) {
|
||||||
|
for (ICPPMethod icppMethod : methods) {
|
||||||
|
addMethodToClass(classType, new Method(icppMethod, declSpecifier, fOptions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return fData.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(ICPPMethod method) {
|
||||||
|
// Search through all saved methods.
|
||||||
|
for (Map.Entry<ICPPClassType, List<Method>> entry : fData.entrySet()) {
|
||||||
|
List<Method> methods = entry.getValue();
|
||||||
|
|
||||||
|
if (methods.remove(new Method(method, fOptions))) {
|
||||||
|
// Check if classType (parent) is empty ie. if there are no
|
||||||
|
// methods to display.
|
||||||
|
if (methods.isEmpty()) {
|
||||||
|
fData.remove(entry.getKey());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,187 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Pavel Marek
|
||||||
|
* Copyright (c) 2019 Marco Stornelli
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Pavel Marek - initial API and implementation
|
||||||
|
* Marco Stornelli - Improvements
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.CRefactoringContext;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.ClassMemberInserter;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.utils.VisibilityEnum;
|
||||||
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
import org.eclipse.core.runtime.OperationCanceledException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds virtual member functions that should be printed (during
|
||||||
|
* <code> VirtualMethodRefactoring.collectModifications() </code>).
|
||||||
|
* @author mayfa
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class VirtualMethodPrintData {
|
||||||
|
private Set<Method> privateMethods = new HashSet<>();
|
||||||
|
private Set<Method> protectedMethods = new HashSet<>();
|
||||||
|
private Set<Method> publicMethods = new HashSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds one method to print.
|
||||||
|
* @param method
|
||||||
|
*/
|
||||||
|
public void addMethod(Method method) {
|
||||||
|
switch (method.getMethod().getVisibility()) {
|
||||||
|
case ICPPASTVisibilityLabel.v_public:
|
||||||
|
publicMethods.add(method);
|
||||||
|
break;
|
||||||
|
case ICPPASTVisibilityLabel.v_protected:
|
||||||
|
protectedMethods.add(method);
|
||||||
|
break;
|
||||||
|
case ICPPASTVisibilityLabel.v_private:
|
||||||
|
privateMethods.add(method);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called when ICPPClassType (parent) is selected in the
|
||||||
|
* tree and all its children are passed to this method.
|
||||||
|
* @param selectedMethods
|
||||||
|
*/
|
||||||
|
public void addMethods(List<Method> selectedMethods) {
|
||||||
|
for (Method method : selectedMethods) {
|
||||||
|
addMethod(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes one method from (further) printing.
|
||||||
|
* @param method
|
||||||
|
*/
|
||||||
|
public void removeMethod(Method method) {
|
||||||
|
switch (method.getMethod().getVisibility()) {
|
||||||
|
case ICPPASTVisibilityLabel.v_public:
|
||||||
|
publicMethods.remove(method);
|
||||||
|
break;
|
||||||
|
case ICPPASTVisibilityLabel.v_protected:
|
||||||
|
protectedMethods.remove(method);
|
||||||
|
break;
|
||||||
|
case ICPPASTVisibilityLabel.v_private:
|
||||||
|
privateMethods.remove(method);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMethods(List<Method> selectedMethods) {
|
||||||
|
for (Method method : selectedMethods) {
|
||||||
|
removeMethod(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return privateMethods.isEmpty() && protectedMethods.isEmpty() && publicMethods.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses all given methods.
|
||||||
|
* @param methods
|
||||||
|
* @return
|
||||||
|
* @throws CoreException
|
||||||
|
* @throws OperationCanceledException
|
||||||
|
*/
|
||||||
|
private List<IASTNode> parseAllMethods(CRefactoringContext context, Set<Method> methods)
|
||||||
|
throws OperationCanceledException, CoreException {
|
||||||
|
List<IASTNode> methodNodes = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Method method : methods) {
|
||||||
|
IASTNode n = method.createNode(context);
|
||||||
|
if (n != null)
|
||||||
|
methodNodes.add(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return methodNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the parent offset. Since every method has a reference to the
|
||||||
|
* same declaration specifier AST node, we can get the value just from
|
||||||
|
* the first one.
|
||||||
|
* @param s The set of methods
|
||||||
|
* @return The parent node offset
|
||||||
|
*/
|
||||||
|
private static int getParentOffset(Set<Method> s) {
|
||||||
|
if (!s.isEmpty()) {
|
||||||
|
Method m = s.iterator().next();
|
||||||
|
return m.getDeclSpecifier().getFileLocation().getNodeOffset();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It gets the node offset of the parent, i.e. the class which contains
|
||||||
|
* the methods.
|
||||||
|
* @return Negative number if offset can't be found, >= 0 otherwise
|
||||||
|
*/
|
||||||
|
public int getParentOffset() {
|
||||||
|
int res = getParentOffset(publicMethods);
|
||||||
|
if (res >= 0)
|
||||||
|
return res;
|
||||||
|
res = getParentOffset(protectedMethods);
|
||||||
|
if (res >= 0)
|
||||||
|
return res;
|
||||||
|
res = getParentOffset(privateMethods);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rewrites all the changes.
|
||||||
|
* @throws CoreException
|
||||||
|
* @throws OperationCanceledException
|
||||||
|
*/
|
||||||
|
public List<IASTSimpleDeclaration> rewriteAST(CRefactoringContext context, ModificationCollector collector,
|
||||||
|
VirtualMethodsASTVisitor visitor) throws OperationCanceledException, CoreException {
|
||||||
|
ICPPASTCompositeTypeSpecifier classNode = (ICPPASTCompositeTypeSpecifier) visitor.getClassNode();
|
||||||
|
List<IASTNode> methodNodes = new ArrayList<>();
|
||||||
|
List<IASTSimpleDeclaration> result = new ArrayList<>();
|
||||||
|
|
||||||
|
methodNodes = parseAllMethods(context, publicMethods);
|
||||||
|
if (!methodNodes.isEmpty()) {
|
||||||
|
result.addAll(methodNodes.stream().map(e -> (IASTSimpleDeclaration) e).collect(Collectors.toList()));
|
||||||
|
// Add all public methods to classNode.
|
||||||
|
ClassMemberInserter.createChange(classNode, VisibilityEnum.v_public, methodNodes, true, collector);
|
||||||
|
}
|
||||||
|
|
||||||
|
methodNodes = parseAllMethods(context, protectedMethods);
|
||||||
|
if (!methodNodes.isEmpty()) {
|
||||||
|
result.addAll(methodNodes.stream().map(e -> (IASTSimpleDeclaration) e).collect(Collectors.toList()));
|
||||||
|
// Add all protected methods to classNode.
|
||||||
|
ClassMemberInserter.createChange(classNode, VisibilityEnum.v_protected, methodNodes, true, collector);
|
||||||
|
}
|
||||||
|
|
||||||
|
methodNodes = parseAllMethods(context, privateMethods);
|
||||||
|
if (!methodNodes.isEmpty()) {
|
||||||
|
result.addAll(methodNodes.stream().map(e -> (IASTSimpleDeclaration) e).collect(Collectors.toList()));
|
||||||
|
// Add all private methods to classNode.
|
||||||
|
ClassMemberInserter.createChange(classNode, VisibilityEnum.v_private, methodNodes, true, collector);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2017 Pavel Marek
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials
|
||||||
|
* are made available under the terms of the Eclipse Public License 2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* https://www.eclipse.org/legal/epl-2.0/
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Pavel Marek - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.browser.IQualifiedTypeName;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||||
|
import org.eclipse.cdt.ui.CUIPlugin;
|
||||||
|
import org.eclipse.jface.text.ITextSelection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits the class definition inside which the selection (cursor) is located.
|
||||||
|
* Gets binding for this class, and from this binding all other necessary
|
||||||
|
* informations are gathered inside fMethodContainer.
|
||||||
|
*/
|
||||||
|
public class VirtualMethodsASTVisitor extends ASTVisitor {
|
||||||
|
private ITextSelection fSelection;
|
||||||
|
private String fFileName;
|
||||||
|
private VirtualMethodContainer fMethodContainer;
|
||||||
|
private IASTNode fClassNode;
|
||||||
|
private String fClassName;
|
||||||
|
private ICPPClassType fClassBinding;
|
||||||
|
private String fElementName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param textSelection
|
||||||
|
* @param fileName
|
||||||
|
* @param methodContainer the VirtualMethodContainer to be filled by this
|
||||||
|
* visitor.
|
||||||
|
*/
|
||||||
|
public VirtualMethodsASTVisitor(ITextSelection textSelection, String fileName,
|
||||||
|
VirtualMethodContainer methodContainer, String elName) {
|
||||||
|
// Visit only decl specifier.
|
||||||
|
shouldVisitDeclSpecifiers = true;
|
||||||
|
|
||||||
|
this.fClassNode = null;
|
||||||
|
this.fSelection = textSelection;
|
||||||
|
this.fFileName = fileName;
|
||||||
|
this.fMethodContainer = methodContainer;
|
||||||
|
this.fElementName = elName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public VirtualMethodContainer getVirtualMethodContainer() {
|
||||||
|
return fMethodContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns class node encapsulating text selection.
|
||||||
|
* @return null if no class was encountered, IASTNode otherwise.
|
||||||
|
*/
|
||||||
|
public IASTNode getClassNode() {
|
||||||
|
return fClassNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassName() {
|
||||||
|
return fClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICPPClassType getClassBinding() {
|
||||||
|
return fClassBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if node is enclosing text selection.
|
||||||
|
* @param node
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean isInsideSelection(ICPPASTCompositeTypeSpecifier node) {
|
||||||
|
IASTFileLocation location = node.getFileLocation();
|
||||||
|
|
||||||
|
// node has no location if it is for example built-in macro
|
||||||
|
if (location == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fSelection == null) {
|
||||||
|
IBinding binding = node.getName().resolveBinding();
|
||||||
|
if (!(binding instanceof ICPPBinding))
|
||||||
|
return false;
|
||||||
|
try {
|
||||||
|
String elName = String.join(IQualifiedTypeName.QUALIFIER, ((ICPPBinding) binding).getQualifiedName());
|
||||||
|
if (elName.equals(fElementName))
|
||||||
|
return true;
|
||||||
|
} catch (DOMException e) {
|
||||||
|
CUIPlugin.log(e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location.getNodeOffset() <= fSelection.getOffset()
|
||||||
|
&& fSelection.getOffset() <= location.getNodeOffset() + location.getNodeLength()
|
||||||
|
&& location.getFileName().contains(fFileName)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitAst(IASTTranslationUnit ast) {
|
||||||
|
ast.accept(this);
|
||||||
|
if (fClassNode != null) {
|
||||||
|
MethodCollector methodCollector = new MethodCollector();
|
||||||
|
methodCollector.fillContainer(fMethodContainer, fClassBinding, (IASTDeclSpecifier) fClassNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int visit(IASTDeclSpecifier declSpecifier) {
|
||||||
|
// In a class or struct
|
||||||
|
if (declSpecifier instanceof ICPPASTCompositeTypeSpecifier) {
|
||||||
|
/*
|
||||||
|
* Check if this class is enclosing text selection and go ahead,
|
||||||
|
* we could hit the selection but there's a nested class so we need
|
||||||
|
* to process the most inner node with selection at the end of tree visit.
|
||||||
|
*/
|
||||||
|
if (isInsideSelection((ICPPASTCompositeTypeSpecifier) declSpecifier)) {
|
||||||
|
|
||||||
|
// Store.
|
||||||
|
fClassNode = declSpecifier;
|
||||||
|
|
||||||
|
// Get binding.
|
||||||
|
ICPPASTCompositeTypeSpecifier typeSpec = (ICPPASTCompositeTypeSpecifier) declSpecifier;
|
||||||
|
IBinding binding = typeSpec.getName().getBinding();
|
||||||
|
|
||||||
|
// Check if the binding is of class type.
|
||||||
|
if (!(binding instanceof ICPPClassType)) {
|
||||||
|
fClassNode = null;
|
||||||
|
return PROCESS_CONTINUE;
|
||||||
|
}
|
||||||
|
// Store class namegetRecursivelyAllBases
|
||||||
|
fClassName = binding.getName();
|
||||||
|
|
||||||
|
ICPPClassType classType = (ICPPClassType) binding;
|
||||||
|
fClassBinding = classType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PROCESS_CONTINUE;
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ import org.eclipse.cdt.internal.ui.editor.CEditor;
|
||||||
import org.eclipse.cdt.internal.ui.editor.ICEditorActionDefinitionIds;
|
import org.eclipse.cdt.internal.ui.editor.ICEditorActionDefinitionIds;
|
||||||
import org.eclipse.cdt.internal.ui.editor.OrganizeIncludesAction;
|
import org.eclipse.cdt.internal.ui.editor.OrganizeIncludesAction;
|
||||||
import org.eclipse.cdt.internal.ui.editor.SortLinesAction;
|
import org.eclipse.cdt.internal.ui.editor.SortLinesAction;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.overridemethods.OverrideMethodsAction;
|
||||||
import org.eclipse.cdt.ui.refactoring.actions.GettersAndSettersAction;
|
import org.eclipse.cdt.ui.refactoring.actions.GettersAndSettersAction;
|
||||||
import org.eclipse.cdt.ui.refactoring.actions.ImplementMethodAction;
|
import org.eclipse.cdt.ui.refactoring.actions.ImplementMethodAction;
|
||||||
import org.eclipse.cdt.ui.refactoring.actions.RefactoringAction;
|
import org.eclipse.cdt.ui.refactoring.actions.RefactoringAction;
|
||||||
|
@ -118,7 +119,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
private List<RefactoringAction> fRefactorActions = new ArrayList<>();
|
private List<RefactoringAction> fRefactorActions = new ArrayList<>();
|
||||||
|
|
||||||
private AddIncludeAction fAddInclude;
|
private AddIncludeAction fAddInclude;
|
||||||
// private OverrideMethodsAction fOverrideMethods;
|
private OverrideMethodsAction fOverrideMethods;
|
||||||
// private GenerateHashCodeEqualsAction fHashCodeEquals;
|
// private GenerateHashCodeEqualsAction fHashCodeEquals;
|
||||||
private GettersAndSettersAction fAddGetterSetter;
|
private GettersAndSettersAction fAddGetterSetter;
|
||||||
private ImplementMethodAction fImplementMethod;
|
private ImplementMethodAction fImplementMethod;
|
||||||
|
@ -178,9 +179,9 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
editor.setAction("CopyQualifiedName", fCopyQualifiedNameAction); //$NON-NLS-1$
|
editor.setAction("CopyQualifiedName", fCopyQualifiedNameAction); //$NON-NLS-1$
|
||||||
editor.markAsSelectionDependentAction("CopyQualifiedName", true); //$NON-NLS-1$
|
editor.markAsSelectionDependentAction("CopyQualifiedName", true); //$NON-NLS-1$
|
||||||
//
|
//
|
||||||
// fOverrideMethods= new OverrideMethodsAction(editor);
|
fOverrideMethods = new OverrideMethodsAction(editor);
|
||||||
// fOverrideMethods.setActionDefinitionId(ICEditorActionDefinitionIds.OVERRIDE_METHODS);
|
fOverrideMethods.setActionDefinitionId(ICEditorActionDefinitionIds.OVERRIDE_METHODS);
|
||||||
// editor.setAction("OverrideMethods", fOverrideMethods); //$NON-NLS-1$
|
editor.setAction("OverrideMethods", fOverrideMethods); //$NON-NLS-1$
|
||||||
//
|
//
|
||||||
fAddGetterSetter = new GettersAndSettersAction(editor);
|
fAddGetterSetter = new GettersAndSettersAction(editor);
|
||||||
fAddGetterSetter.setActionDefinitionId(ICEditorActionDefinitionIds.GETTERS_AND_SETTERS);
|
fAddGetterSetter.setActionDefinitionId(ICEditorActionDefinitionIds.GETTERS_AND_SETTERS);
|
||||||
|
@ -263,9 +264,11 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
fSelectionProvider = selectionProvider == null ? fSite.getSelectionProvider() : selectionProvider;
|
fSelectionProvider = selectionProvider == null ? fSite.getSelectionProvider() : selectionProvider;
|
||||||
ISelection selection = fSelectionProvider.getSelection();
|
ISelection selection = fSelectionProvider.getSelection();
|
||||||
|
|
||||||
// fOverrideMethods= new OverrideMethodsAction(site);
|
fOverrideMethods = new OverrideMethodsAction();
|
||||||
// fOverrideMethods.setActionDefinitionId(ICEditorActionDefinitionIds.OVERRIDE_METHODS);
|
fOverrideMethods.setActionDefinitionId(ICEditorActionDefinitionIds.OVERRIDE_METHODS);
|
||||||
//
|
fOverrideMethods.setSite(fSite);
|
||||||
|
fRefactorActions.add(fOverrideMethods);
|
||||||
|
|
||||||
fAddGetterSetter = new GettersAndSettersAction();
|
fAddGetterSetter = new GettersAndSettersAction();
|
||||||
fAddGetterSetter.setActionDefinitionId(ICEditorActionDefinitionIds.GETTERS_AND_SETTERS);
|
fAddGetterSetter.setActionDefinitionId(ICEditorActionDefinitionIds.GETTERS_AND_SETTERS);
|
||||||
fAddGetterSetter.setSite(fSite);
|
fAddGetterSetter.setSite(fSite);
|
||||||
|
@ -314,7 +317,6 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
// fCleanUp= new CleanUpAction(site);
|
// fCleanUp= new CleanUpAction(site);
|
||||||
// fCleanUp.setActionDefinitionId(ICEditorActionDefinitionIds.CLEAN_UP);
|
// fCleanUp.setActionDefinitionId(ICEditorActionDefinitionIds.CLEAN_UP);
|
||||||
|
|
||||||
// fOverrideMethods.update(selection);
|
|
||||||
// fAddDelegateMethods.update(selection);
|
// fAddDelegateMethods.update(selection);
|
||||||
// fAddUnimplementedConstructors.update(selection);
|
// fAddUnimplementedConstructors.update(selection);
|
||||||
// fGenerateConstructorUsingFields.update(selection);
|
// fGenerateConstructorUsingFields.update(selection);
|
||||||
|
@ -335,7 +337,6 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
fAddTaskAction.setEnabled(false);
|
fAddTaskAction.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// registerSelectionListener(fSelectionProvider, fOverrideMethods);
|
|
||||||
// registerSelectionListener(fSelectionProvider, fAddDelegateMethods);
|
// registerSelectionListener(fSelectionProvider, fAddDelegateMethods);
|
||||||
// registerSelectionListener(fSelectionProvider, fAddUnimplementedConstructors);
|
// registerSelectionListener(fSelectionProvider, fAddUnimplementedConstructors);
|
||||||
// registerSelectionListener(fSelectionProvider, fGenerateConstructorUsingFields);
|
// registerSelectionListener(fSelectionProvider, fGenerateConstructorUsingFields);
|
||||||
|
@ -442,7 +443,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
added += addAction(source, fSortLines);
|
added += addAction(source, fSortLines);
|
||||||
// added+= addAction(source, fCleanUp);
|
// added+= addAction(source, fCleanUp);
|
||||||
source.add(new Separator(GROUP_GENERATE));
|
source.add(new Separator(GROUP_GENERATE));
|
||||||
// added+= addAction(source, fOverrideMethods);
|
added += addAction(source, fOverrideMethods);
|
||||||
added += addAction(source, fAddGetterSetter);
|
added += addAction(source, fAddGetterSetter);
|
||||||
added += addAction(source, fImplementMethod);
|
added += addAction(source, fImplementMethod);
|
||||||
// added+= addAction(source, fAddDelegateMethods);
|
// added+= addAction(source, fAddDelegateMethods);
|
||||||
|
@ -468,7 +469,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
// added+= addAction(source, fSortMembers);
|
// added+= addAction(source, fSortMembers);
|
||||||
// added+= addAction(source, fCleanUp);
|
// added+= addAction(source, fCleanUp);
|
||||||
source.add(new Separator(GROUP_GENERATE));
|
source.add(new Separator(GROUP_GENERATE));
|
||||||
// added+= addAction(source, fOverrideMethods);
|
added += addAction(source, fOverrideMethods);
|
||||||
added += addAction(source, fAddGetterSetter);
|
added += addAction(source, fAddGetterSetter);
|
||||||
added += addAction(source, fImplementMethod);
|
added += addAction(source, fImplementMethod);
|
||||||
// added+= addAction(source, fAddDelegateMethods);
|
// added+= addAction(source, fAddDelegateMethods);
|
||||||
|
@ -503,7 +504,7 @@ public class GenerateActionGroup extends ActionGroup implements ISelectionChange
|
||||||
|
|
||||||
private void setGlobalActionHandlers(IActionBars actionBar) {
|
private void setGlobalActionHandlers(IActionBars actionBar) {
|
||||||
actionBar.setGlobalActionHandler(CdtActionConstants.ADD_INCLUDE, fAddInclude);
|
actionBar.setGlobalActionHandler(CdtActionConstants.ADD_INCLUDE, fAddInclude);
|
||||||
// actionBar.setGlobalActionHandler(CdtActionConstants.OVERRIDE_METHODS, fOverrideMethods);
|
actionBar.setGlobalActionHandler(CdtActionConstants.OVERRIDE_METHODS, fOverrideMethods);
|
||||||
actionBar.setGlobalActionHandler(CdtActionConstants.GETTERS_AND_SETTERS, fAddGetterSetter);
|
actionBar.setGlobalActionHandler(CdtActionConstants.GETTERS_AND_SETTERS, fAddGetterSetter);
|
||||||
actionBar.setGlobalActionHandler(CdtActionConstants.IMPLEMENT_METHOD, fImplementMethod);
|
actionBar.setGlobalActionHandler(CdtActionConstants.IMPLEMENT_METHOD, fImplementMethod);
|
||||||
// actionBar.setGlobalActionHandler(CdtActionConstants.GENERATE_DELEGATE_METHODS, fAddDelegateMethods);
|
// actionBar.setGlobalActionHandler(CdtActionConstants.GENERATE_DELEGATE_METHODS, fAddDelegateMethods);
|
||||||
|
|
|
@ -25,6 +25,7 @@ class Messages extends NLS {
|
||||||
public static String ImplementMethodAction_label;
|
public static String ImplementMethodAction_label;
|
||||||
public static String GettersAndSetters_label;
|
public static String GettersAndSetters_label;
|
||||||
public static String ToggleFunctionAction_label;
|
public static String ToggleFunctionAction_label;
|
||||||
|
public static String OverrideMethods_label;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
NLS.initializeMessages(Messages.class.getName(), Messages.class);
|
NLS.initializeMessages(Messages.class.getName(), Messages.class);
|
||||||
|
|
Loading…
Add table
Reference in a new issue