blob: 92887845de25711cdeea034c9d35eb7163015674 [file] [log] [blame]
/*******************************************************************************
* 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 EvalPackExpansion) {
ICPPEvaluation pattern = ((EvalPackExpansion) 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();
}
}
}