/******************************************************************************* * Copyright (c) 2008, 2013 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.extractfunction; import java.util.Arrays; import java.util.List; import java.util.Map; 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.ILabel; 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.ICPPASTTypeId; 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.ui.CUIPlugin; 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 final IIndex index; public TrailNodeEqualityChecker(Map<String, Integer> names, Container<Integer> namesCounter, IIndex index) { super(); this.names = names; this.namesCounter = namesCounter; this.index = index; } @Override public boolean isEqual(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 isExpressionEqual(trailNode, node); } else if (node instanceof IASTStatement) { return isStatementEqual(trailNode, node); } else if (node instanceof IASTPointerOperator) { return isPointerOperatorEqual(trailNode, node); } else if (node instanceof IASTDeclaration) { return isDeclarationEqual(trailNode, node); } else if (node instanceof IASTDeclarator) { return isDeclaratorEqual(trailNode, node); } else if (node instanceof IASTInitializer) { // No special case, the same type means equality return true; } else if (node instanceof IASTDeclSpecifier) { return isDeclSpecifierEqual(trailNode, node); } else if (node instanceof ICPPASTTypeId) { return idTypeIdEqual((ICPPASTTypeId) trailNode, (ICPPASTTypeId) node); } else if (node instanceof IASTName) { return isNameEqual(trailNode, node); } else { CUIPlugin.logError("Unexpected node type " + node.getClass().getSimpleName()); //$NON-NLS-1$ return true; } } return false; } private boolean isNameEqual(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 isNameEqual(trailName, name); } else { return true; } } private boolean isDeclSpecifierEqual(IASTNode trailNode, IASTNode node) { if (trailNode instanceof IASTSimpleDeclSpecifier) { IASTSimpleDeclSpecifier trailDecl = (IASTSimpleDeclSpecifier) trailNode; IASTSimpleDeclSpecifier decl = (IASTSimpleDeclSpecifier) node; return isSimpleDeclSpecifierEqual(trailDecl, decl); } else if (trailNode instanceof ICPPASTNamedTypeSpecifier) { ICPPASTNamedTypeSpecifier trailDecl = (ICPPASTNamedTypeSpecifier) trailNode; ICPPASTNamedTypeSpecifier decl = (ICPPASTNamedTypeSpecifier) node; return isDeclSpecifierEqual(trailDecl, decl) && isSameNamedTypeSpecifierName(trailDecl, decl) && trailDecl.isConstexpr() == decl.isConstexpr() && trailDecl.isExplicit() == decl.isExplicit() && trailDecl.isFriend() == decl.isFriend() && trailDecl.isThreadLocal() == decl.isThreadLocal() && trailDecl.isTypename() == decl.isTypename() && trailDecl.isVirtual() == decl.isVirtual(); } else if (trailNode instanceof IASTNamedTypeSpecifier) { IASTNamedTypeSpecifier trailDecl = (IASTNamedTypeSpecifier) trailNode; IASTNamedTypeSpecifier decl = (IASTNamedTypeSpecifier) node; return isDeclSpecifierEqual(trailDecl, decl) && isSameNamedTypeSpecifierName(trailDecl, decl); } else if (trailNode instanceof IASTElaboratedTypeSpecifier) { IASTElaboratedTypeSpecifier trailDecl = (IASTElaboratedTypeSpecifier) trailNode; IASTElaboratedTypeSpecifier decl = (IASTElaboratedTypeSpecifier) node; return isDeclSpecifierEqual(trailDecl, decl) && trailDecl.getKind() == decl.getKind(); } else if (trailNode instanceof IASTCompositeTypeSpecifier) { IASTCompositeTypeSpecifier trailDecl = (IASTCompositeTypeSpecifier) trailNode; IASTCompositeTypeSpecifier decl = (IASTCompositeTypeSpecifier) node; return isDeclSpecifierEqual(trailDecl, decl) && trailDecl.getKey() == decl.getKey(); } else if (trailNode instanceof ICPPASTDeclSpecifier) { ICPPASTDeclSpecifier trailDecl = (ICPPASTDeclSpecifier) trailNode; ICPPASTDeclSpecifier decl = (ICPPASTDeclSpecifier) node; return isDeclSpecifierEqual(trailDecl, decl) && trailDecl.isConstexpr() == decl.isConstexpr() && trailDecl.isExplicit() == decl.isExplicit() && trailDecl.isFriend() == decl.isFriend() && trailDecl.isThreadLocal() == decl.isThreadLocal() && trailDecl.isVirtual() == decl.isVirtual(); } else if (trailNode instanceof ICASTDeclSpecifier) { ICASTDeclSpecifier trailDecl = (ICASTDeclSpecifier) trailNode; ICASTDeclSpecifier decl = (ICASTDeclSpecifier) node; return isDeclSpecifierEqual(trailDecl, decl) && trailDecl.isRestrict() == decl.isRestrict(); } else if (trailNode instanceof IASTDeclSpecifier) { IASTDeclSpecifier trailDecl = (IASTDeclSpecifier) trailNode; IASTDeclSpecifier decl = (IASTDeclSpecifier) node; return isDeclSpecifierEqual(trailDecl, decl); } else { // The same. return true; } } private boolean isDeclaratorEqual(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 isDeclarationEqual(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 isPointerOperatorEqual(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 isStatementEqual(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 idTypeIdEqual(ICPPASTTypeId trailNode, ICPPASTTypeId node) { return trailNode.isPackExpansion() == node.isPackExpansion(); } private boolean isExpressionEqual(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.getRawSignature().equals(literal.getRawSignature()); } 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 isDeclSpecifierEqual(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 isDeclSpecifierEqual(IASTDeclSpecifier trailDeclSpeci, IASTDeclSpecifier declSpeci) { if (trailDeclSpeci instanceof ICPPASTDeclSpecifier) { ICPPASTDeclSpecifier trailCppDecl= (ICPPASTDeclSpecifier) trailDeclSpeci; ICPPASTDeclSpecifier cppDecl= (ICPPASTDeclSpecifier) declSpeci; if (trailCppDecl.isConstexpr() != cppDecl.isConstexpr() || trailCppDecl.isExplicit() != cppDecl.isExplicit() || trailCppDecl.isFriend() != cppDecl.isFriend() || trailCppDecl.isThreadLocal() != cppDecl.isThreadLocal() || trailCppDecl.isVirtual() != cppDecl.isVirtual()) { 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 isSimpleDeclSpecifierEqual(IASTSimpleDeclSpecifier trailDeclSpeci, IASTSimpleDeclSpecifier declSpeci) { return isDeclSpecifierEqual(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 isNameEqual(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; } IASTName realName = trailName.getRealName(); IBinding realBind = realName.resolveBinding(); IBinding nameBind = name.resolveBinding(); if (trailName.isGloballyQualified()) { IIndexName[] realDecs; IIndexName[] nameDecs; try { realDecs = index.findDeclarations(realBind); nameDecs = index.findDeclarations(nameBind); } catch (CoreException e) { CUIPlugin.log(e); return false; } if (realDecs.length != nameDecs.length) return false; 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())) return false; } return true; } else { if (realBind instanceof ILabel && nameBind instanceof ILabel) { if (realName.getRawSignature().equals(name.getRawSignature())) { return true; } } else { IType oType = getType(realBind); IType nType = getType(nameBind); 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; } }