1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52:11 +02:00

Resolution of friends, bug 86368.

This commit is contained in:
Markus Schorn 2009-01-22 13:56:25 +00:00
parent c0cbc9010d
commit baf4816657
5 changed files with 185 additions and 29 deletions

View file

@ -6433,4 +6433,72 @@ public class AST2CPPTests extends AST2BaseTest {
ITypedef s2= (ITypedef) ((IPointerType) d.getType()).getType();
assertInstance(((IFunctionType) s2.getType()).getParameterTypes()[0], IBasicType.class);
}
// namespace A {
// class X {
// friend void f(int);
// class Y {
// friend void g(int);
// };
// };
// void test() {
// f(1);
// g(1);
// }
// }
public void testFriendFunctionResolution_86368_1() throws Exception {
final String code= getAboveComment();
parseAndCheckBindings(code);
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
IFunction f1= bh.assertNonProblem("f(int)", 1);
IFunction f2= bh.assertNonProblem("f(1)", 1);
assertSame(f1, f2);
IFunction g1= bh.assertNonProblem("g(int)", 1);
IFunction g2= bh.assertNonProblem("g(1)", 1);
assertSame(g1, g2);
bh= new BindingAssertionHelper(code, true);
f2= bh.assertNonProblem("f(1)", 1);
f1= bh.assertNonProblem("f(int)", 1);
assertSame(f1, f2);
g2= bh.assertNonProblem("g(1)", 1);
g1= bh.assertNonProblem("g(int)", 1);
assertSame(g1, g2);
}
// namespace A {
// void f(int);
// }
// using A::f;
// namespace A {
// void f(char); // openReferences fails
// }
// void foo() {
// f('i');
// }
// void bar() {
// using A::f;
// f('c');
// }
public void testFriendFunctionResolution_86368_2() throws Exception {
final String code= getAboveComment();
parseAndCheckBindings(code);
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
IFunction f1= bh.assertNonProblem("f(int)", 1);
IFunction f2= bh.assertNonProblem("f('i')", 1);
assertSame(f1, f2);
IFunction g1= bh.assertNonProblem("f(char)", 1);
IFunction g2= bh.assertNonProblem("f('c')", 1);
assertSame(g1, g2);
bh= new BindingAssertionHelper(code, true);
f2= bh.assertNonProblem("f('i')", 1);
f1= bh.assertNonProblem("f(int)", 1);
assertSame(f1, f2);
g2= bh.assertNonProblem("f('c')", 1);
g1= bh.assertNonProblem("f(char)", 1);
assertSame(g1, g2);
}
}

View file

@ -166,7 +166,7 @@ final class CPPASTAmbiguityResolver extends ASTVisitor {
private void repopulateScope(IASTDeclaration declaration) {
IScope scope= CPPVisitor.getContainingScope(declaration);
if (scope instanceof ICPPASTInternalScope) {
CPPSemantics.populateCache((ICPPASTInternalScope) scope, declaration, false);
CPPSemantics.populateCache((ICPPASTInternalScope) scope, declaration);
}
}

View file

@ -25,6 +25,7 @@ import java.util.Set;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.EScopeKind;
import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
@ -52,6 +53,7 @@ import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
@ -1171,6 +1173,15 @@ public class CPPSemantics {
} else if (parent instanceof ICPPASTTemplateDeclaration) {
ICPPASTTemplateDeclaration template = (ICPPASTTemplateDeclaration) parent;
nodes = template.getTemplateParameters();
} else if (parent instanceof ICPPASTForStatement) {
ICPPASTForStatement forStatement = (ICPPASTForStatement) parent;
final IASTDeclaration conditionDeclaration = forStatement.getConditionDeclaration();
IASTStatement initDeclaration= forStatement.getInitializerStatement();
if (conditionDeclaration != null) {
nodes= new IASTNode[] {initDeclaration, conditionDeclaration};
} else {
nodes= new IASTNode[] {initDeclaration};
}
}
int idx = -1;
@ -1216,7 +1227,7 @@ public class CPPSemantics {
}
}
} else {
populateCache(scope, item, (item == parent));
populateCache(scope, item);
}
if (nodes != null && ++idx < nodes.length) {
@ -1269,7 +1280,7 @@ public class CPPSemantics {
}
}
public static void populateCache(ICPPASTInternalScope scope, IASTNode node, boolean checkAux) {
public static void populateCache(ICPPASTInternalScope scope, IASTNode node) {
IASTDeclaration declaration = null;
if (node instanceof ICPPASTTemplateDeclaration) {
declaration = ((ICPPASTTemplateDeclaration)node).getDeclaration();
@ -1279,18 +1290,7 @@ public class CPPSemantics {
declaration = ((IASTDeclarationStatement)node).getDeclaration();
} else if (node instanceof ICPPASTCatchHandler) {
declaration = ((ICPPASTCatchHandler)node).getDeclaration();
} else if (node instanceof ICPPASTForStatement && checkAux) {
ICPPASTForStatement forStatement = (ICPPASTForStatement) node;
if (forStatement.getConditionDeclaration() == null) {
if (forStatement.getInitializerStatement() instanceof IASTDeclarationStatement)
declaration = ((IASTDeclarationStatement)forStatement.getInitializerStatement()).getDeclaration();
} else {
if (forStatement.getInitializerStatement() instanceof IASTDeclarationStatement) {
populateCache(scope, forStatement.getInitializerStatement(), checkAux);
}
declaration = forStatement.getConditionDeclaration();
}
} else if (node instanceof ICPPASTSwitchStatement) {
} else if (node instanceof ICPPASTSwitchStatement) {
declaration = ((ICPPASTSwitchStatement)node).getControllerDeclaration();
} else if (node instanceof ICPPASTIfStatement) {
declaration = ((ICPPASTIfStatement)node).getConditionDeclaration();
@ -1323,7 +1323,19 @@ public class CPPSemantics {
IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) declaration;
ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) simpleDeclaration.getDeclSpecifier();
IASTDeclarator[] declarators = simpleDeclaration.getDeclarators();
if (!declSpec.isFriend()) {
IScope dtorScope= scope;
if (declSpec.isFriend()) {
// friends are added to an enclosing scope. They have to be added such that they are
// picked up when this scope is re-populated during ambiguity resolution, while the
// enclosing scope is left as it is.
try {
while (dtorScope.getKind() == EScopeKind.eClassType)
dtorScope= dtorScope.getParent();
} catch (DOMException e) {
dtorScope= null;
}
}
if (dtorScope != null) {
for (IASTDeclarator declarator : declarators) {
IASTDeclarator innermost= null;
while (declarator != null) {
@ -1336,28 +1348,38 @@ public class CPPSemantics {
}
if (innermost != null) {
IASTName declaratorName = innermost.getName();
ASTInternal.addName(scope, declaratorName);
ASTInternal.addName(dtorScope, declaratorName);
}
}
}
// declSpec
IASTName specName = null;
if (declSpec instanceof IASTElaboratedTypeSpecifier) {
if (declarators.length == 0 || scope.getPhysicalNode() instanceof IASTTranslationUnit)
if (declarators.length == 0 || scope.getPhysicalNode() instanceof IASTTranslationUnit) {
specName = ((IASTElaboratedTypeSpecifier)declSpec).getName();
}
} else if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
ICPPASTCompositeTypeSpecifier compSpec = (ICPPASTCompositeTypeSpecifier) declSpec;
specName = compSpec.getName();
// anonymous union? //GCC supports anonymous structs too
if (declarators.length == 0 && /*compSpec.getKey() == IASTCompositeTypeSpecifier.k_union &&*/
specName.getLookupKey().length == 0) {
// anonymous union or struct (GCC supports anonymous structs too)
if (declarators.length == 0 && specName.getLookupKey().length == 0) {
IASTDeclaration[] decls = compSpec.getMembers();
for (IASTDeclaration decl : decls) {
populateCache(scope, decl, checkAux);
populateCache(scope, decl);
}
} else {
// collect friends enclosed in nested classes
switch (scope.getKind()) {
case eLocal:
case eGlobal:
case eNamespace:
compSpec.accept(new FriendCollector(scope));
break;
default:
break;
}
}
} else if (declSpec instanceof IASTEnumerationSpecifier) {
IASTEnumerationSpecifier enumeration = (IASTEnumerationSpecifier) declSpec;

View file

@ -18,6 +18,7 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.EScopeKind;
import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
@ -568,9 +569,11 @@ public class CPPVisitor extends ASTQueries {
if (parent instanceof IASTSimpleDeclaration && scope instanceof ICPPClassScope) {
ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration) parent).getDeclSpecifier();
if (declSpec.isFriend()) {
isFriendDecl= true;
try {
scope = (ICPPScope) getParentScope(scope, name.getTranslationUnit());
isFriendDecl= true;
while (scope.getKind() == EScopeKind.eClassType) {
scope = (ICPPScope) getParentScope(scope, name.getTranslationUnit());
}
} catch (DOMException e1) {
}
}
@ -661,10 +664,6 @@ public class CPPVisitor extends ASTQueries {
} else {
binding = template ? (ICPPFunction) new CPPFunctionTemplate(name)
: new CPPFunction((ICPPASTFunctionDeclarator) funcDeclarator);
// friend functions may be declared in a different scope than the owner scope
if (simpleDecl != null && ((ICPPASTDeclSpecifier) simpleDecl.getDeclSpecifier()).isFriend()) {
ASTInternal.addName(scope, name);
}
}
} else if (parent instanceof IASTSimpleDeclaration) {
IType t1 = null, t2 = null;

View file

@ -0,0 +1,67 @@
/*******************************************************************************
* Copyright (c) 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.semantics;
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.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousDeclarator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPASTInternalScope;
/**
* Utility class to populate scope with friend declarations hidden in nested classes
*/
class FriendCollector extends ASTVisitor {
private final ICPPASTInternalScope fScope;
public FriendCollector(ICPPASTInternalScope scope) {
fScope= scope;
shouldVisitDeclarations= true;
}
@Override
public int visit(IASTDeclaration declaration) {
if (declaration instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration simpleDeclaration = (IASTSimpleDeclaration) declaration;
ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) simpleDeclaration.getDeclSpecifier();
if (declSpec.isFriend()) {
IASTDeclarator[] declarators= simpleDeclaration.getDeclarators();
for (IASTDeclarator declarator : declarators) {
IASTDeclarator innermost= null;
while (declarator != null) {
if (declarator instanceof IASTAmbiguousDeclarator) {
innermost= null;
break;
}
innermost= declarator;
declarator= declarator.getNestedDeclarator();
}
if (innermost != null) {
IASTName declaratorName = innermost.getName();
ASTInternal.addName(fScope, declaratorName);
}
}
return PROCESS_SKIP;
}
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
return PROCESS_CONTINUE;
}
}
return PROCESS_SKIP;
}
}