/******************************************************************************* * 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.ui.CUIPlugin; 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 vec; private final ArrayList names; public class NameInformation { private IASTName name; private IASTName declaration; private final ArrayList references; private ArrayList 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(); } 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 getReferencesAfterSelection() { if (referencesAfterCached == null || lastCachedReferencesHash != references.hashCode()) { lastCachedReferencesHash = references.hashCode(); referencesAfterCached = new ArrayList(); 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) { 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)) { declarator.addPointerOperator(new CPPASTReferenceOperator()); } 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(); names = new ArrayList(); } 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 getAllAfterUsedNames() { ArrayList declarations = new ArrayList(); ArrayList usedAfter = new ArrayList(); 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 getAllAfterUsedNamesChoosenByUser() { ArrayList declarations = new ArrayList(); ArrayList usedAfter = new ArrayList(); 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 getUsedNamesUnique() { ArrayList declarations = new ArrayList(); ArrayList usedAfter = new ArrayList(); 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 getAllDeclaredInScope() { ArrayList declarations = new ArrayList(); ArrayList usedAfter = new ArrayList(); 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 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 getNames() { return names; } }