mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 22:52:11 +02:00
Bug 393717 - Have constructor definitions reference implicitly called
base constructors via implicit names Change-Id: Ib42a44488c5f5851a227295f075f028ff1aa7ded Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
This commit is contained in:
parent
005d40d228
commit
b0d8f8d3f1
4 changed files with 191 additions and 7 deletions
|
@ -11573,4 +11573,57 @@ public class AST2CPPTests extends AST2TestBase {
|
|||
// this test will need to be updated.
|
||||
helper.assertVariableValue("generic_lambdas_supported", 0);
|
||||
}
|
||||
|
||||
// struct A {
|
||||
// A() {}
|
||||
// };
|
||||
//
|
||||
// struct B {
|
||||
// B() {}
|
||||
// };
|
||||
//
|
||||
// struct C : A {
|
||||
// C() {}
|
||||
// };
|
||||
//
|
||||
// struct D : virtual A, virtual B {
|
||||
// D() {}
|
||||
// };
|
||||
//
|
||||
// struct E {
|
||||
// E() {}
|
||||
// };
|
||||
//
|
||||
// struct F : D, virtual E {
|
||||
// F() {}
|
||||
// };
|
||||
public void testImplicitlyCalledBaseConstructor_393717() throws Exception {
|
||||
BindingAssertionHelper helper = getAssertionHelper();
|
||||
|
||||
ICPPConstructor aCtor = helper.assertNonProblem("A()", "A");
|
||||
ICPPConstructor bCtor = helper.assertNonProblem("B()", "B");
|
||||
ICPPConstructor dCtor = helper.assertNonProblem("D()", "D");
|
||||
ICPPConstructor eCtor = helper.assertNonProblem("E()", "E");
|
||||
|
||||
ICPPASTFunctionDefinition ctorDef = helper.assertNode("C() {}");
|
||||
IASTImplicitName[] implicitNames = ((IASTImplicitNameOwner) ctorDef).getImplicitNames();
|
||||
assertEquals(1, implicitNames.length);
|
||||
assertEquals(aCtor, implicitNames[0].resolveBinding());
|
||||
|
||||
ctorDef = helper.assertNode("D() {}");
|
||||
implicitNames = ((IASTImplicitNameOwner) ctorDef).getImplicitNames();
|
||||
sortNames(implicitNames);
|
||||
assertEquals(2, implicitNames.length);
|
||||
assertEquals(aCtor, implicitNames[0].resolveBinding());
|
||||
assertEquals(bCtor, implicitNames[1].resolveBinding());
|
||||
|
||||
ctorDef = helper.assertNode("F() {}");
|
||||
implicitNames = ((IASTImplicitNameOwner) ctorDef).getImplicitNames();
|
||||
sortNames(implicitNames);
|
||||
assertEquals(4, implicitNames.length);
|
||||
assertEquals(aCtor, implicitNames[0].resolveBinding());
|
||||
assertEquals(bCtor, implicitNames[1].resolveBinding());
|
||||
assertEquals(dCtor, implicitNames[2].resolveBinding());
|
||||
assertEquals(eCtor, implicitNames[3].resolveBinding());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import static org.eclipse.cdt.core.parser.ParserLanguage.CPP;
|
|||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -913,4 +915,15 @@ public class AST2TestBase extends BaseTestCase {
|
|||
assertInstance(stmt, IASTExpressionStatement.class);
|
||||
return (T) ((IASTExpressionStatement) stmt).getExpression();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the given array of AST names lexicographically.
|
||||
*/
|
||||
protected static <T extends IASTName> void sortNames(T[] names) {
|
||||
Arrays.sort(names, new Comparator<IASTName>() {
|
||||
@Override
|
||||
public int compare(IASTName a, IASTName b) {
|
||||
return a.toString().compareTo(b.toString());
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2004, 2014 IBM Corporation and others.
|
||||
* Copyright (c) 2004, 2015 IBM Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -12,18 +12,30 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom.parser.cpp;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IScope;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
|
||||
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ASTAttributeOwner;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
|
||||
|
||||
|
@ -32,11 +44,12 @@ import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
|
|||
* it may contain member initializers.
|
||||
*/
|
||||
public class CPPASTFunctionDefinition extends ASTAttributeOwner
|
||||
implements ICPPASTFunctionDefinition, IASTAmbiguityParent {
|
||||
implements ICPPASTFunctionDefinition, IASTAmbiguityParent, IASTImplicitNameOwner {
|
||||
private IASTDeclSpecifier declSpecifier;
|
||||
private IASTFunctionDeclarator declarator;
|
||||
private IASTStatement bodyStatement;
|
||||
private ICPPASTConstructorChainInitializer[] memInits;
|
||||
private IASTImplicitName[] implicitNames; // for constructors: base constructors called implicitly
|
||||
private int memInitPos= -1;
|
||||
private boolean fDeleted;
|
||||
private boolean fDefaulted;
|
||||
|
@ -199,6 +212,14 @@ public class CPPASTFunctionDefinition extends ASTAttributeOwner
|
|||
return false;
|
||||
}
|
||||
|
||||
if (action.shouldVisitImplicitNames) {
|
||||
for (IASTImplicitName implicitName : getImplicitNames()) {
|
||||
if (!implicitName.accept(action)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bodyStatement != null && !bodyStatement.accept(action))
|
||||
return false;
|
||||
|
||||
|
@ -226,4 +247,67 @@ public class CPPASTFunctionDefinition extends ASTAttributeOwner
|
|||
bodyStatement = (IASTStatement) other;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IASTImplicitName[] getImplicitNames() {
|
||||
if (implicitNames == null) {
|
||||
implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY;
|
||||
IASTName functionName = ASTQueries.findInnermostDeclarator(declarator).getName();
|
||||
IBinding function = functionName.resolveBinding();
|
||||
if (function instanceof ICPPConstructor) {
|
||||
ICPPClassType classOwner = ((ICPPConstructor) function).getClassOwner();
|
||||
|
||||
// Determine the bases of 'classOwner' that need to be initialized by this constructor.
|
||||
Set<ICPPClassType> basesThatNeedInitialization = new HashSet<>();
|
||||
for (ICPPBase base : ClassTypeHelper.getBases(classOwner, this)) {
|
||||
IType baseType = base.getBaseClassType();
|
||||
if (baseType instanceof ICPPClassType) {
|
||||
basesThatNeedInitialization.add((ICPPClassType) baseType);
|
||||
}
|
||||
}
|
||||
for (ICPPClassType virtualBase : ClassTypeHelper.getVirtualBases(classOwner, this)) {
|
||||
basesThatNeedInitialization.add(virtualBase);
|
||||
}
|
||||
|
||||
// Go through the bases determined above, and see which ones aren't initialized
|
||||
// explicitly in the mem-initializer list.
|
||||
for (ICPPClassType base : basesThatNeedInitialization) {
|
||||
if (!isInitializedExplicitly(base)) {
|
||||
// Try to find a default constructor to create an implicit name for.
|
||||
for (ICPPConstructor constructor : ClassTypeHelper.getConstructors(base, this)) {
|
||||
if (constructor.getRequiredArgumentCount() == 0) { // default constructor
|
||||
CPPASTImplicitName ctorName = new CPPASTImplicitName(
|
||||
constructor.getNameCharArray(), this);
|
||||
ctorName.setBinding(constructor);
|
||||
ctorName.setOffsetAndLength((ASTNode) functionName);
|
||||
implicitNames = ArrayUtil.append(implicitNames, ctorName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
implicitNames = ArrayUtil.trim(implicitNames);
|
||||
}
|
||||
return implicitNames;
|
||||
}
|
||||
|
||||
// Returns whether the base type 'base' is explicitly initialized by one of the mem-initializers
|
||||
// of this constructor.
|
||||
private boolean isInitializedExplicitly(ICPPClassType base) {
|
||||
for (ICPPASTConstructorChainInitializer memInitializer : getMemberInitializers()) {
|
||||
IBinding binding = memInitializer.getMemberInitializerId().resolveBinding();
|
||||
if (binding instanceof IType) {
|
||||
if (((IType) binding).isSameType(base)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (binding instanceof ICPPConstructor) {
|
||||
if (((ICPPConstructor) binding).getClassOwner().isSameType(base)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2004, 2014 IBM Corporation and others.
|
||||
* Copyright (c) 2004, 2015 IBM Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
|
@ -24,6 +24,7 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
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;
|
||||
|
@ -284,15 +285,15 @@ public class ClassTypeHelper {
|
|||
* @return An array of base classes in arbitrary order.
|
||||
*/
|
||||
public static ICPPClassType[] getAllBases(ICPPClassType classType, IASTNode point) {
|
||||
HashSet<ICPPClassType> result= new HashSet<>();
|
||||
Set<ICPPClassType> result= new HashSet<>();
|
||||
result.add(classType);
|
||||
getAllBases(classType, result, point);
|
||||
result.remove(classType);
|
||||
return result.toArray(new ICPPClassType[result.size()]);
|
||||
}
|
||||
|
||||
private static void getAllBases(ICPPClassType classType, HashSet<ICPPClassType> result, IASTNode point) {
|
||||
ICPPBase[] bases= ClassTypeHelper.getBases(classType, point);
|
||||
private static void getAllBases(ICPPClassType classType, Set<ICPPClassType> result, IASTNode point) {
|
||||
ICPPBase[] bases= getBases(classType, point);
|
||||
for (ICPPBase base : bases) {
|
||||
IBinding b= base.getBaseClass();
|
||||
if (b instanceof ICPPClassType) {
|
||||
|
@ -304,6 +305,39 @@ public class ClassTypeHelper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all (direct or indirect) virtual base classes of 'classType'.
|
||||
* @param point the point of instantiation for name lookups
|
||||
*/
|
||||
public static ICPPClassType[] getVirtualBases(ICPPClassType classType, IASTNode point) {
|
||||
Set<ICPPClassType> result = new HashSet<>();
|
||||
result.add(classType);
|
||||
getVirtualBases(classType, result, point);
|
||||
result.remove(classType);
|
||||
return result.toArray(new ICPPClassType[result.size()]);
|
||||
}
|
||||
|
||||
// Helper function for getVirtualBases(classType, point).
|
||||
private static void getVirtualBases(ICPPClassType classType, Set<ICPPClassType> result, IASTNode point) {
|
||||
ICPPBase[] bases = getBases(classType, point);
|
||||
for (ICPPBase base : bases) {
|
||||
IBinding b = base.getBaseClass();
|
||||
if (b instanceof ICPPClassType) {
|
||||
final ICPPClassType baseClass = (ICPPClassType) b;
|
||||
if (base.isVirtual()) {
|
||||
if (result.add(baseClass)) {
|
||||
getVirtualBases(baseClass, result, point);
|
||||
}
|
||||
} else {
|
||||
// A non-virtual base could have virtual bases in its hierarchy.
|
||||
if (!result.contains(baseClass)) {
|
||||
getVirtualBases(baseClass, result, point);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks inheritance relationship between two classes.
|
||||
* @return {@code true} if {@code subclass} is a subclass of {@code superclass}.
|
||||
|
|
Loading…
Add table
Reference in a new issue