diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java index abd0828487d..8ea564117a0 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java @@ -2313,4 +2313,13 @@ public class IndexCPPTemplateResolutionTest extends IndexBindingResolutionTestBa public void testRegression_408314() throws Exception { checkBindings(); } + + // template struct A { enum { v = 0 }; }; + // template<> struct A { enum { v = 1 }; }; + // template<> struct A { enum { v = 1 }; }; + + // int main() {} + public void testSpecializationRedefinition_409444() throws Exception { + checkBindings(); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java index 21a1b7b34bb..3a11376a207 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java @@ -15,11 +15,20 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; -import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; @@ -64,19 +73,10 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.core.runtime.CoreException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - /** * Holds common implementation of methods for ICPPClassType implementations that have * a corresponding textual definition in the source code. @@ -910,7 +910,7 @@ public class ClassTypeHelper { ICPPClassType specialized = ((ICPPClassSpecialization) classType).getSpecializedBinding(); if (!specialized.equals(member.getOwner())) { if (!(member instanceof ICPPSpecialization)) - throw new IllegalArgumentException(member.getName() + " is not a member of " + specialized.getName()); //$NON-NLS-1$ + throw invalidMember(specialized, member); member = ((ICPPSpecialization) member).getSpecializedBinding(); } return specialized.getVisibility(member); @@ -920,13 +920,46 @@ public class ClassTypeHelper { } } - int visibility = classType.getKey() == ICPPClassType.k_class ? - ICPPClassType.v_private : ICPPClassType.v_public; + ICPPASTCompositeTypeSpecifier classDeclSpec = classType.getCompositeTypeSpecifier(); + int visibility = getVisibility(classDeclSpec, member); + if (visibility >= 0) + return visibility; - IASTDeclaration[] hostMembers = classType.getCompositeTypeSpecifier().getMembers(); + ICPPMethod[] implicitMethods = getImplicitMethods(classType, null); + for (ICPPMethod implicitMethod : implicitMethods) { + if (member.equals(implicitMethod)) { + return ICPPClassType.v_public; + } + } + + // It's possible that we haven't found the member because the class was illegally redefined + // and the member belongs to another definition. Try to search the definition containing + // the member. + if (member instanceof ICPPInternalBinding) { + IASTNode node = ((ICPPInternalBinding) member).getDefinition(); + if (node != null) { + IASTName ownerName = CPPVisitor.findDeclarationOwnerDefinition(node, false); + if (ownerName != null && !ownerName.equals(classDeclSpec.getName()) && + ownerName.getPropertyInParent() == ICPPASTCompositeTypeSpecifier.TYPE_NAME) { + classDeclSpec = (ICPPASTCompositeTypeSpecifier) ownerName.getParent(); + visibility = getVisibility(classDeclSpec, member); + if (visibility >= 0) + return visibility; + } + } + } + + throw invalidMember(classType, member); + } + + private static int getVisibility(ICPPASTCompositeTypeSpecifier classDeclSpec, IBinding member) { + int visibility = classDeclSpec.getKey() == ICPPASTCompositeTypeSpecifier.k_class ? + ICPPClassType.v_private : ICPPClassType.v_public; + IASTDeclaration[] hostMembers = classDeclSpec.getMembers(); for (IASTDeclaration hostMember : hostMembers) { if (hostMember instanceof ICPPASTVisibilityLabel) { visibility = ((ICPPASTVisibilityLabel) hostMember).getVisibility(); + continue; } while (hostMember instanceof ICPPASTTemplateDeclaration) { hostMember = ((ICPPASTTemplateDeclaration) hostMember).getDeclaration(); @@ -970,7 +1003,8 @@ public class ClassTypeHelper { } } } else if (hostMember instanceof IASTFunctionDefinition) { - IASTFunctionDeclarator declarator = ((IASTFunctionDefinition) hostMember).getDeclarator(); + IASTDeclarator declarator = ((IASTFunctionDefinition) hostMember).getDeclarator(); + declarator = ASTQueries.findInnermostDeclarator(declarator); IBinding functionBinding = declarator.getName().resolveBinding(); if (member.equals(functionBinding)){ return visibility; @@ -992,13 +1026,14 @@ public class ClassTypeHelper { } } } - ICPPMethod[] implicitMethods = getImplicitMethods(classType, null); - for (ICPPMethod implicitMethod : implicitMethods) { - if (member.equals(implicitMethod)) { - return ICPPClassType.v_public; - } - } - throw new IllegalArgumentException(member.getName() + " is not a member of " + classType.getName()); //$NON-NLS-1$ + return -1; + } + + private static IllegalArgumentException invalidMember(IBinding classType, IBinding member) { + String name = member.getName(); + if (name.isEmpty()) + name = ""; //$NON-NLS-1$ + return new IllegalArgumentException(name + " is not a member of " + classType.getName()); //$NON-NLS-1$ } private static Map> collectPureVirtualMethods(ICPPClassType classType, diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index eaaa7cfef13..2c87aa7d3ec 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -2554,6 +2554,14 @@ public class CPPVisitor extends ASTQueries { * of the above constructs. */ public static IBinding findDeclarationOwner(IASTNode node, boolean allowFunction) { + IASTName name = findDeclarationOwnerDefinition(node, allowFunction); + if (name == null) + return null; + + return name.resolveBinding(); + } + + public static IASTName findDeclarationOwnerDefinition(IASTNode node, boolean allowFunction) { // Search for declaration boolean isNonSimpleElabDecl= false; while (!(node instanceof IASTDeclaration) && !(node instanceof ICPPASTLambdaExpression)) { @@ -2605,10 +2613,7 @@ public class CPPVisitor extends ASTQueries { break; } } - if (name == null) - return null; - - return name.resolveBinding(); + return name; } public static boolean doesNotSpecifyType(IASTDeclSpecifier declspec) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java index 49eff3995a8..5149e9c0d17 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java @@ -668,6 +668,18 @@ public class PDOMASTAdapter { return binding; } + /** + * Retrieves the original binding from an adapter previously returned by + * {@link #getAdapterForAnonymousASTBinding(IBinding)}. If the parameter binding is not + * an adapter, returns the binding itself. + */ + public static IBinding getOriginalForAdaptedBinding(IBinding binding) { + if (binding instanceof AnonymousCPPBinding) { + return ((AnonymousCPPBinding) binding).fDelegate; + } + return binding; + } + /** * If the name is empty and has no file location, either an adapter * that has a file location is returned, or null if that diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java index 9dbfb06808c..559732393d9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPLinkage.java @@ -529,6 +529,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants { if (bindingOwner instanceof ICPPClassType) { if (bindingOwner instanceof CPPClosureType) return ICPPClassType.v_public; + binding = PDOMASTAdapter.getOriginalForAdaptedBinding(binding); visibility = ((ICPPClassType) bindingOwner).getVisibility(binding); } return visibility;