/******************************************************************************* * Copyright (c) 2013, 2015 Google, Inc 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: * Sergey Prigogin (Google) - initial API and implementation * Marc-Andre Laperle (Ericsson) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom.cpp; 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.ASTTypeUtil; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumerator; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumerationSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.cdt.internal.core.index.IIndexCPPBindingConstants; import org.eclipse.cdt.internal.core.pdom.db.Database; 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.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; /** * Enumeration specialization in the index. */ class PDOMCPPEnumerationSpecialization extends PDOMCPPSpecialization implements IPDOMCPPEnumType, IPDOMMemberOwner, ICPPEnumerationSpecialization { private static final int OFFSET_ENUMERATOR_LIST = PDOMCPPSpecialization.RECORD_SIZE; private static final int OFFSET_MIN_VALUE= OFFSET_ENUMERATOR_LIST + Database.PTR_SIZE; private static final int OFFSET_MAX_VALUE= OFFSET_MIN_VALUE + 8; private static final int OFFSET_FIXED_TYPE = OFFSET_MAX_VALUE + 8; private static final int OFFSET_FLAGS = OFFSET_FIXED_TYPE + Database.TYPE_SIZE; @SuppressWarnings("hiding") protected static final int RECORD_SIZE = OFFSET_FLAGS + 1; private Long fMinValue; // No need for volatile, all fields of Long are final. private Long fMaxValue; // No need for volatile, all fields of Long are final. private volatile IType fFixedType= ProblemBinding.NOT_INITIALIZED; private PDOMCPPEnumScope fScope; // No need for volatile, all fields of PDOMCPPEnumScope are final. public PDOMCPPEnumerationSpecialization(PDOMCPPLinkage linkage, PDOMNode parent, ICPPEnumeration enumeration, PDOMBinding specialized) throws CoreException { super(linkage, parent, (ICPPSpecialization) enumeration, specialized); storeProperties(enumeration); } public PDOMCPPEnumerationSpecialization(PDOMLinkage linkage, long record) { super(linkage, record); } @Override public ICPPEnumeration getSpecializedBinding() { return (ICPPEnumeration) super.getSpecializedBinding(); } @Override public void update(PDOMLinkage linkage, IBinding newBinding, IASTNode point) throws CoreException { storeProperties((ICPPEnumeration) newBinding); } private void storeProperties(ICPPEnumeration enumeration) throws CoreException { final Database db= getDB(); db.putByte(record + OFFSET_FLAGS, enumeration.isScoped() ? (byte) 1 : (byte) 0); getLinkage().storeType(record + OFFSET_FIXED_TYPE, enumeration.getFixedType()); if (enumeration instanceof ICPPInternalBinding) { if (((ICPPInternalBinding) enumeration).getDefinition() != null) { final long minValue = enumeration.getMinValue(); final long maxValue = enumeration.getMaxValue(); db.putLong(record + OFFSET_MIN_VALUE, minValue); db.putLong(record + OFFSET_MAX_VALUE, maxValue); fMinValue= minValue; fMaxValue= maxValue; } } } @Override protected int getRecordSize() { return RECORD_SIZE; } @Override public int getNodeType() { return IIndexCPPBindingConstants.CPP_ENUMERATION_SPECIALIZATION; } @Override public IEnumerator[] getEnumerators() { return PDOMCPPEnumScope.getEnumerators(this); } @Override public void accept(IPDOMVisitor visitor) throws CoreException { PDOMCPPEnumScope.acceptViaCache(this, visitor); } @Override public void addChild(PDOMNode node) throws CoreException { if (node instanceof IPDOMCPPEnumerator) { PDOMNodeLinkedList list = new PDOMNodeLinkedList(getLinkage(), record + OFFSET_ENUMERATOR_LIST); list.addMember(node); PDOMCPPEnumScope.updateCache(this, (IPDOMCPPEnumerator) node); } } @Override public boolean mayHaveChildren() { return true; } @Override 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 IEnumeration) { IEnumeration etype= (IEnumeration) type; char[] nchars = etype.getNameCharArray(); if (nchars.length == 0) { nchars= ASTTypeUtil.createNameForAnonymous(etype); } if (nchars == null || !CharArrayUtils.equals(nchars, getNameCharArray())) return false; return SemanticUtil.haveSameOwner(this, etype); } return false; } @Override public long getMinValue() { if (fMinValue != null) { return fMinValue.longValue(); } long minValue= 0; try { minValue= getDB().getLong(record + OFFSET_MIN_VALUE); } catch (CoreException e) { } fMinValue= minValue; return minValue; } @Override public long getMaxValue() { if (fMaxValue != null) { return fMaxValue.longValue(); } long maxValue= 0; try { maxValue= getDB().getLong(record + OFFSET_MAX_VALUE); } catch (CoreException e) { } fMaxValue= maxValue; return maxValue; } @Override public Object clone() { throw new IllegalArgumentException("Enums must not be cloned"); //$NON-NLS-1$ } @Override public boolean isScoped() { try { return getDB().getByte(record + OFFSET_FLAGS) != 0; } catch (CoreException e) { return false; } } @Override public IType getFixedType() { if (fFixedType == ProblemBinding.NOT_INITIALIZED) { fFixedType= loadFixedType(); } return fFixedType; } private IType loadFixedType() { try { return getLinkage().loadType(record + OFFSET_FIXED_TYPE); } catch (CoreException e) { CCorePlugin.log(e); return null; } } @Override public ICPPScope asScope() { if (fScope == null) { fScope= new PDOMCPPEnumScope(this); } return fScope; } @Override public void loadEnumerators(final List<IPDOMCPPEnumerator> enumerators) { try { PDOMNodeLinkedList list = new PDOMNodeLinkedList(getLinkage(), record + OFFSET_ENUMERATOR_LIST); list.accept(new IPDOMVisitor() { @Override public boolean visit(IPDOMNode node) throws CoreException { if (node instanceof IPDOMCPPEnumerator) { enumerators.add((IPDOMCPPEnumerator) node); } return true; } @Override public void leave(IPDOMNode node) {} }); } catch (CoreException e) { CCorePlugin.log(e); } } @Override public IEnumerator specializeEnumerator(IEnumerator enumerator) { if (enumerator instanceof ICPPSpecialization && ((ICPPSpecialization) enumerator).getOwner() == this) { return enumerator; } // The specialized enumerators are already computed, just need to look up the right one. IEnumerator[] unspecializedEnumerators = getSpecializedBinding().getEnumerators(); for (int i = 0; i < unspecializedEnumerators.length; ++i) { if (enumerator.equals(unspecializedEnumerators[i])) { IEnumerator[] enumerators = getEnumerators(); return i < enumerators.length ? enumerators[i] : enumerator; } } return enumerator; } }