From 6e0560d4f59e2091b15bc5359774fff628108f2d Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Wed, 30 Nov 2011 11:02:58 +0100 Subject: [PATCH] Bug 364226: Invalid redeclaration of class-template. --- .../core/parser/tests/ast2/AST2CPPTests.java | 20 ++- .../parser/cpp/semantics/CPPSemantics.java | 21 +-- .../dom/parser/cpp/semantics/CPPVisitor.java | 126 +++++++++++------- 3 files changed, 111 insertions(+), 56 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index aef89346a57..a0e7f90ae94 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -6392,7 +6392,25 @@ public class AST2CPPTests extends AST2BaseTest { assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDECLARATION, nc.getName(6).resolveBinding()); assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(8).resolveBinding()); } - + + // template class A; + // template class T> class A {}; + // template class T> class A; + // template class T> class B {}; + // template class B; + // template class B {}; + public void testInvalidClassRedeclaration_364226() throws Exception { + final String code = getAboveComment(); + IASTTranslationUnit tu= parse(code, ParserLanguage.CPP, true, false); + CPPNameCollector nc= new CPPNameCollector(); + tu.accept(nc); + assertProblemBindings(nc, 4); + assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(4).resolveBinding()); + assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDECLARATION, nc.getName(7).resolveBinding()); + assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDECLARATION, nc.getName(12).resolveBinding()); + assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(14).resolveBinding()); + } + // struct Foo { // void foo(); // }; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index b52271bd506..102acf013a7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -781,7 +781,9 @@ public class CPPSemantics { data.foundItems = ArrayUtil.addAll(Object.class, (Object[]) data.foundItems, (Object[]) results); } } else { - data.foundItems = mergePrefixResults((CharArrayObjectMap) data.foundItems, results, scoped); + @SuppressWarnings("unchecked") + final CharArrayObjectMap oldItems = (CharArrayObjectMap) data.foundItems; + data.foundItems = mergePrefixResults(oldItems, results, scoped); } } @@ -791,15 +793,17 @@ public class CPPSemantics { * @param scoped * @return */ - static CharArrayObjectMap mergePrefixResults(CharArrayObjectMap dest, Object source, boolean scoped) { + static CharArrayObjectMap mergePrefixResults(CharArrayObjectMap dest, Object source, boolean scoped) { if (source == null) return dest; - CharArrayObjectMap resultMap = (dest != null) ? dest : new CharArrayObjectMap(2); + CharArrayObjectMap resultMap = (dest != null) ? dest : new CharArrayObjectMap(2); - CharArrayObjectMap map = null; + CharArrayObjectMap map = null; Object[] objs = null; int size; if (source instanceof CharArrayObjectMap) { - map = (CharArrayObjectMap) source; + @SuppressWarnings("unchecked") + final CharArrayObjectMap sourceMap = (CharArrayObjectMap) source; + map = sourceMap; size= map.size(); } else { if (source instanceof Object[]) @@ -3499,7 +3503,7 @@ public class CPPSemantics { LookupData data = createLookupData(name); data.contentAssist = true; data.prefixLookup = prefixLookup; - data.foundItems = new CharArrayObjectMap(2); + data.foundItems = new CharArrayObjectMap(2); // Convert namespaces to scopes. List nsScopes= new ArrayList(); @@ -3567,7 +3571,8 @@ public class CPPSemantics { } } catch (DOMException e) { } - CharArrayObjectMap map = (CharArrayObjectMap) data.foundItems; + @SuppressWarnings("unchecked") + CharArrayObjectMap map = (CharArrayObjectMap) data.foundItems; IBinding[] result = IBinding.EMPTY_BINDING_ARRAY; if (!map.isEmpty()) { char[] key = null; @@ -3686,7 +3691,7 @@ public class CPPSemantics { return true; } - private static boolean isSameTemplateParameter(ICPPTemplateParameter tp1, ICPPASTTemplateParameter tp2) { + static boolean isSameTemplateParameter(ICPPTemplateParameter tp1, ICPPASTTemplateParameter tp2) { if (tp1.isParameterPack() != tp2.isParameterPack()) return false; 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 571b28ac652..d5e531c20ed 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 @@ -460,10 +460,9 @@ public class CPPVisitor extends ASTQueries { } try { - boolean template = false; + ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name); ICPPScope scope = (ICPPScope) getContainingScope(name); while (scope instanceof ICPPTemplateScope) { - template = true; scope= (ICPPScope) scope.getParent(); } @@ -493,35 +492,21 @@ public class CPPVisitor extends ASTQueries { if (binding instanceof ICPPClassType) { final ICPPInternalBinding ib = (ICPPInternalBinding) binding; - if ((binding instanceof ICPPClassTemplate) == template) { + if (templateParametersMatch((ICPPClassType) binding, templateDecl)) { ib.addDeclaration(elabType); return binding; } - if (CPPSemantics.declaredBefore(binding, name, false)) { + + if (CPPSemantics.declaredBefore(ib, name, false)) { return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION); } - - // Mark the other declarations as problem and create the binding - final IASTNode[] decls = ib.getDeclarations(); - if (decls != null) { - for (IASTNode decl : decls) { - if (decl instanceof IASTName) { - final IASTName n = (IASTName) decl; - n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDECLARATION)); - } - } - } - IASTNode decl= ib.getDefinition(); - if (decl instanceof IASTName) { - final IASTName n = (IASTName) decl; - n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDEFINITION)); - } + markRedeclaration(ib); } } // Create a binding if (elabType.getKind() != IASTElaboratedTypeSpecifier.k_enum) { - if (template) + if (templateDecl != null) binding = new CPPClassTemplate(name); else binding = new CPPClassType(name, binding); @@ -535,44 +520,91 @@ public class CPPVisitor extends ASTQueries { return binding; } + public static void markRedeclaration(final ICPPInternalBinding ib) { + // Mark the other declarations as problem and create the binding + final IASTNode[] decls = ib.getDeclarations(); + if (decls != null) { + for (IASTNode decl : decls) { + if (decl instanceof IASTName) { + final IASTName n = (IASTName) decl; + n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDECLARATION)); + } + } + } + IASTNode decl= ib.getDefinition(); + if (decl instanceof IASTName) { + final IASTName n = (IASTName) decl; + n.setBinding(new ProblemBinding(n, IProblemBinding.SEMANTIC_INVALID_REDEFINITION)); + } + } + + /** + * Tests whether a class binding matches the template parameters of another declaration + */ + private static boolean templateParametersMatch(ICPPClassType binding, + ICPPASTTemplateDeclaration templateDecl) { + final boolean isTemplate= binding instanceof ICPPClassTemplate; + if (templateDecl == null) + return !isTemplate; + if (!isTemplate) + return false; + + ICPPTemplateParameter[] pars1 = ((ICPPClassTemplate) binding).getTemplateParameters(); + ICPPASTTemplateParameter[] pars2 = templateDecl.getTemplateParameters(); + + int i=0; + for (ICPPASTTemplateParameter p2 : pars2) { + if (i >= pars1.length) + return true; + + if (!CPPSemantics.isSameTemplateParameter(pars1[i++], p2)) + return false; + } + return true; + } + private static IBinding createBinding(ICPPASTCompositeTypeSpecifier compType) { IASTName name = compType.getName(); if (name instanceof ICPPASTQualifiedName) { IASTName[] ns = ((ICPPASTQualifiedName) name).getNames(); name = ns[ns.length - 1]; } - - IBinding binding = null; + if (name instanceof ICPPASTTemplateId) + return CPPTemplates.createBinding((ICPPASTTemplateId) name); + ICPPScope scope = (ICPPScope) getContainingScope(name); - try { - boolean template = false; + try { while (scope instanceof ICPPTemplateScope) { - template = true; scope= (ICPPScope) scope.getParent(); } - if (name instanceof ICPPASTTemplateId) { - return CPPTemplates.createBinding((ICPPASTTemplateId) name); - } - if (name.getLookupKey().length > 0 && scope != null) // can't lookup anonymous things - binding = scope.getBinding(name, false); - if (binding instanceof ICPPInternalBinding && binding instanceof ICPPClassType && name.isActive()) { - ICPPInternalBinding internal = (ICPPInternalBinding) binding; - if (internal.getDefinition() == null && (binding instanceof ICPPClassTemplate) == template) { - ASTInternal.addDefinition(internal, compType); - } else { - binding = new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION); - } - } else { - if (template) { - binding = new CPPClassTemplate(name); - } else { - binding = new CPPClassType(name, binding); - } - } } catch (DOMException e) { - binding = e.getProblem(); + return e.getProblem(); } - return binding; + + // Can't lookup anonymous names + IBinding binding= null; + ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name); + if (name.getLookupKey().length > 0 && scope != null) { + binding = scope.getBinding(name, false); + + if (binding instanceof ICPPInternalBinding + && binding instanceof ICPPClassType && name.isActive()) { + ICPPInternalBinding ib = (ICPPInternalBinding) binding; + if (ib.getDefinition() == null + && templateParametersMatch((ICPPClassType) binding, templateDecl)) { + ASTInternal.addDefinition(ib, compType); + return binding; + } + if (CPPSemantics.declaredBefore(ib, name, false)) { + return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDEFINITION); + } + markRedeclaration(ib); + } + } + if (templateDecl != null) + return new CPPClassTemplate(name); + + return new CPPClassType(name, binding); } private static IBinding createBinding(IASTDeclaration declaration) {