1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Mechanism to resolve bindings in two phases, bug 252554.

This commit is contained in:
Markus Schorn 2008-10-31 10:06:53 +00:00
parent a831e865be
commit 10f412ae84
10 changed files with 304 additions and 189 deletions

View file

@ -111,7 +111,7 @@ import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPPointerToMemberType;
import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPPointerType; import org.eclipse.cdt.core.dom.ast.gnu.cpp.IGPPPointerType;
import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.AbstractCPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
@ -1671,25 +1671,20 @@ public class AST2CPPTests extends AST2BaseTest {
// }; // };
public void testBug84692() throws Exception { public void testBug84692() throws Exception {
// also tests bug 234042. // also tests bug 234042.
boolean old= CPPASTName.fAllowRecursionBindings; AbstractCPPASTName.sAllowRecursionBindings= false;
CPPASTName.fAllowRecursionBindings= false;
try {
IASTTranslationUnit tu = parse(getAboveComment(), ParserLanguage.CPP);
CPPNameCollector col = new CPPNameCollector();
tu.accept(col);
assertEquals(col.size(), 9); IASTTranslationUnit tu = parse(getAboveComment(), ParserLanguage.CPP);
CPPNameCollector col = new CPPNameCollector();
tu.accept(col);
ICPPClassType Node = (ICPPClassType) col.getName(1).resolveBinding(); assertEquals(col.size(), 9);
ICPPClassType Data = (ICPPClassType) col.getName(3).resolveBinding();
assertSame(Data.getScope(), tu.getScope());
assertInstances(col, Node, 3); ICPPClassType Node = (ICPPClassType) col.getName(1).resolveBinding();
assertInstances(col, Data, 2); ICPPClassType Data = (ICPPClassType) col.getName(3).resolveBinding();
} assertSame(Data.getScope(), tu.getScope());
finally {
CPPASTName.fAllowRecursionBindings= old; assertInstances(col, Node, 3);
} assertInstances(col, Data, 2);
} }
// namespace B { int b; } // namespace B { int b; }

View file

@ -32,6 +32,7 @@ import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ElementChangedEvent; import org.eclipse.cdt.core.model.ElementChangedEvent;
import org.eclipse.cdt.core.model.IElementChangedListener; import org.eclipse.cdt.core.model.IElementChangedListener;
import org.eclipse.cdt.core.testplugin.TestScannerProvider; import org.eclipse.cdt.core.testplugin.TestScannerProvider;
import org.eclipse.cdt.internal.core.dom.parser.cpp.AbstractCPPASTName;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILogListener; import org.eclipse.core.runtime.ILogListener;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitor;
@ -56,6 +57,7 @@ public class BaseTestCase extends TestCase {
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
AbstractCPPASTName.sAllowRecursionBindings= true;
} }
@Override @Override

View file

@ -0,0 +1,153 @@
/*******************************************************************************
* Copyright (c) 2008 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 org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
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 AbstractCPPASTName extends ASTNode implements IASTName {
/**
* For test-purposes, only.
*/
public static boolean sAllowRecursionBindings = 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, node.toCharArray());
Assert.isTrue(sAllowRecursionBindings, getMessage());
}
}
/**
* Helper method to resolve intermediate bindings without casting the name.
*/
public static IBinding resolveIntermediateBinding(IASTName name) {
if (name == null)
return null;
if (name instanceof AbstractCPPASTName)
return ((AbstractCPPASTName) name).resolveIntermediateBinding();
return name.resolveBinding();
}
/**
* Helper method to get intermediate bindings without casting the name.
*/
public static IBinding getIntermediateBinding(IASTName name) {
if (name == null)
return null;
if (name instanceof AbstractCPPASTName)
return ((AbstractCPPASTName) name).getIntermediateBinding();
return name.resolveBinding();
}
private IBinding fBinding = null;
private byte fResolutionDepth = 0;
private boolean fIsFinal= false;
public final void incResolutionDepth() {
if (fBinding == null && ++fResolutionDepth > MAX_RESOLUTION_DEPTH) {
fBinding = 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 resolveIntermediateBinding() {
if (fBinding == null) {
if (++fResolutionDepth > MAX_RESOLUTION_DEPTH) {
fBinding= new RecursionResolvingBinding(this);
} else {
fBinding= createIntermediateBinding();
}
}
return fBinding;
}
public IBinding resolveBinding() {
if (fBinding == null) {
if (++fResolutionDepth > MAX_RESOLUTION_DEPTH) {
fBinding= new RecursionResolvingBinding(this);
} else {
fBinding= createIntermediateBinding();
}
}
if (!fIsFinal)
resolveFinalBinding();
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 getIntermediateBinding() {
final IBinding cand= fBinding;
if (cand == null)
return null;
return fBinding;
}
public IBinding getBinding() {
final IBinding cand= fBinding;
if (cand == null)
return null;
if (!fIsFinal)
resolveFinalBinding();
return fBinding;
}
private void resolveFinalBinding() {
if (fBinding instanceof ICPPTwoPhaseBinding) {
ICPPTwoPhaseBinding lazyBinding= (ICPPTwoPhaseBinding) fBinding;
if (++fResolutionDepth > MAX_RESOLUTION_DEPTH) {
fBinding= new RecursionResolvingBinding(this);
} else {
IBinding finalBinding= lazyBinding.resolveFinalBinding();
assert finalBinding.getClass().equals(lazyBinding.getClass());
fBinding= finalBinding;
}
}
fIsFinal= true;
}
public void setBinding(IBinding binding) {
fBinding= binding;
fResolutionDepth= 0;
}
public IASTName getLastName() {
return this;
}
}

View file

@ -6,7 +6,7 @@
* http://www.eclipse.org/legal/epl-v10.html * http://www.eclipse.org/legal/epl-v10.html
* *
* Contributors: * Contributors:
* IBM - Initial API and implementation * John Camelon(IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems) * Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX) * Bryan Wilkinson (QNX)
* Anton Leherbauer (Wind River Systems) * Anton Leherbauer (Wind River Systems)
@ -24,67 +24,32 @@ import org.eclipse.cdt.core.dom.ast.IASTNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.Linkage; 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.IASTInternalNameOwner;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.core.runtime.Assert;
/** /**
* @author jcamelon * Unqualified name, also base class for operator and conversion name.
*/ */
public class CPPASTName extends ASTNode implements IASTName, IASTCompletionContext { public class CPPASTName extends AbstractCPPASTName implements IASTCompletionContext {
/**
* For test-purposes, only.
*/
public static boolean fAllowRecursionBindings= true;
final static class RecursionResolvingBinding extends ProblemBinding {
public RecursionResolvingBinding(IASTName node) {
super(node, IProblemBinding.SEMANTIC_RECURSION_IN_LOOKUP, node.toCharArray());
Assert.isTrue(fAllowRecursionBindings, getMessage());
}
}
private static final char[] EMPTY_CHAR_ARRAY = {};
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
static final int MAX_RESOLUTION_DEPTH = 5;
private char[] name; private char[] name;
private IBinding binding = null;
private int fResolutionDepth= 0;
public CPPASTName(char[] name) { public CPPASTName(char[] name) {
this.name = name; this.name = name;
} }
public CPPASTName() { public CPPASTName() {
name = EMPTY_CHAR_ARRAY; name = CharArrayUtils.EMPTY;
} }
public IBinding resolveBinding() { @Override
if (binding == null) { protected IBinding createIntermediateBinding() {
if (++fResolutionDepth > MAX_RESOLUTION_DEPTH) { return CPPVisitor.createBinding(this);
binding = new RecursionResolvingBinding(this);
} else {
binding = CPPVisitor.createBinding(this);
}
}
return binding;
}
public void incResolutionDepth() {
if (binding == null && ++fResolutionDepth > MAX_RESOLUTION_DEPTH) {
binding = new RecursionResolvingBinding(this);
}
} }
public IASTCompletionContext getCompletionContext() { public IASTCompletionContext getCompletionContext() {
@ -164,19 +129,10 @@ public class CPPASTName extends ASTNode implements IASTName, IASTCompletionConte
return (IBinding[])ArrayUtil.removeNulls(IBinding.class, bindings); return (IBinding[])ArrayUtil.removeNulls(IBinding.class, bindings);
} }
public void setBinding(IBinding binding) {
this.binding = binding;
fResolutionDepth= 0;
}
public IBinding getBinding() {
return binding;
}
@Override @Override
public String toString() { public String toString() {
if (name == EMPTY_CHAR_ARRAY) if (name.length == 0)
return EMPTY_STRING; return ""; //$NON-NLS-1$
return new String(name); return new String(name);
} }
@ -275,8 +231,4 @@ public class CPPASTName extends ASTNode implements IASTName, IASTCompletionConte
public ILinkage getLinkage() { public ILinkage getLinkage() {
return Linkage.CPP_LINKAGE; return Linkage.CPP_LINKAGE;
} }
public IASTName getLastName() {
return this;
}
} }

View file

@ -6,7 +6,7 @@
* http://www.eclipse.org/legal/epl-v10.html * http://www.eclipse.org/legal/epl-v10.html
* *
* Contributors: * Contributors:
* IBM - Initial API and implementation * John Camelon (IBM) - Initial API and implementation
* Bryan Wilkinson (QNX) * Bryan Wilkinson (QNX)
* Markus Schorn (Wind River Systems) * Markus Schorn (Wind River Systems)
*******************************************************************************/ *******************************************************************************/
@ -37,26 +37,54 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.Linkage; 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.IASTInternalNameOwner;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.core.runtime.Assert;
/** /**
* @author jcamelon * Qualified name, which can contain any other name (unqualified, operator-name, conversion name,
* template id).
*/ */
public class CPPASTQualifiedName extends ASTNode implements public class CPPASTQualifiedName extends AbstractCPPASTName
ICPPASTQualifiedName, IASTCompletionContext { implements ICPPASTQualifiedName, IASTCompletionContext {
private IASTName[] names = null;
private int namesPos= -1;
private boolean isFullyQualified;
private String signature;
public CPPASTQualifiedName() { public CPPASTQualifiedName() {
} }
@Override
public final IBinding resolveIntermediateBinding() {
// The full qualified name resolves to the same thing as the last name
return resolveIntermediateBinding(getLastName());
}
@Override
public IBinding resolveBinding() { public IBinding resolveBinding() {
// The full qualified name resolves to the same thing as the last name // The full qualified name resolves to the same thing as the last name
removeNullNames(); IASTName lastName= getLastName();
IASTName lastName = getLastName();
return lastName == null ? null : lastName.resolveBinding(); return lastName == null ? null : lastName.resolveBinding();
} }
@Override
public final IBinding getIntermediateBinding() {
// The full qualified name resolves to the same thing as the last name
return getIntermediateBinding(getLastName());
}
@Override
public IBinding getBinding() {
return getLastName().getBinding();
}
@Override
public void setBinding(IBinding binding) {
getLastName().setBinding(binding);
}
public IASTCompletionContext getCompletionContext() { public IASTCompletionContext getCompletionContext() {
IASTNode node = getParent(); IASTNode node = getParent();
while (node != null) { while (node != null) {
@ -75,6 +103,7 @@ public class CPPASTQualifiedName extends ASTNode implements
} }
public void addName(IASTName name) { public void addName(IASTName name) {
assert !(name instanceof ICPPASTQualifiedName);
if (name != null) { if (name != null) {
names = (IASTName[]) ArrayUtil.append(IASTName.class, names, ++namesPos, name); names = (IASTName[]) ArrayUtil.append(IASTName.class, names, ++namesPos, name);
name.setParent(this); name.setParent(this);
@ -82,23 +111,15 @@ public class CPPASTQualifiedName extends ASTNode implements
} }
} }
private void removeNullNames() {
names = (IASTName[]) ArrayUtil.removeNullsAfter(IASTName.class, names, namesPos);
}
private IASTName[] names = null;
private int namesPos= -1;
private boolean isFullyQualified;
private String signature;
public IASTName[] getNames() { public IASTName[] getNames() {
if (names == null) if (namesPos < 0)
return IASTName.EMPTY_NAME_ARRAY; return IASTName.EMPTY_NAME_ARRAY;
removeNullNames();
names = (IASTName[]) ArrayUtil.removeNullsAfter(IASTName.class, names, namesPos);
return names; return names;
} }
@Override
public IASTName getLastName() { public IASTName getLastName() {
if (namesPos < 0) if (namesPos < 0)
return null; return null;
@ -107,31 +128,29 @@ public class CPPASTQualifiedName extends ASTNode implements
} }
public char[] toCharArray() { public char[] toCharArray() {
if (names == null) if (namesPos < 0)
return new char[0]; return new char[0];
removeNullNames();
// count first // count first
int len = 0; int len = -2;
for (int i = 0; i < names.length; ++i) { for (int i = 0; i <= namesPos; ++i) {
char[] n = names[i].toCharArray(); char[] n = names[i].toCharArray();
if (n == null) if (n == null)
return null; return null;
len += n.length; len+= 2;
if (i != names.length - 1) len+= n.length;
len += 2;
} }
char[] nameArray = new char[len]; char[] nameArray = new char[len];
int pos = 0; int pos = 0;
for (int i = 0; i < names.length; i++) { for (int i = 0; i <= namesPos; i++) {
char[] n = names[i].toCharArray(); if (i != 0) {
System.arraycopy(n, 0, nameArray, pos, n.length);
pos += n.length;
if (i != names.length - 1) {
nameArray[pos++] = ':'; nameArray[pos++] = ':';
nameArray[pos++] = ':'; nameArray[pos++] = ':';
} }
final char[] n = names[i].toCharArray();
System.arraycopy(n, 0, nameArray, pos, n.length);
pos += n.length;
} }
return nameArray; return nameArray;
} }
@ -161,9 +180,8 @@ public class CPPASTQualifiedName extends ASTNode implements
break; break;
} }
} }
IASTName[] ns = getNames(); for (int i = 0; i <= namesPos; i++) {
for (int i = 0; i < ns.length; i++) { if (i == namesPos) {
if (i == names.length - 1) {
// pointer-to-member qualified names have a dummy name as the last part of the name, don't visit it // pointer-to-member qualified names have a dummy name as the last part of the name, don't visit it
if (names[i].toCharArray().length > 0 && !names[i].accept(action)) if (names[i].toCharArray().length > 0 && !names[i].accept(action))
return false; return false;
@ -217,41 +235,28 @@ public class CPPASTQualifiedName extends ASTNode implements
} }
public int getRoleForName(IASTName n) { public int getRoleForName(IASTName n) {
IASTName[] namez = getNames(); for (int i=0; i < namesPos; ++i) {
for(int i = 0; i < names.length; ++i) if (names[i] == n)
if (namez[i] == n) return r_reference;
{ }
if (i < names.length - 1) if (getLastName() == n) {
return r_reference; IASTNode p = getParent();
IASTNode p = getParent(); if (p instanceof IASTNameOwner) {
if (i == names.length - 1 && p instanceof IASTNameOwner) return ((IASTNameOwner)p).getRoleForName(this);
return ((IASTNameOwner)p).getRoleForName(this);
return r_unclear;
} }
}
return r_unclear; return r_unclear;
} }
public IBinding getBinding() {
removeNullNames();
return names[names.length - 1].getBinding();
}
public void setBinding(IBinding binding) {
removeNullNames();
names[names.length - 1].setBinding(binding);
}
public boolean isConversionOrOperator() { public boolean isConversionOrOperator() {
IASTName[] nonNullNames = getNames(); // ensure no null names final IASTName lastName= getLastName();
if (lastName instanceof ICPPASTConversionName || lastName instanceof ICPPASTOperatorName) {
int len=nonNullNames.length;
if (nonNullNames[len - 1] instanceof ICPPASTConversionName || nonNullNames[len - 1] instanceof ICPPASTOperatorName) {
return true; return true;
} }
// check templateId's name // check templateId's name
if (nonNullNames[len - 1] instanceof ICPPASTTemplateId) { if (lastName instanceof ICPPASTTemplateId) {
IASTName tempName = ((ICPPASTTemplateId)nonNullNames[len - 1]).getTemplateName(); IASTName tempName = ((ICPPASTTemplateId)lastName).getTemplateName();
if (tempName instanceof ICPPASTConversionName || tempName instanceof ICPPASTOperatorName) { if (tempName instanceof ICPPASTConversionName || tempName instanceof ICPPASTOperatorName) {
return true; return true;
} }
@ -273,8 +278,8 @@ public class CPPASTQualifiedName extends ASTNode implements
public IBinding[] findBindings(IASTName n, boolean isPrefix) { public IBinding[] findBindings(IASTName n, boolean isPrefix) {
IBinding[] bindings = CPPSemantics.findBindingsForContentAssist(n, isPrefix); IBinding[] bindings = CPPSemantics.findBindingsForContentAssist(n, isPrefix);
if (names.length - 2 >= 0) { if (namesPos > 0) {
IBinding binding = names[names.length - 2].resolveBinding(); IBinding binding = names[namesPos-1].resolveBinding();
if (binding instanceof ICPPClassType) { if (binding instanceof ICPPClassType) {
ICPPClassType classType = (ICPPClassType) binding; ICPPClassType classType = (ICPPClassType) binding;
final boolean isDeclaration = getParent().getParent() instanceof IASTSimpleDeclaration; final boolean isDeclaration = getParent().getParent() instanceof IASTSimpleDeclaration;
@ -344,4 +349,10 @@ public class CPPASTQualifiedName extends ASTNode implements
public ILinkage getLinkage() { public ILinkage getLinkage() {
return Linkage.CPP_LINKAGE; return Linkage.CPP_LINKAGE;
} }
@Override
protected IBinding createIntermediateBinding() {
Assert.isLegal(false);
return null;
}
} }

View file

@ -6,7 +6,7 @@
* http://www.eclipse.org/legal/epl-v10.html * http://www.eclipse.org/legal/epl-v10.html
* *
* Contributors: * Contributors:
* IBM - Initial API and implementation * John Camelon (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems) * Markus Schorn (Wind River Systems)
* Andrew Ferguson (Symbian) * Andrew Ferguson (Symbian)
*******************************************************************************/ *******************************************************************************/
@ -22,23 +22,21 @@ import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAmbiguousTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.Linkage; 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.IASTAmbiguityParent; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalNameOwner; import org.eclipse.cdt.internal.core.dom.parser.IASTInternalNameOwner;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
/** /**
* @author jcamelon * Template ids consist of an unqualified name (or operator or conversion name)
* and an array of template arguments.
*/ */
public class CPPASTTemplateId extends ASTNode implements ICPPASTTemplateId, IASTAmbiguityParent { public class CPPASTTemplateId extends AbstractCPPASTName implements ICPPASTTemplateId, IASTAmbiguityParent {
private IASTName templateName; private IASTName templateName;
private IASTNode[] templateArguments = null; private IASTNode[] templateArguments = null;
private IBinding binding = null;
private int fResolutionDepth = 0;
public CPPASTTemplateId() { public CPPASTTemplateId() {
} }
@ -51,6 +49,7 @@ public class CPPASTTemplateId extends ASTNode implements ICPPASTTemplateId, IAST
} }
public void setTemplateName(IASTName name) { public void setTemplateName(IASTName name) {
assert !(name instanceof ICPPASTQualifiedName) && !(name instanceof ICPPASTTemplateId);
templateName = name; templateName = name;
if (name != null) { if (name != null) {
name.setParent(this); name.setParent(this);
@ -87,17 +86,9 @@ public class CPPASTTemplateId extends ASTNode implements ICPPASTTemplateId, IAST
return (IASTNode[]) ArrayUtil.trim(IASTNode.class, templateArguments); return (IASTNode[]) ArrayUtil.trim(IASTNode.class, templateArguments);
} }
public IBinding resolveBinding() { @Override
if (binding == null) { protected IBinding createIntermediateBinding() {
// protect for infinite recursion return CPPTemplates.createBinding(this);
if (++fResolutionDepth > CPPASTName.MAX_RESOLUTION_DEPTH) {
binding= new CPPASTName.RecursionResolvingBinding(this);
} else {
binding = CPPTemplates.createBinding(this);
}
}
return binding;
} }
public IASTCompletionContext getCompletionContext() { public IASTCompletionContext getCompletionContext() {
@ -152,15 +143,6 @@ public class CPPASTTemplateId extends ASTNode implements ICPPASTTemplateId, IAST
return r_unclear; return r_unclear;
} }
public IBinding getBinding() {
return binding;
}
public void setBinding(IBinding binding) {
this.binding = binding;
fResolutionDepth = 0;
}
public void replace(IASTNode child, IASTNode other) { public void replace(IASTNode child, IASTNode other) {
if (templateArguments == null) return; if (templateArguments == null) return;
for (int i = 0; i < templateArguments.length; ++i) { for (int i = 0; i < templateArguments.length; ++i) {
@ -192,17 +174,7 @@ public class CPPASTTemplateId extends ASTNode implements ICPPASTTemplateId, IAST
return false; return false;
} }
public void incResolutionDepth() {
if (binding == null && ++fResolutionDepth > CPPASTName.MAX_RESOLUTION_DEPTH) {
binding = new CPPASTName.RecursionResolvingBinding(this);
}
}
public ILinkage getLinkage() { public ILinkage getLinkage() {
return Linkage.CPP_LINKAGE; return Linkage.CPP_LINKAGE;
} }
public IASTName getLastName() {
return this;
}
} }

View file

@ -33,7 +33,7 @@ public class CPPTypedefSpecialization extends CPPSpecialization implements IType
final static class RecursionResolvingBinding extends ProblemBinding { final static class RecursionResolvingBinding extends ProblemBinding {
public RecursionResolvingBinding(IASTNode node, char[] arg) { public RecursionResolvingBinding(IASTNode node, char[] arg) {
super(node, IProblemBinding.SEMANTIC_RECURSION_IN_LOOKUP, arg); super(node, IProblemBinding.SEMANTIC_RECURSION_IN_LOOKUP, arg);
Assert.isTrue(CPPASTName.fAllowRecursionBindings, getMessage()); Assert.isTrue(CPPASTName.sAllowRecursionBindings, getMessage());
} }
} }

View file

@ -0,0 +1,36 @@
/*******************************************************************************
* Copyright (c) 2008 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 org.eclipse.cdt.core.dom.ast.IBinding;
/**
* An interface for bindings that are resolvable in two steps. The binding computed
* by the first step is an intermediate binding that can be replaced in a second
* step before the binding is exposed via public API.
* <p>
* The bindings of the two phases may not be equal, but they must have the <b> same type</b>.
* <p>
* This allows for having multiple bindings for one final binding and deferring
* the act of unifying them to a later point in time.
*/
public interface ICPPTwoPhaseBinding extends IBinding {
/**
* Triggers the second step of the resolution where the binding that will be
* exposed via public API has to be computed. If this binding is already final
* {@code this} must be returned.
* <p> Note, that the result of this operation is an instance of
* {@link ICPPTwoPhaseBinding}, however it must resolve to itself using
* {@link #resolveFinalBinding()}.
*/
ICPPTwoPhaseBinding resolveFinalBinding();
}

View file

@ -133,6 +133,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope; import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.dom.parser.Value;
import org.eclipse.cdt.internal.core.dom.parser.cpp.AbstractCPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
@ -174,6 +175,10 @@ public class CPPSemantics {
if (traceBindingResolution) { if (traceBindingResolution) {
System.out.println("Resolving " + name); //$NON-NLS-1$ System.out.println("Resolving " + name); //$NON-NLS-1$
} }
if (name instanceof AbstractCPPASTName) {
((AbstractCPPASTName) name).incResolutionDepth();
}
// 1: get some context info off of the name to figure out what kind of lookup we want // 1: get some context info off of the name to figure out what kind of lookup we want
LookupData data = createLookupData(name, true); LookupData data = createLookupData(name, true);

View file

@ -147,8 +147,6 @@ import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer; import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTemplateId;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArrayType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArrayType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplate; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplate;
@ -1033,16 +1031,7 @@ public class CPPVisitor {
} }
} }
if (name != null) { if (name != null) {
if (name instanceof ICPPASTQualifiedName) { name= name.getLastName();
IASTName ns[] = ((ICPPASTQualifiedName)name).getNames();
name = ns[ns.length - 1];
}
if (name instanceof CPPASTName) {
((CPPASTName) name).incResolutionDepth();
}
else if (name instanceof CPPASTTemplateId) {
((CPPASTTemplateId) name).incResolutionDepth();
}
IBinding binding = name.getBinding(); IBinding binding = name.getBinding();
if (binding == null) { if (binding == null) {
binding = CPPSemantics.resolveBinding(name); binding = CPPSemantics.resolveBinding(name);