mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 364226: Invalid redeclaration of class-template.
This commit is contained in:
parent
d4ea43f6c8
commit
6e0560d4f5
3 changed files with 111 additions and 56 deletions
|
@ -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 <typename T> class A;
|
||||
// template <template<typename> class T> class A {};
|
||||
// template <template<typename> class T> class A;
|
||||
// template <template<typename> class T> class B {};
|
||||
// template <typename T> class B;
|
||||
// template <typename T> 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();
|
||||
// };
|
||||
|
|
|
@ -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<Object> oldItems = (CharArrayObjectMap<Object>) 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<Object> mergePrefixResults(CharArrayObjectMap<Object> dest, Object source, boolean scoped) {
|
||||
if (source == null) return dest;
|
||||
CharArrayObjectMap resultMap = (dest != null) ? dest : new CharArrayObjectMap(2);
|
||||
CharArrayObjectMap<Object> resultMap = (dest != null) ? dest : new CharArrayObjectMap<Object>(2);
|
||||
|
||||
CharArrayObjectMap map = null;
|
||||
CharArrayObjectMap<Object> map = null;
|
||||
Object[] objs = null;
|
||||
int size;
|
||||
if (source instanceof CharArrayObjectMap) {
|
||||
map = (CharArrayObjectMap) source;
|
||||
@SuppressWarnings("unchecked")
|
||||
final CharArrayObjectMap<Object> sourceMap = (CharArrayObjectMap<Object>) 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<Object>(2);
|
||||
|
||||
// Convert namespaces to scopes.
|
||||
List<ICPPScope> nsScopes= new ArrayList<ICPPScope>();
|
||||
|
@ -3567,7 +3571,8 @@ public class CPPSemantics {
|
|||
}
|
||||
} catch (DOMException e) {
|
||||
}
|
||||
CharArrayObjectMap map = (CharArrayObjectMap) data.foundItems;
|
||||
@SuppressWarnings("unchecked")
|
||||
CharArrayObjectMap<Object> map = (CharArrayObjectMap<Object>) 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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue