1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-17 21:25:58 +02:00

Added few methods to ClassTypeHelper and tests for them.

This commit is contained in:
Sergey Prigogin 2011-11-15 11:14:01 -08:00
parent 94a3430cf2
commit 29762a2885
3 changed files with 277 additions and 31 deletions

View file

@ -0,0 +1,123 @@
/*******************************************************************************
* Copyright (c) 2010 Google, Inc 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Sergey Prigogin (Google) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2;
import java.io.IOException;
import junit.framework.TestSuite;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.parser.ParserException;
/**
* Tests for ClassTypeHelper class.
*/
public class ClassTypeHelperTests extends AST2BaseTest {
public ClassTypeHelperTests() {
}
public ClassTypeHelperTests(String name) {
super(name);
}
public static TestSuite suite() {
return suite(ClassTypeHelperTests.class);
}
protected BindingAssertionHelper getAssertionHelper() throws ParserException, IOException {
String code= getAboveComment();
return new BindingAssertionHelper(code, true);
}
// class A {
// public:
// A();
// int x;
// A* y;
// const A& z;
// };
public void testHasTrivialCopyCtor_1() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
ICPPClassType classType = helper.assertNonProblem("A {", 1, ICPPClassType.class);
assertTrue(ClassTypeHelper.hasTrivialCopyCtor(classType));
}
// struct A {
// A(const A& a);
// };
//
// class B {
// public:
// A a;
// };
public void testHasTrivialCopyCtor_2() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
ICPPClassType classType = helper.assertNonProblem("B {", 1, ICPPClassType.class);
assertFalse(ClassTypeHelper.hasTrivialCopyCtor(classType));
}
// class A {
// public:
// A();
// A(const A& a);
// int x;
// A* y;
// const A& z;
// };
public void testHasTrivialDesctructor_1() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
ICPPClassType classType = helper.assertNonProblem("A {", 1, ICPPClassType.class);
assertTrue(ClassTypeHelper.hasTrivialDestructor(classType));
}
// struct A {
// ~A();
// };
//
// class B {
// public:
// A a;
// };
public void testHasTrivialDesctructor_2() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
ICPPClassType classType = helper.assertNonProblem("B {", 1, ICPPClassType.class);
assertFalse(ClassTypeHelper.hasTrivialDestructor(classType));
}
// class A {
// public:
// A();
// A(const A& a);
// void m();
// int x;
// A* y;
// const A& z;
// };
public void testIsPolymorphic_1() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
ICPPClassType classType = helper.assertNonProblem("A {", 1, ICPPClassType.class);
assertFalse(ClassTypeHelper.isPolymorphic(classType));
}
// struct A {
// virtual void m();
// };
//
// class B : public A {
// };
public void testIsPolymorphic_2() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
ICPPClassType classType = helper.assertNonProblem("B", 1, ICPPClassType.class);
assertTrue(ClassTypeHelper.isPolymorphic(classType));
}
}

View file

