/*******************************************************************************
* 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;
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.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTVisibilityLabel;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
/**
* Represents a function or method and adds some useful helper methods to
* determine if 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 ContextType getType() {
return type;
}
public void setType(ContextType type) {
this.type = type;
}
public void setMethodDeclarationName(IASTName tmpname) {
this.declarationName = tmpname;
}
public IASTName getMethodDeclarationName() {
return declarationName;
}
public IASTDeclaration getMethodDeclaration() {
IASTNode parent = declarationName.getParent().getParent();
if (parent instanceof IASTDeclaration) {
return (IASTDeclaration) parent;
}
return null;
}
public ICPPASTVisibilityLabel getMethodDeclarationASTVisibility() {
ICPPASTVisibilityLabel label = new CPPASTVisibilityLabel();
ICPPMember member = (ICPPMember) qname.resolveBinding();
label.setVisibility(member.getVisibility());
return label;
}
public Visibility getMethodDeclarationVisibility() {
return Visibility.getVisibility(declarationName);
}
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) {
IASTName classname = qname.getNames()[qname.getNames().length - 2];
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);
}
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;
}
}