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:
parent
c0cbc9010d
commit
baf4816657
5 changed files with 185 additions and 29 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue