1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Fixes for refactoring by Guido Zgraggen and Lukas Felber, bug 234783, 234786 and 234791.

This commit is contained in:
Markus Schorn 2008-05-30 11:13:33 +00:00
parent 1b0953a434
commit 7e1f9c87fc
26 changed files with 600 additions and 127 deletions

View file

@ -3098,3 +3098,48 @@ int HideMethod::methode2(){
return i; = //comment
=>trailing
=>freestanding
//!CommentRecognition Bug 234786
//#org.eclipse.cdt.core.parser.tests.rewrite.comenthandler.CommentHandlingTest
//@test.h
#ifndef HIDEMETHOD_H_
#define HIDEMETHOD_H_
class HideMethod {
public:
HideMethod();
virtual ~HideMethod();
int methode2();
private:
int i;
};
#endif /* HIDEMETHOD_H_ */
//=
=>leading
=>trailing
=>freestanding
//@test.cpp
#include "test.h"
HideMethod::HideMethod()
{
}
HideMethod::~HideMethod()
{
}
int HideMethod::methode2(){
i++; //comment
return i;
}
//=
=>leading
=>trailing
i++; = //comment
=>freestanding

View file

@ -45,7 +45,7 @@ public class ASTWriter {
/**
* Creates a <code>ASTWriter</code> that indents the code.
*
* @param givenIndentation The indention added to each line
* @param givenIndentation The indentation added to each line
*/
public ASTWriter(String givenIndentation) {
super();
@ -66,7 +66,7 @@ public class ASTWriter {
/**
*
* Genereates the source code representing this node including comments.
* Generates the source code representing this node including comments.
*
* @param rootNode Node to write.
* @param fileScope
@ -84,7 +84,6 @@ public class ASTWriter {
return str;
}
public void setModificationStore(ASTModificationStore modificationStore) {
this.modificationStore = modificationStore;

View file

@ -218,14 +218,27 @@ public class ASTWriterVisitor extends CPPASTVisitor {
writeLeadingComments((ASTNode) parameterDeclaration);
if(!macroHandler.checkisMacroExpansionNode(parameterDeclaration)) {
parameterDeclaration.getDeclSpecifier().accept(this);
IASTDeclarator declarator = parameterDeclaration.getDeclarator();
if(declarator.getName().toString().length() != 0){
IASTDeclarator declarator = getParameterDeclarator(parameterDeclaration);
if(getParameterName(declarator).toString().length() != 0){
scribe.printSpaces(1);
}
declarator.accept(this);
}
return ASTVisitor.PROCESS_SKIP;
}
protected IASTName getParameterName(IASTDeclarator declarator) {
return declarator.getName();
}
protected IASTDeclarator getParameterDeclarator(
IASTParameterDeclaration parameterDeclaration) {
return parameterDeclaration.getDeclarator();
}
@Override
public int visit(ICPPASTNamespaceDefinition namespace) {

View file

@ -129,9 +129,12 @@ public class ASTModificationHelper {
case REPLACE:
if(childModification.getNewNode() instanceof IASTInitializer){
return (IASTInitializer)childModification.getNewNode();
} else if (childModification.getNewNode() == null) {
return null;
}
throw new UnhandledASTModificationException(childModification);
case INSERT_BEFORE:
throw new UnhandledASTModificationException(childModification);

View file

@ -96,6 +96,34 @@ public class ChangeGeneratorWriterVisitor extends ASTWriterVisitor {
}
@Override
protected IASTDeclarator getParameterDeclarator(
IASTParameterDeclaration parameterDeclaration) {
IASTDeclarator newDecl = parameterDeclaration.getDeclarator();
if(stack.getModifiedNodes().contains(newDecl)){
for(ASTModification currentModification : stack.getModificationsForNode(newDecl)){
if(currentModification.getKind() == ASTModification.ModificationKind.REPLACE && currentModification.getTargetNode() == parameterDeclaration){
newDecl = (IASTDeclarator) currentModification.getNewNode();
}
}
}
return newDecl;
}
@Override
protected IASTName getParameterName(IASTDeclarator declarator) {
IASTName newName = declarator.getName();
if(stack.getModifiedNodes().contains(newName)){
for(ASTModification currentModification : stack.getModificationsForNode(newName)){
if(currentModification.getKind() == ASTModification.ModificationKind.REPLACE && currentModification.getTargetNode() == newName){
newName = (IASTName) currentModification.getNewNode();
}
}
}
return newName;
}
@Override
public int leave(ICPPASTBaseSpecifier specifier) {
super.leave(specifier);
@ -320,6 +348,7 @@ public class ChangeGeneratorWriterVisitor extends ASTWriterVisitor {
}
}
//Check all insert before and append modifications for the current node. If necessary put it onto the stack.
for (IASTNode currentModifiedNode : stack.getModifiedNodes()) {
for (ASTModification currentMod : stack.getModificationsForNode(currentModifiedNode)) {
if(currentMod.getNewNode() == node){
@ -330,6 +359,7 @@ public class ChangeGeneratorWriterVisitor extends ASTWriterVisitor {
}
}
}
//Check all replace modifications for the current node. Visit the replacing node if found.
for (IASTNode currentModifiedNode : stack.getModifiedNodes()) {
for (ASTModification currentMod : stack.getModificationsForNode(currentModifiedNode)) {
if(currentMod.getTargetNode() == node && currentMod.getKind() == ModificationKind.REPLACE){

View file

@ -102,7 +102,10 @@ public class ModificationScopeStack {
}
List<ASTModification> modForNodeList = new ArrayList<ASTModification>();
for (ASTModification modification : aktModList) {
modForNodeList.addAll(modStore.getNestedModifications(modification).getModificationsForNode(node));
ASTModificationMap nestedModifications = modStore.getNestedModifications(modification);
if(nestedModifications != null) {
modForNodeList.addAll(nestedModifications.getModificationsForNode(node));
}
}
return Collections.unmodifiableList(modForNodeList);
}

View file

@ -159,8 +159,13 @@ public class NodeCommenter {
int length = OffsetHelper.getNodeOffset(com)-OffsetHelper.getNodeEndPoint(node);
byte[] b = new byte[length];
is.skip(OffsetHelper.getNodeEndPoint(node));
is.read(b, 0, length);
long count = is.skip(OffsetHelper.getEndOffsetWithoutComments(node));
if(count < OffsetHelper.getEndOffsetWithoutComments(node)) {
return false;
}
if(is.read(b, 0, length) == -1) {
return false;
}
for(byte bb : b) {
if(!Character.isWhitespace(bb)) {

View file

@ -742,3 +742,43 @@ public:
#endif /* TEST_H_ */
//!Generate Getters and Setters no Fields
//#org.eclipse.cdt.ui.tests.refactoring.gettersandsetters.GenerateGettersAndSettersTest
//@.config
filename=C.h
fatalerror=true
//@C.h
/*
* test.h
*/
#ifndef TEST_H_
#define TEST_H_
//comment1
class test
{
void //$test$//();
//comment3
};
#endif /* TEST_H_ */
//=
/*
* test.h
*/
#ifndef TEST_H_
#define TEST_H_
//comment1
class test
{
void test();
//comment3
};
#endif /* TEST_H_ */

View file

@ -1,3 +1,101 @@
//!Param const and reference and pointer
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
//@A.h
class X {
public:
bool //$a(int = 100)$// const;
};
//=
class X {
public:
bool a(int = 100) const;
};
inline bool X::a(int int1) const
{
}
//!Param const and reference and pointer two params
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
//@A.h
class X {
public:
bool //$xy(int, int i)$// const;
};
//=
class X {
public:
bool xy(int, int i) const;
};
inline bool X::xy(int int1, int i) const
{
}
//!Test if TemplateMethod stays in header
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
//@A.h
template<class T> class A
{
public:
//$void test();$//
};
//=
template<class T> class A
{
public:
void test();
};
template<class T> inline void A<T>::test()
{
}
//@A.cpp
#include "A.h"
//=
#include "A.h"
//!Test Warning when Method definition in Class selected
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
initialWarnings=1
//@A.h
struct Test
{
void //$bla$//() {}
};
//!Test Warning when ClassName selected
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
initialWarnings=1
//@A.h
struct //$Test$//
{
void bla2();
};
//!class template member functions
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config

View file

@ -30,7 +30,8 @@ import org.eclipse.cdt.internal.ui.refactoring.implementmethod.ImplementMethodRe
*/
public class ImplementMethodRefactoringTest extends RefactoringTest {
protected int warnings;
protected int finalWarnings;
private int initialWarnings;
public ImplementMethodRefactoringTest(String name,Vector<TestSourceFile> files) {
super(name, files);
@ -46,16 +47,21 @@ public class ImplementMethodRefactoringTest extends RefactoringTest {
try {
RefactoringStatus checkInitialConditions = refactoring.checkInitialConditions(NULL_PROGRESS_MONITOR);
assertConditionsOk(checkInitialConditions);
if(initialWarnings == 0) {
assertConditionsOk(checkInitialConditions);
} else {
assertConditionsFatalError(checkInitialConditions, initialWarnings);
return;
}
refactoring.checkFinalConditions(NULL_PROGRESS_MONITOR);
RefactoringStatus finalConditions = refactoring.checkFinalConditions(NULL_PROGRESS_MONITOR);
if (warnings == 0) {
if (finalWarnings == 0) {
Change createChange = refactoring.createChange(NULL_PROGRESS_MONITOR);
assertConditionsOk(finalConditions);
createChange.perform(NULL_PROGRESS_MONITOR);
} else {
assertConditionsWarning(finalConditions, warnings);
assertConditionsWarning(finalConditions, finalWarnings);
}
compareFiles(fileMap);
}
@ -66,6 +72,7 @@ public class ImplementMethodRefactoringTest extends RefactoringTest {
@Override
protected void configureRefactoring(Properties refactoringProperties) {
warnings = new Integer(refactoringProperties.getProperty("warnings", "0")).intValue(); //$NON-NLS-1$//$NON-NLS-2$
finalWarnings = new Integer(refactoringProperties.getProperty("finalWarnings", "0")).intValue(); //$NON-NLS-1$//$NON-NLS-2$
initialWarnings = Integer.parseInt(refactoringProperties.getProperty("initialWarnings", "0")); //$NON-NLS-1$//$NON-NLS-2$
}
}

View file

@ -58,6 +58,6 @@ public class PseudoNameGeneratorTest extends TestCase {
}
public void testWithNamespace() {
assertEquals("string1", pseudoNameGenerator.generateNewName("std::string")); //$NON-NLS-1$//$NON-NLS-2$
assertEquals("string", pseudoNameGenerator.generateNewName("std::string")); //$NON-NLS-1$//$NON-NLS-2$
}
}

View file

@ -61,6 +61,10 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring {
initRefactoring(pm);
if(context.existingFields.size() == 0) {
initStatus.addFatalError(Messages.GenerateGettersAndSettersRefactoring_NoFields);
}
return initStatus;
}

View file

@ -15,12 +15,13 @@ import org.eclipse.osgi.util.NLS;
public final class Messages extends NLS {
private static final String BUNDLE_NAME = "org.eclipse.cdt.internal.ui.refactoring.generategettersandsetters.messages";//$NON-NLS-1$
private static final String BUNDLE_NAME = "org.eclipse.cdt.internal.ui.refactoring.gettersandsetters.messages";//$NON-NLS-1$
private Messages() {
// Do not instantiate
}
public static String GenerateGettersAndSettersRefactoring_NoFields;
public static String GettersAndSetters_Name;
static {

View file

@ -1 +1,13 @@
###############################################################################
# Copyright (c) 2008 Institute for Software, HSR Hochschule fuer Technik
# Rapperswil, University of applied sciences and others
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
# Contributors:
# Institute for Software - initial API and implementation
###############################################################################
GettersAndSetters_Name=Generate Getters and Setters
GenerateGettersAndSettersRefactoring_NoFields=The class does not contain any fields.

View file

@ -21,10 +21,11 @@ import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
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.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
@ -44,7 +45,6 @@ import org.eclipse.cdt.internal.ui.refactoring.CRefactoring;
import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector;
import org.eclipse.cdt.internal.ui.refactoring.utils.DefinitionFinder;
import org.eclipse.cdt.internal.ui.refactoring.utils.NameHelper;
import org.eclipse.cdt.internal.ui.refactoring.utils.NodeFactory;
import org.eclipse.cdt.internal.ui.refactoring.utils.NodeHelper;
import org.eclipse.cdt.internal.ui.refactoring.utils.SelectionHelper;
@ -60,6 +60,8 @@ public class ImplementMethodRefactoring extends CRefactoring {
private IASTSimpleDeclaration methodDeclaration;
private InsertLocation insertLocation;
private ParameterHandler parameterHandler;
private IASTDeclaration createdMethodDefinition;
private CPPASTFunctionDeclarator createdMethodDeclarator;
public ImplementMethodRefactoring(IFile file, ISelection selection, ICElement element) {
super(file, selection, element);
@ -73,8 +75,8 @@ public class ImplementMethodRefactoring extends CRefactoring {
methodDeclaration = SelectionHelper.findFirstSelectedDeclaration(region, unit);
if (methodDeclaration == null) {
initStatus.addFatalError("No method selected"); //$NON-NLS-1$
if (!NodeHelper.isMethodDeclaration(methodDeclaration)) {
initStatus.addFatalError(Messages.ImplementMethodRefactoring_NoMethodSelected);
return initStatus;
}
@ -82,13 +84,13 @@ public class ImplementMethodRefactoring extends CRefactoring {
sm.worked(1);
if (DefinitionFinder.getDefinition(methodDeclaration, file) != null) {
initStatus.addFatalError("This method already has an implementation."); //$NON-NLS-1$
initStatus.addFatalError(Messages.ImplementMethodRefactoring_MethodHasImpl);
return initStatus;
}
if(isProgressMonitorCanceld(sm, initStatus))return initStatus;
sm.worked(1);
sm.done();
parameterHandler.initAditionalArgumentNames();
parameterHandler.initArgumentNames();
sm.worked(1);
sm.done();
findInsertLocation();
@ -102,34 +104,59 @@ public class ImplementMethodRefactoring extends CRefactoring {
protected void collectModifications(IProgressMonitor pm, ModificationCollector collector) throws CoreException, OperationCanceledException {
IASTTranslationUnit targetUnit = insertLocation.getTargetTranslationUnit();
IASTNode parent = insertLocation.getPartenOfNodeToInsertBefore();
IASTNode insertNode = createFunctionDefinition(targetUnit);
createFunctionDefinition(targetUnit);
IASTNode nodeToInsertBefore = insertLocation.getNodeToInsertBefore();
ASTRewrite rewrite = collector.rewriterForTranslationUnit(targetUnit);
rewrite.insertBefore(parent, nodeToInsertBefore, insertNode, null);
ASTRewrite translationUnitRewrite = collector.rewriterForTranslationUnit(targetUnit);
ASTRewrite methodRewrite = translationUnitRewrite.insertBefore(parent, nodeToInsertBefore, createdMethodDefinition, null);
createParameterModifications(methodRewrite);
}
private void createParameterModifications(ASTRewrite methodRewrite) {
for(ParameterInfo actParameterInfo : parameterHandler.getParameterInfos()) {
ASTRewrite parameterRewrite = methodRewrite.insertBefore(createdMethodDeclarator, null, actParameterInfo.getParameter(), null);
createNewNameInsertModification(actParameterInfo, parameterRewrite);
createRemoveDefaultValueModification(actParameterInfo, parameterRewrite);
}
}
private void createRemoveDefaultValueModification(ParameterInfo parameterInfo, ASTRewrite parameterRewrite) {
if(parameterInfo.hasDefaultValue()) {
parameterRewrite.remove(parameterInfo.getDefaultValueNode(), null);
}
}
private void createNewNameInsertModification(ParameterInfo parameterInfo, ASTRewrite parameterRewrite) {
if(parameterInfo.hasNewName()) {
IASTNode insertNode = parameterInfo.getNewNameNode();
IASTName replaceNode = parameterInfo.getNameNode();
parameterRewrite.replace(replaceNode, insertNode, null);
}
}
private void findInsertLocation() throws CoreException {
insertLocation = MethodDefinitionInsertLocationFinder.find(methodDeclaration.getFileLocation(), methodDeclaration.getParent(), file);
if (!insertLocation.hasFile()) {
if (!insertLocation.hasFile() || NodeHelper.isContainedInTemplateDeclaration(methodDeclaration)) {
insertLocation.setInsertFile(file);
insertLocation.setNodeToInsertAfter(NodeHelper
.findTopLevelParent(methodDeclaration));
insertLocation.setNodeToInsertAfter(NodeHelper.findTopLevelParent(methodDeclaration));
}
}
private IASTNode createFunctionDefinition(IASTTranslationUnit unit) {
return createFunctionDefinition(
private void createFunctionDefinition(IASTTranslationUnit unit) {
createFunctionDefinition(
methodDeclaration.getDeclSpecifier(),
(ICPPASTFunctionDeclarator) methodDeclaration.getDeclarators()[0],
methodDeclaration.getParent(), unit);
}
public IASTNode createFunctionDefinition() {
return createFunctionDefinition(unit);
public IASTDeclaration createFunctionDefinition() {
createFunctionDefinition(unit);
return createdMethodDefinition;
}
private IASTNode createFunctionDefinition(IASTDeclSpecifier declSpecifier, ICPPASTFunctionDeclarator functionDeclarator, IASTNode declarationParent, IASTTranslationUnit unit) {
private void createFunctionDefinition(IASTDeclSpecifier declSpecifier, ICPPASTFunctionDeclarator functionDeclarator, IASTNode declarationParent, IASTTranslationUnit unit) {
IASTFunctionDefinition func = new CPPASTFunctionDefinition();
func.setParent(unit);
@ -151,20 +178,14 @@ public class ImplementMethodRefactoring extends CRefactoring {
ICPPASTQualifiedName qname = createQualifiedNameFor(functionDeclarator, declarationParent);
CPPASTFunctionDeclarator newFunctionDeclarator = new CPPASTFunctionDeclarator();
newFunctionDeclarator.setName(qname);
newFunctionDeclarator.setConst(functionDeclarator.isConst());
createdMethodDeclarator = new CPPASTFunctionDeclarator();
createdMethodDeclarator.setName(qname);
createdMethodDeclarator.setConst(functionDeclarator.isConst());
for(Parameter actParameter : parameterHandler.getParameters()) {
IASTParameterDeclaration createdParam = NodeFactory.createParameterDeclaration(actParameter.typeName, actParameter.parameterName);
newFunctionDeclarator.addParameterDeclaration(createdParam);
}
func.setDeclarator(newFunctionDeclarator);
func.setDeclarator(createdMethodDeclarator);
func.setBody(new CPPASTCompoundStatement());
if(classHasTemplates(declarationParent)) {
if(NodeHelper.isContainedInTemplateDeclaration(declarationParent)) {
CPPASTTemplateDeclaration templateDeclaration = new CPPASTTemplateDeclaration();
templateDeclaration.setParent(unit);
@ -173,9 +194,10 @@ public class ImplementMethodRefactoring extends CRefactoring {
}
templateDeclaration.setDeclaration(func);
return templateDeclaration;
createdMethodDefinition = templateDeclaration;
return;
}
return func;
createdMethodDefinition = func;
}
private ICPPASTQualifiedName createQualifiedNameFor(IASTFunctionDeclarator functionDeclarator, IASTNode declarationParent) {
@ -183,10 +205,6 @@ public class ImplementMethodRefactoring extends CRefactoring {
return NameHelper.createQualifiedNameFor(functionDeclarator.getName(), file, region.getOffset(), insertLocation.getInsertFile(), insertOffset);
}
private boolean classHasTemplates(IASTNode declarationParent) {
return declarationParent.getParent() != null && declarationParent.getParent().getParent() instanceof ICPPASTTemplateDeclaration;
}
public IASTSimpleDeclaration getMethodDeclaration() {
return methodDeclaration;
}

View file

@ -24,6 +24,10 @@ public final class Messages extends NLS {
public static String ParameterNamesInputPage_Title;
public static String ParameterNamesInputPage_CompleteMissingMails;
public static String PreviewGenerationNotPossible;
public static String ImplementMethodRefactoringPage_GeneratingPreview;
public static String ImplementMethodRefactoring_NoMethodSelected;
public static String ImplementMethodRefactoring_MethodHasImpl;
static {
NLS.initializeMessages(BUNDLE_NAME, Messages.class);

View file

@ -1,27 +0,0 @@
/*******************************************************************************
* Copyright (c) 2008 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Institute for Software - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.implementmethod;
/**
* @author Lukas Felber
*
*/
public class Parameter {
public Parameter(String typeName, String parameterName, boolean isChangable) {
this.typeName = typeName;
this.parameterName = parameterName;
this.isChangable = isChangable;
}
public String typeName;
public String parameterName;
public boolean isChangable;
}

View file

@ -1,21 +1,44 @@
/*******************************************************************************
* Copyright (c) 2008 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Institute for Software - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.implementmethod;
import java.util.ArrayList;
import java.util.Collection;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.internal.core.dom.rewrite.astwriter.ASTWriter;
import org.eclipse.cdt.ui.refactoring.CTextFileChange;
import org.eclipse.cdt.internal.ui.refactoring.utils.NameHelper;
import org.eclipse.cdt.internal.ui.refactoring.utils.PseudoNameGenerator;
/**
* Manages and creates Method Parameter Infos.
*
* @author Lukas Felber
*
*/
public class ParameterHandler {
private boolean needsAditionalArgumentNames;
private PseudoNameGenerator pseudoNameGenerator;
private ArrayList<Parameter> parameters;
private ArrayList<ParameterInfo> parameterInfos;
private ImplementMethodRefactoring refactoring;
public ParameterHandler(ImplementMethodRefactoring refactoring) {
@ -26,22 +49,21 @@ public class ParameterHandler {
return needsAditionalArgumentNames;
}
public void initAditionalArgumentNames() {
if(parameters != null) {
public void initArgumentNames() {
if(parameterInfos != null) {
return;
}
needsAditionalArgumentNames = false;
parameters = new ArrayList<Parameter>();
parameterInfos = new ArrayList<ParameterInfo>();
for(IASTParameterDeclaration actParam : getParametersFromMethodNode()) {
String actName = actParam.getDeclarator().getName().toString();
boolean isChangable = false;
String typeName = NameHelper.getTypeName(actParam);
if(actName.length() == 0) {
needsAditionalArgumentNames = true;
isChangable = true;
actName = findNameForParameter(typeName);
actName = findNameForParameter(NameHelper.getTypeName(actParam));
}
parameters.add(new Parameter(typeName, actName, isChangable));
parameterInfos.add(new ParameterInfo(actParam, actName, isChangable));
}
}
@ -66,12 +88,34 @@ public class ParameterHandler {
}
public String createFunctionDefinitionSignature() {
ASTWriter writer = new ASTWriter();
IASTNode def = refactoring.createFunctionDefinition();
return writer.write(def);
try {
CompositeChange compositeChange = (CompositeChange) refactoring.createChange(new NullProgressMonitor());
InsertEdit insertEdit = getInsertEdit(compositeChange);
return insertEdit.getText().trim();
} catch (OperationCanceledException e) {
return Messages.PreviewGenerationNotPossible;
} catch (CoreException e) {
return Messages.PreviewGenerationNotPossible;
}
}
public Collection<Parameter> getParameters() {
return parameters;
private InsertEdit getInsertEdit(CompositeChange compositeChange) {
for(Change actChange : compositeChange.getChildren()) {
if(actChange instanceof CompositeChange) {
return getInsertEdit((CompositeChange) actChange);
} else if (actChange instanceof CTextFileChange) {
CTextFileChange textFileChange = (CTextFileChange) actChange;
MultiTextEdit multiEdit = (MultiTextEdit) textFileChange.getEdit();
if(multiEdit.getChildrenSize() == 0) {
continue;
}
return (InsertEdit) multiEdit.getChildren()[0];
}
}
return null;
}
public Collection<ParameterInfo> getParameterInfos() {
return parameterInfos;
}
}

View file

@ -0,0 +1,72 @@
/*******************************************************************************
* Copyright (c) 2008 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Institute for Software - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.implementmethod;
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.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.ui.refactoring.utils.NameHelper;
/**
* @author Lukas Felber
*
*/
public class ParameterInfo {
private IASTParameterDeclaration parameter;
private boolean hasNewName;
private String parameterName;
public ParameterInfo(IASTParameterDeclaration parameter, String parameterName, boolean HasNewName) {
this.parameter = parameter;
this.hasNewName = HasNewName;
this.parameterName = parameterName;
}
public boolean hasNewName() {
return hasNewName;
}
public boolean hasDefaultValue() {
return getDefaultValueNode() != null;
}
public String getTypeName() {
return NameHelper.getTypeName(parameter);
}
public String getParameterName() {
return parameterName;
}
public void setParameterName(String newName) {
this.parameterName = newName;
}
public IASTParameterDeclaration getParameter() {
return parameter;
}
public IASTName getNameNode() {
return parameter.getDeclarator().getName();
}
public IASTName getNewNameNode() {
return new CPPASTName(parameterName.toCharArray());
}
public IASTNode getDefaultValueNode() {
return parameter.getDeclarator().getInitializer();
}
}

View file

@ -9,13 +9,14 @@
* Contributors:
* Institute for Software - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.implementmethod;
import java.util.HashMap;
import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
@ -23,6 +24,7 @@ import org.eclipse.swt.widgets.Label;
import org.eclipse.cdt.internal.ui.preferences.formatter.TranslationUnitPreview;
import org.eclipse.cdt.internal.ui.refactoring.dialogs.ValidatingLabeledTextField;
import org.eclipse.cdt.internal.ui.refactoring.utils.DelayedJobRunner;
/**
* InputPage used by the ImplementMethod refactoring if its necessary to enter additional parameter names.
@ -33,8 +35,9 @@ import org.eclipse.cdt.internal.ui.refactoring.dialogs.ValidatingLabeledTextFiel
public class ParameterNamesInputPage extends UserInputWizardPage {
private final ParameterHandler parameterHandler;
private TranslationUnitPreview translationUnitPreview;
private TranslationUnitPreview translationUnitPreview;
private DelayedJobRunner delayedPreviewUpdater;
public ParameterNamesInputPage(ParameterHandler parameterHandler) {
super(Messages.ParameterNamesInputPage_Title);
this.parameterHandler = parameterHandler;
@ -53,11 +56,11 @@ public class ParameterNamesInputPage extends UserInputWizardPage {
ValidatingLabeledTextField validatingLabeledTextField = new ValidatingLabeledTextField(superComposite);
validatingLabeledTextField.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
for (final Parameter actParameter : parameterHandler.getParameters()) {
for (final ParameterInfo actParameterInfo : parameterHandler.getParameterInfos()) {
String type = actParameter.typeName;
String content = actParameter.parameterName;
boolean readOnly = !actParameter.isChangable;
String type = actParameterInfo.getTypeName();
String content = actParameterInfo.getParameterName();
boolean readOnly = !actParameterInfo.hasNewName();
validatingLabeledTextField.addElement(type, content, readOnly, new ValidatingLabeledTextField.Validator(){
@ -73,22 +76,45 @@ public class ParameterNamesInputPage extends UserInputWizardPage {
@Override
public boolean isValidInput(String newName) {
actParameter.parameterName = newName;
actParameterInfo.setParameterName(newName);
updatePreview();
return true;
}});
}
translationUnitPreview = new TranslationUnitPreview(new HashMap<String, String>(), superComposite);
translationUnitPreview.getControl().setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
updatePreview();
createPreview(superComposite);
setControl(superComposite);
}
private void createPreview(Composite superComposite) {
translationUnitPreview = new TranslationUnitPreview(new HashMap<String, String>(), superComposite);
translationUnitPreview.getControl().setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
Runnable runnable = new Runnable() {
public void run() {
setPreviewText(Messages.ImplementMethodRefactoringPage_GeneratingPreview);
setPreviewText(parameterHandler.createFunctionDefinitionSignature());
}
private void setPreviewText(final String text) {
getShell().getDisplay().asyncExec(new Runnable() {
public void run() {
translationUnitPreview.setPreviewText(text);
}});
}
};
delayedPreviewUpdater = new DelayedJobRunner(runnable, 500);
delayedPreviewUpdater.start();
superComposite.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
delayedPreviewUpdater.stop();
}});
}
private void updatePreview() {
if (translationUnitPreview != null) {
translationUnitPreview.setPreviewText(parameterHandler.createFunctionDefinitionSignature());
if (translationUnitPreview == null) {
return;
}
delayedPreviewUpdater.runJob();
}
}

View file

@ -12,3 +12,7 @@
###############################################################################
ParameterNamesInputPage_Title=Implement Method
ParameterNamesInputPage_CompleteMissingMails=Please complete the missing variable names:
ImplementMethodRefactoring_MethodDefinition=Method Definition
ImplementMethodRefactoringPage_GeneratingPreview=Generating preview...
ImplementMethodRefactoring_NoMethodSelected=No method declaration selected
ImplementMethodRefactoring_MethodHasImpl=This method already has an implementation.

View file

@ -0,0 +1,68 @@
package org.eclipse.cdt.internal.ui.refactoring.utils;
/**
* Runs a job delayed by a given time when <code>runJob</code> gets called. <br>
* Only the time of the last <code>runJob</code> call is considered. So if <code>runJob</code>
* gets called before the time expires the first call will be ignored and the job will be run
* after the time of the second call + the delay time.<br>
* <code>DelayedJobRunner</code> isn't thread save (not neede till now).<br>
* Oh and one more thing. Do call the stop method when the runner isn't needed any more. ;-)
*
* @author Lukas Felber
*
*/
public class DelayedJobRunner {
private Runnable job;
private long lastUpdateEventTime;
private long delayTimeInMillis;
private boolean shouldStop;
private boolean shouldUpdate;
private static final long sleepTimeInMillis = 50;
public DelayedJobRunner(Runnable job, long delayTimeInMillis) {
this.job = job;
this.delayTimeInMillis = delayTimeInMillis;
shouldUpdate = true;
}
public void start() {
shouldStop = false;
new Thread(
new Runnable() {
public void run() {
startUpdateLoop();
}
}
).start();
}
public void runJob() {
shouldUpdate = true;
lastUpdateEventTime = System.currentTimeMillis();
}
private void startUpdateLoop() {
try {
while (!shouldStop) {
if (shouldUpdate && isDelayTimeOver()) {
lastUpdateEventTime = System.currentTimeMillis();
shouldUpdate = false;
job.run();
}
Thread.sleep(sleepTimeInMillis);
}
} catch (Exception e) {
//do nothing expect die.
}
}
private boolean isDelayTimeOver() {
long currentTime = System.currentTimeMillis();
return lastUpdateEventTime + delayTimeInMillis < currentTime;
}
public void stop() {
this.shouldStop = true;
}
}

View file

@ -1,18 +0,0 @@
package org.eclipse.cdt.internal.ui.refactoring.utils;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTDeclarator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNamedTypeSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTParameterDeclaration;
public class NodeFactory {
public static IASTParameterDeclaration createParameterDeclaration(String paramType, String paramName) {
CPPASTNamedTypeSpecifier type = new CPPASTNamedTypeSpecifier(new CPPASTName(paramType.toCharArray()), false);
CPPASTDeclarator declarator = new CPPASTDeclarator(new CPPASTName(paramName.toCharArray()));
return new CPPASTParameterDeclaration(type,declarator);
}
}

View file

@ -24,7 +24,9 @@ import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
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.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNamespaceDefinition;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit;
@ -157,5 +159,20 @@ public class NodeHelper {
}
return null;
}
public static boolean isMethodDeclaration(IASTSimpleDeclaration simpleDeclaration) {
if(simpleDeclaration == null) {
return false;
}
return simpleDeclaration.getDeclarators().length == 1 && simpleDeclaration.getDeclarators()[0] instanceof ICPPASTFunctionDeclarator;
}
public static boolean isContainedInTemplateDeclaration(IASTNode node) {
if(node == null) {
return false;
} else if (node instanceof ICPPASTTemplateDeclaration) {
return true;
}
return isContainedInTemplateDeclaration(node.getParent());
}
}

View file

@ -32,14 +32,19 @@ public class PseudoNameGenerator {
String[] nameParts = typeName.split("::"); //$NON-NLS-1$
typeName = nameParts[nameParts.length - 1];
if(typeName.length() != 0) {
typeName = typeName.substring(0, 1).toLowerCase() + typeName.substring(1);
}
String newNameCandidate = null;
String numberString = ""; //$NON-NLS-1$
String newNameCandidate;
int index = 0;
do {
newNameCandidate = typeName + numberString;
index++;
newNameCandidate = String.format("%s%d", typeName, Integer.valueOf(index)); //$NON-NLS-1$
} while(names.contains(newNameCandidate));
numberString = Integer.toString(index);
} while(names.contains(newNameCandidate) || !NameHelper.isValidLocalVariableName(newNameCandidate) || NameHelper.isKeyword(newNameCandidate));
names.add(newNameCandidate);

View file

@ -70,7 +70,7 @@ public class SelectionHelper {
Region exprPos = createExpressionPosition(expression);
int selStart = textSelection.getOffset();
int selEnd = textSelection.getLength() + selStart;
return exprPos.getOffset()+exprPos.getLength() > selStart && exprPos.getOffset() < selEnd;
return exprPos.getOffset()+exprPos.getLength() >= selStart && exprPos.getOffset() <= selEnd;
}
public static boolean isExpressionWhollyInSelection(Region textSelection, IASTNode expression) {