/******************************************************************************* * Copyright (c) 2008, 2010 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.extractfunction; import java.util.Arrays; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.cdt.core.dom.ast.IASTASMDeclaration; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTFieldReference; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTPointer; import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.c.ICASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConversionName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTOperatorName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel; import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.internal.ui.refactoring.Container; import org.eclipse.cdt.internal.ui.refactoring.EqualityChecker; public class TrailNodeEqualityChecker implements EqualityChecker<IASTNode> { private final Map<String, Integer> names; private final Container<Integer> namesCounter; private IIndex index; public TrailNodeEqualityChecker(Map<String, Integer> names, Container<Integer> namesCounter, IIndex index) { super(); this.names = names; this.namesCounter = namesCounter; this.index = index; } public boolean isEquals(IASTNode trailNode, IASTNode node) { if( (trailNode instanceof TrailName && node instanceof IASTName) || Arrays.equals(getInterfaces(node), getInterfaces(trailNode)) ) { //Is same type if(node instanceof IASTExpression){ return isExpressionEquals(trailNode, node); } else if(node instanceof IASTStatement){ return isStatementEquals(trailNode, node); } else if(node instanceof IASTPointerOperator){ return isPointerOperatorEquals(trailNode, node); } else if(node instanceof IASTDeclaration){ return isDeclarationEquals(trailNode, node); } else if(node instanceof IASTDeclarator){ return isDeclaratorEquals(trailNode, node); } else if(node instanceof IASTInitializer){ //no speciality, is the same type return true return true; } else if(node instanceof IASTDeclSpecifier){ return isDeclSpecifierEquals(trailNode, node); } else if(node instanceof IASTName){ return isNameEquals(trailNode, node); } else { Assert.isLegal(false, "Unexpected Node, this code shoud nod reached"); //$NON-NLS-1$ return true; } } return false; } private boolean isNameEquals(IASTNode trailNode, IASTNode node) { if(trailNode instanceof ICPPASTConversionName) { return true; } else if(trailNode instanceof ICPPASTOperatorName) { ICPPASTOperatorName trailName= ( ICPPASTOperatorName )trailNode; ICPPASTOperatorName name = ( ICPPASTOperatorName )node; return trailName.equals(name); } else if(trailNode instanceof TrailName && node instanceof IASTName) { TrailName trailName = (TrailName) trailNode; IASTName name = (IASTName)node; return isNameEquals(trailName, name); } else { return true; } } private boolean isDeclSpecifierEquals(IASTNode trailNode, IASTNode node) { if (trailNode instanceof IASTSimpleDeclSpecifier) { IASTSimpleDeclSpecifier trailDecl = (IASTSimpleDeclSpecifier) trailNode; IASTSimpleDeclSpecifier decl = (IASTSimpleDeclSpecifier) node; return isSimpleDeclSpecifierEquals(trailDecl, decl); } else if (trailNode instanceof ICPPASTNamedTypeSpecifier) { ICPPASTNamedTypeSpecifier trailDecl = (ICPPASTNamedTypeSpecifier) trailNode; ICPPASTNamedTypeSpecifier decl = (ICPPASTNamedTypeSpecifier) node; return isDeclSpecifierEquals(trailDecl, decl) && isSameNamedTypeSpecifierName(trailDecl, decl) && trailDecl.isTypename() == decl.isTypename() && trailDecl.isExplicit() == decl.isExplicit() && trailDecl.isFriend() == decl.isFriend() && trailDecl.isVirtual() == decl.isVirtual(); } else if (trailNode instanceof IASTNamedTypeSpecifier) { IASTNamedTypeSpecifier trailDecl = (IASTNamedTypeSpecifier) trailNode; IASTNamedTypeSpecifier decl = (IASTNamedTypeSpecifier) node; return isDeclSpecifierEquals(trailDecl, decl) && isSameNamedTypeSpecifierName(trailDecl, decl); } else if (trailNode instanceof IASTElaboratedTypeSpecifier) { IASTElaboratedTypeSpecifier trailDecl = (IASTElaboratedTypeSpecifier) trailNode; IASTElaboratedTypeSpecifier decl = (IASTElaboratedTypeSpecifier) node; return isDeclSpecifierEquals(trailDecl, decl) && trailDecl.getKind() == decl.getKind(); } else if (trailNode instanceof IASTCompositeTypeSpecifier) { IASTCompositeTypeSpecifier trailDecl = (IASTCompositeTypeSpecifier) trailNode; IASTCompositeTypeSpecifier decl = (IASTCompositeTypeSpecifier) node; return isDeclSpecifierEquals(trailDecl, decl) && trailDecl.getKey() == decl.getKey(); } else if (trailNode instanceof ICPPASTDeclSpecifier) { ICPPASTDeclSpecifier trailDecl = (ICPPASTDeclSpecifier) trailNode; ICPPASTDeclSpecifier decl = (ICPPASTDeclSpecifier) node; return isDeclSpecifierEquals(trailDecl, decl) && trailDecl.isExplicit() == decl.isExplicit() && trailDecl.isFriend() == decl.isFriend() && trailDecl.isVirtual() == decl.isVirtual(); } else if (trailNode instanceof ICASTDeclSpecifier) { ICASTDeclSpecifier trailDecl = (ICASTDeclSpecifier) trailNode; ICASTDeclSpecifier decl = (ICASTDeclSpecifier) node; return isDeclSpecifierEquals(trailDecl, decl) && trailDecl.isRestrict() == decl.isRestrict(); } else if (trailNode instanceof IASTDeclSpecifier) { IASTDeclSpecifier trailDecl = (IASTDeclSpecifier) trailNode; IASTDeclSpecifier decl = (IASTDeclSpecifier) node; return isDeclSpecifierEquals(trailDecl, decl); } else { //is same return true; } } private boolean isDeclaratorEquals(IASTNode trailNode, IASTNode node) { if (trailNode instanceof IASTStandardFunctionDeclarator) { IASTStandardFunctionDeclarator trailFunc = (IASTStandardFunctionDeclarator) trailNode; IASTStandardFunctionDeclarator func = (IASTStandardFunctionDeclarator) node; return trailFunc.takesVarArgs() == func.takesVarArgs(); } else if (trailNode instanceof ICPPASTFunctionDeclarator) { ICPPASTFunctionDeclarator trailFunc = (ICPPASTFunctionDeclarator) trailNode; ICPPASTFunctionDeclarator func = (ICPPASTFunctionDeclarator) node; return trailFunc.isConst() == func.isConst() && trailFunc.isPureVirtual() == func.isPureVirtual() && trailFunc.isVolatile() == func.isVolatile(); } else { //same type return true; } } private boolean isDeclarationEquals(IASTNode trailNode, IASTNode node) { if (trailNode instanceof IASTASMDeclaration) { IASTASMDeclaration trailASMDecl = (IASTASMDeclaration) trailNode; IASTASMDeclaration asmDecl = (IASTASMDeclaration) node; return trailASMDecl.getAssembly().equals(asmDecl.getAssembly()); } else if (trailNode instanceof ICPPASTExplicitTemplateInstantiation) { ICPPASTExplicitTemplateInstantiation trailTempl = (ICPPASTExplicitTemplateInstantiation) trailNode; ICPPASTExplicitTemplateInstantiation templ = (ICPPASTExplicitTemplateInstantiation) node; return trailTempl.getModifier() == templ.getModifier(); } else if (trailNode instanceof ICPPASTLinkageSpecification) { ICPPASTLinkageSpecification trailLink = (ICPPASTLinkageSpecification) trailNode; ICPPASTLinkageSpecification link = (ICPPASTLinkageSpecification) node; return trailLink.getLiteral().equals(link.getLiteral()); } else if (trailNode instanceof ICPPASTTemplateDeclaration) { ICPPASTTemplateDeclaration trailTempl = (ICPPASTTemplateDeclaration) trailNode; ICPPASTTemplateDeclaration templ = (ICPPASTTemplateDeclaration) node; return trailTempl.isExported() == templ.isExported(); } else if (trailNode instanceof ICPPASTUsingDeclaration) { ICPPASTUsingDeclaration trailUsing = (ICPPASTUsingDeclaration) trailNode; ICPPASTUsingDeclaration using = (ICPPASTUsingDeclaration) node; return trailUsing.isTypename() == using.isTypename(); } else if (trailNode instanceof ICPPASTVisibilityLabel) { ICPPASTVisibilityLabel trailVisibility = (ICPPASTVisibilityLabel) trailNode; ICPPASTVisibilityLabel visibility = (ICPPASTVisibilityLabel) node; return trailVisibility.getVisibility() == visibility.getVisibility(); } else { //same type return true; } } private boolean isPointerOperatorEquals(IASTNode trailNode, IASTNode node) { if (trailNode instanceof IASTPointer) { IASTPointer trailGPointer = (IASTPointer) trailNode; IASTPointer gPointer = (IASTPointer) node; return trailGPointer.isConst() == gPointer.isConst() && trailGPointer.isRestrict() == gPointer.isRestrict() && trailGPointer.isVolatile() == gPointer.isVolatile(); } else { //same type return true; } } private boolean isStatementEquals(IASTNode trailNode, IASTNode node) { if (trailNode instanceof ICPPASTCatchHandler) { ICPPASTCatchHandler trailCatch = (ICPPASTCatchHandler) trailNode; ICPPASTCatchHandler nodeCatch = (ICPPASTCatchHandler) node; return trailCatch.isCatchAll() == nodeCatch.isCatchAll(); } //same type return true; } private boolean isExpressionEquals(IASTNode trailNode, IASTNode node) { if (trailNode instanceof IASTBinaryExpression) { IASTBinaryExpression trailExpr = (IASTBinaryExpression) trailNode; IASTBinaryExpression expr = (IASTBinaryExpression) node; return trailExpr.getOperator() == expr.getOperator(); } else if (trailNode instanceof ICPPASTFieldReference) { ICPPASTFieldReference trailFieldRef = (ICPPASTFieldReference) trailNode; ICPPASTFieldReference fieldRef = (ICPPASTFieldReference) node; return trailFieldRef.isPointerDereference() == fieldRef.isPointerDereference() && trailFieldRef.isTemplate() == fieldRef.isTemplate(); } else if (trailNode instanceof IASTFieldReference) { IASTFieldReference trailFieldRef = (IASTFieldReference) trailNode; IASTFieldReference fieldRef = (IASTFieldReference) node; return trailFieldRef.isPointerDereference() == fieldRef.isPointerDereference(); } else if (trailNode instanceof IASTLiteralExpression) { IASTLiteralExpression trailLiteral = (IASTLiteralExpression) trailNode; IASTLiteralExpression literal = (IASTLiteralExpression) node; return trailLiteral.getKind() == literal.getKind() && trailLiteral.toString().equals(literal.toString()); } else if (trailNode instanceof IASTUnaryExpression) { IASTUnaryExpression trailExpr = (IASTUnaryExpression) trailNode; IASTUnaryExpression expr = (IASTUnaryExpression) node; return trailExpr.getOperator() == expr.getOperator(); } else if (trailNode instanceof IASTTypeIdExpression) { IASTTypeIdExpression trailIdExpr = (IASTTypeIdExpression) trailNode; IASTTypeIdExpression idExpr = (IASTTypeIdExpression) node; return trailIdExpr.getTypeId() == idExpr.getTypeId(); } else if (trailNode instanceof ICPPASTDeleteExpression) { ICPPASTDeleteExpression trailDelete = (ICPPASTDeleteExpression) trailNode; ICPPASTDeleteExpression delete = (ICPPASTDeleteExpression) node; return trailDelete.isGlobal() == delete.isGlobal() && trailDelete.isVectored() == delete.isVectored(); } else if (trailNode instanceof ICPPASTNewExpression) { ICPPASTNewExpression trailNew = (ICPPASTNewExpression) trailNode; ICPPASTNewExpression nodeNew = (ICPPASTNewExpression) node; return trailNew.isGlobal() == nodeNew.isGlobal() && trailNew.isNewTypeId() == nodeNew.isNewTypeId(); } else if (trailNode instanceof ICPPASTSimpleTypeConstructorExpression) { ICPPASTSimpleTypeConstructorExpression trailConsExpr = (ICPPASTSimpleTypeConstructorExpression) trailNode; ICPPASTSimpleTypeConstructorExpression consExpr = (ICPPASTSimpleTypeConstructorExpression) node; return isDeclSpecifierEquals(trailConsExpr.getDeclSpecifier(), consExpr.getDeclSpecifier()); } else { // same type return true; } } private boolean isSameNamedTypeSpecifierName(IASTNamedTypeSpecifier trailDecl, IASTNamedTypeSpecifier decl) { return trailDecl.getName().getRawSignature().equals(decl.getName().getRawSignature()); } private Class<?>[] getInterfaces(IASTNode node) { Class<?>[] interfaces = node.getClass().getInterfaces(); List<Class<?>> interfaceList = Arrays.asList(interfaces); Class<?>[] returnArray = new Class[interfaceList.size()]; return interfaceList.toArray(returnArray); } private boolean isDeclSpecifierEquals(IASTDeclSpecifier trailDeclSpeci, IASTDeclSpecifier declSpeci){ if (trailDeclSpeci instanceof ICPPASTDeclSpecifier) { ICPPASTDeclSpecifier trailCppDecl= (ICPPASTDeclSpecifier) trailDeclSpeci; ICPPASTDeclSpecifier cppDecl= (ICPPASTDeclSpecifier) declSpeci; if (trailCppDecl.isExplicit() == cppDecl.isExplicit() && trailCppDecl.isFriend() == cppDecl.isFriend() && trailCppDecl.isVirtual() == cppDecl.isVirtual()) { // ok } else { return false; } } return trailDeclSpeci.isConst() == declSpeci.isConst() && trailDeclSpeci.isInline() == declSpeci.isInline() && trailDeclSpeci.isVolatile() == declSpeci.isVolatile() && trailDeclSpeci.isRestrict() == declSpeci.isRestrict() && trailDeclSpeci.getStorageClass() == declSpeci.getStorageClass(); } private boolean isSimpleDeclSpecifierEquals(IASTSimpleDeclSpecifier trailDeclSpeci, IASTSimpleDeclSpecifier declSpeci){ return isDeclSpecifierEquals(trailDeclSpeci, declSpeci) && trailDeclSpeci.isLong() == declSpeci.isLong() && trailDeclSpeci.isShort() == declSpeci.isShort() && trailDeclSpeci.isSigned() == declSpeci.isSigned() && trailDeclSpeci.isUnsigned() == declSpeci.isUnsigned() && trailDeclSpeci.getType() == declSpeci.getType() && trailDeclSpeci.isComplex() == declSpeci.isComplex() && trailDeclSpeci.isImaginary() == declSpeci.isImaginary() && trailDeclSpeci.isLongLong() == declSpeci.isLongLong(); } private boolean isNameEquals(TrailName trailName, IASTName name) { int actCount = namesCounter.getObject().intValue(); if(names.containsKey(name.getRawSignature())){ Integer nameId = names.get(name.getRawSignature()); actCount = nameId.intValue(); } else { ++actCount; namesCounter.setObject(Integer.valueOf(actCount)); names.put(name.getRawSignature(), namesCounter.getObject()); } if(actCount != trailName.getNameNumber()){ return false; } if(trailName.isGloballyQualified()) { IBinding realBind = trailName.getRealName().resolveBinding(); IBinding nameBind = name.resolveBinding(); try { index.acquireReadLock(); IIndexName[] realDecs = index.findDeclarations(realBind); IIndexName[] nameDecs = index.findDeclarations(nameBind); if(realDecs.length == nameDecs.length) { for(int i = 0; i < realDecs.length; ++i) { IASTFileLocation rfl = realDecs[i].getFileLocation(); IASTFileLocation nfl = nameDecs[i].getFileLocation(); if(rfl.getNodeOffset() == nfl.getNodeOffset() && rfl.getFileName().equals(nfl.getFileName())) { continue; }else { return false; } } return true; }else { return false; } } catch (InterruptedException e) {} catch (CoreException e) {} finally { index.releaseReadLock(); } }else { IType oType = getType(trailName.getRealName().resolveBinding()); IType nType = getType(name.resolveBinding()); if (oType == null || nType == null) return false; if(oType.isSameType(nType)) { return true; } } return false; } private IType getType(IBinding binding) { if (binding instanceof ICPPVariable) { ICPPVariable var = (ICPPVariable) binding; return var.getType(); } return null; } }