/******************************************************************************* * Copyright (c) 2013, 2015 Nathan Ridge. * 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: * Nathan Ridge *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; import org.eclipse.cdt.core.dom.ILinkage; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.PlatformObject; /** * Base class for evaluations that are dependent, or that have been instantiated * from a dependent evaluation. These evaluations keep track of the template * in which they are defined, so that certain name lookups can be performed * starting from their point of definition. */ public abstract class CPPDependentEvaluation extends CPPEvaluation { private IBinding fTemplateDefinition; private IScope fTemplateDefinitionScope; CPPDependentEvaluation(IBinding templateDefinition) { fTemplateDefinition = templateDefinition; } @Override public IBinding getTemplateDefinition() { if (fTemplateDefinition instanceof DeferredResolutionBinding) { IBinding toResolve = fTemplateDefinition; // While resolve() is called, set fTemplateDefinition to null to avoid // infinite recursion in some cases where the resolution process ends // up (indirectly) calling getTemplateDefinition() on this evaluation. fTemplateDefinition = null; fTemplateDefinition = ((DeferredResolutionBinding) toResolve).resolve(); } return fTemplateDefinition; } protected IScope getTemplateDefinitionScope() { if (fTemplateDefinitionScope == null) { IBinding templateDefinition = getTemplateDefinition(); if (templateDefinition != null) { if (templateDefinition instanceof ICPPClassType) { fTemplateDefinitionScope = ((ICPPClassType) templateDefinition).getCompositeScope(); } try { fTemplateDefinitionScope = templateDefinition.getScope(); } catch (DOMException e) { } } } return fTemplateDefinitionScope; } /** * If the given node is contained in some template declaration, * returns the binding for that template. Otherwise returns null. */ protected static IBinding findEnclosingTemplate(IASTNode node) { while (node != null) { if (node instanceof ICPPASTTemplateDeclaration) { ICPPASTTemplateDeclaration templateDecl = (ICPPASTTemplateDeclaration) node; IASTName templateName = CPPTemplates.getTemplateName(templateDecl); if (templateName == null) return null; return new DeferredResolutionBinding(templateName); } node = node.getParent(); } return null; } protected void marshalTemplateDefinition(ITypeMarshalBuffer buffer) throws CoreException { // Don't marshal the template definition when building a signature. // While the template definition needs to be stored in the index, it does not // need to be part of the signature, and trying to resolve it at the time a // signature is built sometimes causes recursion (as the call to resolve() // may end up needing the signature). if (!(buffer instanceof SignatureBuilder)) buffer.marshalBinding(getTemplateDefinition()); } /** * Instantiates evaluations that represent subexpressions separated by commas. * If a subexpression is a pack expansion expression, and the template parameter map * contains a mapping for the parameter pack(s) that occur in its expansion pattern, * the expansion pattern is instantiated once for each mapped template argument, * and the resulting evaluations are returned in place of the pack expansion. * * This code is similar to CPPTemplates.instantiateArguments(), but applies to evaluations * rather than template arguments. */ protected static ICPPEvaluation[] instantiateCommaSeparatedSubexpressions( ICPPEvaluation[] subexpressions, InstantiationContext context, int maxDepth) { ICPPEvaluation[] result = subexpressions; int resultShift = 0; for (int i = 0; i < subexpressions.length; i++) { ICPPEvaluation origEval = subexpressions[i]; ICPPEvaluation newEval; if (origEval instanceof EvalParameterPack) { ICPPEvaluation pattern = ((EvalParameterPack) origEval).getExpansionPattern(); if (pattern == null) { newEval = EvalFixed.INCOMPLETE; } else { int packSize = pattern.determinePackSize(context.getParameterMap()); if (packSize == CPPTemplates.PACK_SIZE_FAIL || packSize == CPPTemplates.PACK_SIZE_NOT_FOUND) { newEval = EvalFixed.INCOMPLETE; } else if (packSize == CPPTemplates.PACK_SIZE_DEFER) { newEval = origEval; } else { int shift = packSize - 1; ICPPEvaluation[] newResult = new ICPPEvaluation[subexpressions.length + resultShift + shift]; System.arraycopy(result, 0, newResult, 0, i + resultShift); int oldPackOffset = context.getPackOffset(); for (int j = 0; j < packSize; ++j) { context.setPackOffset(j); newEval = pattern.instantiate(context, maxDepth); newResult[i + resultShift + j] = newEval; } context.setPackOffset(oldPackOffset); result = newResult; resultShift += shift; continue; } } } else { newEval = origEval.instantiate(context, maxDepth); } if (result != subexpressions) { result[i + resultShift] = newEval; } else if (newEval != origEval) { assert resultShift == 0; result = new ICPPEvaluation[subexpressions.length]; System.arraycopy(subexpressions, 0, result, 0, i); result[i] = newEval; } } return result; } /** * Used to defer the resolution of a template definition until it is needed, * to avoid recursion. The only valid operation on this binding is resolve(). */ private static class DeferredResolutionBinding extends PlatformObject implements IBinding { private final IASTName fName; public DeferredResolutionBinding(IASTName name) { fName = name; } public IBinding resolve() { return fName.resolveBinding(); } @Override public String getName() { throw new UnsupportedOperationException(); } @Override public char[] getNameCharArray() { throw new UnsupportedOperationException(); } @Override public ILinkage getLinkage() { throw new UnsupportedOperationException(); } @Override public IBinding getOwner() { throw new UnsupportedOperationException(); } @Override public IScope getScope() throws DOMException { throw new UnsupportedOperationException(); } } }