blob: 103c6ca0431a9d58610a814c861f2ca71e12a7f8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2011 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:
* IBM Rational Software - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c;
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.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.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
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.c.ICASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.c.ICCompositeTypeScope;
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.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.core.runtime.PlatformObject;
/**
* Represents structs and unions.
*/
public class CStructure extends PlatformObject implements ICompositeType, ICInternalBinding {
public static class CStructureProblem extends ProblemBinding implements ICompositeType {
public CStructureProblem(IASTNode node, int id, char[] arg) {
super(node, id, arg);
}
@Override
public IField findField(String name) {
return null;
}
@Override
public IScope getCompositeScope() {
return this;
}
@Override
public IField[] getFields() {
return IField.EMPTY_FIELD_ARRAY;
}
@Override
public int getKey() {
return k_struct;
}
}
private IASTName[] declarations;
private IASTName definition;
private boolean checked;
private ICompositeType typeInIndex;
public CStructure(IASTName name) {
if (name.getPropertyInParent() == IASTCompositeTypeSpecifier.TYPE_NAME) {
definition = name;
} else {
declarations = new IASTName[] { name };
}
name.setBinding(this);
}
@Override
public IASTNode getPhysicalNode() {
return definition != null ? (IASTNode) definition : (IASTNode) declarations[0];
}
private void checkForDefinition() {
if (!checked && definition == null) {
IASTNode declSpec = declarations[0].getParent();
if (declSpec instanceof ICASTElaboratedTypeSpecifier) {
IASTDeclSpecifier spec = CVisitor.findDefinition((ICASTElaboratedTypeSpecifier) declSpec);
if (spec instanceof ICASTCompositeTypeSpecifier) {
ICASTCompositeTypeSpecifier compTypeSpec = (ICASTCompositeTypeSpecifier) spec;
definition = compTypeSpec.getName();
definition.setBinding(this);
}
}
if (definition == null && typeInIndex == null) {
final IASTTranslationUnit translationUnit = declSpec.getTranslationUnit();
IIndex index = translationUnit.getIndex();
if (index != null) {
typeInIndex = (ICompositeType) index.adaptBinding(this);
}
}
}
checked = true;
}
@Override
public String getName() {
if (definition != null)
return definition.toString();
return declarations[0].toString();
}
@Override
public char[] getNameCharArray() {
if (definition != null)
return definition.toCharArray();
return declarations[0].toCharArray();
}
@Override
public IScope getScope() throws DOMException {
IASTDeclSpecifier declSpec = (IASTDeclSpecifier) ((definition != null) ?
(IASTNode) definition.getParent() : declarations[0].getParent());
IScope scope = CVisitor.getContainingScope(declSpec);
while (scope instanceof ICCompositeTypeScope) {
scope = scope.getParent();
}
return scope;
}
@Override
public IField[] getFields() {
checkForDefinition();
if (definition == null) {
return new IField[] { new CField.CFieldProblem(this, declarations[0],
IProblemBinding.SEMANTIC_DEFINITION_NOT_FOUND, getNameCharArray()) };
}
ICASTCompositeTypeSpecifier compSpec = (ICASTCompositeTypeSpecifier) definition.getParent();
IField[] fields = collectFields(compSpec, IField.EMPTY_FIELD_ARRAY);
return ArrayUtil.trim(fields);
}
private IField[] collectFields(ICASTCompositeTypeSpecifier compSpec, IField[] fields) {
IASTDeclaration[] members = compSpec.getMembers();
if (members.length > 0) {
if (fields == null)
fields = new IField[members.length];
for (IASTDeclaration node : members) {
if (node instanceof IASTSimpleDeclaration) {
IASTDeclarator[] declarators = ((IASTSimpleDeclaration) node).getDeclarators();
if (declarators.length == 0) {
IASTDeclSpecifier declspec = ((IASTSimpleDeclaration) node).getDeclSpecifier();
if (declspec instanceof ICASTCompositeTypeSpecifier) {
fields = collectFields((ICASTCompositeTypeSpecifier) declspec, fields);
}
} else {
for (IASTDeclarator declarator : declarators) {
IASTName name = ASTQueries.findInnermostDeclarator(declarator).getName();
IBinding binding = name.resolveBinding();
if (binding instanceof IField)
fields = ArrayUtil.append(fields, (IField) binding);
}
}
}
}
}
return fields;
}
@Override
public IField findField(String name) {
IScope scope = getCompositeScope();
if (scope == null) {
return new CField.CFieldProblem(this, declarations[0],
IProblemBinding.SEMANTIC_DEFINITION_NOT_FOUND, getNameCharArray());
}
final CASTName astName = new CASTName(name.toCharArray());
astName.setPropertyInParent(CVisitor.STRING_LOOKUP_PROPERTY);
IBinding binding = scope.getBinding(astName, true);
if (binding instanceof IField)
return (IField) binding;
return null;
}
@Override
public int getKey() {
return definition != null ?
((IASTCompositeTypeSpecifier) definition.getParent()).getKey() :
((IASTElaboratedTypeSpecifier) declarations[0].getParent()).getKind();
}
@Override
public IScope getCompositeScope() {
checkForDefinition();
if (definition != null) {
return ((IASTCompositeTypeSpecifier) definition.getParent()).getScope();
}
// fwd-declarations must be backed up from the index
if (typeInIndex != null) {
IScope scope = typeInIndex.getCompositeScope();
if (scope instanceof ICCompositeTypeScope)
return scope;
}
return null;
}
@Override
public Object clone() {
IType t = null;
try {
t = (IType) super.clone();
} catch (CloneNotSupportedException e) {
// not going to happen
}
return t;
}
public void addDefinition(ICASTCompositeTypeSpecifier compositeTypeSpec) {
if (compositeTypeSpec.isActive()) {
definition = compositeTypeSpec.getName();
compositeTypeSpec.getName().setBinding(this);
}
}
public void addDeclaration(IASTName decl) {
if (!decl.isActive() || decl.getPropertyInParent() != IASTElaboratedTypeSpecifier.TYPE_NAME)
return;
decl.setBinding(this);
if (declarations == null || declarations.length == 0) {
declarations = new IASTName[] { decl };
return;
}
IASTName first = declarations[0];
if (((ASTNode) first).getOffset() > ((ASTNode) decl).getOffset()) {
declarations[0] = decl;
decl = first;
}
declarations = ArrayUtil.append(IASTName.class, declarations, decl);
}
@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 ILinkage getLinkage() {
return Linkage.C_LINKAGE;
}
@Override
public IASTNode[] getDeclarations() {
return declarations;
}
@Override
public IASTNode getDefinition() {
return definition;
}
@Override
public IBinding getOwner() {
IASTNode node = definition;
if (node == null) {
if (declarations != null && declarations.length > 0) {
node = declarations[0];
}
}
IBinding result = CVisitor.findEnclosingFunction(node); // local or global
if (result != null)
return result;
if (definition != null && isAnonymous()) {
return CVisitor.findDeclarationOwner(definition, false);
}
return null;
}
@Override
public boolean isAnonymous() {
if (getNameCharArray().length > 0 || definition == null)
return false;
IASTCompositeTypeSpecifier spec = ((IASTCompositeTypeSpecifier) definition.getParent());
if (spec != null) {
IASTNode node = spec.getParent();
if (node instanceof IASTSimpleDeclaration) {
if (((IASTSimpleDeclaration) node).getDeclarators().length == 0) {
return true;
}
}
}
return false;
}
/**
* For debugging purposes, only.
*/
@Override
public String toString() {
return getName();
}
}