| /******************************************************************************* |
| * Copyright (c) 2004, 2014 IBM Corporation 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: |
| * Andrew Niefer (IBM Corporation) - initial API and implementation |
| * Markus Schorn (Wind River Systems) |
| * Bryan Wilkinson (QNX) |
| * Sergey Prigogin (Google) |
| * Andrew Ferguson (Symbian) |
| *******************************************************************************/ |
| package org.eclipse.cdt.internal.core.dom.parser.cpp; |
| |
| import org.eclipse.cdt.core.dom.ILinkage; |
| import org.eclipse.cdt.core.dom.ast.DOMException; |
| import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTName; |
| import org.eclipse.cdt.core.dom.ast.IASTNode; |
| import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IBinding; |
| import org.eclipse.cdt.core.dom.ast.IField; |
| import org.eclipse.cdt.core.dom.ast.IScope; |
| import org.eclipse.cdt.core.dom.ast.IType; |
| import org.eclipse.cdt.core.dom.ast.ITypedef; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; |
| 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.ICPPBlockScope; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionScope; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; |
| import org.eclipse.cdt.core.index.IIndex; |
| import org.eclipse.cdt.core.index.IIndexBinding; |
| import org.eclipse.cdt.core.parser.util.ArrayUtil; |
| import org.eclipse.cdt.internal.core.dom.Linkage; |
| import org.eclipse.cdt.internal.core.dom.parser.ASTNode; |
| import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; |
| import org.eclipse.core.runtime.PlatformObject; |
| |
| /** |
| * Binding for a class type. |
| */ |
| public class CPPClassType extends PlatformObject implements ICPPInternalClassTypeMixinHost { |
| |
| public static class CPPClassTypeProblem extends ProblemBinding implements ICPPClassType { |
| public CPPClassTypeProblem(IASTName name, int id) { |
| super(name, id); |
| } |
| public CPPClassTypeProblem(ICPPASTNameSpecifier nameSpec, int id) { |
| super(nameSpec, id, nameSpec instanceof IASTName ? null : nameSpec.toCharArray()); |
| } |
| public CPPClassTypeProblem(IASTNode node, int id, char[] arg) { |
| super(node, id, arg); |
| } |
| @Override |
| public ICPPBase[] getBases() { |
| return ICPPBase.EMPTY_BASE_ARRAY; |
| } |
| @Override |
| public IField[] getFields() { |
| return IField.EMPTY_FIELD_ARRAY; |
| } |
| @Override |
| public ICPPField[] getDeclaredFields() { |
| return ICPPField.EMPTY_CPPFIELD_ARRAY; |
| } |
| @Override |
| public ICPPMethod[] getMethods() { |
| return ICPPMethod.EMPTY_CPPMETHOD_ARRAY; |
| } |
| @Override |
| public ICPPMethod[] getAllDeclaredMethods() { |
| return ICPPMethod.EMPTY_CPPMETHOD_ARRAY; |
| } |
| @Override |
| public ICPPMethod[] getDeclaredMethods() { |
| return ICPPMethod.EMPTY_CPPMETHOD_ARRAY; |
| } |
| @Override |
| public ICPPConstructor[] getConstructors() { |
| return ICPPConstructor.EMPTY_CONSTRUCTOR_ARRAY; |
| } |
| @Override |
| public int getKey() { |
| return k_class; |
| } |
| @Override |
| public IField findField(String name) { |
| return null; |
| } |
| @Override |
| public IScope getCompositeScope() { |
| return this; |
| } |
| @Override |
| public IBinding[] getFriends() { |
| return IBinding.EMPTY_BINDING_ARRAY; |
| } |
| @Override |
| public ICPPClassType[] getNestedClasses() { |
| return ICPPClassType.EMPTY_CLASS_ARRAY; |
| } |
| @Override |
| public ICPPUsingDeclaration[] getUsingDeclarations() { |
| return ICPPUsingDeclaration.EMPTY_USING_DECL_ARRAY; |
| } |
| @Override |
| public boolean isFinal() { |
| return false; |
| } |
| @Override |
| public int getVisibility(IBinding member) { |
| throw new IllegalArgumentException(member.getName() + " is not a member of " + getName()); //$NON-NLS-1$ |
| } |
| } |
| |
| private IASTName definition; |
| private IASTName[] declarations; |
| private boolean checked; |
| private ICPPClassType typeInIndex; |
| private ICPPBase[] bases; |
| |
| public CPPClassType(IASTName name, IBinding indexBinding) { |
| name = stripQualifier(name); |
| IASTNode parent = name.getParent(); |
| while (parent instanceof IASTName) { |
| parent = parent.getParent(); |
| } |
| |
| if (parent instanceof IASTCompositeTypeSpecifier) { |
| definition = name; |
| } else { |
| declarations = new IASTName[] { name }; |
| } |
| name.setBinding(this); |
| if (indexBinding instanceof ICPPClassType && indexBinding instanceof IIndexBinding) { |
| typeInIndex= (ICPPClassType) indexBinding; |
| } |
| } |
| |
| @Override |
| public IASTNode[] getDeclarations() { |
| return declarations; |
| } |
| |
| @Override |
| public IASTNode getDefinition() { |
| return definition; |
| } |
| |
| @Override |
| public void checkForDefinition() { |
| // Ambiguity resolution ensures that definitions are resolved. |
| if (!checked) { |
| if (definition == null && typeInIndex == null) { |
| IIndex index= getPhysicalNode().getTranslationUnit().getIndex(); |
| if (index != null) { |
| typeInIndex= (ICPPClassType) index.adaptBinding(this); |
| } |
| } |
| checked = true; |
| } |
| } |
| |
| @Override |
| public ICPPASTCompositeTypeSpecifier getCompositeTypeSpecifier() { |
| if (definition != null) { |
| IASTNode node = definition; |
| while (node instanceof IASTName) |
| node = node.getParent(); |
| if (node instanceof ICPPASTCompositeTypeSpecifier) |
| return (ICPPASTCompositeTypeSpecifier) node; |
| } |
| return null; |
| } |
| |
| private ICPPASTElaboratedTypeSpecifier getElaboratedTypeSpecifier() { |
| if (declarations != null) { |
| IASTNode node = declarations[0]; |
| while (node instanceof IASTName) |
| node = node.getParent(); |
| if (node instanceof ICPPASTElaboratedTypeSpecifier) |
| return (ICPPASTElaboratedTypeSpecifier) node; |
| } |
| return null; |
| } |
| |
| @Override |
| public final String getName() { |
| return new String(getNameCharArray()); |
| } |
| |
| @Override |
| public char[] getNameCharArray() { |
| return (definition != null) ? definition.getSimpleID() : declarations[0].getSimpleID(); |
| } |
| |
| @Override |
| public IScope getScope() { |
| IASTName name = definition != null ? definition : declarations[0]; |
| name = stripQualifier(name); |
| |
| IScope scope = CPPVisitor.getContainingScope(name); |
| if (definition == null && name.getPropertyInParent() != ICPPASTQualifiedName.SEGMENT_NAME) { |
| IASTNode node = declarations[0].getParent().getParent(); |
| if (node instanceof IASTSimpleDeclaration && ((IASTSimpleDeclaration) node).getDeclarators().length == 0 |
| && !getElaboratedTypeSpecifier().isFriend()) { |
| // 3.3.1.5 class-key identifier ; |
| } else { |
| while (scope instanceof ICPPClassScope || scope instanceof ICPPFunctionScope) { |
| try { |
| scope = scope.getParent(); |
| } catch (DOMException e1) { |
| } |
| } |
| } |
| } |
| return scope; |
| } |
| |
| @Override |
| public ICPPClassScope getCompositeScope() { |
| checkForDefinition(); |
| if (definition != null) { |
| return getCompositeTypeSpecifier().getScope(); |
| } |
| // fwd-declarations must be backed up from the index |
| if (typeInIndex != null) { |
| IScope scope = typeInIndex.getCompositeScope(); |
| if (scope instanceof ICPPClassScope) |
| return (ICPPClassScope) scope; |
| } |
| return null; |
| } |
| |
| public IASTNode getPhysicalNode() { |
| return definition != null ? (IASTNode) definition : declarations[0]; |
| } |
| |
| @Override |
| public int getKey() { |
| if (definition != null) |
| return getCompositeTypeSpecifier().getKey(); |
| |
| return getElaboratedTypeSpecifier().getKind(); |
| } |
| |
| @Override |
| public void addDefinition(IASTNode node) { |
| if (node instanceof ICPPASTCompositeTypeSpecifier) { |
| definition = ((ICPPASTCompositeTypeSpecifier) node).getName(); |
| } else { |
| assert false; |
| } |
| } |
| |
| @Override |
| public void addDeclaration(IASTNode node) { |
| if (node instanceof ICPPASTElaboratedTypeSpecifier) { |
| IASTName name = ((ICPPASTElaboratedTypeSpecifier) node).getName(); |
| |
| if (declarations == null) { |
| declarations = new IASTName[] { name }; |
| return; |
| } |
| |
| // Keep the lowest offset declaration in [0] |
| if (declarations.length > 0 && ((ASTNode) node).getOffset() < ((ASTNode) declarations[0]).getOffset()) { |
| declarations = ArrayUtil.prepend(IASTName.class, declarations, name); |
| } else { |
| declarations = ArrayUtil.append(IASTName.class, declarations, name); |
| } |
| } else { |
| assert false; |
| } |
| } |
| |
| @Override |
| public String[] getQualifiedName() { |
| return CPPVisitor.getQualifiedName(this); |
| } |
| |
| @Override |
| public char[][] getQualifiedNameCharArray() { |
| return CPPVisitor.getQualifiedNameCharArray(this); |
| } |
| |
| @Override |
| public boolean isGloballyQualified() throws DOMException { |
| IScope scope = getScope(); |
| while (scope != null) { |
| if (scope instanceof ICPPBlockScope) |
| return false; |
| scope = scope.getParent(); |
| } |
| return true; |
| } |
| |
| @Override |
| public ILinkage getLinkage() { |
| return Linkage.CPP_LINKAGE; |
| } |
| |
| @Override |
| public boolean isSameType(IType type) { |
| if (type == this) |
| return true; |
| if (type instanceof ITypedef || type instanceof IIndexBinding) |
| return type.isSameType(this); |
| return false; |
| } |
| |
| @Override |
| public ICPPBase[] getBases() { |
| if (bases == null) { |
| ICPPBase[] result = ClassTypeHelper.getBases(this); |
| // Do not cache the computed bases if the class is incomplete. |
| // When the class becomes complete, the answer may be different. |
| if (result != ICPPBase.NO_BASES_BECAUSE_TYPE_IS_INCOMPLETE) { |
| bases = result; |
| } |
| return result; |
| } |
| return bases; |
| } |
| |
| @Override |
| public IField[] getFields() { |
| return ClassTypeHelper.getFields(this); |
| } |
| |
| @Override |
| public ICPPField[] getDeclaredFields() { |
| return ClassTypeHelper.getDeclaredFields(this); |
| } |
| |
| @Override |
| public ICPPMethod[] getMethods() { |
| return ClassTypeHelper.getMethods(this); |
| } |
| |
| @Override |
| public ICPPMethod[] getAllDeclaredMethods() { |
| return ClassTypeHelper.getAllDeclaredMethods(this); |
| } |
| |
| @Override |
| public ICPPMethod[] getDeclaredMethods() { |
| return ClassTypeHelper.getDeclaredMethods(this); |
| } |
| |
| @Override |
| public ICPPConstructor[] getConstructors() { |
| return ClassTypeHelper.getConstructors(this); |
| } |
| |
| @Override |
| public IBinding[] getFriends() { |
| return ClassTypeHelper.getFriends(this); |
| } |
| |
| @Override |
| public ICPPClassType[] getNestedClasses() { |
| return ClassTypeHelper.getNestedClasses(this); |
| } |
| |
| @Override |
| public ICPPUsingDeclaration[] getUsingDeclarations() { |
| return ClassTypeHelper.getUsingDeclarations(this); |
| } |
| |
| @Override |
| public IField findField(String name) { |
| return ClassTypeHelper.findField(this, name); |
| } |
| |
| @Override |
| public Object clone() { |
| try { |
| return super.clone(); |
| } catch (CloneNotSupportedException e) { |
| } |
| return null; |
| } |
| |
| /** |
| * For debugging purposes, only. |
| */ |
| @Override |
| public String toString() { |
| return getName(); |
| } |
| |
| @Override |
| public IBinding getOwner() { |
| if (definition != null) { |
| return CPPVisitor.findNameOwner(definition, true); |
| } |
| return CPPVisitor.findDeclarationOwner(declarations[0], true); |
| } |
| |
| @Override |
| public boolean isAnonymous() { |
| if (getNameCharArray().length > 0) |
| return false; |
| |
| ICPPASTCompositeTypeSpecifier spec= getCompositeTypeSpecifier(); |
| if (spec != null) { |
| IASTNode node= spec.getParent(); |
| if (node instanceof IASTSimpleDeclaration) { |
| if (((IASTSimpleDeclaration) node).getDeclarators().length == 0) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean isFinal() { |
| ICPPASTCompositeTypeSpecifier typeSpecifier = getCompositeTypeSpecifier(); |
| if (typeSpecifier != null) { |
| return typeSpecifier.isFinal(); |
| } |
| return false; |
| } |
| |
| private IASTName stripQualifier(IASTName name) { |
| if (name instanceof ICPPASTQualifiedName) { |
| name = ((ICPPASTQualifiedName) name).getLastName(); |
| } |
| return name; |
| } |
| |
| @Override |
| public int getVisibility(IBinding member) { |
| return ClassTypeHelper.getVisibility(this, member); |
| } |
| } |