blob: f6f0c702a6faf1eb1be161072cc921f31e5674cb [file] [log] [blame]
/*******************************************************************************
* 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;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
/**
* Represents a function or method and adds some useful helper methods to determine
* if two methods are in the same class.
*/
public class MethodContext {
public enum ContextType { NONE, FUNCTION, METHOD }
private ContextType type;
private IASTName declarationName;
private ICPPASTQualifiedName qname;
public MethodContext() {
type = ContextType.NONE;
}
public ContextType getType() {
return type;
}
public void setType(ContextType type) {
this.type = type;
}
public void setMethodDeclarationName(IASTName name) {
this.declarationName = name;
}
public IASTName getMethodDeclarationName() {
return declarationName;
}
public IASTDeclaration getMethodDeclaration() {
if (declarationName != null) {
IASTNode parent = declarationName.getParent().getParent();
if (parent instanceof IASTDeclaration) {
return (IASTDeclaration) parent;
}
}
return null;
}
public void setMethodQName(ICPPASTQualifiedName qname) {
this.qname = qname;
}
public ICPPASTQualifiedName getMethodQName() {
return qname;
}
public static boolean isSameClass(ICPPASTQualifiedName qname1, ICPPASTQualifiedName qname2) {
ICPPClassType bind1 = getClassBinding(qname1);
ICPPClassType bind2 = getClassBinding(qname2);
return bind1.equals(bind2);
}
public static boolean isSameOrSubClass(MethodContext context1, MethodContext contextOfSameOrSubclass) {
ICPPInternalBinding bind1 = getICPPInternalBinding(context1);
ICPPInternalBinding subclassBind = getICPPInternalBinding(contextOfSameOrSubclass);
if (isSameClass(bind1,subclassBind)) {
return true;
}
return isSubclass(bind1,subclassBind);
}
private static boolean isSubclass(ICPPInternalBinding bind1, ICPPInternalBinding subclassBind) {
if (subclassBind instanceof ICPPClassType) {
ICPPClassType classType = (ICPPClassType) subclassBind;
ICPPBase[] bases;
bases = classType.getBases();
for (ICPPBase base : bases) {
if (isSameClass(base,bind1)) {
return true;
}
}
}
return false;
}
public static boolean isSameClass(MethodContext context1, MethodContext context2) {
ICPPInternalBinding bind1 = getICPPInternalBinding(context1);
ICPPInternalBinding bind2 = getICPPInternalBinding(context2);
return isSameClass(bind1,bind2);
}
private static boolean isSameClass(ICPPBase base, ICPPInternalBinding bind2) {
try {
IBinding bind1 = base.getBaseClass();
IScope scope1 = bind1.getScope();
if (scope1 == null)
return false;
IASTNode node1 = ASTInternal.getPhysicalNodeOfScope(scope1);
IScope scope2 = bind2.getScope();
if (scope2 == null)
return false;
IASTNode node2 = ASTInternal.getPhysicalNodeOfScope(scope2);
if (node1.equals(node2)) {
if (bind1 instanceof ICPPInternalBinding) {
ICPPInternalBinding bind1int = (ICPPInternalBinding) bind1;
return bind1int.getDefinition().equals(bind2.getDefinition());
}
return false;
}
return false;
} catch (DOMException e) {
return false;
}
}
private static boolean isSameClass(ICPPInternalBinding bind1, ICPPInternalBinding bind2) {
try {
IScope scope1 = bind1.getScope();
if (scope1 == null)
return false;
IASTNode node1 = ASTInternal.getPhysicalNodeOfScope(scope1);
IScope scope2 = bind2.getScope();
if (scope2 == null)
return false;
IASTNode node2 = ASTInternal.getPhysicalNodeOfScope(scope2);
if (node1.equals(node2)) {
return bind1.getDefinition().equals(bind2.getDefinition());
}
return false;
} catch (DOMException e) {
return false;
}
}
public static ICPPInternalBinding getICPPInternalBinding(MethodContext context) {
IASTName decl = context.getMethodDeclarationName();
IASTNode node = decl;
while (node != null) {
if (node instanceof ICPPASTCompositeTypeSpecifier) {
ICPPASTCompositeTypeSpecifier type = (ICPPASTCompositeTypeSpecifier) node;
IASTName classname = type.getName();
return (ICPPInternalBinding)classname.resolveBinding();
}
node = node.getParent();
}
return null;
}
public boolean isInline() {
return qname == null;
}
private static ICPPClassType getClassBinding(ICPPASTQualifiedName qname) {
ICPPASTNameSpecifier classname = qname.getQualifier()[qname.getQualifier().length - 1];
ICPPClassType bind = (ICPPClassType) classname.resolveBinding();
return bind;
}
public static boolean isSameClass(IASTName declName1, IASTName declName2) {
ICPPClassType bind1 = getClassBinding(declName1);
ICPPClassType bind2 = getClassBinding(declName2);
return bind1.equals(bind2);
}
public static boolean haveSameClass(MethodContext context1, MethodContext context2) {
return isSameClass(context1.declarationName, context2.declarationName);
}
private static ICPPClassType getClassBinding(IASTName declName1) {
if (declName1.getParent().getParent().getParent() instanceof ICPPASTCompositeTypeSpecifier) {
ICPPASTCompositeTypeSpecifier compTypeSpec =
(ICPPASTCompositeTypeSpecifier) declName1.getParent().getParent().getParent();
return (ICPPClassType) compTypeSpec.getName().resolveBinding();
}
return null;
}
}