/*******************************************************************************
* Copyright (c) 2010, 2015 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.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.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IEnumerator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
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.CharArrayObjectMap;
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 ICPPEnumScope, IIndexScope {
private final IPDOMCPPEnumType fBinding;
public PDOMCPPEnumScope(IPDOMCPPEnumType binding) {
fBinding= binding;
}
@Override
public EScopeKind getKind() {
return EScopeKind.eEnumeration;
}
@Override
public IBinding getBinding(IASTName name, boolean resolve) {
return getBinding(name, resolve, null);
}
@Override
public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup) {
return getBindings(new ScopeLookupData(name, resolve, prefixLookup));
}
@Override
public IBinding getBinding(IASTName name, boolean resolve, IIndexFileSet fileSet) {
try {
CharArrayObjectMap<IPDOMCPPEnumerator> map= getBindingMap(fBinding);
return map.get(name.toCharArray());
} catch (CoreException e) {
CCorePlugin.log(e);
return null;
}
}
@Deprecated @Override
public IBinding[] getBindings(IASTName name, boolean resolve, boolean prefixLookup, IIndexFileSet fileSet) {
return getBindings(new ScopeLookupData(name, resolve, prefixLookup));
}
@Override
public IBinding[] getBindings(ScopeLookupData lookup) {
try {
CharArrayObjectMap<IPDOMCPPEnumerator> map= getBindingMap(fBinding);
if (lookup.isPrefixLookup()) {
final List<IBinding> result= new ArrayList<IBinding>();
final char[] nc= lookup.getLookupKey();
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(lookup.getLookupKey());
if (b != null) {
return new IBinding[] {b};
}
} catch (Exception e) {
CCorePlugin.log(e);
}
return IBinding.EMPTY_BINDING_ARRAY;
}
@Override
public IBinding[] find(String name, IASTTranslationUnit tu) {
return CPPSemantics.findBindingsInScope(this, name, tu);
}
@Override @Deprecated
public IBinding[] find(String name) {
return CPPSemantics.findBindings(this, name, false);
}
@Override
public IIndexBinding getScopeBinding() {
return fBinding;
}
@Override
public IIndexScope getParent() {
return fBinding.getScope();
}
@Override
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 CharArrayObjectMap<IPDOMCPPEnumerator> getBindingMap(IPDOMCPPEnumType enumeration) throws CoreException {
final Long key= enumeration.getRecord() + PDOMCPPLinkage.CACHE_MEMBERS;
final PDOM pdom = enumeration.getPDOM();
@SuppressWarnings("unchecked")
Reference<CharArrayObjectMap<IPDOMCPPEnumerator>> cached=
(Reference<CharArrayObjectMap<IPDOMCPPEnumerator>>) pdom.getCachedResult(key);
CharArrayObjectMap<IPDOMCPPEnumerator> map= cached == null ? null : cached.get();
if (map == null) {
// there is no cache, build it:
List<IPDOMCPPEnumerator> enumerators = new ArrayList<>();
enumeration.loadEnumerators(enumerators);
map = new CharArrayObjectMap<>(enumerators.size());
for (IPDOMCPPEnumerator enumerator : enumerators) {
map.put(enumerator.getNameCharArray(), enumerator);
}
pdom.putCachedResult(key, new SoftReference<>(map));
}
return map;
}
public static void updateCache(IPDOMCPPEnumType enumType, IPDOMCPPEnumerator enumItem) {
final Long key= enumType.getRecord() + PDOMCPPLinkage.CACHE_MEMBERS;
final PDOM pdom = enumType.getPDOM();
@SuppressWarnings("unchecked")
Reference<CharArrayObjectMap<IPDOMCPPEnumerator>> cached=
(Reference<CharArrayObjectMap<IPDOMCPPEnumerator>>) pdom.getCachedResult(key);
CharArrayObjectMap<IPDOMCPPEnumerator> map= cached == null ? null : cached.get();
if (map != null) {
map.put(enumItem.getNameCharArray(), enumItem);
}
}
public static IEnumerator[] getEnumerators(IPDOMCPPEnumType enumType) {
try {
// We want to return the enumerators in order of declaration, so we don't
// use the cache (getBindingsMap()) which stores them in a hash map and thus
// loses the order.
List<IPDOMCPPEnumerator> enumerators = new ArrayList<>();
enumType.loadEnumerators(enumerators);
List<IEnumerator> result= new ArrayList<IEnumerator>();
for (IEnumerator value : enumerators) {
if (IndexFilter.ALL_DECLARED.acceptBinding(value)) {
result.add(value);
}
}
return result.toArray(new IEnumerator[result.size()]);
} catch (CoreException e) {
CCorePlugin.log(e);
}
return new IEnumerator[0];
}
public static void acceptViaCache(IPDOMCPPEnumType enumType, IPDOMVisitor visitor) {
try {
CharArrayObjectMap<IPDOMCPPEnumerator> map = getBindingMap(enumType);
for (IPDOMCPPEnumerator enumItem : map.values()) {
visitor.visit(enumItem);
visitor.leave(enumItem);
}
} catch (CoreException e) {
CCorePlugin.log(e);
}
}
@Override
public ICPPEnumeration getEnumerationType() {
return (ICPPEnumeration) getScopeBinding();
}
}