/******************************************************************************* * 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: * Doug Schaefer (QNX) - Initial API and implementation * Markus Schorn (Wind River Systems) * IBM Corporation * Andrew Ferguson (Symbian) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom.c; import org.eclipse.cdt.core.CCorePlugin; 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.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumerator; import org.eclipse.cdt.core.dom.ast.IField; import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; import org.eclipse.cdt.internal.core.dom.parser.ProblemType; import org.eclipse.cdt.internal.core.dom.parser.c.CArrayType; import org.eclipse.cdt.internal.core.dom.parser.c.CBasicType; import org.eclipse.cdt.internal.core.dom.parser.c.CFunctionType; import org.eclipse.cdt.internal.core.dom.parser.c.CPointerType; import org.eclipse.cdt.internal.core.dom.parser.c.CQualifierType; import org.eclipse.cdt.internal.core.index.IIndexCBindingConstants; import org.eclipse.cdt.internal.core.index.composite.CompositeIndexBinding; import org.eclipse.cdt.internal.core.pdom.PDOM; import org.eclipse.cdt.internal.core.pdom.db.IBTreeComparator; import org.eclipse.cdt.internal.core.pdom.dom.FindBinding; 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; /** * Container for c bindings */ class PDOMCLinkage extends PDOMLinkage implements IIndexCBindingConstants { public PDOMCLinkage(PDOM pdom, long record) { super(pdom, record); } public PDOMCLinkage(PDOM pdom) throws CoreException { super(pdom, C_LINKAGE_NAME, C_LINKAGE_NAME.toCharArray()); } @Override public int getNodeType() { return LINKAGE; } public String getLinkageName() { return C_LINKAGE_NAME; } public int getLinkageID() { return C_LINKAGE_ID; } private PDOMBinding addBinding(final IBinding inputBinding, IASTName fromName) throws CoreException { if (cannotAdapt(inputBinding)) { return null; } PDOMBinding pdomBinding= attemptFastAdaptBinding(inputBinding); if (pdomBinding == null) { // assign names to anonymous types. IBinding binding= PDOMASTAdapter.getAdapterForAnonymousASTBinding(inputBinding); if (binding == null) return null; PDOMNode parent = getAdaptedParent(binding); if (parent == null) return null; long[] localToFileHolder= {0}; pdomBinding = adaptBinding(parent, binding, localToFileHolder); if (pdomBinding == null) { pdomBinding = createBinding(parent, binding, localToFileHolder[0]); if (pdomBinding != null) { getPDOM().putCachedResult(inputBinding, pdomBinding); } return pdomBinding; } getPDOM().putCachedResult(inputBinding, pdomBinding); } if (shouldUpdate(pdomBinding, fromName)) { pdomBinding.update(this, fromName.getBinding()); } return pdomBinding; } private PDOMBinding createBinding(PDOMNode parent, IBinding binding, long localToFile) throws CoreException { PDOMBinding pdomBinding= null; PDOMNode insertIntoIndex= null; if (binding instanceof IField) { // must be before IVariable if (parent instanceof IPDOMMemberOwner) pdomBinding = new PDOMCField(this, (IPDOMMemberOwner)parent, (IField) binding); } else if (binding instanceof IVariable) { IVariable var= (IVariable) binding; pdomBinding = new PDOMCVariable(this, parent, var); } else if (binding instanceof IFunction) { IFunction func= (IFunction) binding; pdomBinding = new PDOMCFunction(this, parent, func); } else if (binding instanceof ICompositeType) { pdomBinding = new PDOMCStructure(this, parent, (ICompositeType) binding); } else if (binding instanceof IEnumeration) { pdomBinding = new PDOMCEnumeration(this, parent, (IEnumeration) binding); } else if (binding instanceof IEnumerator) { assert parent instanceof IEnumeration; pdomBinding = new PDOMCEnumerator(this, parent, (IEnumerator) binding); insertIntoIndex= parent.getParentNode(); if (insertIntoIndex == null) { insertIntoIndex= this; } } else if (binding instanceof ITypedef) { pdomBinding = new PDOMCTypedef(this, parent, (ITypedef)binding); } if (pdomBinding != null) { pdomBinding.setLocalToFileRec(localToFile); parent.addChild(pdomBinding); if (insertIntoIndex != null) { insertIntoIndex.addChild(pdomBinding); } if (parent != this && insertIntoIndex != this) { insertIntoNestedBindingsIndex(pdomBinding); } } return pdomBinding; } private boolean shouldUpdate(PDOMBinding pdomBinding, IASTName fromName) throws CoreException { if (fromName != null) { if (fromName.isDefinition()) { return true; } if (fromName.isReference()) { return false; } return !pdomBinding.hasDefinition(); } return false; } @Override public PDOMBinding addBinding(IASTName name) throws CoreException { if (name == null) return null; char[] namechars = name.getSimpleID(); if (namechars == null) return null; IBinding binding = name.resolveBinding(); return addBinding(binding, name); } @Override public int getBindingType(IBinding binding) { if (binding instanceof IField) // This needs to be before variable return CFIELD; else if (binding instanceof IVariable) return CVARIABLE; else if (binding instanceof IFunction) return CFUNCTION; else if (binding instanceof ICompositeType) return CSTRUCTURE; else if (binding instanceof IEnumeration) return CENUMERATION; else if (binding instanceof IEnumerator) return CENUMERATOR; else if (binding instanceof ITypedef) return CTYPEDEF; else return 0; } /** * Adapts the parent of the given binding to an object contained in this linkage. May return * <code>null</code> if the binding cannot be adapted or the binding does not exist and addParent * is set to <code>false</code>. * @param binding the binding to adapt * @return <ul> * <li> null - skip this binding (don't add to pdom) * <li> this - for global scope * <li> a PDOMBinding instance - parent adapted binding * </ul> * @throws CoreException */ final private PDOMNode getAdaptedParent(IBinding binding) throws CoreException { if (binding instanceof IIndexBinding) { IIndexBinding ib= (IIndexBinding) binding; if (ib.isFileLocal()) { return null; } } IBinding owner= binding.getOwner(); if (owner == null) { return this; } if (owner instanceof IFunction) { return null; } return adaptBinding(owner); } @Override public final PDOMBinding adaptBinding(final IBinding inputBinding) throws CoreException { return adaptBinding(null, inputBinding, FILE_LOCAL_REC_DUMMY); } private final PDOMBinding adaptBinding(final PDOMNode parent, IBinding inputBinding, long[] localToFileHolder) throws CoreException { if (inputBinding instanceof CompositeIndexBinding) { inputBinding= ((CompositeIndexBinding) inputBinding).getRawBinding(); } if (cannotAdapt(inputBinding)) { return null; } PDOMBinding result= attemptFastAdaptBinding(inputBinding); if (result != null) { return result; } // assign names to anonymous types. IBinding binding= PDOMASTAdapter.getAdapterForAnonymousASTBinding(inputBinding); if (binding == null) { return null; } result= doAdaptBinding(parent, binding, localToFileHolder); if (result != null) { getPDOM().putCachedResult(inputBinding, result); } return result; } private final PDOMBinding doAdaptBinding(PDOMNode parent, final IBinding binding, long[] localToFileHolder) throws CoreException { if (parent == null) { parent= getAdaptedParent(binding); } if (parent == this) { final int[] bindingTypes = new int[] {getBindingType(binding)}; final char[] nameChars = binding.getNameCharArray(); PDOMBinding nonLocal= FindBinding.findBinding(getIndex(), this, nameChars, bindingTypes, 0); long localToFileRec= getLocalToFileRec(parent, binding, nonLocal); if (localToFileRec == 0) return nonLocal; localToFileHolder[0]= localToFileRec; return FindBinding.findBinding(getIndex(), this, nameChars, bindingTypes, localToFileRec); } if (parent instanceof IPDOMMemberOwner) { final int[] bindingTypes = new int[] {getBindingType(binding)}; final char[] nameChars = binding.getNameCharArray(); PDOMBinding nonLocal= FindBinding.findBinding(parent, this, nameChars, bindingTypes, 0); long localToFileRec= getLocalToFileRec(parent, binding, nonLocal); if (localToFileRec == 0) return nonLocal; localToFileHolder[0]= localToFileRec; return FindBinding.findBinding(parent, this, nameChars, bindingTypes, localToFileRec); } return null; } @Override public PDOMNode getNode(long record, int nodeType) throws CoreException { switch (nodeType) { case CVARIABLE: return new PDOMCVariable(this, record); case CFUNCTION: return new PDOMCFunction(this, record); case CSTRUCTURE: return new PDOMCStructure(this, record); case CFIELD: return new PDOMCField(this, record); case CENUMERATION: return new PDOMCEnumeration(this, record); case CENUMERATOR: return new PDOMCEnumerator(this, record); case CTYPEDEF: return new PDOMCTypedef(this, record); } assert false; return null; } @Override public IBTreeComparator getIndexComparator() { return new FindBinding.DefaultBindingBTreeComparator(this); } @Override public PDOMBinding addTypeBinding(IBinding type) throws CoreException { return addBinding(type, null); } @Override public IType unmarshalType(ITypeMarshalBuffer buffer) throws CoreException { int firstByte= buffer.getByte(); switch((firstByte & ITypeMarshalBuffer.KIND_MASK)) { case ITypeMarshalBuffer.ARRAY: return CArrayType.unmarshal(firstByte, buffer); case ITypeMarshalBuffer.BASIC_TYPE: return CBasicType.unmarshal(firstByte, buffer); case ITypeMarshalBuffer.CVQUALIFIER: return CQualifierType.unmarshal(firstByte, buffer); case ITypeMarshalBuffer.FUNCTION_TYPE: return CFunctionType.unmarshal(firstByte, buffer); case ITypeMarshalBuffer.POINTER: return CPointerType.unmarshal(firstByte, buffer); case ITypeMarshalBuffer.PROBLEM_TYPE: return ProblemType.unmarshal(firstByte, buffer); } throw new CoreException(CCorePlugin.createStatus("Cannot unmarshal a type, first byte=" + firstByte)); //$NON-NLS-1$ } }