| /******************************************************************************* |
| * Copyright (c) 2008, 2009 Institute for Software, HSR Hochschule fuer Technik |
| * Rapperswil, University of applied sciences and others |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * 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; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.ILog; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| |
| import org.eclipse.cdt.core.dom.ast.DOMException; |
| import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTArrayModifier; |
| import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTFileLocation; |
| import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation; |
| import org.eclipse.cdt.core.dom.ast.IASTName; |
| import org.eclipse.cdt.core.dom.ast.IASTNode; |
| import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; |
| import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; |
| import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; |
| import org.eclipse.cdt.core.dom.ast.IBinding; |
| import org.eclipse.cdt.core.dom.ast.IVariable; |
| import org.eclipse.cdt.core.dom.ast.cpp.CPPASTVisitor; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter; |
| import org.eclipse.cdt.core.parser.ParserLanguage; |
| import org.eclipse.cdt.ui.CUIPlugin; |
| |
| import org.eclipse.cdt.internal.core.dom.parser.c.CASTPointer; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTArrayDeclarator; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTDeclarator; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTParameterDeclaration; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReferenceOperator; |
| import org.eclipse.cdt.internal.core.dom.rewrite.astwriter.ASTWriter; |
| |
| public class NodeContainer { |
| |
| public final NameInformation NULL_NAME_INFORMATION = new NameInformation( |
| new CPPASTName()); |
| |
| private final ArrayList<IASTNode> vec; |
| private final ArrayList<NameInformation> names; |
| |
| public class NameInformation { |
| |
| private IASTName name; |
| private IASTName declaration; |
| private final ArrayList<IASTName> references; |
| private ArrayList<IASTName> referencesAfterCached; |
| private int lastCachedReferencesHash; |
| private boolean isReference; |
| private boolean isReturnValue; |
| private boolean isConst; |
| private boolean isWriteAccess; |
| |
| private boolean userSetIsReference; |
| private boolean userSetIsReturnValue; |
| private String userSetName; |
| private int userOrder; |
| |
| public int getUserOrder() { |
| return userOrder; |
| } |
| |
| public void setUserOrder(int userOrder) { |
| this.userOrder = userOrder; |
| } |
| |
| public NameInformation(IASTName name) { |
| super(); |
| this.name = name; |
| references = new ArrayList<IASTName>(); |
| } |
| |
| public IASTName getDeclaration() { |
| return declaration; |
| } |
| |
| public void setDeclaration(IASTName declaration) { |
| this.declaration = declaration; |
| } |
| |
| public IASTName getName() { |
| return name; |
| } |
| |
| public void setName(IASTName name) { |
| this.name = name; |
| } |
| |
| public void addReference(IASTName name) { |
| references.add(name); |
| } |
| |
| public ArrayList<IASTName> getReferencesAfterSelection() { |
| if (referencesAfterCached == null |
| || lastCachedReferencesHash != references.hashCode()) { |
| |
| lastCachedReferencesHash = references.hashCode(); |
| referencesAfterCached = new ArrayList<IASTName>(); |
| for (IASTName ref : references) { |
| IASTFileLocation loc = ref.getFileLocation(); |
| if (loc.getNodeOffset() >= getEndOffset()) { |
| referencesAfterCached.add(ref); |
| } |
| } |
| } |
| return referencesAfterCached; |
| } |
| |
| public boolean isUsedAfterReferences() { |
| return getReferencesAfterSelection().size() > 0; |
| } |
| |
| public ICPPASTParameterDeclaration getICPPASTParameterDeclaration( |
| boolean isReference, ParserLanguage lang) { |
| ICPPASTParameterDeclaration para = new CPPASTParameterDeclaration(); |
| IASTDeclarator sourceDeclarator = (IASTDeclarator) getDeclaration() |
| .getParent(); |
| |
| if (sourceDeclarator.getParent() instanceof IASTSimpleDeclaration) { |
| IASTSimpleDeclaration decl = (IASTSimpleDeclaration) sourceDeclarator |
| .getParent(); |
| para.setDeclSpecifier(decl.getDeclSpecifier().copy()); |
| } else if (sourceDeclarator.getParent() instanceof IASTParameterDeclaration) { |
| IASTParameterDeclaration decl = (IASTParameterDeclaration) sourceDeclarator |
| .getParent(); |
| para.setDeclSpecifier(decl.getDeclSpecifier().copy()); |
| } |
| |
| IASTDeclarator declarator; |
| if (sourceDeclarator instanceof IASTArrayDeclarator) { |
| IASTArrayDeclarator arrDeclarator = (IASTArrayDeclarator) sourceDeclarator; |
| declarator = new CPPASTArrayDeclarator(); |
| IASTArrayModifier[] arrayModifiers = arrDeclarator |
| .getArrayModifiers(); |
| for (IASTArrayModifier arrayModifier : arrayModifiers) { |
| ((IASTArrayDeclarator) declarator) |
| .addArrayModifier(arrayModifier.copy()); |
| } |
| |
| } else { |
| declarator = new CPPASTDeclarator(); |
| } |
| declarator.setName(new CPPASTName(getDeclaration().toCharArray())); |
| for (IASTPointerOperator pointerOp : sourceDeclarator |
| .getPointerOperators()) { |
| declarator.addPointerOperator(pointerOp.copy()); |
| } |
| |
| if (isReference && !hasReferenceOperartor(declarator)) { |
| switch (lang) { |
| case C: |
| declarator.addPointerOperator(new CASTPointer()); |
| break; |
| case CPP: |
| declarator.addPointerOperator(new CPPASTReferenceOperator()); |
| break; |
| } |
| } |
| |
| declarator.setNestedDeclarator(sourceDeclarator |
| .getNestedDeclarator()); |
| para.setDeclarator(declarator); |
| |
| return para; |
| } |
| |
| public boolean hasReferenceOperartor(IASTDeclarator declarator) { |
| for (IASTPointerOperator pOp : declarator.getPointerOperators()) { |
| if (pOp instanceof ICPPASTReferenceOperator) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public String getType() { |
| IASTDeclSpecifier declSpec = null; |
| |
| IASTNode node = getDeclaration().getParent(); |
| if (node instanceof ICPPASTSimpleTypeTemplateParameter) { |
| ICPPASTSimpleTypeTemplateParameter parameter = (ICPPASTSimpleTypeTemplateParameter) node; |
| return parameter.getName().toString(); |
| } |
| IASTDeclarator sourceDeclarator = (IASTDeclarator) node; |
| if (sourceDeclarator.getParent() instanceof IASTSimpleDeclaration) { |
| IASTSimpleDeclaration decl = (IASTSimpleDeclaration) sourceDeclarator |
| .getParent(); |
| declSpec = decl.getDeclSpecifier(); |
| } else if (sourceDeclarator.getParent() instanceof IASTParameterDeclaration) { |
| IASTParameterDeclaration decl = (IASTParameterDeclaration) sourceDeclarator |
| .getParent(); |
| declSpec = decl.getDeclSpecifier(); |
| } |
| |
| ASTWriter writer = new ASTWriter(); |
| return writer.write(declSpec); |
| } |
| |
| public boolean isDeclarationInScope() { |
| if(declaration.toCharArray().length > 0) { |
| int declOffset = declaration.getFileLocation().getNodeOffset(); |
| return declOffset >= getStartOffset() |
| && declOffset <= getEndOffset(); |
| } |
| return true; |
| } |
| |
| @Override |
| public String toString() { |
| return Messages.NodeContainer_Name + name + ' ' |
| + isDeclarationInScope(); |
| } |
| |
| public boolean isReference() { |
| return isReference; |
| } |
| |
| public void setReference(boolean isReference) { |
| this.isReference = isReference; |
| } |
| |
| public boolean isReturnValue() { |
| return isReturnValue; |
| } |
| |
| public void setReturnValue(boolean isReturnValue) { |
| this.isReturnValue = isReturnValue; |
| } |
| |
| public boolean isUserSetIsReference() { |
| return userSetIsReference; |
| } |
| |
| public void setUserSetIsReference(boolean userSetIsReference) { |
| this.userSetIsReference = userSetIsReference; |
| } |
| |
| public boolean isUserSetIsReturnValue() { |
| return userSetIsReturnValue; |
| } |
| |
| public void setUserSetIsReturnValue(boolean userSetIsReturnValue) { |
| this.userSetIsReturnValue = userSetIsReturnValue; |
| } |
| |
| public String getUserSetName() { |
| return userSetName; |
| } |
| |
| public void setUserSetName(String userSetName) { |
| this.userSetName = userSetName; |
| } |
| |
| public boolean isConst() { |
| return isConst; |
| } |
| |
| public void setConst(boolean isConst) { |
| this.isConst = isConst; |
| } |
| |
| public boolean isWriteAccess() { |
| return isWriteAccess; |
| } |
| |
| public void setWriteAccess(boolean isWriteAceess) { |
| this.isWriteAccess = isWriteAceess; |
| } |
| |
| } |
| |
| public NodeContainer() { |
| super(); |
| vec = new ArrayList<IASTNode>(); |
| names = new ArrayList<NameInformation>(); |
| } |
| |
| public int size() { |
| return vec.size(); |
| } |
| |
| public void add(IASTNode node) { |
| vec.add(node); |
| } |
| |
| public void findAllNames() { |
| for (IASTNode node : vec) { |
| node.accept(new CPPASTVisitor() { |
| { |
| shouldVisitNames = true; |
| } |
| |
| @Override |
| public int visit(IASTName name) { |
| IBinding bind = name.resolveBinding(); |
| |
| if (bind instanceof ICPPBinding |
| && !(bind instanceof ICPPTemplateTypeParameter)) { |
| ICPPBinding cppBind = (ICPPBinding) bind; |
| try { |
| if (!cppBind.isGloballyQualified()) { |
| NameInformation nameInformation = new NameInformation( |
| name); |
| |
| IASTName[] refs = name.getTranslationUnit() |
| .getReferences(bind); |
| for (IASTName ref : refs) { |
| nameInformation.addReference(ref); |
| } |
| names.add(nameInformation); |
| } |
| } catch (DOMException e) { |
| ILog logger = CUIPlugin.getDefault().getLog(); |
| IStatus status = new Status(IStatus.WARNING, |
| CUIPlugin.PLUGIN_ID, IStatus.OK, e |
| .getMessage(), e); |
| logger.log(status); |
| } |
| }else if(bind instanceof IVariable) { |
| NameInformation nameInformation = new NameInformation( |
| name); |
| |
| IASTName[] refs = name.getTranslationUnit() |
| .getReferences(bind); |
| for (IASTName ref : refs) { |
| nameInformation.addReference(ref); |
| } |
| names.add(nameInformation); |
| } |
| return super.visit(name); |
| } |
| }); |
| } |
| |
| for (NameInformation nameInf : names) { |
| IASTName name = nameInf.getName(); |
| |
| IASTTranslationUnit unit = name.getTranslationUnit(); |
| IASTName[] decls = unit.getDeclarationsInAST(name.resolveBinding()); |
| for (IASTName declaration : decls) { |
| nameInf.setDeclaration(declaration); |
| } |
| } |
| } |
| |
| /* |
| * Returns all local names in the selection which will be used after the |
| * selection expected the ones which are pointers |
| */ |
| public ArrayList<NameInformation> getAllAfterUsedNames() { |
| ArrayList<IASTName> declarations = new ArrayList<IASTName>(); |
| ArrayList<NameInformation> usedAfter = new ArrayList<NameInformation>(); |
| |
| if (names.size() <= 0) { |
| findAllNames(); |
| } |
| |
| for (NameInformation nameInf : names) { |
| if (!declarations.contains(nameInf.getDeclaration())) { |
| |
| declarations.add(nameInf.getDeclaration()); |
| if (nameInf.isUsedAfterReferences()) { |
| usedAfter.add(nameInf); |
| nameInf.setReference(true); |
| } |
| } |
| } |
| |
| return usedAfter; |
| } |
| |
| public ArrayList<NameInformation> getAllAfterUsedNamesChoosenByUser() { |
| ArrayList<IASTName> declarations = new ArrayList<IASTName>(); |
| ArrayList<NameInformation> usedAfter = new ArrayList<NameInformation>(); |
| |
| for (NameInformation nameInf : names) { |
| if (!declarations.contains(nameInf.getDeclaration())) { |
| |
| declarations.add(nameInf.getDeclaration()); |
| if (nameInf.isUserSetIsReference() |
| || nameInf.isUserSetIsReturnValue()) { |
| usedAfter.add(nameInf); |
| } |
| } |
| } |
| |
| return usedAfter; |
| } |
| |
| public ArrayList<NameInformation> getUsedNamesUnique() { |
| ArrayList<IASTName> declarations = new ArrayList<IASTName>(); |
| ArrayList<NameInformation> usedAfter = new ArrayList<NameInformation>(); |
| |
| if (names.size() <= 0) { |
| findAllNames(); |
| } |
| |
| for (NameInformation nameInf : names) { |
| if (!declarations.contains(nameInf.getDeclaration())) { |
| |
| declarations.add(nameInf.getDeclaration()); |
| usedAfter.add(nameInf); |
| } else { |
| for (NameInformation nameInformation : usedAfter) { |
| if (nameInf.isWriteAccess() |
| && nameInf.getDeclaration() == nameInformation |
| .getDeclaration()) { |
| nameInformation.setWriteAccess(true); |
| } |
| } |
| } |
| } |
| |
| return usedAfter; |
| } |
| |
| /* |
| * Returns all local names in the selection which will be used after the |
| * selection expected the ones which are pointers |
| * XXX Was soll dieser Kommentar aussagen? --Mirko |
| */ |
| public ArrayList<NameInformation> getAllDeclaredInScope() { |
| ArrayList<IASTName> declarations = new ArrayList<IASTName>(); |
| ArrayList<NameInformation> usedAfter = new ArrayList<NameInformation>(); |
| |
| for (NameInformation nameInf : names) { |
| if (nameInf.isDeclarationInScope() |
| && !declarations.contains(nameInf.getDeclaration()) && nameInf.isUsedAfterReferences()) { |
| |
| declarations.add(nameInf.getDeclaration()); |
| usedAfter.add(nameInf); |
| // is return value candidate, set returnvalue to true and |
| // reference to false |
| nameInf.setReturnValue(true); |
| nameInf.setReference(false); |
| } |
| } |
| |
| return usedAfter; |
| } |
| |
| public List<IASTNode> getNodesToWrite() { |
| return vec; |
| } |
| |
| public int getStartOffset() { |
| return getOffset(false); |
| } |
| |
| public int getStartOffsetIncludingComments() { |
| return getOffset(true); |
| } |
| |
| private int getOffset(boolean includeComments) { |
| int start = Integer.MAX_VALUE; |
| |
| for (IASTNode node : vec) { |
| int nodeStart = Integer.MAX_VALUE; |
| |
| IASTNodeLocation[] nodeLocations = node.getNodeLocations(); |
| if (nodeLocations.length != 1) { |
| for (IASTNodeLocation location : nodeLocations) { |
| int nodeOffset; |
| if (location instanceof IASTMacroExpansionLocation) { |
| IASTMacroExpansionLocation macroLoc = (IASTMacroExpansionLocation) location; |
| nodeOffset = macroLoc.asFileLocation().getNodeOffset(); |
| }else { |
| nodeOffset = node.getFileLocation().getNodeOffset(); |
| } |
| if(nodeOffset < nodeStart) { |
| nodeStart = nodeOffset; |
| } |
| } |
| } else { |
| nodeStart = node.getFileLocation().getNodeOffset(); |
| } |
| if (nodeStart < start) { |
| start = nodeStart; |
| } |
| } |
| |
| return start; |
| } |
| |
| public int getEndOffset() { |
| return getEndOffset(false); |
| } |
| |
| public int getEndOffsetIncludingComments() { |
| return getEndOffset(true); |
| } |
| |
| private int getEndOffset(boolean includeComments) { |
| int end = 0; |
| |
| for (IASTNode node : vec) { |
| int fileOffset = 0; |
| int length = 0; |
| |
| IASTNodeLocation[] nodeLocations = node.getNodeLocations(); |
| for (IASTNodeLocation location : nodeLocations) { |
| int nodeOffset, nodeLength; |
| if (location instanceof IASTMacroExpansionLocation) { |
| IASTMacroExpansionLocation macroLoc = (IASTMacroExpansionLocation) location; |
| nodeOffset = macroLoc.asFileLocation().getNodeOffset(); |
| nodeLength = macroLoc.asFileLocation().getNodeLength(); |
| }else { |
| nodeOffset = location.getNodeOffset(); |
| nodeLength = location.getNodeLength(); |
| } |
| if(fileOffset < nodeOffset) { |
| fileOffset = nodeOffset; |
| length = nodeLength; |
| } |
| } |
| int endNode = fileOffset + length; |
| if (endNode > end) { |
| end = endNode; |
| } |
| } |
| |
| return end; |
| } |
| |
| @Override |
| public String toString() { |
| return vec.toString(); |
| } |
| |
| public ArrayList<NameInformation> getNames() { |
| return names; |
| } |
| |
| } |