1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-22 00:15:25 +02:00

Bug 292851 - [performance] Source->Implement Method were defined throughout a class hierarchy takes too long

This commit is contained in:
Marc-Andre Laperle 2011-04-18 16:11:23 +00:00
parent 3cf16d06a7
commit eb7b349013
17 changed files with 463 additions and 279 deletions

View file

@ -2,6 +2,7 @@
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
infos=1
//@A.h
class X {
public:
@ -24,6 +25,7 @@ inline bool X::a(int int1) const
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
infos=1
//@A.h
class X {
public:
@ -46,6 +48,7 @@ inline bool X::xy(int int1, int i) const
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
infos=1
//@A.h
template<class T> class A
{
@ -76,6 +79,7 @@ template<class T> inline void A<T>::test()
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
infos=1
//@A.h
template<class T> class A
{
@ -137,6 +141,7 @@ void Demo::SubClass::test()
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
infos=1
//@A.h
class A
{
@ -431,6 +436,7 @@ int A::foo(int param1, int param2)
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
infos=1
//@A.h
class A
{
@ -581,6 +587,7 @@ namespace OuterSpace {
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=A.h
infos=1
//@A.h
template<class T, class U> class A
{
@ -714,6 +721,7 @@ void Test::doNothing(void)
//#org.eclipse.cdt.ui.tests.refactoring.implementmethod.ImplementMethodRefactoringTest
//@.config
filename=TestClass.h
infos=1
//@TestClass.h
#ifndef TESTCLASS_H_
#define TESTCLASS_H_

View file

@ -8,6 +8,7 @@
*
* Contributors:
* Institute for Software - initial API and implementation
* Marc-Andre Laperle
*******************************************************************************/
package org.eclipse.cdt.ui.tests.refactoring.implementmethod;
@ -18,10 +19,12 @@ import org.eclipse.core.resources.IFile;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.ui.tests.refactoring.RefactoringTest;
import org.eclipse.cdt.ui.tests.refactoring.TestSourceFile;
import org.eclipse.cdt.internal.ui.refactoring.CRefactoring;
import org.eclipse.cdt.internal.ui.refactoring.CRefactoring2;
import org.eclipse.cdt.internal.ui.refactoring.implementmethod.ImplementMethodRefactoring;
/**
@ -30,6 +33,7 @@ import org.eclipse.cdt.internal.ui.refactoring.implementmethod.ImplementMethodRe
public class ImplementMethodRefactoringTest extends RefactoringTest {
protected int finalWarnings;
private int initialWarnings;
private int infos;
public ImplementMethodRefactoringTest(String name, Collection<TestSourceFile> files) {
super(name, files);
@ -38,37 +42,36 @@ public class ImplementMethodRefactoringTest extends RefactoringTest {
@Override
protected void runTest() throws Throwable {
IFile refFile = project.getFile(fileName);
CRefactoring refactoring = new ImplementMethodRefactoring(refFile, selection, null, cproject);
try {
refactoring.lockIndex();
RefactoringStatus checkInitialConditions = refactoring.checkInitialConditions(NULL_PROGRESS_MONITOR);
ICElement element = CoreModel.getDefault().create(refFile);
CRefactoring2 refactoring = new ImplementMethodRefactoring(element, selection, cproject, astCache);
RefactoringStatus checkInitialConditions = refactoring.checkInitialConditions(NULL_PROGRESS_MONITOR);
if(initialWarnings == 0) {
assertConditionsOk(checkInitialConditions);
} else {
assertConditionsFatalError(checkInitialConditions, initialWarnings);
return;
}
refactoring.checkFinalConditions(NULL_PROGRESS_MONITOR);
RefactoringStatus finalConditions = refactoring.checkFinalConditions(NULL_PROGRESS_MONITOR);
if (finalWarnings == 0) {
Change createChange = refactoring.createChange(NULL_PROGRESS_MONITOR);
assertConditionsOk(finalConditions);
createChange.perform(NULL_PROGRESS_MONITOR);
} else {
assertConditionsWarning(finalConditions, finalWarnings);
}
compareFiles(fileMap);
} finally {
refactoring.unlockIndex();
if (initialWarnings == 0) {
assertConditionsOk(checkInitialConditions);
} else {
assertConditionsFatalError(checkInitialConditions, initialWarnings);
return;
}
RefactoringStatus finalConditions = refactoring.checkFinalConditions(NULL_PROGRESS_MONITOR);
Change createChange = refactoring.createChange(NULL_PROGRESS_MONITOR);
if (finalWarnings > 0) {
assertConditionsWarning(finalConditions, finalWarnings);
} else if (infos > 0) {
assertConditionsInfo(finalConditions, infos);
} else {
assertConditionsOk(finalConditions);
}
createChange.perform(NULL_PROGRESS_MONITOR);
compareFiles(fileMap);
}
@Override
protected void configureRefactoring(Properties refactoringProperties) {
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$
infos = Integer.parseInt(refactoringProperties.getProperty("infos", "0")); //$NON-NLS-1$//$NON-NLS-2$
}
}

View file

@ -44,7 +44,7 @@ public class DefinitionFinderTest extends RefactoringTest {
IASTTranslationUnit ast = astCache.getAST((ITranslationUnit) element, null);
for (IASTDeclaration declaration : ast.getDeclarations()) {
if (declaration instanceof IASTSimpleDeclaration) {
assertNotNull(DefinitionFinder2.getDefinition((IASTSimpleDeclaration) declaration, astCache));
assertNotNull(DefinitionFinder2.getDefinition((IASTSimpleDeclaration) declaration, astCache, NULL_PROGRESS_MONITOR));
}
}
}

View file

@ -122,7 +122,7 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring2 {
CheckConditionsContext checkContext) throws CoreException, OperationCanceledException {
RefactoringStatus result = new RefactoringStatus();
if (!context.isImplementationInHeader()) {
findDefinitionInsertLocation();
findDefinitionInsertLocation(pm);
if (definitionInsertLocation == null || tu.equals(definitionInsertLocation.getTranslationUnit())) {
result.addInfo(Messages.GenerateGettersAndSettersRefactoring_NoImplFile);
}
@ -238,7 +238,7 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring2 {
}
}
if (!context.isImplementationInHeader()) {
addDefinition(collector, definitions);
addDefinition(collector, definitions, pm);
}
ICPPASTCompositeTypeSpecifier classDefinition =
(ICPPASTCompositeTypeSpecifier) context.existingFields.get(context.existingFields.size() - 1).getParent();
@ -247,9 +247,9 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring2 {
getterAndSetters, false, collector);
}
private void addDefinition(ModificationCollector collector, List<IASTFunctionDefinition> definitions)
private void addDefinition(ModificationCollector collector, List<IASTFunctionDefinition> definitions, IProgressMonitor pm)
throws CoreException {
findDefinitionInsertLocation();
findDefinitionInsertLocation(pm);
IASTNode parent = definitionInsertLocation.getParentOfNodeToInsertBefore();
IASTTranslationUnit ast = parent.getTranslationUnit();
ASTRewrite rewrite = collector.rewriterForTranslationUnit(ast);
@ -265,14 +265,15 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring2 {
return context;
}
private void findDefinitionInsertLocation() throws CoreException {
private void findDefinitionInsertLocation(IProgressMonitor pm) throws CoreException {
if (definitionInsertLocation != null) {
return;
}
IASTSimpleDeclaration decl = context.existingFields.get(0);
InsertLocation2 location = MethodDefinitionInsertLocationFinder2.find(
tu, decl.getFileLocation(), decl.getParent(), astCache);
MethodDefinitionInsertLocationFinder2 methodDefinitionInsertLocationFinder = new MethodDefinitionInsertLocationFinder2();
InsertLocation2 location = methodDefinitionInsertLocationFinder.find(
tu, decl.getFileLocation(), decl.getParent(), astCache, pm);
if (location.getFile() == null || NodeHelper.isContainedInTemplateDeclaration(decl)) {
location.setNodeToInsertAfter(NodeHelper.findTopLevelParent(decl), tu);

View file

@ -1,5 +1,5 @@
###############################################################################
# Copyright (c) 2008, 2009 Institute for Software, HSR Hochschule fuer Technik
# Copyright (c) 2008, 2011 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
@ -18,4 +18,4 @@ GenerateGettersAndSettersInputPage_SelectGetters=Select Getters
GenerateGettersAndSettersInputPage_SelectSetters=Select Setters
GenerateGettersAndSettersRefactoring_NoCassDefFound=No class definition found
GenerateGettersAndSettersRefactoring_NoFields=The class does not contain any fields.
GenerateGettersAndSettersRefactoring_NoImplFile=No implementation file found. Insert definition into the header file.
GenerateGettersAndSettersRefactoring_NoImplFile=No implementation file found. Inserting definition into the header file.

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2010 Institute for Software, HSR Hochschule fuer Technik
* Copyright (c) 2008, 2011 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
@ -8,11 +8,14 @@
*
* Contributors:
* Institute for Software - initial API and implementation
* Marc-Andre Laperle
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.implementmethod;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
@ -23,10 +26,13 @@ import org.eclipse.core.runtime.SubMonitor;
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;
import org.eclipse.cdt.core.dom.ast.ASTNodeFactoryFactory;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTName;
@ -35,23 +41,26 @@ import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle;
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
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.ICPPASTDeclSpecifier;
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.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNodeFactory;
import org.eclipse.cdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTCompoundStatement;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionDeclarator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionDefinition;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTemplateDeclaration;
import org.eclipse.cdt.internal.ui.refactoring.CRefactoring;
import org.eclipse.cdt.internal.ui.refactoring.CRefactoring2;
import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector;
import org.eclipse.cdt.internal.ui.refactoring.utils.DefinitionFinder;
import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache;
import org.eclipse.cdt.internal.ui.refactoring.utils.Checks;
import org.eclipse.cdt.internal.ui.refactoring.utils.NameHelper;
import org.eclipse.cdt.internal.ui.refactoring.utils.NodeHelper;
import org.eclipse.cdt.internal.ui.refactoring.utils.SelectionHelper;
@ -62,14 +71,18 @@ import org.eclipse.cdt.internal.ui.refactoring.utils.SelectionHelper;
*
* @author Mirko Stocker, Lukas Felber, Emanuel Graf
*/
public class ImplementMethodRefactoring extends CRefactoring {
private InsertLocation insertLocation;
private CPPASTFunctionDeclarator createdMethodDeclarator;
public class ImplementMethodRefactoring extends CRefactoring2 {
private ICPPASTFunctionDeclarator createdMethodDeclarator;
private ImplementMethodData data;
private MethodDefinitionInsertLocationFinder2 methodDefinitionInsertLocationFinder;
private Map<IASTSimpleDeclaration, InsertLocation2> insertLocations;
private static ICPPNodeFactory nodeFactory = ASTNodeFactoryFactory.getDefaultCPPNodeFactory();
public ImplementMethodRefactoring(IFile file, ISelection selection, ICElement element, ICProject project) {
super(file, selection, element, project);
public ImplementMethodRefactoring(ICElement element, ISelection selection, ICProject project, RefactoringASTCache astCache) {
super(element, selection, project, astCache);
data = new ImplementMethodData();
methodDefinitionInsertLocationFinder = new MethodDefinitionInsertLocationFinder2();
insertLocations = new HashMap<IASTSimpleDeclaration, InsertLocation2>();
}
@Override
@ -78,10 +91,10 @@ public class ImplementMethodRefactoring extends CRefactoring {
super.checkInitialConditions(sm.newChild(6));
if (!initStatus.hasFatalError()) {
data.setMethodDeclarations(findUnimplementedMethodDeclarations(ast));
data.setMethodDeclarations(findUnimplementedMethodDeclarations(pm));
if (region.getLength() > 0) {
IASTSimpleDeclaration methodDeclaration = SelectionHelper.findFirstSelectedDeclaration(region, ast);
if (selectedRegion.getLength() > 0) {
IASTSimpleDeclaration methodDeclaration = SelectionHelper.findFirstSelectedDeclaration(selectedRegion, astCache.getAST(tu, pm));
if (NodeHelper.isMethodDeclaration(methodDeclaration)) {
for (MethodToImplementConfig config : data.getMethodDeclarations()) {
if (config.getDeclaration() == methodDeclaration) {
@ -95,10 +108,10 @@ public class ImplementMethodRefactoring extends CRefactoring {
return initStatus;
}
private List<IASTSimpleDeclaration> findUnimplementedMethodDeclarations(
IASTTranslationUnit unit) {
private List<IASTSimpleDeclaration> findUnimplementedMethodDeclarations(IProgressMonitor pm) throws OperationCanceledException, CoreException {
IASTTranslationUnit ast = astCache.getAST(tu, pm);
final List<IASTSimpleDeclaration> list = new ArrayList<IASTSimpleDeclaration>();
unit.accept(new ASTVisitor() {
ast.accept(new ASTVisitor() {
{
shouldVisitDeclarations = true;
}
@ -107,40 +120,76 @@ public class ImplementMethodRefactoring extends CRefactoring {
public int visit(IASTDeclaration declaration) {
if (declaration instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) declaration;
try {
if (NodeHelper.isMethodDeclaration(simpleDeclaration) && DefinitionFinder.getDefinition(simpleDeclaration, file) == null) {
if (NodeHelper.isMethodDeclaration(simpleDeclaration)) {
IASTDeclarator[] declarators = simpleDeclaration.getDeclarators();
IBinding binding = declarators[0].getName().resolveBinding();
if (isUnimplementedMethodBinding(binding)) {
list.add(simpleDeclaration);
return ASTVisitor.PROCESS_SKIP;
}
} catch (CoreException e) {}
}
}
return ASTVisitor.PROCESS_CONTINUE;
}
});
return list;
}
private boolean isUnimplementedMethodBinding(IBinding binding) {
if (binding instanceof ICPPFunction) {
if (binding instanceof ICPPMethod) {
ICPPMethod methodBinding = (ICPPMethod) binding;
if (methodBinding.isPureVirtual()) {
return false; //Êpure virtual not handled for now, see bug 303870
}
}
try {
IIndexName[] indexNames = astCache.getIndex().findNames(binding, IIndex.FIND_DEFINITIONS
| IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
if (indexNames.length == 0) {
return true;
}
} catch (CoreException e) {
CUIPlugin.log(e);
}
}
return false;
}
@Override
protected void collectModifications(IProgressMonitor pm, ModificationCollector collector)
throws CoreException, OperationCanceledException {
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) {
createDefinition(collector, config, sm.newChild(4));
}
}
}
protected void createDefinition(ModificationCollector collector,
MethodToImplementConfig config, IProgressMonitor subMonitor) throws CoreException {
MethodToImplementConfig config, IProgressMonitor subMonitor) throws CoreException, OperationCanceledException {
if (subMonitor.isCanceled()) {
throw new OperationCanceledException();
}
IASTSimpleDeclaration decl = config.getDeclaration();
insertLocation = findInsertLocation(decl);
InsertLocation2 insertLocation = findInsertLocation(decl, subMonitor);
if (subMonitor.isCanceled()) {
throw new OperationCanceledException();
}
subMonitor.worked(1);
IASTTranslationUnit targetUnit = insertLocation.getTargetTranslationUnit();
IASTNode parent = insertLocation.getPartenOfNodeToInsertBefore();
ASTRewrite translationUnitRewrite = collector.rewriterForTranslationUnit(targetUnit);
IASTNode parent = insertLocation.getParentOfNodeToInsertBefore();
IASTTranslationUnit ast = parent.getTranslationUnit();
ASTRewrite translationUnitRewrite = collector.rewriterForTranslationUnit(ast);
subMonitor.worked(1);
if (subMonitor.isCanceled()) {
throw new OperationCanceledException();
}
IASTNode nodeToInsertBefore = insertLocation.getNodeToInsertBefore();
IASTNode createdMethodDefinition = createFunctionDefinition(targetUnit, decl);
IASTNode createdMethodDefinition = createFunctionDefinition(ast, decl, insertLocation);
subMonitor.worked(1);
ASTRewrite methodRewrite = translationUnitRewrite.insertBefore(parent, nodeToInsertBefore, createdMethodDefinition , null);
createParameterModifications(methodRewrite, config.getParaHandler());
@ -169,35 +218,30 @@ public class ImplementMethodRefactoring extends CRefactoring {
}
}
private InsertLocation findInsertLocation(IASTSimpleDeclaration methodDeclaration) throws CoreException {
InsertLocation insertLocation = MethodDefinitionInsertLocationFinder.find(methodDeclaration.getFileLocation(), methodDeclaration.getParent(), file);
if (!insertLocation.hasFile() || NodeHelper.isContainedInTemplateDeclaration(methodDeclaration)) {
insertLocation.setInsertFile(file);
insertLocation.setNodeToInsertAfter(NodeHelper.findTopLevelParent(methodDeclaration));
private InsertLocation2 findInsertLocation(IASTSimpleDeclaration methodDeclaration, IProgressMonitor subMonitor) throws CoreException {
if (insertLocations.containsKey(methodDeclaration)) {
return insertLocations.get(methodDeclaration);
}
InsertLocation2 insertLocation = methodDefinitionInsertLocationFinder.find(tu, methodDeclaration.getFileLocation(), methodDeclaration.getParent(), astCache, subMonitor);
if (insertLocation.getTranslationUnit() == null || NodeHelper.isContainedInTemplateDeclaration(methodDeclaration)) {
insertLocation.setNodeToInsertAfter(NodeHelper.findTopLevelParent(methodDeclaration), tu);
}
insertLocations.put(methodDeclaration, insertLocation);
return insertLocation;
}
private IASTDeclaration createFunctionDefinition(IASTTranslationUnit unit, IASTSimpleDeclaration methodDeclaration) throws CoreException {
return createFunctionDefinition(
methodDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations),
(ICPPASTFunctionDeclarator) methodDeclaration.getDeclarators()[0],
methodDeclaration.getParent(), unit);
}
private IASTDeclaration createFunctionDefinition(IASTDeclSpecifier declSpecifier, ICPPASTFunctionDeclarator functionDeclarator,
IASTNode declarationParent, IASTTranslationUnit unit) throws CoreException {
IASTFunctionDefinition func = new CPPASTFunctionDefinition();
func.setParent(unit);
private IASTDeclaration createFunctionDefinition(IASTTranslationUnit unit, IASTSimpleDeclaration methodDeclaration, InsertLocation2 insertLocation) throws CoreException {
IASTDeclSpecifier declSpecifier = methodDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations);
ICPPASTFunctionDeclarator functionDeclarator = (ICPPASTFunctionDeclarator) methodDeclaration.getDeclarators()[0];
IASTNode declarationParent = methodDeclaration.getParent();
if (declSpecifier instanceof ICPPASTDeclSpecifier) {
((ICPPASTDeclSpecifier) declSpecifier).setVirtual(false);
}
String currentFileName = declarationParent.getNodeLocations()[0].asFileLocation().getFileName();
if (Path.fromOSString(currentFileName).equals(insertLocation.getInsertFile().getLocation())) {
if (Path.fromOSString(currentFileName).equals(insertLocation.getFile().getLocation())) {
declSpecifier.setInline(true);
}
@ -205,38 +249,36 @@ methodDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations),
declSpecifier.setStorageClass(IASTDeclSpecifier.sc_unspecified);
}
func.setDeclSpecifier(declSpecifier);
ICPPASTQualifiedName qName = createQualifiedNameFor(functionDeclarator, declarationParent, insertLocation);
ICPPASTQualifiedName qname = createQualifiedNameFor(functionDeclarator, declarationParent);
createdMethodDeclarator = new CPPASTFunctionDeclarator();
createdMethodDeclarator.setName(qname);
createdMethodDeclarator = nodeFactory.newFunctionDeclarator(qName);
createdMethodDeclarator.setConst(functionDeclarator.isConst());
for (IASTPointerOperator pop : functionDeclarator.getPointerOperators()) {
createdMethodDeclarator.addPointerOperator(pop.copy(CopyStyle.withLocations));
}
func.setDeclarator(createdMethodDeclarator);
func.setBody(new CPPASTCompoundStatement());
IASTFunctionDefinition functionDefinition = nodeFactory.newFunctionDefinition(declSpecifier, createdMethodDeclarator, nodeFactory.newCompoundStatement());
functionDefinition.setParent(unit);
if (NodeHelper.isContainedInTemplateDeclaration(declarationParent)) {
CPPASTTemplateDeclaration templateDeclaration = new CPPASTTemplateDeclaration();
ICPPASTTemplateDeclaration templateDeclaration = nodeFactory.newTemplateDeclaration(functionDefinition);
templateDeclaration.setParent(unit);
for (ICPPASTTemplateParameter templateParameter : ((ICPPASTTemplateDeclaration) declarationParent.getParent().getParent() ).getTemplateParameters()) {
templateDeclaration.addTemplateParameter(templateParameter.copy(CopyStyle.withLocations));
}
templateDeclaration.setDeclaration(func);
return templateDeclaration;
}
return func;
return functionDefinition;
}
private ICPPASTQualifiedName createQualifiedNameFor(IASTFunctionDeclarator functionDeclarator,
IASTNode declarationParent) throws CoreException {
IASTNode declarationParent, InsertLocation2 insertLocation) throws CoreException {
int insertOffset = insertLocation.getInsertPosition();
return NameHelper.createQualifiedNameFor(functionDeclarator.getName(), file, functionDeclarator.getFileLocation().getNodeOffset(), insertLocation.getInsertFile(), insertOffset);
return NameHelper.createQualifiedNameFor(
functionDeclarator.getName(), tu, functionDeclarator.getFileLocation().getNodeOffset(),
insertLocation.getTranslationUnit(), insertOffset, astCache);
}
public ImplementMethodData getRefactoringData() {
@ -248,4 +290,52 @@ methodDeclaration.getDeclSpecifier().copy(CopyStyle.withLocations),
// TODO egraf add Descriptor
return null;
}
private IFile[] getAllFilesToModify() {
List<IFile> files = new ArrayList<IFile>(2);
IFile file = (IFile) tu.getResource();
if (file != null) {
files.add(file);
}
for (InsertLocation2 insertLocation : insertLocations.values()) {
if (insertLocation != null) {
file = insertLocation.getFile();
if (file != null) {
files.add(file);
}
}
}
return files.toArray(new IFile[files.size()]);
}
@Override
protected RefactoringStatus checkFinalConditions(IProgressMonitor subProgressMonitor,
CheckConditionsContext checkContext) throws CoreException, OperationCanceledException {
RefactoringStatus result = new RefactoringStatus();
if (isOneOrMoreImplementationInHeader(subProgressMonitor)) {
result.addInfo(Messages.ImplementMethodRefactoring_NoImplFile);
}
Checks.addModifiedFilesToChecker(getAllFilesToModify(), checkContext);
return result;
}
private boolean isOneOrMoreImplementationInHeader(IProgressMonitor subProgressMonitor) throws CoreException {
for (MethodToImplementConfig config : data.getMethodsToImplement()) {
IASTSimpleDeclaration decl = config.getDeclaration();
findInsertLocation(decl, subProgressMonitor);
}
if (insertLocations.isEmpty()) {
return true;
}
for (InsertLocation2 insertLocation : insertLocations.values()) {
if (insertLocation != null && tu.equals(insertLocation.getTranslationUnit())) {
return true;
}
}
return false;
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2009 Institute for Software, HSR Hochschule fuer Technik
* Copyright (c) 2008, 2011 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
@ -7,49 +7,40 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Institute for Software - initial API and implementation
* Institute for Software - initial API and implementation
* Marc-Andre Laperle
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.implementmethod;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.internal.ui.refactoring.RefactoringRunner;
import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache;
import org.eclipse.cdt.internal.ui.refactoring.RefactoringRunner2;
/**
* @author Lukas Felber
*/
public class ImplementMethodRefactoringRunner extends RefactoringRunner {
public class ImplementMethodRefactoringRunner extends RefactoringRunner2 {
public ImplementMethodRefactoringRunner(IFile file, ISelection selection, ICElement element,
public ImplementMethodRefactoringRunner(ICElement element, ISelection selection,
IShellProvider shellProvider, ICProject cProject) {
super(file, selection, element, shellProvider, cProject);
super(element, selection, shellProvider, cProject);
}
@Override
public void run() {
ImplementMethodRefactoring refactoring = new ImplementMethodRefactoring(file, selection, celement, project);
public void run(RefactoringASTCache astCache) {
ImplementMethodRefactoring refactoring = new ImplementMethodRefactoring(element, selection, project, astCache);
ImplementMethodRefactoringWizard wizard = new ImplementMethodRefactoringWizard(refactoring);
RefactoringWizardOpenOperation operator = new RefactoringWizardOpenOperation(wizard);
try {
refactoring.lockIndex();
try {
operator.run(shellProvider.getShell(), refactoring.getName());
} finally {
refactoring.unlockIndex();
}
operator.run(shellProvider.getShell(), refactoring.getName());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (CoreException e) {
CUIPlugin.log(e);
}
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008 Institute for Software, HSR Hochschule fuer Technik
* Copyright (c) 2008, 2011 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
@ -7,15 +7,21 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Institute for Software - initial API and implementation
* Institute for Software - initial API and implementation
* Marc-Andre Laperle
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.implementmethod;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
import org.eclipse.cdt.ui.CUIPlugin;
/**
* @author Mirko Stocker
*
@ -46,4 +52,62 @@ public class ImplementMethodRefactoringWizard extends RefactoringWizard {
public ParameterNamesInputPage getPageForConfig(MethodToImplementConfig config) {
return pagesMap.get(config);
}
/**
* - When cancelling the wizard, RefactoringASTCache gets disposed and releases the lock on the index but
* the preview jobs might still be running and access the index or an index based AST so we need to make sure they
* are done before disposing the cache
* - When proceeding to the last page and finishing the wizard, the
* refactoring will run and possibly use concurrently the same ASTs that the jobs use, so we need to make
* sure the jobs are joined.
*/
protected void cancelAndJoinPreviewJobs() {
boolean isOnePreviewJobRunning = false;
for (ParameterNamesInputPage parameterNamesInputPage : pagesMap.values()) {
isOnePreviewJobRunning |= parameterNamesInputPage.cancelPreviewJob();
}
// There are good chances that one job is still running, show a progress bar to the user, join everything
if(isOnePreviewJobRunning) {
try {
getContainer().run(false, false, new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
monitor.beginTask(Messages.ImplementMethodRefactoringWizard_CancelingPreviewGeneration, pagesMap.size() + 1);
monitor.worked(1);
for (ParameterNamesInputPage parameterNamesInputPage : pagesMap.values()) {
parameterNamesInputPage.joinPreviewJob();
monitor.worked(1);
}
monitor.done();
}
});
} catch (InvocationTargetException e) {
CUIPlugin.log(e);
} catch (InterruptedException e) {
// ignore since not cancelable
}
}
// We don't take any chances, we still join everything. But there are good chances that the jobs are stopped
// so we don't show a progress bar.
else {
for (ParameterNamesInputPage parameterNamesInputPage : pagesMap.values()) {
parameterNamesInputPage.joinPreviewJob();
}
}
}
@Override
public boolean performCancel() {
cancelAndJoinPreviewJobs();
return super.performCancel();
}
@Override
public boolean performFinish() {
cancelAndJoinPreviewJobs();
return super.performFinish();
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2005, 2009 IBM Corporation and others.
* Copyright (c) 2005, 2011 IBM Corporation 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
@ -23,13 +23,16 @@ public final class Messages extends NLS {
public static String ParameterNamesInputPage_Title;
public static String ParameterNamesInputPage_CompleteMissingMails;
public static String PreviewGenerationNotPossible;
public static String ImplementMethodInputPage_PageTitle;
public static String ImplementMethodInputPage_SelectAll;
public static String ImplementMethodInputPage_DeselectAll;
public static String ImplementMethodRefactoringPage_GeneratingPreview;
public static String ImplementMethodRefactoringPage_PreviewCanceled;
public static String ImplementMethodRefactoringPage_PreviewGenerationNotPossible;
public static String ImplementMethodRefactoring_NoMethodSelected;
public static String ImplementMethodRefactoring_MethodHasImpl;
public static String ImplementMethodRefactoring_NoImplFile;
public static String ImplementMethodRefactoringWizard_CancelingPreviewGeneration;
public static String ImplementMethodInputPage_Header;
static {

View file

@ -9,14 +9,19 @@
* Contributors:
* Institute for Software - initial API and implementation
* Sergey Prigogin (Google)
* Marc-Andre Laperle
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.implementmethod;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
@ -42,23 +47,55 @@ import org.eclipse.cdt.internal.ui.refactoring.utils.NodeHelper;
*/
public class MethodDefinitionInsertLocationFinder2 {
public static InsertLocation2 find(ITranslationUnit declarationTu, IASTFileLocation methodDeclarationLocation,
IASTNode parent, RefactoringASTCache astCache) throws CoreException {
// We cache DefinitionFinder2.getDefinition results because refactorings like Implement Method might want to find multiple
// insert locations in the same translation unit. This prevents many redundant calls to DefinitionFinder2.getDefinition
// and speeds up the process quite a bit. Unfortunately, this has the minor side-effect or having to instantiate this class.
Map<IASTSimpleDeclaration, IASTName> cachedDeclarationToDefinition = new HashMap<IASTSimpleDeclaration, IASTName>();
public InsertLocation2 find(ITranslationUnit declarationTu, IASTFileLocation methodDeclarationLocation,
IASTNode parent, RefactoringASTCache astCache, IProgressMonitor pm) throws CoreException {
IASTDeclaration[] declarations = NodeHelper.getDeclarations(parent);
InsertLocation2 insertLocation = new InsertLocation2();
Collection<IASTSimpleDeclaration> allPreviousSimpleDeclarationsFromClassInReverseOrder = getAllPreviousSimpleDeclarationsFromClassInReverseOrder(declarations, methodDeclarationLocation, pm);
Collection<IASTSimpleDeclaration> allFollowingSimpleDeclarationsFromClass = getAllFollowingSimpleDeclarationsFromClass(declarations, methodDeclarationLocation, pm);
for (IASTSimpleDeclaration simpleDeclaration : getAllPreviousSimpleDeclarationsFromClassInReverseOrder(
declarations, methodDeclarationLocation)) {
IASTName definition = DefinitionFinder2.getDefinition(simpleDeclaration, astCache);
if (definition != null) {
insertLocation.setNodeToInsertAfter(findFirstSurroundingParentFunctionNode(definition),
definition.getTranslationUnit().getOriginatingTranslationUnit());
for (IASTSimpleDeclaration simpleDeclaration : allPreviousSimpleDeclarationsFromClassInReverseOrder) {
if (pm != null && pm.isCanceled()) {
throw new OperationCanceledException();
}
IASTName definition = null;
if (cachedDeclarationToDefinition.containsKey(simpleDeclaration)) {
definition = cachedDeclarationToDefinition.get(simpleDeclaration);
} else {
definition = DefinitionFinder2.getDefinition(simpleDeclaration, astCache, pm);
if (definition != null) {
cachedDeclarationToDefinition.put(simpleDeclaration, definition);
}
}
if (definition != null) {
insertLocation.setNodeToInsertAfter(findFirstSurroundingParentFunctionNode(
definition), definition.getTranslationUnit().getOriginatingTranslationUnit());
}
}
for (IASTSimpleDeclaration simpleDeclaration : getAllFollowingSimpleDeclarationsFromClass(
declarations, methodDeclarationLocation)) {
IASTName definition = DefinitionFinder2.getDefinition(simpleDeclaration, astCache);
for (IASTSimpleDeclaration simpleDeclaration : allFollowingSimpleDeclarationsFromClass) {
if (pm != null && pm.isCanceled()) {
throw new OperationCanceledException();
}
IASTName definition = null;
if (cachedDeclarationToDefinition.containsKey(simpleDeclaration)) {
definition = cachedDeclarationToDefinition.get(simpleDeclaration);
} else {
definition = DefinitionFinder2.getDefinition(simpleDeclaration, astCache, pm);
if (definition != null) {
cachedDeclarationToDefinition.put(simpleDeclaration, definition);
}
}
if (definition != null) {
insertLocation.setNodeToInsertBefore(findFirstSurroundingParentFunctionNode(definition),
definition.getTranslationUnit().getOriginatingTranslationUnit());
@ -105,13 +142,17 @@ public class MethodDefinitionInsertLocationFinder2 {
*
* @param declarations to be searched
* @param methodPosition on which the search aborts
* @param pm
* @return all declarations, sorted in reverse order
*/
private static Collection<IASTSimpleDeclaration> getAllPreviousSimpleDeclarationsFromClassInReverseOrder(
IASTDeclaration[] declarations, IASTFileLocation methodPosition) {
IASTDeclaration[] declarations, IASTFileLocation methodPosition, IProgressMonitor pm) {
ArrayList<IASTSimpleDeclaration> outputDeclarations = new ArrayList<IASTSimpleDeclaration>();
if (declarations.length >= 0) {
for (IASTDeclaration decl : declarations) {
if (pm != null && pm.isCanceled()) {
return outputDeclarations;
}
if (decl.getFileLocation().getStartingLineNumber() >= methodPosition.getStartingLineNumber()) {
break;
}
@ -125,11 +166,14 @@ public class MethodDefinitionInsertLocationFinder2 {
}
private static Collection<IASTSimpleDeclaration> getAllFollowingSimpleDeclarationsFromClass(
IASTDeclaration[] declarations, IASTFileLocation methodPosition) {
IASTDeclaration[] declarations, IASTFileLocation methodPosition, IProgressMonitor pm) {
ArrayList<IASTSimpleDeclaration> outputDeclarations = new ArrayList<IASTSimpleDeclaration>();
if (declarations.length >= 0) {
for (IASTDeclaration decl : declarations) {
if (pm != null && pm.isCanceled()) {
return outputDeclarations;
}
if (isMemberFunctionDeclaration(decl) &&
decl.getFileLocation().getStartingLineNumber() > methodPosition.getStartingLineNumber() ) {
outputDeclarations.add((IASTSimpleDeclaration) decl);

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008 Institute for Software, HSR Hochschule fuer Technik
* Copyright (c) 2008, 2011 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
@ -7,35 +7,38 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Institute for Software - initial API and implementation
* Institute for Software - initial API and implementation
* Marc-Andre Laperle
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.implementmethod;
import java.util.HashMap;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
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;
import org.eclipse.swt.widgets.Label;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.refactoring.CTextFileChange;
import org.eclipse.cdt.internal.ui.preferences.formatter.TranslationUnitPreview;
import org.eclipse.cdt.internal.ui.refactoring.CCompositeChange;
import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector;
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.
@ -45,9 +48,10 @@ import org.eclipse.cdt.internal.ui.refactoring.utils.DelayedJobRunner;
*/
public class ParameterNamesInputPage extends UserInputWizardPage {
private static final int PREVIEW_UPDATE_DELAY = 500;
private MethodToImplementConfig config;
private TranslationUnitPreview translationUnitPreview;
private DelayedJobRunner delayedPreviewUpdater;
private Job delayedPreviewUpdater;
private ImplementMethodRefactoringWizard wizard;
public ParameterNamesInputPage(MethodToImplementConfig config, ImplementMethodRefactoringWizard wizard) {
@ -62,9 +66,8 @@ public class ParameterNamesInputPage extends UserInputWizardPage {
superComposite.setLayout(new GridLayout());
Label label = new Label(superComposite, SWT.NONE);
label.setText(Messages.ParameterNamesInputPage_CompleteMissingMails);
label.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
setTitle(Messages.ImplementMethodInputPage_PageTitle);
setMessage(Messages.ParameterNamesInputPage_CompleteMissingMails);
ValidatingLabeledTextField validatingLabeledTextField = new ValidatingLabeledTextField(superComposite);
validatingLabeledTextField.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
@ -101,56 +104,79 @@ public class ParameterNamesInputPage extends UserInputWizardPage {
}
private InsertEdit getInsertEdit(CompositeChange compositeChange) {
for(Change actChange : compositeChange.getChildren()) {
if(actChange instanceof 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;
TextEdit edit = textFileChange.getEdit();
if (edit instanceof MultiTextEdit) {
MultiTextEdit multiEdit = (MultiTextEdit) edit;
if (multiEdit.getChildrenSize() == 0) {
continue;
}
TextEdit textEdit = multiEdit.getChildren()[0];
if (textEdit instanceof InsertEdit) {
return (InsertEdit) textEdit;
}
}
return (InsertEdit) multiEdit.getChildren()[0];
}
}
return null;
}
public String createFunctionDefinitionSignature() {
public String createFunctionDefinitionSignature(IProgressMonitor monitor) {
try {
ModificationCollector collector = new ModificationCollector();
((ImplementMethodRefactoring)wizard.getRefactoring()).createDefinition(collector, config, new NullProgressMonitor());
InsertEdit insertEdit = getInsertEdit(collector.createFinalChange());
ImplementMethodRefactoring implementMethodRefactoring = (ImplementMethodRefactoring)wizard.getRefactoring();
CCompositeChange finalChange = null;
// We can have multiple preview jobs. We don't
// want multiple jobs concurrently using the same ASTs
synchronized (implementMethodRefactoring) {
implementMethodRefactoring.createDefinition(collector, config, monitor);
finalChange = collector.createFinalChange();
}
InsertEdit insertEdit = getInsertEdit(finalChange);
if (insertEdit == null) {
return Messages.ImplementMethodRefactoringPage_PreviewGenerationNotPossible;
}
return insertEdit.getText().trim();
} catch (OperationCanceledException e) {
return Messages.PreviewGenerationNotPossible;
return Messages.ImplementMethodRefactoringPage_PreviewCanceled;
} catch (CoreException e) {
return Messages.PreviewGenerationNotPossible;
return Messages.ImplementMethodRefactoringPage_PreviewGenerationNotPossible;
}
}
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() {
delayedPreviewUpdater = new Job(Messages.ImplementMethodRefactoringPage_GeneratingPreview) {
@Override
protected IStatus run(IProgressMonitor monitor) {
setPreviewText(Messages.ImplementMethodRefactoringPage_GeneratingPreview);
setPreviewText(createFunctionDefinitionSignature());
String functionDefinitionSignature = createFunctionDefinitionSignature(monitor);
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
setPreviewText(functionDefinitionSignature);
return Status.OK_STATUS;
}
private void setPreviewText(final String text) {
getShell().getDisplay().asyncExec(new Runnable() {
public void run() {
translationUnitPreview.setPreviewText(text);
}});
if (getShell() != null && getShell().getDisplay() != null) {
getShell().getDisplay().asyncExec(new Runnable() {
public void run() {
if (translationUnitPreview.getControl() != null && !translationUnitPreview.getControl().isDisposed()) {
translationUnitPreview.setPreviewText(text);
}
}});
}
}
};
delayedPreviewUpdater = new DelayedJobRunner(runnable, 500);
delayedPreviewUpdater.start();
superComposite.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
delayedPreviewUpdater.stop();
}});
delayedPreviewUpdater.schedule(PREVIEW_UPDATE_DELAY);
}
@Override
@ -161,18 +187,35 @@ public class ParameterNamesInputPage extends UserInputWizardPage {
@Override
public IWizardPage getNextPage() {
MethodToImplementConfig nextConfig = ((ImplementMethodRefactoring)wizard.getRefactoring()).getRefactoringData().getNextConfigNeedingParameterNames(config);
if(nextConfig != null) {
if (nextConfig != null) {
return wizard.getPageForConfig(nextConfig);
}else {
} else {
wizard.cancelAndJoinPreviewJobs();
return computeSuccessorPage();
}
}
protected boolean cancelPreviewJob() {
// We cannot rely on getState being accurate in all cases so we only use this
// as a hint to change the preview text
if (delayedPreviewUpdater.getState() != Job.NONE) {
translationUnitPreview.setPreviewText(Messages.ImplementMethodRefactoringPage_PreviewCanceled);
}
return !delayedPreviewUpdater.cancel();
}
protected void joinPreviewJob() {
try {
delayedPreviewUpdater.join();
} catch (InterruptedException e1) {
CUIPlugin.log(e1);
}
}
private void updatePreview() {
if (translationUnitPreview == null) {
return;
}
delayedPreviewUpdater.runJob();
}
delayedPreviewUpdater.schedule(PREVIEW_UPDATE_DELAY);
}
}

View file

@ -1,5 +1,5 @@
###############################################################################
# Copyright (c) 2008, 2009 Institute for Software, HSR Hochschule fuer Technik
# Copyright (c) 2008, 2011 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
@ -9,6 +9,7 @@
# Contributors:
# Institute for Software - initial API and implementation
# IBM Corporation
# Marc-Andre Laperle
###############################################################################
ParameterNamesInputPage_Title=Implement Method
ImplementMethodInputPage_Header=Select Methods to implement:
@ -16,8 +17,10 @@ ParameterNamesInputPage_CompleteMissingMails=Please complete the missing variabl
ImplementMethodInputPage_PageTitle=Implement Method
ImplementMethodInputPage_SelectAll=Select All
ImplementMethodInputPage_DeselectAll=Deselect All
ImplementMethodRefactoring_MethodDefinition=Method Definition
PreviewGenerationNotPossible=Preview generation not possible
ImplementMethodRefactoringPage_PreviewGenerationNotPossible=Preview generation not possible
ImplementMethodRefactoringPage_GeneratingPreview=Generating preview...
ImplementMethodRefactoringPage_PreviewCanceled=Preview canceled
ImplementMethodRefactoring_NoMethodSelected=No method declaration selected
ImplementMethodRefactoring_MethodHasImpl=This method already has an implementation.
ImplementMethodRefactoring_MethodHasImpl=This method already has an implementation.
ImplementMethodRefactoring_NoImplFile=No implementation file found for one or more method. Inserting definition(s) into the header file.
ImplementMethodRefactoringWizard_CancelingPreviewGeneration=Canceling preview generation

View file

@ -44,7 +44,7 @@ import org.eclipse.cdt.internal.ui.util.EditorUtility;
public class DefinitionFinder2 {
public static IASTName getDefinition(IASTSimpleDeclaration simpleDeclaration,
RefactoringASTCache astCache) throws CoreException {
RefactoringASTCache astCache, IProgressMonitor pm) throws CoreException {
IIndex index = astCache.getIndex();
IASTDeclarator declarator = simpleDeclaration.getDeclarators()[0];
if (index == null) {
@ -54,15 +54,18 @@ public class DefinitionFinder2 {
if (binding == null) {
return null;
}
return getDefinition(binding, astCache, index);
return getDefinition(binding, astCache, index, pm);
}
private static IASTName getDefinition(IIndexBinding binding,
RefactoringASTCache astCache, IIndex index) throws CoreException {
RefactoringASTCache astCache, IIndex index, IProgressMonitor pm) throws CoreException {
Set<String> searchedFiles = new HashSet<String>();
List<IASTName> definitions = new ArrayList<IASTName>();
IEditorPart[] dirtyEditors = EditorUtility.getDirtyEditors(true);
for (IEditorPart editor : dirtyEditors) {
if (pm != null && pm.isCanceled()) {
throw new OperationCanceledException();
}
IEditorInput editorInput = editor.getEditorInput();
if (editorInput instanceof ITranslationUnitEditorInput) {
ITranslationUnit tu =
@ -74,10 +77,13 @@ public class DefinitionFinder2 {
IIndexName[] definitionsFromIndex = index.findDefinitions(binding);
for (IIndexName name : definitionsFromIndex) {
if (pm != null && pm.isCanceled()) {
throw new OperationCanceledException();
}
ITranslationUnit tu = CoreModelUtil.findTranslationUnitForLocation(
name.getFile().getLocation(), null);
if (searchedFiles.add(tu.getLocation().toOSString())) {
findDefinitionsInTranslationUnit(binding, tu, astCache, definitions, null);
findDefinitionsInTranslationUnit(binding, tu, astCache, definitions, pm);
}
}

View file

@ -1,78 +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.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,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2010 Institute for Software, HSR Hochschule fuer Technik
* Copyright (c) 2008, 2011 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
@ -13,7 +13,6 @@ package org.eclipse.cdt.internal.ui.refactoring.utils;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
@ -24,11 +23,14 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.core.parser.util.CharArrayIntMap;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTQualifiedName;
import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache;
/**
* Helps with IASTNames.
*
@ -56,19 +58,19 @@ public class NameHelper {
* the namespace at the declaration position and the target namespace at the target position.
*
* @param declaratorName of the method or function
* @param declarationFile
* @param declarationTu translation unit of the method or function declaration
* @param insertFileTu translation unit of the file where the implementation is being inserted
* @param selectionOffset the offset in the declarationFile, usually the position or selection of the declaration
* @param insertFile the target file in which the definition is inserted
* @param insertLocation
* @return the correct name for the target
* @throws CoreException
*/
public static ICPPASTQualifiedName createQualifiedNameFor(IASTName declaratorName, IFile declarationFile, int selectionOffset, IFile insertFile, int insertLocation)
public static ICPPASTQualifiedName createQualifiedNameFor(IASTName declaratorName, ITranslationUnit declarationTu, int selectionOffset, ITranslationUnit insertFileTu, int insertLocation, RefactoringASTCache astCache)
throws CoreException {
ICPPASTQualifiedName qname = new CPPASTQualifiedName();
IASTName[] declarationNames = NamespaceHelper.getSurroundingNamespace(declarationFile, selectionOffset).getNames();
IASTName[] implementationNames = NamespaceHelper.getSurroundingNamespace(insertFile, insertLocation).getNames();
IASTName[] declarationNames = NamespaceHelper.getSurroundingNamespace(declarationTu, selectionOffset, astCache).getNames();
IASTName[] implementationNames = NamespaceHelper.getSurroundingNamespace(insertFileTu, insertLocation, astCache).getNames();
for (int i = 0; i < declarationNames.length; i++) {
if (i >= implementationNames.length) {

View file

@ -11,8 +11,8 @@
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.utils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTName;
@ -24,6 +24,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNamedTypeSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTQualifiedName;
@ -31,27 +32,30 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleTypeTemplatePara
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTemplateId;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTypeId;
import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache;
/**
* Helper class to find Namespace informations.
* @author Mirko Stocker
*/
public class NamespaceHelper {
/**
* Returns the qualified name of all namespaces that are defined at the specified file and offset.
* Returns the qualified name of all namespaces that are defined at the specified translation unit and offset.
*
* @param insertFile
* @param translationUnit
* @param offset
* @param astCache
* @return ICPPASTQualifiedName with the names of all namespaces
* @throws CoreException
*/
public static ICPPASTQualifiedName getSurroundingNamespace(final IFile insertFile, final int offset)
public static ICPPASTQualifiedName getSurroundingNamespace(final ITranslationUnit translationUnit, final int offset, RefactoringASTCache astCache)
throws CoreException {
final CPPASTQualifiedName qualifiedName = new CPPASTQualifiedName();
TranslationUnitHelper.loadTranslationUnit(insertFile, false).accept(new CPPASTAllVisitor() {
astCache.getAST(translationUnit, null).accept(new CPPASTAllVisitor() {
@Override
public int visit(IASTDeclSpecifier declSpec) {
if (declSpec instanceof ICPPASTCompositeTypeSpecifier && checkFileNameAndLocation(insertFile, offset, declSpec)) {
if (declSpec instanceof ICPPASTCompositeTypeSpecifier && checkFileNameAndLocation(translationUnit.getLocation(), offset, declSpec)) {
qualifiedName.addName(createNameWithTemplates(declSpec));
}
return super.visit(declSpec);
@ -59,7 +63,7 @@ public class NamespaceHelper {
@Override
public int visit(ICPPASTNamespaceDefinition namespace) {
if (checkFileNameAndLocation(insertFile, offset, namespace)) {
if (checkFileNameAndLocation(translationUnit.getLocation(), offset, namespace)) {
qualifiedName.addName((namespace).getName().copy());
}
@ -70,8 +74,8 @@ public class NamespaceHelper {
return qualifiedName;
}
private static boolean checkFileNameAndLocation(final IFile insertFile, final int offset, IASTNode namespace) {
boolean fileNameOk = namespace.getFileLocation().getFileName().endsWith(insertFile.getLocation().toOSString());
private static boolean checkFileNameAndLocation(final IPath path, final int offset, IASTNode namespace) {
boolean fileNameOk = namespace.getFileLocation().getFileName().endsWith(path.toOSString());
if (!fileNameOk) {
return false;
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2009 Institute for Software, HSR Hochschule fuer Technik
* Copyright (c) 2008, 2011 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
@ -48,14 +48,14 @@ public class ImplementMethodAction extends RefactoringAction {
@Override
public void run(IShellProvider shellProvider, ICElement elem) {
new ImplementMethodRefactoringRunner(null, null, elem, shellProvider, elem.getCProject()).run();
new ImplementMethodRefactoringRunner(elem, null, shellProvider, elem.getCProject()).run();
}
@Override
public void run(IShellProvider shellProvider, IWorkingCopy wc, ITextSelection selection) {
IResource res = wc.getResource();
if (res instanceof IFile) {
new ImplementMethodRefactoringRunner((IFile) res, selection, null, shellProvider, wc.getCProject()).run();
new ImplementMethodRefactoringRunner(wc, selection, shellProvider, wc.getCProject()).run();
}
}