@ -30,6 +30,7 @@ public class DOMParserTestSuite extends TestCase {
suite.addTest(ASTCPPSpecDefectTests.suite());
suite.addTest(AST2CPPImplicitNameTests.suite());
suite.addTest(AST2TemplateTests.suite());
suite.addTest(ClassTypeHelperTests.suite());
suite.addTestSuite(QuickParser2Tests.class);
suite.addTest(CompleteParser2Tests.suite());
suite.addTest(DOMLocationTests.suite());

View file

@ -15,6 +15,10 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ARRAY;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -446,10 +450,9 @@ public class ClassTypeHelper {
return field;
}
/**
* Returns whether {@code method} is virtual. This is the case if it is declared to be virtual or
* overrides another virtual method.
* Returns whether {@code method} is virtual. This is the case if it is declared to be virtual
* or overrides another virtual method.
*/
public static boolean isVirtual(ICPPMethod m) {
if (m instanceof ICPPConstructor)
@ -809,6 +812,126 @@ public class ClassTypeHelper {
return true;
}
/**
* Returns <code>true</code> if and only if the given class has a trivial copy constructor.
* A copy constructor is trivial if:
* <ul>
* <li>it is implicitly defined by the compiler, and</li>
* <li><code>isPolymorphic(classTarget) == false</code>, and</li>
* <li>the class has no virtual base classes, and</li>
* <li>every direct base class has trivial copy constructor, and</li>
* <li>for every nonstatic data member that has class type or array of class type, that type
* has trivial copy constructor.</li>
* </ul>
* Similar to <code>std::tr1::has_trivial_copy</code>.
*
* @param classTarget the class to check
* @return <code>true</code> if the class has a trivial copy constructor
*/
public static boolean hasTrivialCopyCtor(ICPPClassType classTarget) {
if (getImplicitCopyCtor(classTarget) == null)
return false;
if (isPolymorphic(classTarget))
return false;
for (ICPPBase base : classTarget.getBases()) {
if (base.isVirtual())
return false;
}
for (ICPPClassType baseClass : getAllBases(classTarget)) {
if (!classTarget.isSameType(baseClass) && !hasTrivialCopyCtor(baseClass))
return false;
}
for (ICPPField field : classTarget.getDeclaredFields()) {
if (!field.isStatic()) {
IType type = field.getType();
type = SemanticUtil.getNestedType(type, TDEF | CVTYPE | ARRAY);
if (type instanceof ICPPClassType && !classTarget.isSameType(type) &&
!hasTrivialCopyCtor((ICPPClassType) type)) {
return false;
}
}
}
return true;
}
/**
* Returns the compiler-generated copy constructor for the given class, or <code>null</code>
* if the class doesn't have a compiler-generated copy constructor.
*
* @param classTarget the class to get the copy ctor for.
* @return the compiler-generated copy constructor, or <code>null</code> if the class doesn't
* have a compiler-generated copy constructor.
*/
private static ICPPConstructor getImplicitCopyCtor(ICPPClassType classTarget) {
for (ICPPConstructor ctor : classTarget.getConstructors()) {
if (ctor.isImplicit() && getImplicitMethodKind(classTarget, ctor) == KIND_COPY_CTOR)
return ctor;
}
return null;
}
/**
* Returns <code>true</code> if and only if the given class has a trivial destructor.
* A destructor is trivial if:
* <ul>
* <li>it is implicitly defined by the compiler, and</li>
* <li>every direct base class has trivial destructor, and</li>
* <li>for every nonstatic data member that has class type or array of class type, that type
* has trivial destructor.</li>
* </ul>
* Similar to <code>std::tr1::has_trivial_destructor</code>.
*
* @param classTarget the class to check
* @return <code>true</code> if the class has a trivial destructor
*/
public static boolean hasTrivialDestructor(ICPPClassType classTarget) {
for (ICPPMethod method : classTarget.getDeclaredMethods()) {
if (method.isDestructor())
return false;
}
for (ICPPClassType baseClass : getAllBases(classTarget)) {
if (!classTarget.isSameType(baseClass) && !hasTrivialDestructor(baseClass))
return false;
}
for (ICPPField field : classTarget.getDeclaredFields()) {
if (!field.isStatic()) {
IType type = field.getType();
type = SemanticUtil.getNestedType(type, TDEF | CVTYPE | ARRAY);
if (type instanceof ICPPClassType && !classTarget.isSameType(type) &&
!hasTrivialDestructor((ICPPClassType) type)) {
return false;
}
}
}
return true;
}
/**
* Returns <code>true</code> if and only if the given class declares or inherits a virtual
* function. Similar to <code>std::tr1::is_polymorphic</code>.
*
* @param classTarget the class to check
* @return <code>true</code> if the class declares or inherits a virtual function.
*/
public static boolean isPolymorphic(ICPPClassType classTarget) {
if (hasDeclaredVirtualMethod(classTarget))
return true;
for (ICPPClassType baseClass : getAllBases(classTarget)) {
if (hasDeclaredVirtualMethod(baseClass))
return true;
}
return false;
}
private static boolean hasDeclaredVirtualMethod(ICPPClassType classTarget) {
for (ICPPMethod method : classTarget.getDeclaredMethods()) {
if (method.isVirtual()) {
return true;
}
}
return false;
}
/**
* Checks whether class is abstract, i.e. has pure virtual functions that were
* not implemented in base after declaration.
@ -837,7 +960,6 @@ public class ClassTypeHelper {
private static Map<String, List<ICPPMethod>> collectPureVirtualMethods(ICPPClassType classType,
Map<ICPPClassType, Map<String, List<ICPPMethod>>> cache) {
Map<String, List<ICPPMethod>> result = cache.get(classType);
if (result != null)
return result;