/*******************************************************************************
* Copyright (c) 2010, 2011 Wind River Systems, 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:
* Markus Schorn - initial API and implementation
* Jens Elmenthaler - http://bugs.eclipse.org/173458 (camel case completion)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom.cpp;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Collections;
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.IEnumerator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPScope;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.index.IndexFilter;
import org.eclipse.cdt.core.parser.util.CharArrayMap;
import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.index.IIndexScope;
import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory;
import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.core.runtime.CoreException;
/**
* Represents the enum scope for an enum stored in the index.
* For safe use all fields need to be final.
*/
class PDOMCPPEnumScope implements ICPPScope, IIndexScope {
private final IPDOMCPPEnumType fBinding;
public PDOMCPPEnumScope(IPDOMCPPEnumType binding) {
fBinding= binding;
}
public EScopeKind getKind() {
return EScopeKind.eEnumeration;
}
public IBinding getBinding(IASTName name, boolean resolve) {
return getBinding(name, resolve, null);
}
public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup) {
return getBindings(name, resolve, prefixLookup, null);
}
public IBinding getBinding(IASTName name, boolean resolve, IIndexFileSet fileSet) {
try {
CharArrayMap<PDOMCPPEnumerator> map= getBindingMap(fBinding);
return map.get(name.toCharArray());
} catch (CoreException e) {
CCorePlugin.log(e);
return null;
}
}
public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup, IIndexFileSet fileSet) {
try {
CharArrayMap<PDOMCPPEnumerator> map= getBindingMap(fBinding);
if (prefixLookup) {
final List<IBinding> result= new ArrayList<IBinding>();
final char[] nc= name.toCharArray();
IContentAssistMatcher matcher = ContentAssistMatcherFactory.getInstance().createMatcher(nc);
for (char[] key : map.keys()) {
if (matcher.match(key)) {
result.add(map.get(key));
}
}
return result.toArray(new IBinding[result.size()]);
}
IBinding b= map.get(name.toCharArray());
if (b != null) {
return new IBinding[] {b};
}
} catch (Exception e) {
CCorePlugin.log(e);
}
return IBinding.EMPTY_BINDING_ARRAY;
}
public IBinding[] find(String name) {
return CPPSemantics.findBindings(this, name, false);
}
public IIndexBinding getScopeBinding() {
return fBinding;
}
public IIndexScope getParent() {
return fBinding.getScope();
}
public IIndexName getScopeName() {
return fBinding.getScopeName();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof PDOMCPPEnumScope)
return fBinding.equals(((PDOMCPPEnumScope) obj).fBinding);
return false;
}
@Override
public int hashCode() {
return fBinding.hashCode();
}
private static CharArrayMap<PDOMCPPEnumerator> getBindingMap(IPDOMCPPEnumType enumeration) throws CoreException {
final Long key= enumeration.getRecord() + PDOMCPPLinkage.CACHE_MEMBERS;
final PDOM pdom = enumeration.getPDOM();
@SuppressWarnings("unchecked")
Reference<CharArrayMap<PDOMCPPEnumerator>> cached= (Reference<CharArrayMap<PDOMCPPEnumerator>>) pdom.getCachedResult(key);
CharArrayMap<PDOMCPPEnumerator> map= cached == null ? null : cached.get();
if (map == null) {
// there is no cache, build it:
map= new CharArrayMap<PDOMCPPEnumerator>();
enumeration.loadEnumerators(map);
pdom.putCachedResult(key, new SoftReference<CharArrayMap<?>>(map));
}
return map;
}
public static void updateCache(PDOMCPPEnumeration enumType, PDOMCPPEnumerator enumItem) {
final Long key= enumType.getRecord() + PDOMCPPLinkage.CACHE_MEMBERS;
final PDOM pdom = enumType.getPDOM();
@SuppressWarnings("unchecked")
Reference<CharArrayMap<PDOMCPPEnumerator>> cached= (Reference<CharArrayMap<PDOMCPPEnumerator>>) pdom.getCachedResult(key);
CharArrayMap<PDOMCPPEnumerator> map= cached == null ? null : cached.get();
if (map != null) {
map.put(enumType.getNameCharArray(), enumItem);
}
}
public static IEnumerator[] getEnumerators(PDOMCPPEnumeration enumType) {
try {
CharArrayMap<PDOMCPPEnumerator> map = getBindingMap(enumType);
List<IEnumerator> result= new ArrayList<IEnumerator>();
for (IEnumerator value : map.values()) {
if (IndexFilter.ALL_DECLARED.acceptBinding(value)) {
result.add(value);
}
}
Collections.reverse(result);
return result.toArray(new IEnumerator[result.size()]);
} catch (CoreException e) {
CCorePlugin.log(e);
}
return new IEnumerator[0];
}
public static void acceptViaCache(PDOMCPPEnumeration enumType, IPDOMVisitor visitor) {
try {
CharArrayMap<PDOMCPPEnumerator> map = getBindingMap(enumType);
for (PDOMCPPEnumerator enumItem : map.values()) {
visitor.visit(enumItem);
visitor.leave(enumItem);
}
} catch (CoreException e) {
CCorePlugin.log(e);
}
}
}