blob: 96a145e1e326d935f62f4849433f4673ed21f46d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2011 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)
* Andrew Ferguson (Symbian)
* Bryan Wilkinson (QNX)
* Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom.cpp;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.core.CCorePlugin;
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.cpp.ICPPNamespace;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective;
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.core.parser.Keywords;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.index.IIndexCPPBindingConstants;
import org.eclipse.cdt.internal.core.index.IIndexScope;
import org.eclipse.cdt.internal.core.model.ASTStringUtil;
import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.db.BTree;
import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor;
import org.eclipse.cdt.internal.core.pdom.dom.BindingCollector;
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;
/**
* Represents a namespace scope for a namespace stored in the index.
*/
class PDOMCPPNamespace extends PDOMCPPBinding
implements ICPPNamespace, ICPPNamespaceScope, IIndexScope {
private static final int INDEX_OFFSET = PDOMCPPBinding.RECORD_SIZE;
private static final int FIRST_NAMESPACE_CHILD_OFFSET = INDEX_OFFSET + Database.PTR_SIZE;
private static final int NEXT_NAMESPACE_SIBBLING_OFFSET = FIRST_NAMESPACE_CHILD_OFFSET + Database.PTR_SIZE;
private static final int FLAG_OFFSET = NEXT_NAMESPACE_SIBBLING_OFFSET + Database.PTR_SIZE;
@SuppressWarnings("hiding")
protected static final int RECORD_SIZE = FLAG_OFFSET + 1;
private static int INLINE_FLAG= 0x1;
private int fFlag= -1;
private volatile ICPPNamespaceScope[] fInlineNamespaces;
public PDOMCPPNamespace(PDOMLinkage linkage, PDOMNode parent, ICPPNamespace namespace) throws CoreException {
super(linkage, parent, namespace.getNameCharArray());
updateFlag(namespace);
}
public PDOMCPPNamespace(PDOMLinkage linkage, long record) throws CoreException {
super(linkage, record);
}
@Override
public void update(PDOMLinkage linkage, IBinding newBinding) throws CoreException {
updateFlag((ICPPNamespace) newBinding);
}
private void updateFlag(ICPPNamespace namespace) throws CoreException {
int flag= 0;
if (namespace.isInline())
flag |= INLINE_FLAG;
getDB().putByte(record + FLAG_OFFSET, (byte) flag);
}
public EScopeKind getKind() {
return EScopeKind.eNamespace;
}
@Override
protected int getRecordSize() {
return RECORD_SIZE;
}
@Override
public int getNodeType() {
return IIndexCPPBindingConstants.CPPNAMESPACE;
}
public BTree getIndex() throws CoreException {
return new BTree(getDB(), record + INDEX_OFFSET, getLinkage().getIndexComparator());
}
@Override
public void accept(final IPDOMVisitor visitor) throws CoreException {
if (visitor instanceof IBTreeVisitor) {
getIndex().accept((IBTreeVisitor) visitor);
} else {
getIndex().accept(new IBTreeVisitor() {
public int compare(long record) throws CoreException {
return 0;
}
public boolean visit(long record) throws CoreException {
PDOMBinding binding = getLinkage().getBinding(record);
if (binding != null) {
if (visitor.visit(binding))
binding.accept(visitor);
visitor.leave(binding);
}
return true;
}
});
}
}
@Override
public void addChild(PDOMNode child) throws CoreException {
final long childRec = child.getRecord();
getIndex().insert(childRec);
if (child instanceof PDOMCPPNamespace) {
((PDOMCPPNamespace) child).addToList(record + FIRST_NAMESPACE_CHILD_OFFSET);
}
}
public void addToList(final long listRecord) throws CoreException {
final Database db= getDB();
final long nextRec= db.getRecPtr(listRecord);
db.putRecPtr(record + NEXT_NAMESPACE_SIBBLING_OFFSET, nextRec);
db.putRecPtr(listRecord, record);
}
public ICPPNamespaceScope getNamespaceScope() {
return this;
}
public ICPPUsingDirective[] getUsingDirectives() {
return new ICPPUsingDirective[0];
}
public IBinding[] find(String name) {
try {
BindingCollector visitor = new BindingCollector(getLinkage(), name.toCharArray(),
IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE, false, false, true);
getIndex().accept(visitor);
return visitor.getBindings();
} catch (CoreException e) {
CCorePlugin.log(e);
}
return IIndexBinding.EMPTY_INDEX_BINDING_ARRAY;
}
@Override
public IBinding getBinding(IASTName name, boolean resolve, IIndexFileSet fileSet) {
try {
IBinding[] bindings= getBindingsViaCache(name.getLookupKey());
if (fileSet != null) {
bindings= fileSet.filterFileLocalBindings(bindings);
}
return CPPSemantics.resolveAmbiguities(name, bindings);
} catch (CoreException e) {
CCorePlugin.log(e);
}
return null;
}
@Override
public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup, IIndexFileSet fileSet) {
IBinding[] result = null;
try {
if (!prefixLookup) {
result= getBindingsViaCache(name.getLookupKey());
} else {
BindingCollector visitor= new BindingCollector(getLinkage(), name.getLookupKey(),
IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE, prefixLookup, prefixLookup, !prefixLookup);
getIndex().accept(visitor);
result = visitor.getBindings();
}
if (fileSet != null) {
result= fileSet.filterFileLocalBindings(result);
}
} catch (CoreException e) {
CCorePlugin.log(e);
}
return (IBinding[]) ArrayUtil.trim(IBinding.class, result);
}
private IBinding[] getBindingsViaCache(final char[] name) throws CoreException {
final PDOM pdom = getPDOM();
final String key= pdom.createKeyForCache(record, name);
IBinding[] result= (IBinding[]) pdom.getCachedResult(key);
if (result != null) {
return result;
}
BindingCollector visitor = new BindingCollector(getLinkage(), name,
IndexFilter.CPP_DECLARED_OR_IMPLICIT_NO_INSTANCE, false, false, true);
getIndex().accept(visitor);
result = visitor.getBindings();
pdom.putCachedResult(key, result);
return result;
}
@Override
public boolean mayHaveChildren() {
return true;
}
public IBinding[] getMemberBindings() {
IBinding[] result = null;
final List<PDOMNode> preresult = new ArrayList<PDOMNode>();
try {
getIndex().accept(new IBTreeVisitor() {
public int compare(long record) throws CoreException {
return 0;
}
public boolean visit(long record) throws CoreException {
preresult.add(getLinkage().getNode(record));
return true;
}
});
result = preresult.toArray(new IBinding[preresult.size()]);
} catch (CoreException ce) {
CCorePlugin.log(ce);
}
return result;
}
public void addUsingDirective(ICPPUsingDirective directive) {
throw new UnsupportedOperationException();
}
public IIndexBinding getScopeBinding() {
return this;
}
@Override
protected String toStringBase() {
String[] names = CPPVisitor.getQualifiedName(this);
if (names.length == 0) {
return "<unnamed namespace>"; //$NON-NLS-1$
}
return ASTStringUtil.join(names, String.valueOf(Keywords.cpCOLONCOLON));
}
public ICPPNamespaceScope[] getInlineNamespaces() {
if (fInlineNamespaces == null) {
List<PDOMCPPNamespace> nslist = collectInlineNamespaces(getDB(), getLinkage(),
record + FIRST_NAMESPACE_CHILD_OFFSET);
if (nslist == null) {
fInlineNamespaces= new PDOMCPPNamespace[0];
} else {
fInlineNamespaces= nslist.toArray(new PDOMCPPNamespace[nslist.size()]);
}
}
return fInlineNamespaces;
}
public static List<PDOMCPPNamespace> collectInlineNamespaces(Database db, PDOMLinkage linkage,
long listRecord) {
List<PDOMCPPNamespace> nslist= null;
try {
long rec= db.getRecPtr(listRecord);
while (rec != 0) {
PDOMCPPNamespace ns= new PDOMCPPNamespace(linkage, rec);
if (ns.isInline()) {
if (nslist == null) {
nslist= new ArrayList<PDOMCPPNamespace>();
}
nslist.add(ns);
}
rec= db.getRecPtr(rec + NEXT_NAMESPACE_SIBBLING_OFFSET);
}
} catch (CoreException e) {
CCorePlugin.log(e);
}
return nslist;
}
public boolean isInline() {
if (fFlag == -1) {
try {
fFlag= getDB().getByte(record + FLAG_OFFSET);
} catch (CoreException e) {
CCorePlugin.log(e);
fFlag= 0;
}
}
return (fFlag & INLINE_FLAG) != 0;
}
}