1
0
Fork 0
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:
Nathan Ridge 2017-03-05 03:14:35 -05:00
parent be635f520a
commit e0e7f9c1d7
14 changed files with 80 additions and 14 deletions

View file

@ -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 {}

View file

@ -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();
} }

View file

@ -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);
} }
} }

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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" })

View file

@ -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

View file

@ -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) {

View file

@ -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()) {

View file

@ -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) {

View file

@ -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> {

View file

@ -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();

View file

@ -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();
} }