1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-09 18:56:02 +02:00

Fix recursion in binding resolution, bug 234042.

This commit is contained in:
Markus Schorn 2008-05-27 15:10:18 +00:00
parent c4d5a8d334
commit a244296645
14 changed files with 207 additions and 45 deletions

View file

@ -106,6 +106,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.OverloadableOperator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
@ -1653,18 +1654,26 @@ public class AST2CPPTests extends AST2BaseTest {
// friend struct Glob;
// };
public void testBug84692() throws Exception {
IASTTranslationUnit tu = parse(getAboveComment(), ParserLanguage.CPP);
CPPNameCollector col = new CPPNameCollector();
tu.accept(col);
assertEquals(col.size(), 9);
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);
// 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);
assertEquals(col.size(), 9);
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;
}
}
// namespace B { int b; }

View file

@ -4736,4 +4736,23 @@ public class AST2Tests extends AST2BaseTest {
assertFalse(t instanceof ITypedef);
}
}
// int a;
// int b= a; // ref
// struct S;
// typedef struct S S; // td
public void testRedefineStructInScopeThatIsFullyResolved() throws Exception {
final boolean[] isCpps= {false, true};
String code= getAboveComment();
for (boolean isCpp : isCpps) {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), isCpp);
ba.assertNonProblem("a; // ref", 1);
// now scope is fully resolved
ICompositeType ct= ba.assertNonProblem("S;", 1, ICompositeType.class);
ITypedef td= ba.assertNonProblem("S; // td", 1, ITypedef.class);
IType t= td.getType();
assertFalse(t instanceof IProblemBinding);
assertSame(t, ct);
}
}
}

View file

@ -1,14 +1,14 @@
/*******************************************************************************
* Copyright (c) 2004, 2007 IBM Corporation and others.
* Copyright (c) 2004, 2008 IBM Corporation 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:
* IBM - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
* IBM - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast;
@ -51,6 +51,18 @@ public interface IASTName extends IASTNode, IName {
*/
public IBinding resolveBinding();
/**
* Get the role of this name. If the name needs to be resolved to determine that and
* <code>allowResolution</code> is set to <code>false</code>, then {@link IASTNameOwner#r_unclear}
* is returned.
*
* @param allowResolution whether or not resolving the name is allowed.
* @return {@link IASTNameOwner#r_definition}, {@link IASTNameOwner#r_declaration},
* {@link IASTNameOwner#r_reference}, {@link IASTNameOwner#r_unclear}.
* @since 5.0
*/
public int getRoleOfName(boolean allowResolution);
/**
* Return the completion context for this name.
*

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2005 IBM Corporation and others.
* Copyright (c) 2005, 2008 IBM Corporation 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
@ -7,11 +7,12 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast;
/**
* This interface repesents a mechanism for a name to discover more information about it's parent.
* This interface represents a mechanism for a name to discover more information about it's parent.
* All interfaces that claim ownership/residence of a name should extend this interface.
*
* @author jcamelon
@ -39,9 +40,9 @@ public interface IASTNameOwner {
/**
* Get the role for the name.
*
* @param n <code>IASTName</code>
* @return r_declaration, r_reference or r_unclear.
* @param name the name to determine the role for.
* @return r_definition, r_declaration, r_reference or r_unclear.
*/
public int getRoleForName( IASTName n );
public int getRoleForName(IASTName name);
}

View file

@ -0,0 +1,31 @@
/*******************************************************************************
* 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;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNameOwner;
/**
* Provides additional methods for internal use by the name resolution.
*/
public interface IASTInternalNameOwner extends IASTNameOwner {
/**
* Get the role for the name. If the name needs to be resolved to determine that and
* <code>allowResolution</code> is set to <code>false</code>, then {@link IASTNameOwner#r_unclear}
* is returned.
*
* @param n a name to determine the role of.
* @param allowResolution whether or not resolving the name is allowed.
* @return r_definition, r_declaration, r_reference or r_unclear.
*/
public int getRoleForName(IASTName n, boolean allowResolution);
}

View file

@ -1,15 +1,15 @@
/*******************************************************************************
* Copyright (c) 2005, 2007 IBM Corporation and others.
* Copyright (c) 2005, 2008 IBM Corporation 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:
* IBM Rational Software - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Yuan Zhang / Beth Tibbitts (IBM Research)
* Bryan Wilkinson (QNX)
* IBM Rational Software - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Yuan Zhang / Beth Tibbitts (IBM Research)
* Bryan Wilkinson (QNX)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c;
@ -26,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.Linkage;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalNameOwner;
/**
* @author jcamelon
@ -117,6 +118,17 @@ public class CASTName extends CASTNode implements IASTName, IASTCompletionContex
}
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) {

View file

@ -11,20 +11,22 @@
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
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.parser.IASTInternalNameOwner;
/**
* @author jcamelon
*/
public class CPPASTElaboratedTypeSpecifier extends CPPASTBaseDeclSpecifier
implements ICPPASTElaboratedTypeSpecifier {
implements ICPPASTElaboratedTypeSpecifier, IASTInternalNameOwner {
private int kind;
private IASTName name;
@ -78,24 +80,36 @@ public class CPPASTElaboratedTypeSpecifier extends CPPASTBaseDeclSpecifier
}
public int getRoleForName(IASTName n) {
return getRoleForName(n, true);
}
public int getRoleForName(IASTName n, boolean allowResolution) {
if (n != name) return r_unclear;
IASTNode parent = getParent();
if (!(parent instanceof IASTDeclaration))
return r_reference;
if (parent instanceof IASTSimpleDeclaration) {
IASTDeclarator[] dtors = ((IASTSimpleDeclaration)parent).getDeclarators();
if (dtors.length == 0)
return r_declaration;
}
//can't tell, resolve the binding
IBinding binding = name.resolveBinding();
if (binding instanceof ICPPInternalBinding) {
IASTNode[] decls = ((ICPPInternalBinding)binding).getDeclarations();
if (ArrayUtil.contains(decls, name))
return r_declaration;
// 7.1.5.3.2: check for simple form <class-key> <identifier>, then it may be a declaration
final int kind= getKind();
if (kind == k_class || kind == k_union || kind == k_struct) {
if (name instanceof ICPPASTQualifiedName == false
&& name instanceof ICPPASTTemplateId == false) {
IBinding binding = allowResolution ? name.resolveBinding() : name.getBinding();
if (binding != null) {
if (binding instanceof ICPPInternalBinding) {
IASTNode[] decls = ((ICPPInternalBinding)binding).getDeclarations();
if (ArrayUtil.contains(decls, name))
return r_declaration;
}
return r_reference;
}
// resolution is not allowed.
return r_unclear;
}
}
return r_reference;
}

View file

@ -30,19 +30,24 @@ 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.internal.core.dom.Linkage;
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
*/
public class CPPASTName extends CPPASTNode 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());
if (fShowRecursionProblems)
System.out.println(getMessage());
Assert.isTrue(fAllowRecursionBindings, getMessage());
}
}
@ -51,7 +56,6 @@ public class CPPASTName extends CPPASTNode implements IASTName, IASTCompletionCo
static final int MAX_RESOLUTION_DEPTH = 5;
private static boolean fShowRecursionProblems = false;
private char[] name;
private IBinding binding = null;
@ -209,6 +213,17 @@ public class CPPASTName extends CPPASTNode implements IASTName, IASTCompletionCo
}
return true;
}
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();

View file

@ -37,6 +37,7 @@ 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.IASTInternalNameOwner;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
/**
@ -182,6 +183,17 @@ public class CPPASTQualifiedName extends CPPASTNode implements
return true;
}
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();

View file

@ -26,6 +26,7 @@ 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.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalNameOwner;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
/**
@ -170,6 +171,17 @@ public class CPPASTTemplateId extends CPPASTNode implements ICPPASTTemplateId, I
}
}
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 isDefinition() {
IASTNode parent = getParent();
if (parent instanceof IASTNameOwner) {

View file

@ -44,6 +44,7 @@ import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTInitializerExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
@ -1649,7 +1650,7 @@ public class CPPSemantics {
boolean declaredBefore = declaredBefore(o, name, indexBased);
boolean checkResolvedNamesOnly= false;
if (!data.checkWholeClassScope && !declaredBefore) {
if (!name.isReference()) {
if (name.getRoleOfName(false) != IASTNameOwner.r_reference) {
checkResolvedNamesOnly= true;
declaredBefore= true;
} else {

View file

@ -532,10 +532,9 @@ public class CPPVisitor {
}
while (tmpNode instanceof IASTDeclarator);
IASTName name = declarator.getName();
IASTName name= declarator.getName();
if (name instanceof ICPPASTQualifiedName) {
IASTName[] ns = ((ICPPASTQualifiedName)name).getNames();
name = ns[ns.length - 1];
name= ((ICPPASTQualifiedName)name).getLastName();
}
ASTNodeProperty prop = parent.getPropertyInParent();
@ -613,7 +612,13 @@ public class CPPVisitor {
}
return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION, name.toCharArray());
}
binding = new CPPTypedef(name);
// if we don't resolve the target type first, we get a problem binding in case the typedef
// redeclares the target type:
// typedef struct S S;
IType targetType= CPPVisitor.createType(declarator);
CPPTypedef td= new CPPTypedef(name);
td.setType(targetType);
binding = td;
} else if (funcDeclarator != null) {
if (binding instanceof ICPPInternalBinding && binding instanceof IFunction) {
IFunction function = (IFunction) binding;

View file

@ -16,6 +16,7 @@ import org.eclipse.cdt.core.dom.ast.IASTCompletionContext;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation;
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.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
@ -66,6 +67,10 @@ class ASTPreprocessorName extends ASTPreprocessorNode implements IASTName {
return new String(fName);
}
public void setBinding(IBinding binding) {assert false;}
public int getRoleOfName(boolean allowResolution) {
return IASTNameOwner.r_unclear;
}
}
class ASTPreprocessorDefinition extends ASTPreprocessorName {
@ -78,6 +83,11 @@ class ASTPreprocessorDefinition extends ASTPreprocessorName {
public boolean isDefinition() {
return true;
}
@Override
public int getRoleOfName(boolean allowResolution) {
return IASTNameOwner.r_definition;
}
}
@ -132,6 +142,11 @@ class ASTMacroReferenceName extends ASTPreprocessorName {
fImageLocationInfo= imgLocationInfo;
}
@Override
public int getRoleOfName(boolean allowResolution) {
return IASTNameOwner.r_unclear;
}
@Override
public boolean isReference() {
return true;

View file

@ -115,6 +115,10 @@ public class PDOMASTAdapter {
return fDelegate.getTranslationUnit();
}
public int getRoleOfName(boolean allowResolution) {
return fDelegate.getRoleOfName(allowResolution);
}
public boolean isDeclaration() {
return fDelegate.isDeclaration();
}