blob: 834b25700f724bb4b7195eef2e492567cd3d4e0f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2014 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
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.regex.Pattern;
import org.eclipse.cdt.core.dom.ILinkage;
import org.eclipse.cdt.core.dom.ast.IASTCompletionContext;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.internal.core.dom.Linkage;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalNameOwner;
import org.eclipse.cdt.internal.core.dom.parser.IRecursionResolvingBinding;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.core.runtime.Assert;
/**
* Common base class for all sorts of c++ names: unqualified, qualified, operator and conversion
* names plus template-ids
*/
public abstract class CPPASTNameBase extends ASTNode implements ICPPASTName {
protected static final Pattern WHITESPACE_SEQ = Pattern.compile("\\s+"); //$NON-NLS-1$
/**
* For test-purposes, only.
*/
public static boolean sAllowRecursionBindings = true;
public static boolean sAllowNameComputation = true;
private static final byte MAX_RESOLUTION_DEPTH= 6;
protected final static class RecursionResolvingBinding extends ProblemBinding implements IRecursionResolvingBinding {
public RecursionResolvingBinding(IASTName node, char[] arg) {
super(node, IProblemBinding.SEMANTIC_RECURSION_IN_LOOKUP, arg);
Assert.isTrue(sAllowRecursionBindings, getMessage());
}
}
private RecursionResolvingBinding createRecursionResolvingBinding() {
// We create a recursion resolving binding when the resolution depth
// exceeds MAX_RESOLUTION_DEPTH. If the resolution depth exceeds
// MAX_RESOLUTION_DEPTH + 1, it means that attempting to create the
// recursion resolving binding has led us back to trying to resolve
// the binding for this name again, so the recursion isn't broken.
// This can happen because the constructor of RecursionResolvingBinding
// calls ProblemBinding.getMessage(), which can try to do name
// resolution to build an argument string if one wasn't provided in the
// ProblemBinding constructor. To break the recursion in a case
// like, this we provide the argument string "(unknown)" instead.
char[] args = (fResolutionDepth > MAX_RESOLUTION_DEPTH + 1) ? "(unknown)".toCharArray() : null; //$NON-NLS-1$
return new RecursionResolvingBinding(this, args);
}
private IBinding fBinding;
private byte fResolutionDepth;
private boolean fIsFinal;
public final void incResolutionDepth() {
if (fBinding == null && ++fResolutionDepth > MAX_RESOLUTION_DEPTH) {
setBinding(createRecursionResolvingBinding());
}
}
/**
* Called to perform the binding resolution. Subclasses may return lazy bindings that
* will not be exposed within public API.
*/
protected abstract IBinding createIntermediateBinding();
/**
* Resolves the name at least up to the intermediate binding and returns it.
* @see ICPPTwoPhaseBinding
*/
@Override
public IBinding resolvePreBinding() {
if (fBinding == null) {
if (++fResolutionDepth > MAX_RESOLUTION_DEPTH) {
setBinding(createRecursionResolvingBinding());
} else {
setBinding(createIntermediateBinding());
}
}
return fBinding;
}
@Override
public IBinding resolveBinding() {
if (fBinding == null) {
if (++fResolutionDepth > MAX_RESOLUTION_DEPTH) {
setBinding(createRecursionResolvingBinding());
} else {
fIsFinal= false;
final IBinding b= createIntermediateBinding();
if (b instanceof ProblemBinding) {
ProblemBinding pb= (ProblemBinding) b;
final IASTNode node= pb.getASTNode();
if (node == null || node.getParent() == null) {
pb.setASTNode(this);
}
}
setBinding(b);
}
}
if (!fIsFinal)
resolveFinalBinding(this);
return fBinding;
}
/**
* If this name has not yet been resolved at all, <code>null</code> will be returned.
* Otherwise the intermediate or final binding for this name is returned.
* @see ICPPTwoPhaseBinding
*/
@Override
public IBinding getPreBinding() {
return fBinding;
}
/**
* If this name has not yet been resolved at all, <code>null</code> will be returned.
* Otherwise the final binding for this name is returned.
* @see ICPPTwoPhaseBinding
*/
@Override
public IBinding getBinding() {
final IBinding cand= fBinding;
if (cand == null)
return null;
if (!fIsFinal)
resolveFinalBinding(this);
return fBinding;
}
private void resolveFinalBinding(CPPASTNameBase astName) {
if (fBinding instanceof ICPPTwoPhaseBinding) {
ICPPTwoPhaseBinding intermediateBinding= (ICPPTwoPhaseBinding) fBinding;
if (++fResolutionDepth > MAX_RESOLUTION_DEPTH) {
setBinding(createRecursionResolvingBinding());
} else {
setBinding(intermediateBinding.resolveFinalBinding(astName));
}
}
fIsFinal= true;
}
@Override
public void setBinding(IBinding binding) {
fBinding= binding;
fResolutionDepth= 0;
}
@Override
public IASTName getLastName() {
return this;
}
@Override
public boolean isQualified() {
IASTNode parent= getParent();
if (parent instanceof ICPPASTQualifiedName) {
ICPPASTQualifiedName qn= (ICPPASTQualifiedName) parent;
if (qn.isFullyQualified())
return true;
ICPPASTNameSpecifier[] qualifier = qn.getQualifier();
if (qualifier.length > 0 && qualifier[0] == this)
return false;
return true;
}
return false;
}
@Override
public final String toString() {
return new String(toCharArray());
}
@Override
public IASTCompletionContext getCompletionContext() {
IASTNode node = getParent();
while (node != null) {
if (node instanceof IASTCompletionContext) {
return (IASTCompletionContext) node;
}
node = node.getParent();
}
return null;
}
@Override
public int getRoleOfName(boolean allowResolution) {
IASTNode parent = getParent();
if (parent instanceof IASTInternalNameOwner) {
return ((IASTInternalNameOwner) parent).getRoleForName(this, allowResolution);
}
if (parent instanceof IASTNameOwner) {
return ((IASTNameOwner) parent).getRoleForName(this);
}
return IASTNameOwner.r_unclear;
}
@Override
public boolean isDeclaration() {
IASTNode parent = getParent();
if (parent instanceof IASTNameOwner) {
int role = ((IASTNameOwner) parent).getRoleForName(this);
switch (role) {
case IASTNameOwner.r_reference:
case IASTNameOwner.r_unclear:
return false;
default:
return true;
}
}
return false;
}
@Override
public boolean isReference() {
IASTNode parent = getParent();
if (parent instanceof IASTNameOwner) {
int role = ((IASTNameOwner) parent).getRoleForName(this);
return role == IASTNameOwner.r_reference;
}
return false;
}
@Override
public boolean isDefinition() {
IASTNode parent = getParent();
if (parent instanceof IASTNameOwner) {
int role = ((IASTNameOwner) parent).getRoleForName(this);
return role == IASTNameOwner.r_definition;
}
return false;
}
@Override
public ILinkage getLinkage() {
return Linkage.CPP_LINKAGE;
}
}