/******************************************************************************* * Copyright (c) 2007, 2013 Symbian 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: * Andrew Ferguson (Symbian) - Initial implementation * Markus Schorn (Wind River Systems) * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.index.composite.cpp; import java.util.HashSet; import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IField; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.core.parser.util.ObjectMap; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassSpecialization.RecursionResolvingBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPClassSpecializationScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates; import org.eclipse.cdt.internal.core.index.IIndexFragment; import org.eclipse.cdt.internal.core.index.IIndexFragmentBinding; import org.eclipse.cdt.internal.core.index.IIndexScope; import org.eclipse.cdt.internal.core.index.composite.ICompositesFactory; public class CompositeCPPClassSpecialization extends CompositeCPPClassType implements ICPPClassSpecialization { private ObjectMap specializationMap; private final ThreadLocal<Set<IBinding>> fInProgress= new ThreadLocal<Set<IBinding>>() { @Override protected Set<IBinding> initialValue() { return new HashSet<IBinding>(); } }; public CompositeCPPClassSpecialization(ICompositesFactory cf, ICPPClassType rbinding) { super(cf, rbinding); } @Override public ICPPClassScope getCompositeScope() { return (ICPPClassScope) cf.getCompositeScope((IIndexScope) ((ICPPClassType) rbinding).getCompositeScope()); } @Override public ICPPClassType getSpecializedBinding() { return (ICPPClassType) TemplateInstanceUtil.getSpecializedBinding(cf, rbinding); } @Override public ICPPTemplateParameterMap getTemplateParameterMap() { IBinding owner= getOwner(); if (owner instanceof ICPPSpecialization) { return ((ICPPSpecialization) owner).getTemplateParameterMap(); } return CPPTemplateParameterMap.EMPTY; } @Override public IBinding specializeMember(IBinding original) { return specializeMember(original, null); } @Override public IBinding specializeMember(IBinding original, IASTNode point) { if (specializationMap == null) { final Object key= CPPCompositesFactory.createSpecializationKey(cf, rbinding); final IIndexFragment frag= rbinding.getFragment(); Object cached= frag.getCachedResult(key); if (cached != null) { specializationMap= (ObjectMap) cached; } else { final ObjectMap newMap= new ObjectMap(2); // In any fragment explicit specializations may be defined. IIndexFragmentBinding[] frags= cf.findEquivalentBindings(rbinding); for (IIndexFragmentBinding fb : frags) { if (fb instanceof ICPPClassType) { final ICPPClassType[] nested = ClassTypeHelper.getNestedClasses((ICPPClassType) fb, point); if (nested.length > 0) { for (ICPPClassType ct : nested) { if (ct instanceof ICPPClassSpecialization && !(ct.getCompositeScope() instanceof ICPPClassSpecializationScope)) { ICPPClassSpecialization cspec= (ICPPClassSpecialization) cf.getCompositeBinding((IIndexFragmentBinding) ct); newMap.put(cspec.getSpecializedBinding(), cspec); } } if (!newMap.isEmpty()) break; } } } specializationMap= (ObjectMap) frag.putCachedResult(key, newMap, false); } } synchronized (specializationMap) { IBinding result= (IBinding) specializationMap.get(original); if (result != null) return result; } IBinding newSpec; Set<IBinding> recursionProtectionSet= fInProgress.get(); if (!recursionProtectionSet.add(original)) return RecursionResolvingBinding.createFor(original, point); try { newSpec= CPPTemplates.createSpecialization(this, original, point); } finally { recursionProtectionSet.remove(original); } synchronized (specializationMap) { IBinding oldSpec= (IBinding) specializationMap.put(original, newSpec); if (oldSpec != null) { specializationMap.put(original, oldSpec); return oldSpec; } } return newSpec; } @Override public final ICPPBase[] getBases() { CCorePlugin.log(new Exception("Unsafe method call. Instantiation of dependent expressions may not work.")); //$NON-NLS-1$ return getBases(null); } @Override public final ICPPBase[] getBases(IASTNode point) { IScope scope= getCompositeScope(); if (scope instanceof ICPPClassSpecializationScope) { return ((ICPPClassSpecializationScope) scope).getBases(point); } ICPPBase[] bases = ClassTypeHelper.getBases((ICPPClassType) rbinding, point); return wrapBases(bases); } @Override public final ICPPConstructor[] getConstructors() { CCorePlugin.log(new Exception("Unsafe method call. Instantiation of dependent expressions may not work.")); //$NON-NLS-1$ return getConstructors(null); } @Override public final ICPPConstructor[] getConstructors(IASTNode point) { IScope scope= getCompositeScope(); if (scope instanceof ICPPClassSpecializationScope) { return ((ICPPClassSpecializationScope) scope).getConstructors(point); } ICPPConstructor[] result = ClassTypeHelper.getConstructors((ICPPClassType) rbinding, point); return wrapBindings(result); } @Override public ICPPMethod[] getMethods() { CCorePlugin.log(new Exception("Unsafe method call. Instantiation of dependent expressions may not work.")); //$NON-NLS-1$ return getMethods(null); } @Override public ICPPMethod[] getMethods(IASTNode point) { return ClassTypeHelper.getMethods(this, point); } @Override public final ICPPMethod[] getDeclaredMethods() { CCorePlugin.log(new Exception("Unsafe method call. Instantiation of dependent expressions may not work.")); //$NON-NLS-1$ return getDeclaredMethods(null); } @Override public final ICPPMethod[] getDeclaredMethods(IASTNode point) { IScope scope= getCompositeScope(); if (scope instanceof ICPPClassSpecializationScope) { return ((ICPPClassSpecializationScope) scope).getDeclaredMethods(point); } ICPPMethod[] result = ClassTypeHelper.getDeclaredMethods((ICPPClassType) rbinding, point); return wrapBindings(result); } @Override public final ICPPMethod[] getAllDeclaredMethods() { CCorePlugin.log(new Exception("Unsafe method call. Instantiation of dependent expressions may not work.")); //$NON-NLS-1$ return getAllDeclaredMethods(null); } @Override public final ICPPMethod[] getAllDeclaredMethods(IASTNode point) { return ClassTypeHelper.getAllDeclaredMethods(this, point); } @Override public final ICPPField[] getDeclaredFields() { CCorePlugin.log(new Exception("Unsafe method call. Instantiation of dependent expressions may not work.")); //$NON-NLS-1$ return getDeclaredFields(null); } @Override public final ICPPField[] getDeclaredFields(IASTNode point) { IScope scope= getCompositeScope(); if (scope instanceof ICPPClassSpecializationScope) { return ((ICPPClassSpecializationScope) scope).getDeclaredFields(point); } ICPPField[] result = ClassTypeHelper.getDeclaredFields((ICPPClassType) rbinding, point); return wrapBindings(result); } @Override public IField[] getFields() { CCorePlugin.log(new Exception("Unsafe method call. Instantiation of dependent expressions may not work.")); //$NON-NLS-1$ return getFields(null); } @Override public final IField[] getFields(IASTNode point) { return ClassTypeHelper.getFields(this, point); } @Override public final IBinding[] getFriends() { CCorePlugin.log(new Exception("Unsafe method call. Instantiation of dependent expressions may not work.")); //$NON-NLS-1$ return getFriends(null); } @Override public final IBinding[] getFriends(IASTNode point) { IScope scope= getCompositeScope(); if (scope instanceof ICPPClassSpecializationScope) { return ((ICPPClassSpecializationScope) scope).getFriends(point); } IBinding[] result = ClassTypeHelper.getFriends((ICPPClassType) rbinding, point); return wrapBindings(result); } @Override public final ICPPClassType[] getNestedClasses() { CCorePlugin.log(new Exception("Unsafe method call. Instantiation of dependent expressions may not work.")); //$NON-NLS-1$ return getNestedClasses(null); } @Override public final ICPPClassType[] getNestedClasses(IASTNode point) { IScope scope= getCompositeScope(); if (scope instanceof ICPPClassSpecializationScope) { return ((ICPPClassSpecializationScope) scope).getNestedClasses(point); } ICPPClassType[] result = ClassTypeHelper.getNestedClasses((ICPPClassType) rbinding, point); return wrapBindings(result); } }