From 67fe42e072320eb2963e85866066a34cde0bb652 Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Fri, 16 Oct 2009 10:03:44 +0000 Subject: [PATCH] Computation of naming type, bug 292232. --- .../parser/tests/ast2/AccessControlTests.java | 51 ++++++++++++++++ .../parser/cpp/semantics/AccessContext.java | 59 +++++++++++++++++-- 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AccessControlTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AccessControlTests.java index 403e5fbbb58..11bbfd143b2 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AccessControlTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AccessControlTests.java @@ -106,4 +106,55 @@ public class AccessControlTests extends AST2BaseTest { AccessAssertionHelper ah= new AccessAssertionHelper(code); ah.assertNotAccessible("a = 0", 1); } + + // class A0 { + // public: + // enum Ex {e1}; + // }; + // + // class A : public A0 { + // class B { + // void test() { + // Ex a; // we compute 'B' as the naming type, whereas it should be 'A' + // } + // }; + // }; + public void testEnclosingAsNamingClass_292232() throws Exception { + final String code = getAboveComment(); + parseAndCheckBindings(code, ParserLanguage.CPP); + AccessAssertionHelper ah= new AccessAssertionHelper(code); + ah.assertAccessible("Ex a;", 2); + } + + // // Example from C++-specification 11.2-3 + // class B { + // public: + // int mi; + // static int si; + // }; + // class D : private B {}; + // class DD : public D { + // void f(); + // }; + // + // void DD::f() { + // mi=3; // private + // si=3; // private + // B b; + // b.mi=4; + // b.si=4; + // B* bp; + // bp->mi=5; + // } + public void testEnclosingAsNamingClass_292232a() throws Exception { + final String code = getAboveComment(); + parseAndCheckBindings(code, ParserLanguage.CPP); + AccessAssertionHelper ah= new AccessAssertionHelper(code); + ah.assertNotAccessible("mi=3;", 2); + ah.assertNotAccessible("si=3;", 2); + ah.assertAccessible("mi=4;", 2); + ah.assertAccessible("si=4;", 2); + ah.assertAccessible("mi=5;", 2); + } + } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AccessContext.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AccessContext.java index ec1d9bb639c..ca348b85572 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AccessContext.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/AccessContext.java @@ -55,7 +55,9 @@ public class AccessContext { /** * A class through which the bindings are accessed (11.2.4). */ - private ICPPClassType namingClass; + private boolean isUnqualifiedLookup; + private ICPPClassType namingClass; // depends on the binding for which we check the access + private ICPPClassType firstCandidateForNamingClass; // the first candidate is independent of the binding for which we do the access-check private DOMException initializationException; public AccessContext(IASTName name) { @@ -77,7 +79,8 @@ public class AccessContext { if (!(owner instanceof ICPPClassType)) { return true; // The binding is not a class member. } - if (!Initialize()) { + ICPPClassType accessOwner= (ICPPClassType) owner; + if (!initialize(accessOwner)) { return true; // Assume visibility if anything goes wrong. } if (namingClass == null) { @@ -93,20 +96,25 @@ public class AccessContext { /** * @return true if initialization succeeded. */ - private boolean Initialize() { + private boolean initialize(ICPPClassType accessOwner) { if (context == null) { if (initializationException != null) { return false; } try { - namingClass = getNamingClass(name); context = getContext(name); + firstCandidateForNamingClass= getFirstCandidateForNamingClass(name); } catch (DOMException e) { CCorePlugin.log(e); initializationException = e; return false; } } + try { + namingClass = getNamingClass(accessOwner); + } catch (DOMException e) { + return false; + } return true; } @@ -198,8 +206,10 @@ public class AccessContext { return false; } - private static ICPPClassType getNamingClass(IASTName name) throws DOMException { + private ICPPClassType getFirstCandidateForNamingClass(IASTName name) throws DOMException { LookupData data = new LookupData(name); + isUnqualifiedLookup= !data.qualified(); + ICPPScope scope= CPPSemantics.getLookupScope(name, data); while (scope != null && !(scope instanceof ICPPClassScope)) { scope = CPPSemantics.getParentScope(scope, data.tu); @@ -210,6 +220,45 @@ public class AccessContext { return null; } + + private ICPPClassType getNamingClass(ICPPClassType accessOwner) throws DOMException { + ICPPClassType classType = firstCandidateForNamingClass; + if (classType != null && isUnqualifiedLookup) { + IBinding owner = classType.getOwner(); + while (owner instanceof ICPPClassType && !derivesFrom(classType, accessOwner, CPPSemantics.MAX_INHERITANCE_DEPTH)) { + classType= (ICPPClassType) owner; + owner= classType.getOwner(); + } + } + return classType; + } + + private static boolean derivesFrom(ICPPClassType derived, ICPPClassType target, int maxdepth) { + if (derived == target || derived.isSameType(target)) { + return true; + } + if (maxdepth > 0) { + try { + for (ICPPBase cppBase : derived.getBases()) { + try { + IBinding base= cppBase.getBaseClass(); + if (base instanceof ICPPClassType) { + ICPPClassType tbase= (ICPPClassType) base; + if (tbase.isSameType(target)) { + return true; + } + if (derivesFrom(tbase, target, maxdepth - 1)) + return true; + } + } catch (DOMException e) { + } + } + } catch (DOMException e) { + } + } + return false; + } + private static IBinding[] getContext(IASTName name) throws DOMException { IBinding[] accessibilityContext = IBinding.EMPTY_BINDING_ARRAY; for (IBinding binding = CPPVisitor.findEnclosingFunctionOrClass(name);