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_REDECLARATION, nc.getName(6).resolveBinding());
|
||||||
assertProblemBinding(IProblemBinding.SEMANTIC_INVALID_REDEFINITION, nc.getName(8).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 {
|
// struct Foo {
|
||||||
// void foo();
|
// void foo();
|
||||||
// };
|
// };
|
||||||
|
|
|
@ -781,7 +781,9 @@ public class CPPSemantics {
|
||||||
data.foundItems = ArrayUtil.addAll(Object.class, (Object[]) data.foundItems, (Object[]) results);
|
data.foundItems = ArrayUtil.addAll(Object.class, (Object[]) data.foundItems, (Object[]) results);
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
* @param scoped
|
||||||
* @return
|
* @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;
|
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;
|
Object[] objs = null;
|
||||||
int size;
|
int size;
|
||||||
if (source instanceof CharArrayObjectMap) {
|
if (source instanceof CharArrayObjectMap) {
|
||||||
map = (CharArrayObjectMap) source;
|
@SuppressWarnings("unchecked")
|
||||||
|
final CharArrayObjectMap<Object> sourceMap = (CharArrayObjectMap<Object>) source;
|
||||||
|
map = sourceMap;
|
||||||
size= map.size();
|
size= map.size();
|
||||||
} else {
|
} else {
|
||||||
if (source instanceof Object[])
|
if (source instanceof Object[])
|
||||||
|
@ -3499,7 +3503,7 @@ public class CPPSemantics {
|
||||||
LookupData data = createLookupData(name);
|
LookupData data = createLookupData(name);
|
||||||
data.contentAssist = true;
|
data.contentAssist = true;
|
||||||
data.prefixLookup = prefixLookup;
|
data.prefixLookup = prefixLookup;
|
||||||
data.foundItems = new CharArrayObjectMap(2);
|
data.foundItems = new CharArrayObjectMap<Object>(2);
|
||||||
|
|
||||||
// Convert namespaces to scopes.
|
// Convert namespaces to scopes.
|
||||||
List<ICPPScope> nsScopes= new ArrayList<ICPPScope>();
|
List<ICPPScope> nsScopes= new ArrayList<ICPPScope>();
|
||||||
|
@ -3567,7 +3571,8 @@ public class CPPSemantics {
|
||||||
}
|
}
|
||||||
} catch (DOMException e) {
|
} catch (DOMException e) {
|
||||||
}
|
}
|
||||||
CharArrayObjectMap map = (CharArrayObjectMap) data.foundItems;
|
@SuppressWarnings("unchecked")
|
||||||
|
CharArrayObjectMap<Object> map = (CharArrayObjectMap<Object>) data.foundItems;
|
||||||
IBinding[] result = IBinding.EMPTY_BINDING_ARRAY;
|
IBinding[] result = IBinding.EMPTY_BINDING_ARRAY;
|
||||||
if (!map.isEmpty()) {
|
if (!map.isEmpty()) {
|
||||||
char[] key = null;
|
char[] key = null;
|
||||||
|
@ -3686,7 +3691,7 @@ public class CPPSemantics {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isSameTemplateParameter(ICPPTemplateParameter tp1, ICPPASTTemplateParameter tp2) {
|
static boolean isSameTemplateParameter(ICPPTemplateParameter tp1, ICPPASTTemplateParameter tp2) {
|
||||||
if (tp1.isParameterPack() != tp2.isParameterPack())
|
if (tp1.isParameterPack() != tp2.isParameterPack())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -460,10 +460,9 @@ public class CPPVisitor extends ASTQueries {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
boolean template = false;
|
ICPPASTTemplateDeclaration templateDecl = CPPTemplates.getTemplateDeclaration(name);
|
||||||
ICPPScope scope = (ICPPScope) getContainingScope(name);
|
ICPPScope scope = (ICPPScope) getContainingScope(name);
|
||||||
while (scope instanceof ICPPTemplateScope) {
|
while (scope instanceof ICPPTemplateScope) {
|
||||||
template = true;
|
|
||||||
scope= (ICPPScope) scope.getParent();
|
scope= (ICPPScope) scope.getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,35 +492,21 @@ public class CPPVisitor extends ASTQueries {
|
||||||
|
|
||||||
if (binding instanceof ICPPClassType) {
|
if (binding instanceof ICPPClassType) {
|
||||||
final ICPPInternalBinding ib = (ICPPInternalBinding) binding;
|
final ICPPInternalBinding ib = (ICPPInternalBinding) binding;
|
||||||
if ((binding instanceof ICPPClassTemplate) == template) {
|
if (templateParametersMatch((ICPPClassType) binding, templateDecl)) {
|
||||||
ib.addDeclaration(elabType);
|
ib.addDeclaration(elabType);
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
if (CPPSemantics.declaredBefore(binding, name, false)) {
|
|
||||||
|
if (CPPSemantics.declaredBefore(ib, name, false)) {
|
||||||
return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION);
|
return new ProblemBinding(name, IProblemBinding.SEMANTIC_INVALID_REDECLARATION);
|
||||||
}
|
}
|
||||||
|
markRedeclaration(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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a binding
|
// Create a binding
|
||||||
if (elabType.getKind() != IASTElaboratedTypeSpecifier.k_enum) {
|
if (elabType.getKind() != IASTElaboratedTypeSpecifier.k_enum) {
|
||||||
if (template)
|
if (templateDecl != null)
|
||||||
binding = new CPPClassTemplate(name);
|
binding = new CPPClassTemplate(name);
|
||||||
else
|
else
|
||||||
binding = new CPPClassType(name, binding);
|
binding = new CPPClassType(name, binding);
|
||||||
|
@ -535,44 +520,91 @@ public class CPPVisitor extends ASTQueries {
|
||||||
return binding;
|
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) {
|
private static IBinding createBinding(ICPPASTCompositeTypeSpecifier compType) {
|
||||||
IASTName name = compType.getName();
|
IASTName name = compType.getName();
|
||||||
if (name instanceof ICPPASTQualifiedName) {
|
if (name instanceof ICPPASTQualifiedName) {
|
||||||
IASTName[] ns = ((ICPPASTQualifiedName) name).getNames();
|
IASTName[] ns = ((ICPPASTQualifiedName) name).getNames();
|
||||||
name = ns[ns.length - 1];
|
name = ns[ns.length - 1];
|
||||||
}
|
}
|
||||||
|
if (name instanceof ICPPASTTemplateId)
|
||||||
IBinding binding = null;
|
return CPPTemplates.createBinding((ICPPASTTemplateId) name);
|
||||||
|
|
||||||
ICPPScope scope = (ICPPScope) getContainingScope(name);
|
ICPPScope scope = (ICPPScope) getContainingScope(name);
|
||||||
try {
|
try {
|
||||||
boolean template = false;
|
|
||||||
while (scope instanceof ICPPTemplateScope) {
|
while (scope instanceof ICPPTemplateScope) {
|
||||||
template = true;
|
|
||||||
scope= (ICPPScope) scope.getParent();
|
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) {
|
} 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) {
|
private static IBinding createBinding(IASTDeclaration declaration) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue