From 10f412ae8482918a418f1d656e39fb1711565a08 Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Fri, 31 Oct 2008 10:06:53 +0000 Subject: [PATCH] Mechanism to resolve bindings in two phases, bug 252554. --- .../core/parser/tests/ast2/AST2CPPTests.java | 29 ++-- .../core/testplugin/util/BaseTestCase.java | 2 + .../dom/parser/cpp/AbstractCPPASTName.java | 153 ++++++++++++++++++ .../core/dom/parser/cpp/CPPASTName.java | 68 ++------ .../dom/parser/cpp/CPPASTQualifiedName.java | 139 ++++++++-------- .../core/dom/parser/cpp/CPPASTTemplateId.java | 46 ++---- .../parser/cpp/CPPTypedefSpecialization.java | 2 +- .../dom/parser/cpp/ICPPTwoPhaseBinding.java | 36 +++++ .../parser/cpp/semantics/CPPSemantics.java | 5 + .../dom/parser/cpp/semantics/CPPVisitor.java | 13 +- 10 files changed, 304 insertions(+), 189 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/AbstractCPPASTName.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPTwoPhaseBinding.java diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index 15a91c6d251..08b80d79fa4 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -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.parser.ParserLanguage; 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.OverloadableOperator; 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 { // also tests bug 234042. - boolean old= CPPASTName.fAllowRecursionBindings; - CPPASTName.fAllowRecursionBindings= false; - try { - IASTTranslationUnit tu = parse(getAboveComment(), ParserLanguage.CPP); - CPPNameCollector col = new CPPNameCollector(); - tu.accept(col); + AbstractCPPASTName.sAllowRecursionBindings= false; + + IASTTranslationUnit tu = parse(getAboveComment(), ParserLanguage.CPP); + CPPNameCollector col = new CPPNameCollector(); + tu.accept(col); - assertEquals(col.size(), 9); + assertEquals(col.size(), 9); - ICPPClassType Node = (ICPPClassType) col.getName(1).resolveBinding(); - ICPPClassType Data = (ICPPClassType) col.getName(3).resolveBinding(); - assertSame(Data.getScope(), tu.getScope()); + ICPPClassType Node = (ICPPClassType) col.getName(1).resolveBinding(); + ICPPClassType Data = (ICPPClassType) col.getName(3).resolveBinding(); + assertSame(Data.getScope(), tu.getScope()); - assertInstances(col, Node, 3); - assertInstances(col, Data, 2); - } - finally { - CPPASTName.fAllowRecursionBindings= old; - } + assertInstances(col, Node, 3); + assertInstances(col, Data, 2); } // namespace B { int b; } diff --git a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java index 622c7749d1c..32e3cc81c34 100644 --- a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java +++ b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/util/BaseTestCase.java @@ -32,6 +32,7 @@ import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ElementChangedEvent; import org.eclipse.cdt.core.model.IElementChangedListener; 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.ILogListener; import org.eclipse.core.runtime.IProgressMonitor; @@ -56,6 +57,7 @@ public class BaseTestCase extends TestCase { @Override protected void setUp() throws Exception { + AbstractCPPASTName.sAllowRecursionBindings= true; } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/AbstractCPPASTName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/AbstractCPPASTName.java new file mode 100644 index 00000000000..feffc4375e0 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/AbstractCPPASTName.java @@ -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, null 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; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTName.java index ed1bb91ea13..5b710b92427 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTName.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * IBM - Initial API and implementation + * John Camelon(IBM) - Initial API and implementation * Markus Schorn (Wind River Systems) * Bryan Wilkinson (QNX) * 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.IBinding; 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.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; 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.parser.ASTNode; 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.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 { - /** - * 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; - +public class CPPASTName extends AbstractCPPASTName implements IASTCompletionContext { private char[] name; - private IBinding binding = null; - private int fResolutionDepth= 0; - public CPPASTName(char[] name) { this.name = name; } public CPPASTName() { - name = EMPTY_CHAR_ARRAY; + name = CharArrayUtils.EMPTY; } - public IBinding resolveBinding() { - if (binding == null) { - if (++fResolutionDepth > MAX_RESOLUTION_DEPTH) { - 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); - } + @Override + protected IBinding createIntermediateBinding() { + return CPPVisitor.createBinding(this); } public IASTCompletionContext getCompletionContext() { @@ -164,19 +129,10 @@ public class CPPASTName extends ASTNode implements IASTName, IASTCompletionConte return (IBinding[])ArrayUtil.removeNulls(IBinding.class, bindings); } - public void setBinding(IBinding binding) { - this.binding = binding; - fResolutionDepth= 0; - } - - public IBinding getBinding() { - return binding; - } - @Override public String toString() { - if (name == EMPTY_CHAR_ARRAY) - return EMPTY_STRING; + if (name.length == 0) + return ""; //$NON-NLS-1$ return new String(name); } @@ -275,8 +231,4 @@ public class CPPASTName extends ASTNode implements IASTName, IASTCompletionConte public ILinkage getLinkage() { return Linkage.CPP_LINKAGE; } - - public IASTName getLastName() { - return this; - } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java index 51f4ee8cbb0..808e4b2e42e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTQualifiedName.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * IBM - Initial API and implementation + * John Camelon (IBM) - Initial API and implementation * Bryan Wilkinson (QNX) * 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.CharArrayUtils; 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.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 - ICPPASTQualifiedName, IASTCompletionContext { +public class CPPASTQualifiedName extends AbstractCPPASTName + implements ICPPASTQualifiedName, IASTCompletionContext { + + private IASTName[] names = null; + private int namesPos= -1; + private boolean isFullyQualified; + private String signature; 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() { // 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(); } + @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() { IASTNode node = getParent(); while (node != null) { @@ -75,6 +103,7 @@ public class CPPASTQualifiedName extends ASTNode implements } public void addName(IASTName name) { + assert !(name instanceof ICPPASTQualifiedName); if (name != null) { names = (IASTName[]) ArrayUtil.append(IASTName.class, names, ++namesPos, name); 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() { - if (names == null) + if (namesPos < 0) return IASTName.EMPTY_NAME_ARRAY; - removeNullNames(); + + names = (IASTName[]) ArrayUtil.removeNullsAfter(IASTName.class, names, namesPos); return names; } + @Override public IASTName getLastName() { if (namesPos < 0) return null; @@ -107,31 +128,29 @@ public class CPPASTQualifiedName extends ASTNode implements } public char[] toCharArray() { - if (names == null) + if (namesPos < 0) return new char[0]; - removeNullNames(); // count first - int len = 0; - for (int i = 0; i < names.length; ++i) { + int len = -2; + for (int i = 0; i <= namesPos; ++i) { char[] n = names[i].toCharArray(); if (n == null) return null; - len += n.length; - if (i != names.length - 1) - len += 2; + len+= 2; + len+= n.length; } - + char[] nameArray = new char[len]; int pos = 0; - for (int i = 0; i < names.length; i++) { - char[] n = names[i].toCharArray(); - System.arraycopy(n, 0, nameArray, pos, n.length); - pos += n.length; - if (i != names.length - 1) { + for (int i = 0; i <= namesPos; i++) { + if (i != 0) { nameArray[pos++] = ':'; nameArray[pos++] = ':'; } + final char[] n = names[i].toCharArray(); + System.arraycopy(n, 0, nameArray, pos, n.length); + pos += n.length; } return nameArray; } @@ -161,9 +180,8 @@ public class CPPASTQualifiedName extends ASTNode implements break; } } - IASTName[] ns = getNames(); - for (int i = 0; i < ns.length; i++) { - if (i == names.length - 1) { + for (int i = 0; i <= namesPos; i++) { + if (i == namesPos) { // 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)) return false; @@ -217,41 +235,28 @@ public class CPPASTQualifiedName extends ASTNode implements } public int getRoleForName(IASTName n) { - IASTName[] namez = getNames(); - for(int i = 0; i < names.length; ++i) - if (namez[i] == n) - { - if (i < names.length - 1) - return r_reference; - IASTNode p = getParent(); - if (i == names.length - 1 && p instanceof IASTNameOwner) - return ((IASTNameOwner)p).getRoleForName(this); - return r_unclear; + for (int i=0; i < namesPos; ++i) { + if (names[i] == n) + return r_reference; + } + if (getLastName() == n) { + IASTNode p = getParent(); + if (p instanceof IASTNameOwner) { + return ((IASTNameOwner)p).getRoleForName(this); } + } 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() { - IASTName[] nonNullNames = getNames(); // ensure no null names - - int len=nonNullNames.length; - if (nonNullNames[len - 1] instanceof ICPPASTConversionName || nonNullNames[len - 1] instanceof ICPPASTOperatorName) { + final IASTName lastName= getLastName(); + if (lastName instanceof ICPPASTConversionName || lastName instanceof ICPPASTOperatorName) { return true; } // check templateId's name - if (nonNullNames[len - 1] instanceof ICPPASTTemplateId) { - IASTName tempName = ((ICPPASTTemplateId)nonNullNames[len - 1]).getTemplateName(); + if (lastName instanceof ICPPASTTemplateId) { + IASTName tempName = ((ICPPASTTemplateId)lastName).getTemplateName(); if (tempName instanceof ICPPASTConversionName || tempName instanceof ICPPASTOperatorName) { return true; } @@ -273,8 +278,8 @@ public class CPPASTQualifiedName extends ASTNode implements public IBinding[] findBindings(IASTName n, boolean isPrefix) { IBinding[] bindings = CPPSemantics.findBindingsForContentAssist(n, isPrefix); - if (names.length - 2 >= 0) { - IBinding binding = names[names.length - 2].resolveBinding(); + if (namesPos > 0) { + IBinding binding = names[namesPos-1].resolveBinding(); if (binding instanceof ICPPClassType) { ICPPClassType classType = (ICPPClassType) binding; final boolean isDeclaration = getParent().getParent() instanceof IASTSimpleDeclaration; @@ -344,4 +349,10 @@ public class CPPASTQualifiedName extends ASTNode implements public ILinkage getLinkage() { return Linkage.CPP_LINKAGE; } + + @Override + protected IBinding createIntermediateBinding() { + Assert.isLegal(false); + return null; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateId.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateId.java index e194f42263f..c5ca1df62ba 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateId.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTemplateId.java @@ -6,7 +6,7 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * IBM - Initial API and implementation + * John Camelon (IBM) - Initial API and implementation * Markus Schorn (Wind River Systems) * 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.IBinding; 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.parser.util.ArrayUtil; 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.IASTInternalNameOwner; 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 IASTNode[] templateArguments = null; - private IBinding binding = null; - private int fResolutionDepth = 0; - public CPPASTTemplateId() { } @@ -51,6 +49,7 @@ public class CPPASTTemplateId extends ASTNode implements ICPPASTTemplateId, IAST } public void setTemplateName(IASTName name) { + assert !(name instanceof ICPPASTQualifiedName) && !(name instanceof ICPPASTTemplateId); templateName = name; if (name != null) { name.setParent(this); @@ -87,17 +86,9 @@ public class CPPASTTemplateId extends ASTNode implements ICPPASTTemplateId, IAST return (IASTNode[]) ArrayUtil.trim(IASTNode.class, templateArguments); } - public IBinding resolveBinding() { - if (binding == null) { - // protect for infinite recursion - if (++fResolutionDepth > CPPASTName.MAX_RESOLUTION_DEPTH) { - binding= new CPPASTName.RecursionResolvingBinding(this); - } else { - binding = CPPTemplates.createBinding(this); - } - } - - return binding; + @Override + protected IBinding createIntermediateBinding() { + return CPPTemplates.createBinding(this); } public IASTCompletionContext getCompletionContext() { @@ -152,15 +143,6 @@ public class CPPASTTemplateId extends ASTNode implements ICPPASTTemplateId, IAST 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) { if (templateArguments == null) return; for (int i = 0; i < templateArguments.length; ++i) { @@ -192,17 +174,7 @@ public class CPPASTTemplateId extends ASTNode implements ICPPASTTemplateId, IAST return false; } - public void incResolutionDepth() { - if (binding == null && ++fResolutionDepth > CPPASTName.MAX_RESOLUTION_DEPTH) { - binding = new CPPASTName.RecursionResolvingBinding(this); - } - } - public ILinkage getLinkage() { return Linkage.CPP_LINKAGE; } - - public IASTName getLastName() { - return this; - } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTypedefSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTypedefSpecialization.java index 98a8c750cfa..de69f171b37 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTypedefSpecialization.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTypedefSpecialization.java @@ -33,7 +33,7 @@ public class CPPTypedefSpecialization extends CPPSpecialization implements IType final static class RecursionResolvingBinding extends ProblemBinding { public RecursionResolvingBinding(IASTNode node, char[] arg) { super(node, IProblemBinding.SEMANTIC_RECURSION_IN_LOOKUP, arg); - Assert.isTrue(CPPASTName.fAllowRecursionBindings, getMessage()); + Assert.isTrue(CPPASTName.sAllowRecursionBindings, getMessage()); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPTwoPhaseBinding.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPTwoPhaseBinding.java new file mode 100644 index 00000000000..7c594f51742 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ICPPTwoPhaseBinding.java @@ -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. + *

+ * The bindings of the two phases may not be equal, but they must have the same type. + *

+ * 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. + *

Note, that the result of this operation is an instance of + * {@link ICPPTwoPhaseBinding}, however it must resolve to itself using + * {@link #resolveFinalBinding()}. + */ + ICPPTwoPhaseBinding resolveFinalBinding(); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 31d6880c3b8..96378c21c47 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -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.ProblemBinding; 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.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; @@ -174,6 +175,10 @@ public class CPPSemantics { if (traceBindingResolution) { 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 LookupData data = createLookupData(name, true); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index e38a8eca76c..b34890636f7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -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.ITypeContainer; 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.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplate; @@ -1033,16 +1031,7 @@ public class CPPVisitor { } } if (name != null) { - if (name instanceof ICPPASTQualifiedName) { - 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(); - } + name= name.getLastName(); IBinding binding = name.getBinding(); if (binding == null) { binding = CPPSemantics.resolveBinding(name);