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:
parent
be635f520a
commit
e0e7f9c1d7
14 changed files with 80 additions and 14 deletions
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" })
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue