diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index 9ad88841064..403943d2030 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2010 IBM Corporation and others. + * Copyright (c) 2004, 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 @@ -75,6 +75,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumerator; +import org.eclipse.cdt.core.dom.ast.IField; import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.ILabel; @@ -1409,12 +1410,26 @@ public class CPPVisitor extends ASTQueries { if (nameBinding.equals(binding)) { return true; } - // a using declaration is a declaration for the references of its delegates + // A using declaration is a declaration for the references of its delegates if (nameBinding instanceof ICPPUsingDeclaration) { if (ArrayUtil.contains(((ICPPUsingDeclaration) nameBinding).getDelegates(), binding)) { return true; } } + // Handle the case when one of the bindings is from the index and another + // one is from an AST. + if ((nameBinding instanceof IIndexBinding) != (binding instanceof IIndexBinding) && + SemanticUtil.isSameOwner(nameBinding.getOwner(), binding.getOwner())) { + if (nameBinding instanceof IFunction && binding instanceof IFunction) { + if (((IFunction) nameBinding).getType().isSameType(((IFunction) binding).getType())) { + return true; + } + } else if (nameBinding instanceof IField && binding instanceof IField) { + if (((IField) nameBinding).getType().isSameType(((IField) binding).getType())) { + return true; + } + } + } } } return false; diff --git a/core/org.eclipse.cdt.ui.tests/resources/refactoring/GenerateGettersAndSetters.rts b/core/org.eclipse.cdt.ui.tests/resources/refactoring/GenerateGettersAndSetters.rts index 063fca53a50..1fdc5ece39d 100644 --- a/core/org.eclipse.cdt.ui.tests/resources/refactoring/GenerateGettersAndSetters.rts +++ b/core/org.eclipse.cdt.ui.tests/resources/refactoring/GenerateGettersAndSetters.rts @@ -914,32 +914,35 @@ getters=name //@C.cpp #include "C.h" -int Person::SocSecNo(){ +namespace Personal { + +int Person::SocSecNo() { return socSecNo; } +} // namespace Personal + int main(int argc, char **argv) { - } //= #include "C.h" -int Person::SocSecNo(){ +namespace Personal { + char *Person::getName() const + { + return name; + } + + int Person::SocSecNo() { return socSecNo; } +} // namespace Personal + int main(int argc, char **argv) { - } -char *Person::getName() const -{ - return name; -} - - - //@C.h #ifndef C_H_ #define C_H_ diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTest.java index fb7892c93c6..b4d1ec08979 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/RefactoringTest.java @@ -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,7 +7,8 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Institute for Software - initial API and implementation + * Institute for Software - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.ui.tests.refactoring; @@ -24,16 +25,17 @@ import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.core.index.IIndexManager; import org.eclipse.cdt.ui.testplugin.CTestPlugin; +import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache; + /** * @author Emanuel Graf - * */ public abstract class RefactoringTest extends RefactoringBaseTest { - private static final String CONFIG_FILE_NAME = ".config"; //$NON-NLS-1$ protected String fileName; - + protected RefactoringASTCache astCache; + public RefactoringTest(String name, Vector files) { super(name, files); initializeConfiguration(files); @@ -52,6 +54,13 @@ public abstract class RefactoringTest extends RefactoringBaseTest { CCorePlugin.getIndexManager().reindex(cproject); boolean joined = CCorePlugin.getIndexManager().joinIndexer(IIndexManager.FOREVER, NULL_PROGRESS_MONITOR); assertTrue(joined); + astCache = new RefactoringASTCache(); + } + + @Override + protected void tearDown() throws Exception { + astCache.dispose(); + super.tearDown(); } private void initializeConfiguration(Vector files) { @@ -76,7 +85,6 @@ public abstract class RefactoringTest extends RefactoringBaseTest { initCommonFields(refactoringProperties); configureRefactoring(refactoringProperties); files.remove(configFile); - } private void initCommonFields(Properties refactoringProperties) { @@ -84,8 +92,8 @@ public abstract class RefactoringTest extends RefactoringBaseTest { } protected void assertConditionsOk(RefactoringStatus conditions) { - assertTrue(conditions.isOK() ? "OK" : "Error or Warning in Conditions: " + conditions.getEntries()[0].getMessage() //$NON-NLS-1$ //$NON-NLS-2$ - , conditions.isOK()); + assertTrue(conditions.isOK() ? "OK" : "Error or Warning in Conditions: " + conditions.getEntries()[0].getMessage(), //$NON-NLS-1$ //$NON-NLS-2$ + conditions.isOK()); } protected void assertConditionsWarning(RefactoringStatus conditions, int number) { diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/gettersandsetters/GenerateGettersAndSettersTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/gettersandsetters/GenerateGettersAndSettersTest.java index 561229a3e4d..84371d6885e 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/gettersandsetters/GenerateGettersAndSettersTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/gettersandsetters/GenerateGettersAndSettersTest.java @@ -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 * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -7,12 +7,14 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Emanuel Graf & Leo Buettiker - initial API and implementation - * Thomas Corbat - implementation + * Emanuel Graf & Leo Buettiker - initial API and implementation + * Thomas Corbat - implementation + * Sergey Prigogin (Google) ******************************************************************************/ package org.eclipse.cdt.ui.tests.refactoring.gettersandsetters; import java.util.ArrayList; +import java.util.List; import java.util.Properties; import java.util.Vector; @@ -22,6 +24,8 @@ import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; +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; @@ -30,19 +34,16 @@ import org.eclipse.cdt.internal.ui.refactoring.gettersandsetters.GetterAndSetter /** * @author Thomas Corbat - * */ public class GenerateGettersAndSettersTest extends RefactoringTest { - protected boolean fatalError; private int warnings; - private ArrayList selectedGetters; - private ArrayList selectedSetters; + private List selectedGetters; + private List selectedSetters; private GenerateGettersAndSettersRefactoring refactoring; private boolean keepInHeader; private int infos; - /** * @param name * @param files @@ -53,60 +54,53 @@ public class GenerateGettersAndSettersTest extends RefactoringTest { @Override protected void runTest() throws Throwable { - IFile refFile = project.getFile(fileName); - refactoring = new GenerateGettersAndSettersRefactoring(refFile, selection, null, cproject); + IFile file = project.getFile(fileName); + ICElement element = CoreModel.getDefault().create(file); + refactoring = new GenerateGettersAndSettersRefactoring(element, selection, cproject, astCache); RefactoringStatus initialConditions = refactoring.checkInitialConditions(NULL_PROGRESS_MONITOR); - - if(fatalError){ + if (fatalError) { assertConditionsFatalError(initialConditions); return; - } - else{ + } else { assertConditionsOk(initialConditions); executeRefactoring(); } - - } private void executeRefactoring() throws CoreException, Exception { - selectFields(); refactoring.getContext().setImplementationInHeader(keepInHeader); RefactoringStatus finalConditions = refactoring.checkFinalConditions(NULL_PROGRESS_MONITOR); Change createChange = refactoring.createChange(NULL_PROGRESS_MONITOR); - if(warnings > 0){ + if (warnings > 0) { assertConditionsWarning(finalConditions, warnings); - }else if(infos >0) { + } else if (infos > 0) { assertConditionsInfo(finalConditions, infos); - } - else{ + } else { assertConditionsOk(finalConditions); } createChange.perform(NULL_PROGRESS_MONITOR); - compareFiles(fileMap); } private void selectFields() { GetterAndSetterContext context = refactoring.getContext(); - for(IASTSimpleDeclaration currentDecl : context.existingFields){ + for (IASTSimpleDeclaration currentDecl : context.existingFields) { String name = currentDecl.getDeclarators()[0].getName().getRawSignature(); - if(selectedGetters.contains(name) ){ + if (selectedGetters.contains(name)) { selectedGetters.remove(name); context.selectedFunctions.add(context.createGetterInserter(currentDecl)); } - if(selectedSetters.contains(name) ){ + if (selectedSetters.contains(name)) { selectedSetters.remove(name); context.selectedFunctions.add(context.createSetterInserter(currentDecl)); } } } - @Override protected void configureRefactoring(Properties refactoringProperties) { @@ -118,13 +112,12 @@ public class GenerateGettersAndSettersTest extends RefactoringTest { keepInHeader = Boolean.valueOf(refactoringProperties.getProperty("inHeader", "false")); selectedGetters = new ArrayList(); - for(String getterName : getters.split(",")){ //$NON-NLS-1$ + for (String getterName : getters.split(",")) { //$NON-NLS-1$ selectedGetters.add(getterName); } selectedSetters = new ArrayList(); - for(String setterName : setters.split(",")){ //$NON-NLS-1$ + for (String setterName : setters.split(",")) { //$NON-NLS-1$ selectedSetters.add(setterName); } } - } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/CRefactoring2.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/CRefactoring2.java new file mode 100644 index 00000000000..4d33409cd33 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/CRefactoring2.java @@ -0,0 +1,250 @@ +/******************************************************************************* + * 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 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Institute for Software - initial API and implementation + * Sergey Prigogin (Google) + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.refactoring; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.ltk.core.refactoring.Change; +import org.eclipse.ltk.core.refactoring.Refactoring; +import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor; +import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; +import org.eclipse.ltk.core.refactoring.RefactoringStatus; +import org.eclipse.osgi.util.NLS; + +import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTProblem; +import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTProblemExpression; +import org.eclipse.cdt.core.dom.ast.IASTProblemStatement; +import org.eclipse.cdt.core.dom.ast.IASTProblemTypeId; +import org.eclipse.cdt.core.dom.ast.IASTStatement; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IASTTypeId; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; +import org.eclipse.cdt.core.model.CModelException; +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.ISourceRange; +import org.eclipse.cdt.core.model.ISourceReference; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.ui.CUIPlugin; + +import org.eclipse.cdt.internal.corext.util.CModelUtil; + +import org.eclipse.cdt.internal.ui.refactoring.utils.SelectionHelper; + +/** + * The base class for all AST based refactorings, provides some common implementations for + * AST creation, condition checking, change generating, and selection handling. + * This class is intended as a replacement for CRefactoring. + */ +public abstract class CRefactoring2 extends Refactoring { + protected String name = Messages.Refactoring_name; + protected final ICProject project; + protected final ITranslationUnit tu; + protected final RefactoringStatus initStatus; + protected final RefactoringASTCache astCache; + protected Region selectedRegion; + + public CRefactoring2(ICElement element, ISelection selection, ICProject project, + RefactoringASTCache astCache) { + this.project = project; + this.astCache = astCache; + this.initStatus= new RefactoringStatus(); + if (!(element instanceof ISourceReference)) { + this.tu = null; + initStatus.addFatalError(Messages.Refactoring_SelectionNotValid); + return; + } + + ISourceReference sourceRef= (ISourceReference) element; + tu = CModelUtil.toWorkingCopy(sourceRef.getTranslationUnit()); + + if (selection instanceof ITextSelection) { + this.selectedRegion = SelectionHelper.getRegion(selection); + } else { + try { + ISourceRange sourceRange = sourceRef.getSourceRange(); + this.selectedRegion = new Region(sourceRange.getIdStartPos(), sourceRange.getIdLength()); + } catch (CModelException e) { + CUIPlugin.log(e); + } + } + } + + private class ProblemFinder extends ASTVisitor { + private boolean problemFound = false; + private final RefactoringStatus status; + + public ProblemFinder(RefactoringStatus status) { + this.status = status; + } + + { + shouldVisitProblems = true; + shouldVisitDeclarations = true; + shouldVisitExpressions = true; + shouldVisitStatements = true; + shouldVisitTypeIds = true; + } + + @Override + public int visit(IASTProblem problem) { + addWarningToState(); + return ASTVisitor.PROCESS_CONTINUE; + } + + @Override + public int visit(IASTDeclaration declaration) { + if (declaration instanceof IASTProblemDeclaration) { + addWarningToState(); + } + return ASTVisitor.PROCESS_CONTINUE; + } + + @Override + public int visit(IASTExpression expression) { + if (expression instanceof IASTProblemExpression) { + addWarningToState(); + } + return ASTVisitor.PROCESS_CONTINUE; + } + + @Override + public int visit(IASTStatement statement) { + if (statement instanceof IASTProblemStatement) { + addWarningToState(); + } + return ASTVisitor.PROCESS_CONTINUE; + } + + @Override + public int visit(IASTTypeId typeId) { + if (typeId instanceof IASTProblemTypeId) { + addWarningToState(); + } + return ASTVisitor.PROCESS_CONTINUE; + } + + public boolean hasProblem() { + return problemFound; + } + + private void addWarningToState() { + if (!problemFound) { + status.addWarning(Messages.Refactoring_CompileErrorInTU); + problemFound = true; + } + } + } + + @Override + public RefactoringStatus checkFinalConditions(IProgressMonitor pm) + throws CoreException, OperationCanceledException { + return new RefactoringStatus(); + } + + @Override + public RefactoringStatus checkInitialConditions(IProgressMonitor pm) + throws CoreException, OperationCanceledException { + SubMonitor sm = SubMonitor.convert(pm, 10); + sm.subTask(Messages.Refactoring_PM_LoadTU); + if (isProgressMonitorCanceld(sm, initStatus)) { + return initStatus; + } + IASTTranslationUnit ast = getAST(tu, sm); + if (ast == null) { + initStatus.addError(NLS.bind(Messages.Refactoring_ParsingError, tu.getPath())); + return initStatus; + } + if (isProgressMonitorCanceld(sm, initStatus)) { + return initStatus; + } + sm.subTask(Messages.Refactoring_PM_CheckTU); + checkAST(ast); + sm.worked(2); + sm.subTask(Messages.Refactoring_PM_InitRef); + sm.done(); + return initStatus; + } + + protected static boolean isProgressMonitorCanceld(IProgressMonitor sm, RefactoringStatus status) { + if (sm.isCanceled()) { + status.addFatalError(Messages.Refactoring_CanceledByUser); + return true; + } + return false; + } + + @Override + public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException { + ModificationCollector collector = new ModificationCollector(); + collectModifications(pm, collector); + CCompositeChange finalChange = collector.createFinalChange(); + finalChange.setDescription(new RefactoringChangeDescriptor(getRefactoringDescriptor())); + return finalChange; + } + + abstract protected RefactoringDescriptor getRefactoringDescriptor(); + + abstract protected void collectModifications(IProgressMonitor pm, ModificationCollector collector) + throws CoreException, OperationCanceledException; + + @Override + public String getName() { + return name; + } + + protected IASTTranslationUnit getAST(ITranslationUnit tu, IProgressMonitor pm) + throws CoreException, OperationCanceledException { + return astCache.getAST(tu, pm); + } + + protected boolean checkAST(IASTTranslationUnit ast) { + ProblemFinder problemFinder = new ProblemFinder(initStatus); + ast.accept(problemFinder); + return problemFinder.hasProblem(); + } + + protected List findAllMarkedNames(IASTTranslationUnit ast) { + final List names = new ArrayList(); + + ast.accept(new ASTVisitor() { + { + shouldVisitNames = true; + } + + @Override + public int visit(IASTName name) { + if (name.isPartOfTranslationUnitFile() && + SelectionHelper.isSelectionOnExpression(selectedRegion, name) && + !(name instanceof ICPPASTQualifiedName)) { + names.add(name); + } + return super.visit(name); + } + }); + return names; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/Messages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/Messages.java index e1082acd7af..881ec182586 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/Messages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/Messages.java @@ -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,14 +7,14 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Institute for Software - initial API and implementation + * Institute for Software - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.ui.refactoring; import org.eclipse.osgi.util.NLS; public final class Messages extends NLS { - public static String DeleteFileChange_0; public static String DeleteFileChange_1; public static String Refactoring_name; @@ -33,6 +33,7 @@ public final class Messages extends NLS { public static String Refactoring_SelectionNotValid; public static String Refactoring_CantLoadTU; public static String Refactoring_Ambiguity; + public static String Refactoring_ParsingError; public static String NodeContainer_Name; public static String NO_FILE; public static String RefactoringSaveHelper_unexpected_exception; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/Messages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/Messages.properties index f4514b14dd0..ba6dbe706c6 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/Messages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/Messages.properties @@ -7,7 +7,8 @@ # http://www.eclipse.org/legal/epl-v10.html # # Contributors: -# Institute for Software - initial API and implementation +# Institute for Software - initial API and implementation +# Sergey Prigogin (Google) ############################################################################### DeleteFileChange_0=Delete File DeleteFileChange_1=File doesn't exist. @@ -18,7 +19,7 @@ Refactoring_PM_InitRef=Initialize Refactoring Refactoring_PM_ParseTU=Parse Translation Unit Refactoring_PM_MergeComments=Merge Comments Refactoring_CanceledByUser=Refactoring canceled by user. -Refactoring_CompileErrorInTU=The Translation Unit contains one or several problems. This can be caused by a syntax error in the code or a parser flaw. The refactoring will possibly fail. +Refactoring_CompileErrorInTU=The translation unit contains one or several problems. This can be caused by a syntax error in the code or a parser flaw. The refactoring will possibly fail. AddDeclarationNodeToClassChange_AddDeclaration=Add Declaration to Class {0}. CreateFileChange_CreateFile=Create file: {0} CreateFileChange_UnknownLoc=Unknown Location: {0} @@ -27,6 +28,7 @@ CRefactoring_FileNotFound=The file {0} is not on the build path of a C/C++ proje Refactoring_SelectionNotValid=Selection is not valid. Refactoring_CantLoadTU=Can not load translation unit. Refactoring_Ambiguity=Translation unit is ambiguous. +Refactoring_ParsingError=Unable to parse {0}. NO_FILE=File not found. NodeContainer_Name=name: RefactoringSaveHelper_unexpected_exception=An unexpected exception occurred. See the error log for more details. diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/RefactoringASTCache.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/RefactoringASTCache.java new file mode 100644 index 00000000000..9cd00af8f45 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/RefactoringASTCache.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Google, Inc 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: + * Sergey Prigogin (Google) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.refactoring; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +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.ui.services.IDisposable; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.index.IIndex; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.ILanguage; +import org.eclipse.cdt.core.model.ITranslationUnit; + +import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable; +import org.eclipse.cdt.internal.corext.util.CModelUtil; + +import org.eclipse.cdt.internal.ui.editor.ASTProvider; + +/** + * Cache containing ASTs for the translation units participating in refactoring. + * The cache object has to be disposed of after use. Failure to do so may cause + * loss of index lock. + */ +public class RefactoringASTCache implements IDisposable { + private IIndex fIndex; + private Map fASTCache; + private boolean fDisposed; + + public RefactoringASTCache() { + fASTCache = new HashMap(); + } + + /** + * Returns an AST for the given translation unit. The AST is built for the working + * copy of the translation unit if such working copy exists. The returned AST is a shared + * one whenever possible. + * NOTE: No references to the AST or its nodes can be kept after calling the {@link #dispose()} method. + * @param tu The translation unit. + * @param pm A progress monitor. + * @return An AST, or null if the AST cannot be obtained. + */ + public IASTTranslationUnit getAST(ITranslationUnit tu, IProgressMonitor pm) + throws CoreException, OperationCanceledException { + Assert.isTrue(!fDisposed, "RefactoringASTCache is already disposed"); //$NON-NLS-1$ + if (fIndex == null) { + ICProject[] projects; + projects = CoreModel.getDefault().getCModel().getCProjects(); + IIndex index = CCorePlugin.getIndexManager().getIndex(projects); + try { + index.acquireReadLock(); + } catch (InterruptedException e) { + throw new OperationCanceledException(); + } + fIndex = index; + } + + tu= CModelUtil.toWorkingCopy(tu); + IASTTranslationUnit ast= fASTCache.get(tu); + if (ast == null) { + // Try to get a shared AST before creating our own. + final IASTTranslationUnit[] astHolder = new IASTTranslationUnit[1]; + ASTProvider.getASTProvider().runOnAST(tu, ASTProvider.WAIT_IF_OPEN, pm, new ASTRunnable() { + public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) throws CoreException { + // Leaking of AST outside of runOnAST method is dangerous, but it does not cause + // harm here since the index remains locked for the duration of the AST life span. + astHolder[0] = ast; + return Status.OK_STATUS; + } + }); + ast = astHolder[0]; + if (ast == null) { + int options= ITranslationUnit.AST_CONFIGURE_USING_SOURCE_CONTEXT | + ITranslationUnit.AST_SKIP_INDEXED_HEADERS; + ast= tu.getAST(fIndex, options); + fASTCache.put(tu, ast); + } + } + if (pm != null) { + pm.done(); + } + return ast; + } + + /** + * Returns the index that can be safely used for reading until the cache is disposed. + * + * @return The index. + */ + public IIndex getIndex() { + Assert.isTrue(!fDisposed, "RefactoringASTCache is already disposed"); //$NON-NLS-1$ + return fIndex; + } + + /** + * @see IDisposable#dispose() + */ + public void dispose() { + Assert.isTrue(!fDisposed, "RefactoringASTCache.dispose() called more than once"); //$NON-NLS-1$ + fDisposed = true; + if (fIndex != null) { + fIndex.releaseReadLock(); + } + } + + @Override + protected void finalize() throws Throwable { + Assert.isTrue(fDisposed, "RefactoringASTCache was not disposed"); //$NON-NLS-1$ + super.finalize(); + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/RefactoringRunner2.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/RefactoringRunner2.java new file mode 100644 index 00000000000..48daeea5500 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/RefactoringRunner2.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2011 Google, Inc 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: + * Sergey Prigogin (Google) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.refactoring; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.window.IShellProvider; + +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ICProject; + +/** + * Base class for all refactoring runners. This class is intended as a replacement + * for RefactoringRunner. + */ +public abstract class RefactoringRunner2 { + protected final ISelection selection; + protected final ICElement element; + protected final IShellProvider shellProvider; + protected final ICProject project; + protected final RefactoringStarter starter; + + public RefactoringRunner2(ICElement element, ISelection selection, + IShellProvider shellProvider, ICProject cProject) { + this.selection = selection; + this.element= element; + this.shellProvider= shellProvider; + this.project = cProject; + this.starter = new RefactoringStarter(); + } + + public final void run() { + RefactoringASTCache astCache = new RefactoringASTCache(); + try { + run(astCache); + } finally { + astCache.dispose(); + } + } + + protected abstract void run(RefactoringASTCache astCache); +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoring.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoring.java index 278662ef59f..b5918e39ec0 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoring.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoring.java @@ -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,18 +7,18 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Institute for Software - initial API and implementation + * Institute for Software - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.ui.refactoring.gettersandsetters; import java.util.ArrayList; +import java.util.List; -import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.SubMonitor; -import org.eclipse.jface.text.Region; import org.eclipse.jface.viewers.ISelection; import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; import org.eclipse.ltk.core.refactoring.RefactoringStatus; @@ -43,20 +43,20 @@ import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.internal.core.dom.rewrite.astwriter.ContainerNode; +import org.eclipse.cdt.internal.ui.refactoring.CRefactoring2; import org.eclipse.cdt.internal.ui.refactoring.AddDeclarationNodeToClassChange; -import org.eclipse.cdt.internal.ui.refactoring.CRefactoring; import org.eclipse.cdt.internal.ui.refactoring.Container; import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector; -import org.eclipse.cdt.internal.ui.refactoring.implementmethod.InsertLocation; -import org.eclipse.cdt.internal.ui.refactoring.implementmethod.MethodDefinitionInsertLocationFinder; +import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache; +import org.eclipse.cdt.internal.ui.refactoring.implementmethod.InsertLocation2; +import org.eclipse.cdt.internal.ui.refactoring.implementmethod.MethodDefinitionInsertLocationFinder2; import org.eclipse.cdt.internal.ui.refactoring.utils.NodeHelper; -import org.eclipse.cdt.internal.ui.refactoring.utils.SelectionHelper; import org.eclipse.cdt.internal.ui.refactoring.utils.VisibilityEnum; /** * @author Thomas Corbat */ -public class GenerateGettersAndSettersRefactoring extends CRefactoring { +public class GenerateGettersAndSettersRefactoring extends CRefactoring2 { private final class CompositeTypeSpecFinder extends ASTVisitor { private final int start; @@ -74,7 +74,7 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring { public int visit(IASTDeclSpecifier declSpec) { if (declSpec instanceof IASTCompositeTypeSpecifier) { IASTFileLocation loc = declSpec.getFileLocation(); - if (start > loc.getNodeOffset() && start < loc.getNodeOffset()+ loc.getNodeLength()) { + if (start > loc.getNodeOffset() && start < loc.getNodeOffset() + loc.getNodeLength()) { container.setObject((IASTCompositeTypeSpecifier) declSpec); return ASTVisitor.PROCESS_ABORT; } @@ -85,12 +85,13 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring { } private static final String MEMBER_DECLARATION = "MEMBER_DECLARATION"; //$NON-NLS-1$ - private final GetterAndSetterContext context = new GetterAndSetterContext(); - private InsertLocation definitionInsertLocation; + private final GetterAndSetterContext context; + private InsertLocation2 definitionInsertLocation; - public GenerateGettersAndSettersRefactoring(IFile file, ISelection selection, ICElement element, - ICProject project) { - super(file, selection, element, project); + public GenerateGettersAndSettersRefactoring(ICElement element, ISelection selection, + ICProject project, RefactoringASTCache astCache) { + super(element, selection, project, astCache); + context = new GetterAndSetterContext(); } @Override @@ -105,7 +106,7 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring { if (!initStatus.hasFatalError()) { initRefactoring(pm); - if (context.existingFields.size() == 0) { + if (context.existingFields.isEmpty()) { initStatus.addFatalError(Messages.GenerateGettersAndSettersRefactoring_NoFields); } } @@ -116,30 +117,24 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring { public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException { RefactoringStatus finalStatus = null; - try { - lockIndex(); - finalStatus = super.checkFinalConditions(pm); - if (!context.isImplementationInHeader()) { - definitionInsertLocation = findInsertLocation(); - if (file.equals(definitionInsertLocation.getInsertFile())) { - finalStatus.addInfo(Messages.GenerateGettersAndSettersRefactoring_NoImplFile); - } + finalStatus = super.checkFinalConditions(pm); + if (!context.isImplementationInHeader()) { + definitionInsertLocation = findInsertLocation(); + if (definitionInsertLocation == null || tu.equals(definitionInsertLocation.getTranslationUnit())) { + finalStatus.addInfo(Messages.GenerateGettersAndSettersRefactoring_NoImplFile); } - } catch (InterruptedException e) { - } finally { - unlockIndex(); } return finalStatus; } - private void initRefactoring(IProgressMonitor pm) { - loadTranslationUnit(initStatus, pm); - context.selectedName = getSelectedName(); + private void initRefactoring(IProgressMonitor pm) throws OperationCanceledException, CoreException { + IASTTranslationUnit ast = astCache.getAST(tu, null); + context.selectedName = getSelectedName(ast); IASTCompositeTypeSpecifier compositeTypeSpecifier = null; if (context.selectedName != null) { compositeTypeSpecifier = getCompositeTypeSpecifier(context.selectedName); } else { - compositeTypeSpecifier = findCurrentCompositeTypeSpecifier(); + compositeTypeSpecifier = findCurrentCompositeTypeSpecifier(ast); } if (compositeTypeSpecifier != null) { findDeclarations(compositeTypeSpecifier); @@ -148,8 +143,9 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring { } } - private IASTCompositeTypeSpecifier findCurrentCompositeTypeSpecifier() { - final int start = region.getOffset(); + private IASTCompositeTypeSpecifier findCurrentCompositeTypeSpecifier(IASTTranslationUnit ast) + throws OperationCanceledException, CoreException { + final int start = selectedRegion.getOffset(); Container container = new Container(); ast.accept(new CompositeTypeSpecFinder(start, container)); return container.getObject(); @@ -163,12 +159,12 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring { return (IASTCompositeTypeSpecifier) node; } - private IASTName getSelectedName() { - ArrayList names = findAllMarkedNames(); + private IASTName getSelectedName(IASTTranslationUnit ast) { + List names = findAllMarkedNames(ast); if (names.size() < 1) { return null; } - return names.get(names.size()-1); + return names.get(names.size() - 1); } protected void findDeclarations(IASTCompositeTypeSpecifier compositeTypeSpecifier) { @@ -191,10 +187,8 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring { } if ((innermostDeclarator instanceof IASTFunctionDeclarator)) { context.existingFunctionDeclarations.add(fieldDeclaration); - } else { - if (SelectionHelper.isInSameFile(fieldDeclaration, file)) { - context.existingFields.add(fieldDeclaration); - } + } else if (fieldDeclaration.isPartOfTranslationUnitFile()) { + context.existingFields.add(fieldDeclaration); } } } @@ -214,38 +208,32 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring { @Override protected void collectModifications(IProgressMonitor pm,ModificationCollector collector) throws CoreException, OperationCanceledException { - try { - lockIndex(); - ArrayList getterAndSetters = new ArrayList(); - ArrayList definitions = new ArrayList(); - for (GetterSetterInsertEditProvider currentProvider : context.selectedFunctions) { - if (context.isImplementationInHeader()) { - getterAndSetters.add(currentProvider.getFunctionDefinition(false)); - } else { - getterAndSetters.add(currentProvider.getFunctionDeclaration()); - definitions.add(currentProvider.getFunctionDefinition(true)); - } + List getterAndSetters = new ArrayList(); + List definitions = new ArrayList(); + for (GetterSetterInsertEditProvider currentProvider : context.selectedFunctions) { + if (context.isImplementationInHeader()) { + getterAndSetters.add(currentProvider.getFunctionDefinition(false)); + } else { + getterAndSetters.add(currentProvider.getFunctionDeclaration()); + definitions.add(currentProvider.getFunctionDefinition(true)); } - if (!context.isImplementationInHeader()) { - addDefinition(collector, definitions); - } - ICPPASTCompositeTypeSpecifier classDefinition = - (ICPPASTCompositeTypeSpecifier) context.existingFields.get(context.existingFields.size() - 1).getParent(); - - AddDeclarationNodeToClassChange.createChange(classDefinition, VisibilityEnum.v_public, - getterAndSetters, false, collector); - } catch (InterruptedException e) { - } finally { - unlockIndex(); } + if (!context.isImplementationInHeader()) { + addDefinition(collector, definitions); + } + ICPPASTCompositeTypeSpecifier classDefinition = + (ICPPASTCompositeTypeSpecifier) context.existingFields.get(context.existingFields.size() - 1).getParent(); + + AddDeclarationNodeToClassChange.createChange(classDefinition, VisibilityEnum.v_public, + getterAndSetters, false, collector); } - private void addDefinition(ModificationCollector collector, ArrayList definitions) + private void addDefinition(ModificationCollector collector, List definitions) throws CoreException { - InsertLocation location = findInsertLocation(); - IASTTranslationUnit targetUnit = location.getTargetTranslationUnit(); - IASTNode parent = location.getPartenOfNodeToInsertBefore(); - ASTRewrite rewrite = collector.rewriterForTranslationUnit(targetUnit); + InsertLocation2 location = findInsertLocation(); + IASTNode parent = location.getParentOfNodeToInsertBefore(); + IASTTranslationUnit ast = parent.getTranslationUnit(); + ASTRewrite rewrite = collector.rewriterForTranslationUnit(ast); IASTNode nodeToInsertBefore = location.getNodeToInsertBefore(); ContainerNode cont = new ContainerNode(); for (IASTFunctionDefinition functionDefinition : definitions) { @@ -258,20 +246,15 @@ public class GenerateGettersAndSettersRefactoring extends CRefactoring { return context; } - public Region getRegion() { - return region; - } - - private InsertLocation findInsertLocation() throws CoreException { - IASTSimpleDeclaration decl = context.existingFields.get(0); - InsertLocation insertLocation = MethodDefinitionInsertLocationFinder.find(decl.getFileLocation(), - decl.getParent(), file); + private InsertLocation2 findInsertLocation() throws CoreException { + IASTSimpleDeclaration decl = context.existingFields.get(0); + InsertLocation2 insertLocation = MethodDefinitionInsertLocationFinder2.find( + decl.getFileLocation(), decl.getParent(), astCache); - if (!insertLocation.hasFile() || NodeHelper.isContainedInTemplateDeclaration(decl)) { - insertLocation.setInsertFile(file); - insertLocation.setNodeToInsertAfter(NodeHelper.findTopLevelParent(decl)); + if (insertLocation.getFile() == null || NodeHelper.isContainedInTemplateDeclaration(decl)) { + insertLocation.setNodeToInsertAfter(NodeHelper.findTopLevelParent(decl), tu); } - + return insertLocation; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoringRunner.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoringRunner.java index 08f60ad9bbd..04684f8190c 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoringRunner.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/gettersandsetters/GenerateGettersAndSettersRefactoringRunner.java @@ -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,45 +7,47 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Institute for Software - initial API and implementation + * Institute for Software - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.ui.refactoring.gettersandsetters; -import org.eclipse.core.resources.IFile; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.window.IShellProvider; -import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation; +import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICProject; -import org.eclipse.cdt.internal.ui.refactoring.RefactoringRunner; +import org.eclipse.cdt.internal.ui.refactoring.RefactoringRunner2; +import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache; +import org.eclipse.cdt.internal.ui.refactoring.RefactoringSaveHelper; /** * @author Thomas Corbat - * */ -public class GenerateGettersAndSettersRefactoringRunner extends RefactoringRunner { +public class GenerateGettersAndSettersRefactoringRunner extends RefactoringRunner2 { - public GenerateGettersAndSettersRefactoringRunner(IFile file, ISelection selection, - ICElement elem, IShellProvider shellProvider, ICProject cProject) { - super(file, selection, elem, shellProvider, cProject); + public GenerateGettersAndSettersRefactoringRunner(ICElement element, ISelection selection, + IShellProvider shellProvider, ICProject cProject) { + super(element, selection, shellProvider, cProject); } @Override - public void run() { - if (PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor() instanceof ITextEditor) { - GenerateGettersAndSettersRefactoring refactoring = new GenerateGettersAndSettersRefactoring(file, selection, celement, project); - GenerateGettersAndSettersRefactoringWizard wizard = new GenerateGettersAndSettersRefactoringWizard(refactoring); - RefactoringWizardOpenOperation operator = new RefactoringWizardOpenOperation(wizard); - - try { - operator.run(shellProvider.getShell(), refactoring.getName()); - } catch (InterruptedException e) { - //initial condition checking got canceled by the user. - } + public void run(RefactoringASTCache astCache) { + if (getActiveEditor() instanceof ITextEditor) { + GenerateGettersAndSettersRefactoring refactoring = + new GenerateGettersAndSettersRefactoring(element, selection, project, astCache); + GenerateGettersAndSettersRefactoringWizard wizard = + new GenerateGettersAndSettersRefactoringWizard(refactoring); + starter.activate(wizard, shellProvider.getShell(), refactoring.getName(), + RefactoringSaveHelper.SAVE_REFACTORING); } } + + private IEditorPart getActiveEditor() { + return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/InsertLocation2.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/InsertLocation2.java new file mode 100644 index 00000000000..06c53779904 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/InsertLocation2.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * 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 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Institute for Software - initial API and implementation + * Sergey Prigogin (Google) + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.refactoring.implementmethod; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.model.ITranslationUnit; + +/** + * Is returned when using the find method of the MethodDefinitionInsertLocationFinder. + * Contains all the information needed to insert at the correct position. + * This class is intended as a replacement for InsertLocation. + * + * @author Lukas Felber + */ +public class InsertLocation2 { + private IASTNode nodeToInsertAfter; + private IASTNode nodeToInsertBefore; + private IASTNode parentNode; + private ITranslationUnit tu; + + public InsertLocation2() { + } + + public boolean hasAnyNode() { + return nodeToInsertAfter != null || nodeToInsertBefore != null; + } + + public IASTNode getNodeToInsertBefore() { + return nodeToInsertBefore; + } + + public IASTNode getParentOfNodeToInsertBefore() throws CoreException { + IASTNode node = nodeToInsertBefore != null ? nodeToInsertBefore : nodeToInsertAfter; + return node != null ? node.getParent() : parentNode; + } + + public ITranslationUnit getTranslationUnit() { + return tu; + } + + public IFile getFile() { + return tu != null ? (IFile) tu.getResource() : null; + } + + public int getInsertPosition() { + if (nodeToInsertBefore != null) { + return nodeToInsertBefore.getFileLocation().getNodeOffset(); + } else if (nodeToInsertAfter != null) { + return nodeToInsertAfter.getFileLocation().getNodeOffset() + + nodeToInsertAfter.getFileLocation().getNodeLength(); + } + return 0; + } + + public void setNodeToInsertAfter(IASTNode nodeToInsertAfter, ITranslationUnit tu) { + this.nodeToInsertAfter = nodeToInsertAfter; + this.tu = tu; + } + + public void setNodeToInsertBefore(IASTNode nodeToInsertBefore, ITranslationUnit tu) { + this.nodeToInsertBefore = nodeToInsertBefore; + this.tu = tu; + } + + public void setParentNode(IASTNode parentNode, ITranslationUnit tu) { + this.parentNode = parentNode; + this.tu = tu; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/MethodDefinitionInsertLocationFinder2.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/MethodDefinitionInsertLocationFinder2.java new file mode 100644 index 00000000000..aa513697d1e --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/implementmethod/MethodDefinitionInsertLocationFinder2.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * 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 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Institute for Software - initial API and implementation + * Sergey Prigogin (Google) + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.refactoring.implementmethod; + +import java.util.ArrayList; +import java.util.Collection; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTFileLocation; +import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; + +import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache; +import org.eclipse.cdt.internal.ui.refactoring.utils.ASTNameInContext; +import org.eclipse.cdt.internal.ui.refactoring.utils.DefinitionFinder2; +import org.eclipse.cdt.internal.ui.refactoring.utils.NodeHelper; + +/** + * Finds the information that are needed to tell where a method definition of a certain + * method declaration should be inserted. + * This class is intended as a replacement for MethodDefinitionInsertLocationFinder. + * + * @author Mirko Stocker, Lukas Felber + */ +public class MethodDefinitionInsertLocationFinder2 { + + private static IASTNode findFunctionDefinitionInParents(IASTNode node) { + if (node == null) { + return null; + } else if (node instanceof IASTFunctionDefinition) { + if (node.getParent() instanceof ICPPASTTemplateDeclaration) { + node = node.getParent(); + } + return node; + } + return findFunctionDefinitionInParents(node.getParent()); + } + + private static IASTNode findFirstSurroundingParentFunctionNode(IASTNode definition) { + IASTNode functionDefinitionInParents = findFunctionDefinitionInParents(definition); + if (functionDefinitionInParents == null || + functionDefinitionInParents.getNodeLocations().length == 0) { + return null; + } + return functionDefinitionInParents; + } + + public static InsertLocation2 find(IASTFileLocation methodDeclarationLocation, IASTNode parent, + RefactoringASTCache astCache) throws CoreException { + IASTDeclaration[] declarations = NodeHelper.getDeclarations(parent); + InsertLocation2 insertLocation = new InsertLocation2(); + + for (IASTSimpleDeclaration simpleDeclaration : getAllPreviousSimpleDeclarationsFromClassInReverseOrder( + declarations, methodDeclarationLocation)) { + ASTNameInContext definition = DefinitionFinder2.getDefinition(simpleDeclaration, astCache); + if (definition != null) { + insertLocation.setNodeToInsertAfter(findFirstSurroundingParentFunctionNode( + definition.getName()), definition.getTranslationUnit()); + } + } + + for (IASTSimpleDeclaration simpleDeclaration : getAllFollowingSimpleDeclarationsFromClass( + declarations, methodDeclarationLocation)) { + ASTNameInContext definition = DefinitionFinder2.getDefinition(simpleDeclaration, astCache); + if (definition != null) { + insertLocation.setNodeToInsertBefore(findFirstSurroundingParentFunctionNode( + definition.getName()), definition.getTranslationUnit()); + } + } + + return insertLocation; + } + + /** + * Searches the given class for all IASTSimpleDeclarations occurring before 'method' + * and returns them in reverse order. + * + * @param declarations to be searched + * @param methodPosition on which the search aborts + * @return all declarations, sorted in reverse order + */ + private static Collection getAllPreviousSimpleDeclarationsFromClassInReverseOrder( + IASTDeclaration[] declarations, IASTFileLocation methodPosition) { + ArrayList allIASTSimpleDeclarations = new ArrayList(); + for (IASTDeclaration decl : declarations) { + if (decl.getFileLocation().getStartingLineNumber() >= methodPosition.getStartingLineNumber()) { + return allIASTSimpleDeclarations; + } + if (isMemberFunctionDeclaration(decl)) { + allIASTSimpleDeclarations.add(0, (IASTSimpleDeclaration) decl); + } + } + return allIASTSimpleDeclarations; + } + + private static Collection getAllFollowingSimpleDeclarationsFromClass( + IASTDeclaration[] declarations, IASTFileLocation methodPosition) { + ArrayList allIASTSimpleDeclarations = new ArrayList(); + + for (IASTDeclaration decl : declarations) { + if (isMemberFunctionDeclaration(decl) && + decl.getFileLocation().getStartingLineNumber() > methodPosition.getStartingLineNumber() ) { + allIASTSimpleDeclarations.add((IASTSimpleDeclaration) decl); + } + } + return allIASTSimpleDeclarations; + } + + private static boolean isMemberFunctionDeclaration(IASTDeclaration decl) { + return decl instanceof IASTSimpleDeclaration && + ((IASTSimpleDeclaration) decl).getDeclarators().length > 0 && + ((IASTSimpleDeclaration) decl).getDeclarators()[0] instanceof IASTFunctionDeclarator; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/utils/ASTNameInContext.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/utils/ASTNameInContext.java new file mode 100644 index 00000000000..0e1ea0d3cc3 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/utils/ASTNameInContext.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2011 Google, Inc 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: + * Sergey Prigogin (Google) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.refactoring.utils; + +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.model.ITranslationUnit; + +/** + * Encapsulates an IASTName and the ITranslationUnit it belongs to. + */ +public class ASTNameInContext { + private final IASTName name; + private final ITranslationUnit tu; + + ASTNameInContext(IASTName name, ITranslationUnit tu) { + this.name = name; + this.tu = tu; + } + + public IASTName getName() { + return name; + } + + public ITranslationUnit getTranslationUnit() { + return tu; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/utils/DefinitionFinder2.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/utils/DefinitionFinder2.java new file mode 100644 index 00000000000..ff796f46274 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/utils/DefinitionFinder2.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2011 Google, Inc 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: + * Sergey Prigogin (Google) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.refactoring.utils; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; + +import org.eclipse.cdt.core.dom.IName; +import org.eclipse.cdt.core.dom.ast.IASTDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTName; +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.index.IIndexName; +import org.eclipse.cdt.core.model.CoreModelUtil; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.ui.CUIPlugin; + +import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache; + +/** + * Helper class to find definitions. This class is intended as a replacement for DefinitionFinder. + */ +public class DefinitionFinder2 { + + public static ASTNameInContext getDefinition(IASTSimpleDeclaration simpleDeclaration, + RefactoringASTCache astCache) throws CoreException { + IASTDeclarator declarator = simpleDeclaration.getDeclarators()[0]; + IBinding binding = declarator.getName().resolveBinding(); + return getDefinition(binding, astCache); + } + + private static ASTNameInContext getDefinition(IBinding binding, RefactoringASTCache astCache) + throws CoreException { + Set searchedFiles = new HashSet(); + ITranslationUnit[] workingCopies = CUIPlugin.getSharedWorkingCopies(); + List definitions = new ArrayList(); + for (ITranslationUnit tu : workingCopies) { + findDefinitionsInTranslationUnit(binding, tu, astCache, definitions, null); + searchedFiles.add(tu.getLocation().toOSString()); + } + + IIndexName[] definitionsFromIndex = astCache.getIndex().findDefinitions(binding); + + if (definitionsFromIndex.length > 0) { + for (IIndexName name : definitionsFromIndex) { + ITranslationUnit tu = CoreModelUtil.findTranslationUnitForLocation( + name.getFile().getLocation(), null); + if (searchedFiles.add(tu.getLocation().toOSString())) { + findDefinitionsInTranslationUnit(binding, tu, astCache, definitions, null); + } + } + } + if (definitions.size() != 1) { + return null; + } + return definitions.get(0); + } + + private static void findDefinitionsInTranslationUnit(IBinding binding, ITranslationUnit tu, + RefactoringASTCache astCache, List definitions, IProgressMonitor pm) + throws OperationCanceledException, CoreException { + IASTTranslationUnit ast = astCache.getAST(tu, pm); + findDefinitionsInAST(binding, ast, tu, definitions); + } + + private static void findDefinitionsInAST(IBinding binding, IASTTranslationUnit ast, + ITranslationUnit tu, List definitions) { + for (IName definition : ast.getDefinitions(binding)) { + if (definition instanceof IASTName) { + definitions.add(new ASTNameInContext((IASTName) definition, tu)); + } + } + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/GettersAndSettersAction.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/GettersAndSettersAction.java index 1ea55ac0729..2e07fdd7fee 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/GettersAndSettersAction.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/refactoring/actions/GettersAndSettersAction.java @@ -1,13 +1,14 @@ /******************************************************************************* - * 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 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html - * + * * Contributors: - * Institute for Software - initial API and implementation + * Institute for Software - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.ui.refactoring.actions; @@ -30,38 +31,38 @@ import org.eclipse.cdt.internal.ui.refactoring.gettersandsetters.GenerateGetters * @noextend This class is not intended to be subclassed by clients. */ public class GettersAndSettersAction extends RefactoringAction { - + public GettersAndSettersAction() { - super(Messages.GettersAndSetters_label); + super(Messages.GettersAndSetters_label); + setSaveRequired(false); } - + /** * @since 5.1 */ public GettersAndSettersAction(IEditorPart editor) { - super(Messages.GettersAndSetters_label); + this(); setEditor(editor); } @Override public void run(IShellProvider shellProvider, ICElement elem) { - new GenerateGettersAndSettersRefactoringRunner(null, null, elem, shellProvider, elem.getCProject()).run(); + new GenerateGettersAndSettersRefactoringRunner(elem, null, shellProvider, elem.getCProject()).run(); } @Override public void run(IShellProvider shellProvider, IWorkingCopy wc, ITextSelection s) { IResource res= wc.getResource(); if (res instanceof IFile) { - new GenerateGettersAndSettersRefactoringRunner((IFile) res, s, null, shellProvider, wc.getCProject()).run(); + new GenerateGettersAndSettersRefactoringRunner(wc, s, shellProvider, wc.getCProject()).run(); } } @Override public void updateSelection(ICElement elem) { super.updateSelection(elem); - if (elem instanceof IField == false - || elem instanceof ISourceReference == false - || ((ISourceReference) elem).getTranslationUnit().getResource() instanceof IFile == false) { + if (!(elem instanceof IField) || !(elem instanceof ISourceReference) || + !(((ISourceReference) elem).getTranslationUnit().getResource() instanceof IFile)) { setEnabled(false); } }