1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 09:25:31 +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

@ -10586,6 +10586,20 @@ public class AST2CPPTests extends AST2TestBase {
public void testFriendConstructorDestructor_400940() throws Exception {
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 {
// virtual void mFuncDecl() final;

View file

@ -114,6 +114,7 @@ public interface IScope {
private boolean fResolve= true;
private boolean fPrefixLookup;
private boolean fIgnorePointOfDeclaration;
private boolean fArgumentDependent;
public ScopeLookupData(IASTName name, boolean resolve, boolean prefixLookup) {
if (name == null)
@ -162,6 +163,11 @@ public interface IScope {
public final void setIgnorePointOfDeclaration(boolean ignorePointOfDeclaration) {
fIgnorePointOfDeclaration = ignorePointOfDeclaration;
}
/** @since 6.3 */
public final void setArgumentDependent(boolean argumentDependent) {
fArgumentDependent = argumentDependent;
}
public final void setLookupKey(char[] key) {
fLookupKey= key;
@ -187,6 +193,11 @@ public interface IScope {
return fIgnorePointOfDeclaration;
}
/** @since 6.3 */
public final boolean isArgumentDependent() {
return fArgumentDependent;
}
public final IIndexFileSet getIncludedFiles() {
return fTu == null ? IIndexFileSet.EMPTY : fTu.getIndexFileSet();
}

View file

@ -91,8 +91,12 @@ public class ASTInternal {
}
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) {
((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);
/**
* 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

View file

@ -192,7 +192,7 @@ public class ProblemBinding extends PlatformObject implements IProblemBinding, I
}
@Override
public void addName(IASTName name) {
public void addName(IASTName name, boolean adlOnly) {
}
@Override

View file

@ -194,7 +194,7 @@ public class CScope implements ICScope, IASTInternalScope {
}
@Override
public void addName(IASTName name) {
public void addName(IASTName name, boolean adlOnly) {
final char[] nchars = name.toCharArray();
if (nchars.length == 0)
return;

View file

@ -212,7 +212,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope {
}
@Override
public void addName(IASTName name) {
public void addName(IASTName name, boolean adlOnly) {
// Don't add names from inactive code branches.
if (!name.isActive())
return;
@ -251,7 +251,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope {
return;
}
}
super.addName(name);
super.addName(name, adlOnly);
}
@SuppressWarnings({ "rawtypes", "unchecked" })

View file

@ -29,7 +29,7 @@ public class CPPClassSpecializationScope extends AbstractCPPClassSpecializationS
// This scope does not cache its own names
@Override
public void addName(IASTName name) {}
public void addName(IASTName name, boolean adlOnly) {}
@Override
public IASTNode getPhysicalNode() { return null; }
@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.IIndexFileSet;
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.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPScopeMapper.InlineNamespaceDirective;
@ -59,6 +60,9 @@ public class CPPNamespaceScope extends CPPScope implements ICPPInternalNamespace
private ICPPNamespaceScope[] fEnclosingNamespaceSet;
private List<ICPPASTNamespaceDefinition> fInlineNamespaceDefinitions;
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) {
super(physicalNode);
@ -154,10 +158,23 @@ public class CPPNamespaceScope extends CPPScope implements ICPPInternalNamespace
}
@Override
public void addName(IASTName name) {
public void addName(IASTName name, boolean adlOnly) {
if (name instanceof ICPPASTQualifiedName && !canDenoteNamespaceMember((ICPPASTQualifiedName) name))
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) {

View file

@ -90,7 +90,7 @@ abstract public class CPPScope implements ICPPASTInternalScope {
@Override
@SuppressWarnings({ "unchecked" })
public void addName(IASTName name) {
public void addName(IASTName name, boolean adlOnly) {
// Don't add inactive names to the scope.
if (!name.isActive())
return;
@ -224,11 +224,18 @@ abstract public class CPPScope implements ICPPASTInternalScope {
return ArrayUtil.trim(IBinding.class, result);
}
protected boolean nameIsVisibleToLookup(ScopeLookupData lookup) {
return true;
}
public IBinding[] getBindingsInAST(ScopeLookupData lookup) {
populateCache();
final char[] c = lookup.getLookupKey();
IBinding[] result = IBinding.EMPTY_BINDING_ARRAY;
if (!nameIsVisibleToLookup(lookup)) {
return result;
}
Object obj = null;
if (lookup.isPrefixLookup()) {

View file

@ -178,7 +178,7 @@ public class CPPUnknownTypeScope implements ICPPInternalUnknownScope {
}
@Override
public void addName(IASTName name) {
public void addName(IASTName name, boolean adlOnly) {
}
protected IBinding getOrCreateBinding(final char[] name, int idx) {

View file

@ -631,6 +631,7 @@ public class CPPSemantics {
// don't ascend into enclosing scopes.
boolean originalQualified = data.qualified;
data.qualified = true;
data.setArgumentDependent(true);
Set<ICPPFunction> friendFns = new HashSet<>(2);
Set<ICPPNamespaceScope> associated = getAssociatedScopes(data, friendFns);
for (ICPPNamespaceScope scope : associated) {
@ -643,6 +644,7 @@ public class CPPSemantics {
new NameMatcherPredicate(data.getLookupKey())).toArray();
mergeResults(data, matchingFriendFns, false);
data.qualified = originalQualified;
data.setArgumentDependent(false);
}
private static class NameMatcherPredicate implements IUnaryPredicate<ICPPFunction> {

View file

@ -550,7 +550,14 @@ public class CPPVisitor extends ASTQueries {
binding = new CPPClassType(name, binding);
}
// 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) {
binding = e.getProblem();

View file

@ -96,7 +96,7 @@ public class C99Scope implements IC99Scope, IASTInternalScope {
}
@Override
public void addName(IASTName name) {
public void addName(IASTName name, boolean adlOnly) {
throw new UnsupportedOperationException();
}