mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-09 09:15:38 +02:00
Bug 512932 - Name lookup for friend class
Change-Id: I6550b2cdef4dfacf012fa736104b72794db8c0cc
This commit is contained in:
parent
be635f520a
commit
e0e7f9c1d7
14 changed files with 80 additions and 14 deletions
|
@ -10587,6 +10587,20 @@ public class AST2CPPTests extends AST2TestBase {
|
||||||
parseAndCheckBindings();
|
parseAndCheckBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// namespace Hugo {
|
||||||
|
// class C {
|
||||||
|
// friend class Waldo;
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// using namespace Hugo;
|
||||||
|
// class Waldo {};
|
||||||
|
// void foo() {
|
||||||
|
// Waldo c; // error here
|
||||||
|
// }
|
||||||
|
public void testFriendClassLookup_512932() throws Exception {
|
||||||
|
parseAndCheckBindings();
|
||||||
|
}
|
||||||
|
|
||||||
// struct S {
|
// struct S {
|
||||||
// virtual void mFuncDecl() final;
|
// virtual void mFuncDecl() final;
|
||||||
// virtual void mFuncDef() final {}
|
// virtual void mFuncDef() final {}
|
||||||
|
|
|
@ -114,6 +114,7 @@ public interface IScope {
|
||||||
private boolean fResolve= true;
|
private boolean fResolve= true;
|
||||||
private boolean fPrefixLookup;
|
private boolean fPrefixLookup;
|
||||||
private boolean fIgnorePointOfDeclaration;
|
private boolean fIgnorePointOfDeclaration;
|
||||||
|
private boolean fArgumentDependent;
|
||||||
|
|
||||||
public ScopeLookupData(IASTName name, boolean resolve, boolean prefixLookup) {
|
public ScopeLookupData(IASTName name, boolean resolve, boolean prefixLookup) {
|
||||||
if (name == null)
|
if (name == null)
|
||||||
|
@ -163,6 +164,11 @@ public interface IScope {
|
||||||
fIgnorePointOfDeclaration = ignorePointOfDeclaration;
|
fIgnorePointOfDeclaration = ignorePointOfDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 6.3 */
|
||||||
|
public final void setArgumentDependent(boolean argumentDependent) {
|
||||||
|
fArgumentDependent = argumentDependent;
|
||||||
|
}
|
||||||
|
|
||||||
public final void setLookupKey(char[] key) {
|
public final void setLookupKey(char[] key) {
|
||||||
fLookupKey= key;
|
fLookupKey= key;
|
||||||
}
|
}
|
||||||
|
@ -187,6 +193,11 @@ public interface IScope {
|
||||||
return fIgnorePointOfDeclaration;
|
return fIgnorePointOfDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @since 6.3 */
|
||||||
|
public final boolean isArgumentDependent() {
|
||||||
|
return fArgumentDependent;
|
||||||
|
}
|
||||||
|
|
||||||
public final IIndexFileSet getIncludedFiles() {
|
public final IIndexFileSet getIncludedFiles() {
|
||||||
return fTu == null ? IIndexFileSet.EMPTY : fTu.getIndexFileSet();
|
return fTu == null ? IIndexFileSet.EMPTY : fTu.getIndexFileSet();
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,8 +91,12 @@ public class ASTInternal {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addName(IScope scope, IASTName name) {
|
public static void addName(IScope scope, IASTName name) {
|
||||||
|
addName(scope, name, /* adlOnly = */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addName(IScope scope, IASTName name, boolean adlOnly) {
|
||||||
if (scope instanceof IASTInternalScope) {
|
if (scope instanceof IASTInternalScope) {
|
||||||
((IASTInternalScope) scope).addName(name);
|
((IASTInternalScope) scope).addName(name, adlOnly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,13 @@ public interface IASTInternalScope extends IScope {
|
||||||
public void addBinding(IBinding binding);
|
public void addBinding(IBinding binding);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an IASTName to be cached in this scope
|
* Adds an IASTName to be cached in this scope.
|
||||||
|
* @param adlOnly whether this declaration of this name only makes the name visible to
|
||||||
|
* argument-dependent lookup
|
||||||
|
*
|
||||||
|
* Implementation note: only CPPNamespaceScope cares about "adlOnly".
|
||||||
*/
|
*/
|
||||||
public void addName(IASTName name);
|
public void addName(IASTName name, boolean adlOnly);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can be called during ambiguity resolution to populate a scope without considering
|
* Can be called during ambiguity resolution to populate a scope without considering
|
||||||
|
|
|
@ -192,7 +192,7 @@ public class ProblemBinding extends PlatformObject implements IProblemBinding, I
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addName(IASTName name) {
|
public void addName(IASTName name, boolean adlOnly) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -194,7 +194,7 @@ public class CScope implements ICScope, IASTInternalScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addName(IASTName name) {
|
public void addName(IASTName name, boolean adlOnly) {
|
||||||
final char[] nchars = name.toCharArray();
|
final char[] nchars = name.toCharArray();
|
||||||
if (nchars.length == 0)
|
if (nchars.length == 0)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -212,7 +212,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addName(IASTName name) {
|
public void addName(IASTName name, boolean adlOnly) {
|
||||||
// Don't add names from inactive code branches.
|
// Don't add names from inactive code branches.
|
||||||
if (!name.isActive())
|
if (!name.isActive())
|
||||||
return;
|
return;
|
||||||
|
@ -251,7 +251,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.addName(name);
|
super.addName(name, adlOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
|
|
@ -29,7 +29,7 @@ public class CPPClassSpecializationScope extends AbstractCPPClassSpecializationS
|
||||||
|
|
||||||
// This scope does not cache its own names
|
// This scope does not cache its own names
|
||||||
@Override
|
@Override
|
||||||
public void addName(IASTName name) {}
|
public void addName(IASTName name, boolean adlOnly) {}
|
||||||
@Override
|
@Override
|
||||||
public IASTNode getPhysicalNode() { return null; }
|
public IASTNode getPhysicalNode() { return null; }
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -40,6 +40,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective;
|
||||||
import org.eclipse.cdt.core.index.IIndex;
|
import org.eclipse.cdt.core.index.IIndex;
|
||||||
import org.eclipse.cdt.core.index.IIndexFileSet;
|
import org.eclipse.cdt.core.index.IIndexFileSet;
|
||||||
import org.eclipse.cdt.core.index.IIndexName;
|
import org.eclipse.cdt.core.index.IIndexName;
|
||||||
|
import org.eclipse.cdt.core.parser.util.CharArraySet;
|
||||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
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.cpp.CPPScopeMapper.InlineNamespaceDirective;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScopeMapper.InlineNamespaceDirective;
|
||||||
|
@ -60,6 +61,9 @@ public class CPPNamespaceScope extends CPPScope implements ICPPInternalNamespace
|
||||||
private List<ICPPASTNamespaceDefinition> fInlineNamespaceDefinitions;
|
private List<ICPPASTNamespaceDefinition> fInlineNamespaceDefinitions;
|
||||||
private ICPPInternalNamespaceScope[] fInlineNamespaces;
|
private ICPPInternalNamespaceScope[] fInlineNamespaces;
|
||||||
|
|
||||||
|
// The set of names declared in this scope that are currently only visible to argument-dependent lookup.
|
||||||
|
private CharArraySet fVisibleToAdlOnly = new CharArraySet(0);
|
||||||
|
|
||||||
public CPPNamespaceScope(IASTNode physicalNode) {
|
public CPPNamespaceScope(IASTNode physicalNode) {
|
||||||
super(physicalNode);
|
super(physicalNode);
|
||||||
}
|
}
|
||||||
|
@ -154,10 +158,23 @@ public class CPPNamespaceScope extends CPPScope implements ICPPInternalNamespace
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addName(IASTName name) {
|
public void addName(IASTName name, boolean adlOnly) {
|
||||||
if (name instanceof ICPPASTQualifiedName && !canDenoteNamespaceMember((ICPPASTQualifiedName) name))
|
if (name instanceof ICPPASTQualifiedName && !canDenoteNamespaceMember((ICPPASTQualifiedName) name))
|
||||||
return;
|
return;
|
||||||
super.addName(name);
|
super.addName(name, adlOnly);
|
||||||
|
if (adlOnly) {
|
||||||
|
fVisibleToAdlOnly.put(name.getLookupKey());
|
||||||
|
} else {
|
||||||
|
fVisibleToAdlOnly.remove(name.getLookupKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean nameIsVisibleToLookup(ScopeLookupData lookup) {
|
||||||
|
if (lookup.isArgumentDependent()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !fVisibleToAdlOnly.containsKey(lookup.getLookupKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canDenoteNamespaceMember(ICPPASTQualifiedName name) {
|
public boolean canDenoteNamespaceMember(ICPPASTQualifiedName name) {
|
||||||
|
|
|
@ -90,7 +90,7 @@ abstract public class CPPScope implements ICPPASTInternalScope {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
public void addName(IASTName name) {
|
public void addName(IASTName name, boolean adlOnly) {
|
||||||
// Don't add inactive names to the scope.
|
// Don't add inactive names to the scope.
|
||||||
if (!name.isActive())
|
if (!name.isActive())
|
||||||
return;
|
return;
|
||||||
|
@ -225,10 +225,17 @@ abstract public class CPPScope implements ICPPASTInternalScope {
|
||||||
return ArrayUtil.trim(IBinding.class, result);
|
return ArrayUtil.trim(IBinding.class, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean nameIsVisibleToLookup(ScopeLookupData lookup) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public IBinding[] getBindingsInAST(ScopeLookupData lookup) {
|
public IBinding[] getBindingsInAST(ScopeLookupData lookup) {
|
||||||
populateCache();
|
populateCache();
|
||||||
final char[] c = lookup.getLookupKey();
|
final char[] c = lookup.getLookupKey();
|
||||||
IBinding[] result = IBinding.EMPTY_BINDING_ARRAY;
|
IBinding[] result = IBinding.EMPTY_BINDING_ARRAY;
|
||||||
|
if (!nameIsVisibleToLookup(lookup)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Object obj = null;
|
Object obj = null;
|
||||||
if (lookup.isPrefixLookup()) {
|
if (lookup.isPrefixLookup()) {
|
||||||
|
|
|
@ -178,7 +178,7 @@ public class CPPUnknownTypeScope implements ICPPInternalUnknownScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addName(IASTName name) {
|
public void addName(IASTName name, boolean adlOnly) {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IBinding getOrCreateBinding(final char[] name, int idx) {
|
protected IBinding getOrCreateBinding(final char[] name, int idx) {
|
||||||
|
|
|
@ -631,6 +631,7 @@ public class CPPSemantics {
|
||||||
// don't ascend into enclosing scopes.
|
// don't ascend into enclosing scopes.
|
||||||
boolean originalQualified = data.qualified;
|
boolean originalQualified = data.qualified;
|
||||||
data.qualified = true;
|
data.qualified = true;
|
||||||
|
data.setArgumentDependent(true);
|
||||||
Set<ICPPFunction> friendFns = new HashSet<>(2);
|
Set<ICPPFunction> friendFns = new HashSet<>(2);
|
||||||
Set<ICPPNamespaceScope> associated = getAssociatedScopes(data, friendFns);
|
Set<ICPPNamespaceScope> associated = getAssociatedScopes(data, friendFns);
|
||||||
for (ICPPNamespaceScope scope : associated) {
|
for (ICPPNamespaceScope scope : associated) {
|
||||||
|
@ -643,6 +644,7 @@ public class CPPSemantics {
|
||||||
new NameMatcherPredicate(data.getLookupKey())).toArray();
|
new NameMatcherPredicate(data.getLookupKey())).toArray();
|
||||||
mergeResults(data, matchingFriendFns, false);
|
mergeResults(data, matchingFriendFns, false);
|
||||||
data.qualified = originalQualified;
|
data.qualified = originalQualified;
|
||||||
|
data.setArgumentDependent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class NameMatcherPredicate implements IUnaryPredicate<ICPPFunction> {
|
private static class NameMatcherPredicate implements IUnaryPredicate<ICPPFunction> {
|
||||||
|
|
|
@ -550,7 +550,14 @@ public class CPPVisitor extends ASTQueries {
|
||||||
binding = new CPPClassType(name, binding);
|
binding = new CPPClassType(name, binding);
|
||||||
}
|
}
|
||||||
// Name may live in a different scope, so make sure to add it to the owner scope as well.
|
// Name may live in a different scope, so make sure to add it to the owner scope as well.
|
||||||
ASTInternal.addName(scope, elabType.getName());
|
// [namespace.memdef] p3:
|
||||||
|
// "If a friend declaration in a non-local class first declares a
|
||||||
|
// class, function, class template or function template the friend
|
||||||
|
// is a member of the innermost enclosing namespace. The friend
|
||||||
|
// declaration does not by itself make the name visible to
|
||||||
|
// unqualified lookup or qualified lookup."
|
||||||
|
boolean visibleToAdlOnly = isFriend;
|
||||||
|
ASTInternal.addName(scope, elabType.getName(), visibleToAdlOnly);
|
||||||
}
|
}
|
||||||
} catch (DOMException e) {
|
} catch (DOMException e) {
|
||||||
binding = e.getProblem();
|
binding = e.getProblem();
|
||||||
|
|
|
@ -96,7 +96,7 @@ public class C99Scope implements IC99Scope, IASTInternalScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addName(IASTName name) {
|
public void addName(IASTName name, boolean adlOnly) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue