/******************************************************************************* * Copyright (c) 2008, 2009 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.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.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 IASTName { 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 { public RecursionResolvingBinding(IASTName node) { super(node, IProblemBinding.SEMANTIC_RECURSION_IN_LOOKUP); Assert.isTrue(sAllowRecursionBindings, getMessage()); } } private IBinding fBinding = null; private byte fResolutionDepth = 0; private boolean fIsFinal= false; public final void incResolutionDepth() { if (fBinding == null && ++fResolutionDepth > MAX_RESOLUTION_DEPTH) { setBinding(new RecursionResolvingBinding(this)); } } /** * 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 */ public IBinding resolvePreBinding() { if (fBinding == null) { if (++fResolutionDepth > MAX_RESOLUTION_DEPTH) { setBinding(new RecursionResolvingBinding(this)); } else { setBinding(createIntermediateBinding()); } } return fBinding; } public IBinding resolveBinding() { if (fBinding == null) { if (++fResolutionDepth > MAX_RESOLUTION_DEPTH) { setBinding(new RecursionResolvingBinding(this)); } 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 */ 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 */ 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(new RecursionResolvingBinding(this)); } else { setBinding(intermediateBinding.resolveFinalBinding(astName)); } } fIsFinal= true; } public void setBinding(IBinding binding) { fBinding= binding; fResolutionDepth= 0; } public IASTName getLastName() { return this; } @Override public final String toString() { return new String(toCharArray()); } public IASTCompletionContext getCompletionContext() { IASTNode node = getParent(); while (node != null) { if (node instanceof IASTCompletionContext) { return (IASTCompletionContext) node; } node = node.getParent(); } return null; } 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; } 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; } public boolean isReference() { IASTNode parent = getParent(); if (parent instanceof IASTNameOwner) { int role = ((IASTNameOwner) parent).getRoleForName(this); return role == IASTNameOwner.r_reference; } return false; } public boolean isDefinition() { IASTNode parent = getParent(); if (parent instanceof IASTNameOwner) { int role = ((IASTNameOwner) parent).getRoleForName(this); return role == IASTNameOwner.r_definition; } return false; } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.IASTName#getLinkage() */ public ILinkage getLinkage() { return Linkage.CPP_LINKAGE; } }