/******************************************************************************* * Copyright (c) 2006, 2010 QNX Software Systems 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: * QNX - Initial API and implementation * Markus Schorn (Wind River Systems) * Andrew Ferguson (Symbian) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom.c; import java.util.ArrayList; import java.util.List; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMNode; import org.eclipse.cdt.core.dom.IPDOMVisitor; import org.eclipse.cdt.core.dom.ast.EScopeKind; import org.eclipse.cdt.core.dom.ast.IASTName; 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.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.ICCompositeTypeScope; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.index.IndexFilter; import org.eclipse.cdt.internal.core.index.IIndexCBindingConstants; import org.eclipse.cdt.internal.core.index.IIndexScope; import org.eclipse.cdt.internal.core.index.IIndexType; import org.eclipse.cdt.internal.core.pdom.PDOM; import org.eclipse.cdt.internal.core.pdom.db.PDOMNodeLinkedList; import org.eclipse.cdt.internal.core.pdom.dom.IPDOMMemberOwner; import org.eclipse.cdt.internal.core.pdom.dom.PDOMASTAdapter; import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding; import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Status; /** * @author Doug Schaefer * */ public class PDOMCStructure extends PDOMBinding implements ICompositeType, ICCompositeTypeScope, IPDOMMemberOwner, IIndexType, IIndexScope { private static final int MEMBERLIST = PDOMBinding.RECORD_SIZE; private static final int KEY = MEMBERLIST + 4; // byte private static final int ANONYMOUS= MEMBERLIST + 5; @SuppressWarnings("hiding") protected static final int RECORD_SIZE = MEMBERLIST + 6; public PDOMCStructure(PDOMLinkage linkage, PDOMNode parent, ICompositeType compType) throws CoreException { super(linkage, parent, compType.getNameCharArray()); setKind(compType); setAnonymous(compType); // linked list is initialized by malloc zeroing allocated storage } public PDOMCStructure(PDOMLinkage linkage, long record) { super(linkage, record); } public EScopeKind getKind() { return EScopeKind.eClassType; } @Override public void update(PDOMLinkage linkage, IBinding newBinding) throws CoreException { if (newBinding instanceof ICompositeType) { ICompositeType ct= (ICompositeType) newBinding; setKind(ct); setAnonymous(ct); super.update(linkage, newBinding); } } private void setKind(ICompositeType ct) throws CoreException { getDB().putByte(record + KEY, (byte) ct.getKey()); } private void setAnonymous(ICompositeType ct) throws CoreException { getDB().putByte(record + ANONYMOUS, (byte) (ct.isAnonymous() ? 1 : 0)); } @Override public void accept(IPDOMVisitor visitor) throws CoreException { super.accept(visitor); new PDOMNodeLinkedList(getLinkage(), record + MEMBERLIST).accept(visitor); } @Override public int getNodeType() { return IIndexCBindingConstants.CSTRUCTURE; } @Override public Object clone() { throw new UnsupportedOperationException(); } public int getKey() { try { return getDB().getByte(record + KEY); } catch (CoreException e) { CCorePlugin.log(e); return ICompositeType.k_struct; // or something } } public boolean isAnonymous() { try { return getDB().getByte(record + ANONYMOUS) != 0; } catch (CoreException e) { CCorePlugin.log(e); return false; } } private static class GetFields implements IPDOMVisitor { private List<IPDOMNode> fields = new ArrayList<IPDOMNode>(); public boolean visit(IPDOMNode node) throws CoreException { if (node instanceof IField) { IField field= (IField) node; if (IndexFilter.ALL_DECLARED_OR_IMPLICIT.acceptBinding(field)) { fields.add(node); } } else if (node instanceof ICompositeType) { if (((ICompositeType) node).isAnonymous()) { return true; // visit children } } return false; } public void leave(IPDOMNode node) throws CoreException { } public IField[] getFields() { return fields.toArray(new IField[fields.size()]); } } public IField[] getFields() { try { GetFields fields = new GetFields(); accept(fields); return fields.getFields(); } catch (CoreException e) { CCorePlugin.log(e); return new IField[0]; } } public static class FindField implements IPDOMVisitor { private IField field; private final String name; public FindField(String name) { this.name = name; } public boolean visit(IPDOMNode node) throws CoreException { if (node instanceof IField) { IField tField = (IField)node; if (IndexFilter.ALL_DECLARED_OR_IMPLICIT.acceptBinding(tField)) { if (name.equals(tField.getName())) { field = tField; throw new CoreException(Status.OK_STATUS); } } } else if (node instanceof ICompositeType) { if (((ICompositeType) node).isAnonymous()) { return true; // visit children } } return false; } public void leave(IPDOMNode node) throws CoreException { } public IField getField() { return field; } } public IField findField(String name) { final PDOM pdom = getPDOM(); final String key= pdom.createKeyForCache(record, name.toCharArray()); IField result= (IField) pdom.getCachedResult(key); if (result != null) { return result; } FindField visitor = new FindField(name); try { accept(visitor); // returned => not found return null; } catch (CoreException e) { if (e.getStatus().equals(Status.OK_STATUS)) { result= visitor.getField(); } else { CCorePlugin.log(e); return null; } } if (result != null) { pdom.putCachedResult(key, result); } return result; } public IScope getCompositeScope() { return this; } public boolean isSameType(IType type) { if (type instanceof ITypedef) { return type.isSameType(this); } if (type instanceof PDOMNode) { PDOMNode node= (PDOMNode) type; if (node.getPDOM() == getPDOM()) { return node.getRecord() == getRecord(); } } if (type instanceof ICompositeType) { ICompositeType etype= (ICompositeType) type; etype= (ICompositeType) PDOMASTAdapter.getAdapterForAnonymousASTBinding(etype); try { return getDBName().equals(etype.getNameCharArray()); } catch (CoreException e) { CCorePlugin.log(e); } } return false; } @Override protected int getRecordSize() { return RECORD_SIZE; } @Override public void addChild(PDOMNode member) throws CoreException { new PDOMNodeLinkedList(getLinkage(), record+MEMBERLIST).addMember(member); } @Override public boolean mayHaveChildren() { return true; } public ICompositeType getCompositeType() { return this; } public IBinding getBinding(char[] name) { return findField(new String(name)); } @Override public IBinding getBinding(IASTName name, boolean resolve, IIndexFileSet fileSet) { return getBinding(name.toCharArray()); } @Override public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup, IIndexFileSet fileSet) { return getBindings(name.toCharArray()); } public IBinding[] find(String name) { return getBindings(name.toCharArray()); } private IBinding[] getBindings(char[] name) { IBinding b= getBinding(name); if (b == null) return IBinding.EMPTY_BINDING_ARRAY; return new IBinding[]{b}; } public IIndexBinding getScopeBinding() { return this; } }