From fd7b8220ee5865c8d262dc4872d18d770ed89e9a Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Wed, 22 Aug 2012 10:18:46 -0700 Subject: Bug 367993 - Error due to CDT not recognizing compiler built-ins like __is_pod. --- .../cdt/core/parser/tests/ast2/AST2BaseTest.java | 2 +- .../core/parser/tests/ast2/AST2TemplateTests.java | 25 +- .../parser/tests/ast2/ClassTypeHelperTests.java | 122 ------- .../core/parser/tests/ast2/DOMParserTestSuite.java | 2 +- .../tests/ast2/GCCCompleteParseExtensionsTest.java | 2 +- .../core/parser/tests/ast2/TypeTraitsTests.java | 239 +++++++++++++ .../eclipse/cdt/core/dom/rewrite/TypeHelper.java | 6 +- .../internal/core/dom/parser/SizeofCalculator.java | 15 + .../cdt/internal/core/dom/parser/Value.java | 152 +++++++-- .../core/dom/parser/cpp/ClassTypeHelper.java | 379 ++++++--------------- .../dom/parser/cpp/semantics/CPPEvaluation.java | 10 - .../cpp/semantics/CPPVariableReadWriteFlags.java | 3 +- .../core/dom/parser/cpp/semantics/Conversions.java | 2 +- .../dom/parser/cpp/semantics/EvalBinaryTypeId.java | 10 +- .../core/dom/parser/cpp/semantics/EvalUnary.java | 5 +- .../dom/parser/cpp/semantics/EvalUnaryTypeID.java | 53 +-- .../core/dom/parser/cpp/semantics/TypeTraits.java | 328 ++++++++++++++++++ .../tests/LRGCCCompleteParseExtensionsTest.java | 2 +- 18 files changed, 865 insertions(+), 492 deletions(-) delete mode 100644 core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ClassTypeHelperTests.java create mode 100644 core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/TypeTraitsTests.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeTraits.java diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java index 3cdbabd1573..dbebb3faec8 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java @@ -105,7 +105,7 @@ public class AST2BaseTest extends BaseTestCase { private static Map getGnuMap() { Map map= new HashMap(); map.put("__GNUC__", "4"); - map.put("__GNUC_MINOR__", "5"); + map.put("__GNUC_MINOR__", "7"); map.put("__SIZEOF_INT__", "4"); map.put("__SIZEOF_LONG__", "8"); return map; diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index a35448d8d20..2f54ed2d440 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -1330,7 +1330,7 @@ public class AST2TemplateTests extends AST2BaseTest { ICPPClassType sc0= assertInstance(b0.getSpecializedBinding(), ICPPClassType.class); ICPPClassType sc1= assertInstance(b1.getSpecializedBinding(), ICPPClassType.class); assertTrue(sc0.isSameType(sc1)); - + assertInstance(b0, ICPPSpecialization.class); assertInstance(b1, ICPPTemplateInstance.class); @@ -5988,4 +5988,27 @@ public class AST2TemplateTests extends AST2BaseTest { public void testSFINAE_b() throws Exception { parseAndCheckBindings(); } + + // template + // struct is_pod { + // static const bool value = __is_pod(T); + // }; + // + // template + // struct enable_if {}; + // + // template + // struct enable_if { + // typedef T type; + // }; + // + // template + // void f(typename enable_if::value>::type* = 0); + // + // void test() { + // f(); + // } + public void testIsPOD_367993() throws Exception { + parseAndCheckBindings(getAboveComment(), CPP, true); + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ClassTypeHelperTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ClassTypeHelperTests.java deleted file mode 100644 index aadfeac5678..00000000000 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ClassTypeHelperTests.java +++ /dev/null @@ -1,122 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 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); - } - - // struct A { - // A(const A& a); - // }; - // - // class B { - // public: - // B(); - // int x; - // A* y; - // const A& z; - // static A s; - // }; - // - // class C { - // public: - // A a; - // }; - public void testHasTrivialCopyCtor() throws Exception { - BindingAssertionHelper helper = getAssertionHelper(); - ICPPClassType classA = helper.assertNonProblem("A {", 1, ICPPClassType.class); - assertFalse(ClassTypeHelper.hasTrivialCopyCtor(classA, null)); - ICPPClassType classB = helper.assertNonProblem("B {", 1, ICPPClassType.class); - assertTrue(ClassTypeHelper.hasTrivialCopyCtor(classB, null)); - ICPPClassType classC = helper.assertNonProblem("C {", 1, ICPPClassType.class); - assertFalse(ClassTypeHelper.hasTrivialCopyCtor(classC, null)); - } - - // struct A { - // ~A(); - // }; - // - // class B { - // public: - // B(); - // B(const B& a); - // int x; - // B* y; - // const B& z; - // static A s; - // }; - // - // class C { - // public: - // A a; - // }; - public void testHasTrivialDestructor() throws Exception { - BindingAssertionHelper helper = getAssertionHelper(); - ICPPClassType classA = helper.assertNonProblem("A {", 1, ICPPClassType.class); - assertFalse(ClassTypeHelper.hasTrivialDestructor(classA, null)); - ICPPClassType classB = helper.assertNonProblem("B {", 1, ICPPClassType.class); - assertTrue(ClassTypeHelper.hasTrivialDestructor(classB, null)); - ICPPClassType classC = helper.assertNonProblem("C {", 1, ICPPClassType.class); - assertFalse(ClassTypeHelper.hasTrivialDestructor(classC, null)); - } - - // struct A { - // virtual void m(); - // }; - // - // class B { - // public: - // B(); - // B(const B& a); - // void m(); - // int x; - // B* y; - // const B& z; - // }; - // - // class C : public A { - // }; - public void testIsPolymorphic() throws Exception { - BindingAssertionHelper helper = getAssertionHelper(); - ICPPClassType classA = helper.assertNonProblem("A {", 1, ICPPClassType.class); - assertTrue(ClassTypeHelper.isPolymorphic(classA)); - ICPPClassType classB = helper.assertNonProblem("B {", 1, ICPPClassType.class); - assertFalse(ClassTypeHelper.isPolymorphic(classB)); - ICPPClassType classC = helper.assertNonProblem("C", 1, ICPPClassType.class); - assertTrue(ClassTypeHelper.isPolymorphic(classC)); - } -} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java index aff28ece1a5..6b46417c965 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMParserTestSuite.java @@ -30,7 +30,7 @@ public class DOMParserTestSuite extends TestCase { suite.addTest(ASTCPPSpecDefectTests.suite()); suite.addTest(AST2CPPImplicitNameTests.suite()); suite.addTest(AST2TemplateTests.suite()); - suite.addTest(ClassTypeHelperTests.suite()); + suite.addTest(TypeTraitsTests.suite()); suite.addTestSuite(QuickParser2Tests.class); suite.addTest(CompleteParser2Tests.suite()); suite.addTest(DOMLocationTests.suite()); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java index be16c393abe..48f4e1a6c1a 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/GCCCompleteParseExtensionsTest.java @@ -426,7 +426,7 @@ public class GCCCompleteParseExtensionsTest extends AST2BaseTest { // b= __is_polymorphic (int); // b= __is_union (int); // } - public void testTypetraits_Bug342683() throws Exception { + public void testTypeTraits_Bug342683() throws Exception { parseGPP(getAboveComment()); } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/TypeTraitsTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/TypeTraitsTests.java new file mode 100644 index 00000000000..7fff28bb67d --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/TypeTraitsTests.java @@ -0,0 +1,239 @@ +/******************************************************************************* + * Copyright (c) 2011, 2012 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.semantics.TypeTraits; +import org.eclipse.cdt.internal.core.parser.ParserException; + +/** + * Tests for ClassTypeHelper class. + */ +public class TypeTraitsTests extends AST2BaseTest { + + public TypeTraitsTests() { + } + + public TypeTraitsTests(String name) { + super(name); + } + + public static TestSuite suite() { + return suite(TypeTraitsTests.class); + } + + protected BindingAssertionHelper getAssertionHelper() throws ParserException, IOException { + String code= getAboveComment(); + return new BindingAssertionHelper(code, true); + } + + // struct A { + // A(const A& a); + // }; + // + // class B { + // public: + // B(); + // int x; + // A* y; + // const A& z; + // static A s; + // }; + // + // class C { + // public: + // A a; + // }; + public void testHasTrivialCopyCtor() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + ICPPClassType classA = helper.assertNonProblem("A {", 1, ICPPClassType.class); + assertFalse(TypeTraits.hasTrivialCopyCtor(classA, null)); + ICPPClassType classB = helper.assertNonProblem("B {", 1, ICPPClassType.class); + assertTrue(TypeTraits.hasTrivialCopyCtor(classB, null)); + ICPPClassType classC = helper.assertNonProblem("C {", 1, ICPPClassType.class); + assertFalse(TypeTraits.hasTrivialCopyCtor(classC, null)); + } + + // struct A { + // ~A(); + // }; + // + // class B { + // public: + // B(); + // B(const B& a); + // int x; + // B* y; + // const B& z; + // static A s; + // }; + // + // class C { + // public: + // A a; + // }; + public void testHasTrivialDestructor() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + ICPPClassType classA = helper.assertNonProblem("A {", 1, ICPPClassType.class); + assertFalse(TypeTraits.hasTrivialDestructor(classA, null)); + ICPPClassType classB = helper.assertNonProblem("B {", 1, ICPPClassType.class); + assertTrue(TypeTraits.hasTrivialDestructor(classB, null)); + ICPPClassType classC = helper.assertNonProblem("C {", 1, ICPPClassType.class); + assertFalse(TypeTraits.hasTrivialDestructor(classC, null)); + } + + // struct A { + // virtual void m(); + // }; + // + // class B { + // public: + // B(); + // B(const B& a); + // void m(); + // int x; + // B* y; + // const B& z; + // }; + // + // class C : public A { + // }; + public void testIsPolymorphic() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + ICPPClassType classA = helper.assertNonProblem("A {", 1, ICPPClassType.class); + assertTrue(TypeTraits.isPolymorphic(classA, null)); + ICPPClassType classB = helper.assertNonProblem("B {", 1, ICPPClassType.class); + assertFalse(TypeTraits.isPolymorphic(classB, null)); + ICPPClassType classC = helper.assertNonProblem("C", 1, ICPPClassType.class); + assertTrue(TypeTraits.isPolymorphic(classC, null)); + } + + // struct A { + // A* a; + // int b; + // A(A* a, int b); + // A(A& a); + // ~A(); + // }; + // + // class B : public A { + // static int c; + // void m(A* a); + // }; + // + // class C : public A { + // int c; + // }; + // + // struct D { + // C c; + // }; + // + // struct E : public C { + // }; + // + // struct F : public B { + // virtual ~F(); + // }; + // + // struct G { + // int a; + // private: + // int b; + // }; + // + // struct H { + // int& a; + // }; + public void testIsStandardLayout() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + ICPPClassType classA = helper.assertNonProblem("A {", 1, ICPPClassType.class); + assertTrue(TypeTraits.isStandardLayout(classA, null)); + ICPPClassType classB = helper.assertNonProblem("B {", 1, ICPPClassType.class); + assertTrue(TypeTraits.isStandardLayout(classB, null)); + ICPPClassType classC = helper.assertNonProblem("C :", 1, ICPPClassType.class); + assertFalse(TypeTraits.isStandardLayout(classC, null)); + ICPPClassType classD = helper.assertNonProblem("D {", 1, ICPPClassType.class); + assertFalse(TypeTraits.isStandardLayout(classD, null)); + ICPPClassType classE = helper.assertNonProblem("E :", 1, ICPPClassType.class); + assertFalse(TypeTraits.isStandardLayout(classE, null)); + ICPPClassType classF = helper.assertNonProblem("F :", 1, ICPPClassType.class); + assertFalse(TypeTraits.isStandardLayout(classF, null)); + ICPPClassType classG = helper.assertNonProblem("G {", 1, ICPPClassType.class); + assertFalse(TypeTraits.isStandardLayout(classG, null)); + ICPPClassType classH = helper.assertNonProblem("H {", 1, ICPPClassType.class); + assertFalse(TypeTraits.isStandardLayout(classH, null)); + } + + // struct A { + // A* a; + // int b; + // A(char* s); + // A(const A& a, int b); + // A& operator =(const A& a, A* b); + // }; + // + // class B : public A { + // A a; + // }; + // + // struct C { + // C(char* s = 0); + // }; + // + // struct D { + // D(const D& a, int b = 1); + // }; + // + // struct E { + // E& operator =(const E& a, E* b = nullptr); + // }; + // + // struct F { + // ~F(); + // }; + // + // struct G { + // C c; + // }; + // + // struct H : public C { + // }; + // + // struct I { + // virtual void m(); + // }; + public void testIsTrivial() throws Exception { + BindingAssertionHelper helper = getAssertionHelper(); + ICPPClassType classA = helper.assertNonProblem("A {", 1, ICPPClassType.class); + assertTrue(TypeTraits.isTrivial(classA, null)); + ICPPClassType classB = helper.assertNonProblem("B :", 1, ICPPClassType.class); + assertTrue(TypeTraits.isTrivial(classB, null)); + ICPPClassType classC = helper.assertNonProblem("C {", 1, ICPPClassType.class); + assertFalse(TypeTraits.isTrivial(classC, null)); + ICPPClassType classD = helper.assertNonProblem("D {", 1, ICPPClassType.class); + assertFalse(TypeTraits.isTrivial(classD, null)); + ICPPClassType classE = helper.assertNonProblem("E {", 1, ICPPClassType.class); + assertFalse(TypeTraits.isTrivial(classE, null)); + ICPPClassType classF = helper.assertNonProblem("F {", 1, ICPPClassType.class); + assertFalse(TypeTraits.isTrivial(classF, null)); + ICPPClassType classG = helper.assertNonProblem("G {", 1, ICPPClassType.class); + assertFalse(TypeTraits.isTrivial(classG, null)); + ICPPClassType classH = helper.assertNonProblem("H :", 1, ICPPClassType.class); + assertFalse(TypeTraits.isTrivial(classH, null)); + ICPPClassType classI = helper.assertNonProblem("I {", 1, ICPPClassType.class); + assertFalse(TypeTraits.isTrivial(classI, null)); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/rewrite/TypeHelper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/rewrite/TypeHelper.java index 6283e41a767..64d073363f3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/rewrite/TypeHelper.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/rewrite/TypeHelper.java @@ -20,9 +20,9 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit; import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator; import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment; import org.eclipse.cdt.internal.core.dom.parser.c.CVisitor; -import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.TypeTraits; /** * A collection of static methods related to types. @@ -48,8 +48,8 @@ public class TypeHelper { if (type instanceof ICompositeType) { if (type instanceof ICPPClassType) { ICPPClassType classType = ((ICPPClassType) type); - if (!ClassTypeHelper.hasTrivialCopyCtor(classType, ast) || - !ClassTypeHelper.hasTrivialDestructor(classType, ast)) { + if (!TypeTraits.hasTrivialCopyCtor(classType, ast) || + !TypeTraits.hasTrivialDestructor(classType, ast)) { return true; } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java index cdc024cd703..b8d7de011e3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java @@ -13,6 +13,7 @@ package org.eclipse.cdt.internal.core.dom.parser; import java.util.HashMap; import java.util.Map; +import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IArrayType; @@ -73,6 +74,20 @@ public class SizeofCalculator { private final IASTTranslationUnit ast; + /** + * Calculates size and alignment for the given type. + * + * @param type the type to get size and alignment for. + * @param point a node belonging to the AST of the translation unit defining context for + * the size calculation. + * @return size and alignment, or null if could not be calculated. + */ + public static SizeAndAlignment getSizeAndAlignment(IType type, IASTNode point) { + SizeofCalculator calc = point == null ? + getDefault() : ((ASTTranslationUnit) point.getTranslationUnit()).getSizeofCalculator(); + return calc.sizeAndAlignment(type); + } + /** * Returns the default instance of sizeof calculator. The default instance is not aware * of the parser configuration and can only calculate sizes that are the same across all diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java index 44e298d51fb..a3bc301dad0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java @@ -11,29 +11,58 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_alignof; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_nothrow_constructor; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_nothrow_copy; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_assign; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_constructor; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_copy; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_trivial_destructor; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_has_virtual_destructor; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_abstract; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_class; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_empty; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_enum; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_literal_type; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_pod; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_polymorphic; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_standard_layout; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_trivial; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_is_union; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_sizeof; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_typeid; +import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_typeof; + import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; +import org.eclipse.cdt.core.dom.ast.IASTBinaryTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTCastExpression; import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; +import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.ICompositeType; +import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumerator; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalBinding; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.TypeTraits; import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator; import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator.EvalException; import org.eclipse.cdt.internal.core.pdom.db.TypeMarshalBuffer; @@ -201,7 +230,7 @@ public class Value implements IValue { public static IValue evaluateBinaryExpression(final int op, final long v1, final long v2) { try { - return create(combineBinary(op, v1, v2)); + return create(applyBinaryOperator(op, v1, v2)); } catch (UnknownValueException e) { } return UNKNOWN; @@ -209,12 +238,101 @@ public class Value implements IValue { public static IValue evaluateUnaryExpression(final int unaryOp, final long value) { try { - return create(combineUnary(unaryOp, value)); + return create(applyUnaryOperator(unaryOp, value)); } catch (UnknownValueException e) { } return UNKNOWN; } + public static IValue evaluateUnaryTypeIdExpression(int operator, IType type, IASTNode point) { + try { + return create(applyUnaryTypeIdOperator(operator, type, point)); + } catch (UnknownValueException e) { + } + return UNKNOWN; + } + + public static IValue evaluateBinaryTypeIdExpression(IASTBinaryTypeIdExpression.Operator operator, + IType type1, IType type2, IASTNode point) { + try { + return create(applyBinaryTypeIdOperator(operator, type1, type2, point)); + } catch (UnknownValueException e) { + } + return UNKNOWN; + } + + private static long applyUnaryTypeIdOperator(int operator, IType type, IASTNode point) throws UnknownValueException{ + switch (operator) { + case op_sizeof: + return getSizeAndAlignment(type, point).size; + case op_alignof: + return getSizeAndAlignment(type, point).alignment; + case op_typeid: + break; // TODO(sprigogin): Implement + case op_has_nothrow_copy: + break; // TODO(sprigogin): Implement + case op_has_nothrow_constructor: + break; // TODO(sprigogin): Implement + case op_has_trivial_assign: + break; // TODO(sprigogin): Implement + case op_has_trivial_constructor: + break; // TODO(sprigogin): Implement + case op_has_trivial_copy: + return !(type instanceof ICPPClassType) || + TypeTraits.hasTrivialCopyCtor((ICPPClassType) type, point) ? 1 : 0; + case op_has_trivial_destructor: + break; // TODO(sprigogin): Implement + case op_has_virtual_destructor: + break; // TODO(sprigogin): Implement + case op_is_abstract: + return type instanceof ICPPClassType && + TypeTraits.isAbstract((ICPPClassType) type, point) ? 1 : 0; + case op_is_class: + return type instanceof ICompositeType && + ((ICompositeType) type).getKey() != ICompositeType.k_union ? 1 : 0; + case op_is_empty: + break; // TODO(sprigogin): Implement + case op_is_enum: + return type instanceof IEnumeration ? 1 : 0; + case op_is_literal_type: + break; // TODO(sprigogin): Implement + case op_is_pod: + return TypeTraits.isPOD(type, point) ? 1 : 0; + case op_is_polymorphic: + return type instanceof ICPPClassType && + TypeTraits.isPolymorphic((ICPPClassType) type, point) ? 1 : 0; + case op_is_standard_layout: + return TypeTraits.isStandardLayout(type, point) ? 1 : 0; + case op_is_trivial: + return type instanceof ICPPClassType && + TypeTraits.isTrivial((ICPPClassType) type, point) ? 1 : 0; + case op_is_union: + return type instanceof ICompositeType && + ((ICompositeType) type).getKey() == ICompositeType.k_union ? 1 : 0; + case op_typeof: + break; // TODO(sprigogin): Implement + } + throw UNKNOWN_EX; + } + + public static long applyBinaryTypeIdOperator(IASTBinaryTypeIdExpression.Operator operator, + IType type1, IType type2, IASTNode point) throws UnknownValueException { + switch (operator) { + case __is_base_of: + if (type1 instanceof ICPPClassType && type1 instanceof ICPPClassType) { + return ClassTypeHelper.isSubclass((ICPPClassType) type2, (ICPPClassType) type1) ? 1 : 0; + } + } + throw UNKNOWN_EX; + } + + private static SizeAndAlignment getSizeAndAlignment(IType type, IASTNode point) throws UnknownValueException { + SizeAndAlignment sizeAndAlignment = SizeofCalculator.getSizeAndAlignment(type, point); + if (sizeAndAlignment == null) + throw UNKNOWN_EX; + return sizeAndAlignment; + } + /** * Tests whether the value is a template parameter (or a parameter pack). * @@ -348,19 +466,15 @@ public class Value implements IValue { } } if (exp instanceof IASTTypeIdExpression) { - IASTTypeIdExpression typeIdEx = (IASTTypeIdExpression) exp; - switch (typeIdEx.getOperator()) { - case IASTTypeIdExpression.op_sizeof: - ASTTranslationUnit ast = (ASTTranslationUnit) typeIdEx.getTranslationUnit(); - final IType type = ast.createType(typeIdEx.getTypeId()); - if (type instanceof ICPPUnknownType) - return null; - SizeofCalculator calculator = ast.getSizeofCalculator(); - SizeAndAlignment info = calculator.sizeAndAlignment(type); - if (info == null) - throw UNKNOWN_EX; - return info.size; - } + ASTTranslationUnit ast = (ASTTranslationUnit) exp.getTranslationUnit(); + final IType type = ast.createType(((IASTTypeIdExpression) exp).getTypeId()); + if (type instanceof ICPPUnknownType) + return null; + return applyUnaryTypeIdOperator(((IASTTypeIdExpression) exp).getOperator(), type, exp); + } + + if (exp instanceof IASTBinaryTypeIdExpression) { + } throw UNKNOWN_EX; } @@ -422,10 +536,10 @@ public class Value implements IValue { final Long value= evaluate(exp.getOperand(), maxdepth); if (value == null) return null; - return combineUnary(unaryOp, value); + return applyUnaryOperator(unaryOp, value); } - private static long combineUnary(final int unaryOp, final long value) throws UnknownValueException { + private static long applyUnaryOperator(final int unaryOp, final long value) throws UnknownValueException { switch (unaryOp) { case IASTUnaryExpression.op_bracketedPrimary: case IASTUnaryExpression.op_plus: @@ -470,10 +584,10 @@ public class Value implements IValue { if (o2 == null) return null; - return combineBinary(op, o1, o2); + return applyBinaryOperator(op, o1, o2); } - private static long combineBinary(final int op, final long v1, final long v2) + private static long applyBinaryOperator(final int op, final long v1, final long v2) throws UnknownValueException { switch (op) { case IASTBinaryExpression.op_multiply: diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java index 3ddeba3b2fb..615bb1a3eb8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java @@ -15,9 +15,6 @@ *******************************************************************************/ 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; @@ -39,7 +36,6 @@ import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IField; -import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IQualifierType; import org.eclipse.cdt.core.dom.ast.IScope; @@ -60,8 +56,8 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; import org.eclipse.cdt.core.index.IIndex; @@ -78,8 +74,8 @@ import org.eclipse.core.runtime.CoreException; /** * Holds common implementation of methods for ICPPClassType implementations that have - * a corresponding textual definition in the source code. - * + * a corresponding textual definition in the source code. + * * @see CPPClassType * @see CPPClassTemplate */ @@ -101,8 +97,9 @@ public class ClassTypeHelper { ObjectSet resultSet = new ObjectSet(2); IASTDeclaration[] members = host.getCompositeTypeSpecifier().getMembers(); for (IASTDeclaration decl : members) { - while (decl instanceof ICPPASTTemplateDeclaration) + while (decl instanceof ICPPASTTemplateDeclaration) { decl = ((ICPPASTTemplateDeclaration) decl).getDeclaration(); + } if (decl instanceof IASTSimpleDeclaration) { ICPPASTDeclSpecifier declSpec = (ICPPASTDeclSpecifier) ((IASTSimpleDeclaration) decl).getDeclSpecifier(); @@ -115,7 +112,7 @@ public class ClassTypeHelper { if (dtor == null) break; dtor= ASTQueries.findInnermostDeclarator(dtor); resultSet.put(dtor.getName().resolveBinding()); - } + } } } } else if (decl instanceof IASTFunctionDefinition) { @@ -134,7 +131,7 @@ public class ClassTypeHelper { /** * Checks if a binding is a friend of a class. Only classes and functions can be friends of a class. * A class is considered a friend of itself. - * @param binding a binding. + * @param binding a binding. * @param classType a class. * @return true if binding is a friend of classType. */ @@ -198,7 +195,7 @@ public class ClassTypeHelper { bindings[i] = new CPPBaseClause(bases[i]); } - return bindings; + return bindings; } public static ICPPField[] getDeclaredFields(ICPPInternalClassTypeMixinHost host) { @@ -278,7 +275,7 @@ public class ClassTypeHelper { } /** - * Returns all direct and indirect base classes. + * Returns all direct and indirect base classes. * @param classType a class * @return An array of visible base classes in arbitrary order. */ @@ -296,7 +293,7 @@ public class ClassTypeHelper { IBinding b= base.getBaseClass(); if (b instanceof ICPPClassType) { final ICPPClassType baseClass = (ICPPClassType) b; - if (result.add(baseClass)) { + if (result.add(baseClass)) { getAllBases(baseClass, result, point); } } @@ -346,7 +343,7 @@ public class ClassTypeHelper { /** * Returns methods either declared by the given class or generated by the compiler. Does not - * include methods declared in base classes. + * include methods declared in base classes. */ private static ObjectSet getOwnMethods(ICPPClassType classType, IASTNode point) { ObjectSet set= new ObjectSet(4); @@ -460,7 +457,7 @@ public class ClassTypeHelper { } if (binding instanceof ICPPClassType) result = ArrayUtil.append(ICPPClassType.class, result, (ICPPClassType) binding); - } + } } return ArrayUtil.trim(ICPPClassType.class, result); } @@ -498,7 +495,7 @@ public class ClassTypeHelper { public static boolean isVirtual(ICPPMethod m) { if (m instanceof ICPPConstructor) return false; - if (m.isVirtual()) + if (m.isVirtual()) return true; final char[] mname= m.getNameCharArray(); @@ -528,7 +525,7 @@ public class ClassTypeHelper { IType[] paramsA = a.getParameterTypes(); IType[] paramsB = b.getParameterTypes(); - + if (paramsA.length == 1 && paramsB.length == 0) { if (!SemanticUtil.isVoidType(paramsA[0])) return false; @@ -550,9 +547,9 @@ public class ClassTypeHelper { * Returns {@code true} if {@code source} overrides {@code target}. */ public static boolean isOverrider(ICPPMethod source, ICPPMethod target) { - if (source instanceof ICPPConstructor || target instanceof ICPPConstructor) + if (source instanceof ICPPConstructor || target instanceof ICPPConstructor) return false; - if (!isVirtual(target)) + if (!isVirtual(target)) return false; if (!functionTypesAllowOverride(source.getType(), target.getType())) return false; @@ -580,7 +577,7 @@ public class ClassTypeHelper { final char[] mname= method.getNameCharArray(); final ICPPClassType mcl= method.getClassOwner(); - if (mcl == null) + if (mcl == null) return ICPPMethod.EMPTY_CPPMETHOD_ARRAY; final ArrayList result= new ArrayList(); @@ -646,14 +643,14 @@ public class ClassTypeHelper { /** * Returns all methods found in the index, that override the given {@code method}. - * @throws CoreException + * @throws CoreException */ public static ICPPMethod[] findOverriders(IIndex index, ICPPMethod method) throws CoreException { if (!isVirtual(method)) return ICPPMethod.EMPTY_CPPMETHOD_ARRAY; final ICPPClassType mcl= method.getClassOwner(); - if (mcl == null) + if (mcl == null) return ICPPMethod.EMPTY_CPPMETHOD_ARRAY; ICPPClassType[] subclasses= getSubClasses(index, mcl); @@ -714,24 +711,76 @@ public class ClassTypeHelper { } } - private static final int KIND_DEFAULT_CTOR= 0; - private static final int KIND_COPY_CTOR= 1; - private static final int KIND_ASSIGNMENT_OP= 2; - private static final int KIND_DTOR= 3; - private static final int KIND_OTHER= 4; + public enum MethodKind { + DEFAULT_CTOR, + COPY_CTOR, + MOVE_CTOR, + COPY_ASSIGNMENT_OP, + MOVE_ASSIGNMENT_OP, + DTOR, + OTHER + } + + public static MethodKind getMethodKind(ICPPClassType classType, ICPPMethod method) { + if (method instanceof ICPPConstructor) { + final List params= getTypesOfRequiredParameters(method); + if (params.isEmpty()) + return MethodKind.DEFAULT_CTOR; + if (params.size() == 1) { + IType t= SemanticUtil.getNestedType(params.get(0), SemanticUtil.TDEF); + if (SemanticUtil.isVoidType(t)) + return MethodKind.DEFAULT_CTOR; + + ICPPReferenceType refToClass = getRefToClass(classType, t); + if (refToClass != null) + return refToClass.isRValueReference() ? MethodKind.MOVE_CTOR : MethodKind.COPY_CTOR; + } + return MethodKind.OTHER; + } + + if (method.isDestructor()) + return MethodKind.DTOR; + + if (CharArrayUtils.equals(method.getNameCharArray(), OverloadableOperator.ASSIGN.toCharArray())) { + final List params= getTypesOfRequiredParameters(method); + if (params.size() == 1) { + IType t= params.get(0); + ICPPReferenceType refToClass = getRefToClass(classType, t); + if (refToClass != null) + return refToClass.isRValueReference() ? MethodKind.MOVE_ASSIGNMENT_OP : MethodKind.COPY_ASSIGNMENT_OP; + } + return MethodKind.OTHER; + } + return MethodKind.OTHER; + } + + /** + * Returns types of method parameters that don't have defaults. + */ + private static List getTypesOfRequiredParameters(ICPPMethod method) { + ICPPParameter[] parameters = method.getParameters(); + if (parameters.length == 0) + return Collections.emptyList(); + List types = new ArrayList(parameters.length); + for (ICPPParameter parameter : parameters) { + if (!parameter.hasDefaultValue() && !parameter.isParameterPack()) + types.add(parameter.getType()); + } + return types; + } /** - * For implicit methods the exception specification is inherited, search it + * For implicit methods the exception specification is inherited, search it. */ public static IType[] getInheritedExceptionSpecification(ICPPMethod implicitMethod, IASTNode point) { // See 15.4.13 ICPPClassType owner= implicitMethod.getClassOwner(); - if (owner == null || ClassTypeHelper.getBases(owner, point).length == 0) + if (owner == null || ClassTypeHelper.getBases(owner, point).length == 0) return null; - // we use a list as types aren't comparable, and can have duplicates (15.4.6) - int kind= getImplicitMethodKind(owner, implicitMethod); - if (kind == KIND_OTHER) + // We use a list as types aren't comparable, and can have duplicates (15.4.6) + MethodKind kind= getMethodKind(owner, implicitMethod); + if (kind == MethodKind.OTHER) return null; List inheritedTypeids = new ArrayList(); @@ -741,7 +790,7 @@ public class ClassTypeHelper { ICPPMethod baseMethod= getMethodInClass(base, kind, point); if (baseMethod != null) { IType[] baseExceptionSpec= baseMethod.getExceptionSpecification(); - if (baseExceptionSpec == null) + if (baseExceptionSpec == null) return null; for (IType baseTypeId : baseMethod.getExceptionSpecification()) { inheritedTypeids.add(baseTypeId); @@ -752,275 +801,71 @@ public class ClassTypeHelper { return inheritedTypeids.toArray(new IType[inheritedTypeids.size()]); } - private static int getImplicitMethodKind(ICPPClassType ct, ICPPMethod method) { - if (method instanceof ICPPConstructor) { - final IFunctionType type= method.getType(); - final IType[] params= type.getParameterTypes(); - if (params.length == 0) - return KIND_DEFAULT_CTOR; - if (params.length == 1) { - IType t= SemanticUtil.getNestedType(params[0], SemanticUtil.TDEF); - if (SemanticUtil.isVoidType(t)) - return KIND_DEFAULT_CTOR; - - if (isRefToConstClass(ct, t)) - return KIND_COPY_CTOR; - } - return KIND_OTHER; + /** + * If {@code type} is a, possibly qualified, reference type referring to {@code classType}, + * returns that reference type. Otherwise returns {@code null}. + */ + private static ICPPReferenceType getRefToClass(ICPPClassType classType, IType type) { + while (type instanceof ITypedef) { + type= ((ITypedef) type).getType(); } - if (method.isDestructor()) - return KIND_DTOR; - - if (CharArrayUtils.equals(method.getNameCharArray(), OverloadableOperator.ASSIGN.toCharArray())) { - final IFunctionType type= method.getType(); - final IType[] params= type.getParameterTypes(); - if (params.length == 1) { - IType t= params[0]; - if (isRefToConstClass(ct, t)) - return KIND_ASSIGNMENT_OP; + if (type instanceof ICPPReferenceType) { + ICPPReferenceType refType = (ICPPReferenceType) type; + type= refType.getType(); + while (type instanceof ITypedef) { + type= ((ITypedef) type).getType(); } - return KIND_OTHER; - } - return KIND_OTHER; - } - - private static boolean isRefToConstClass(ICPPClassType ct, IType t) { - while (t instanceof ITypedef) - t= ((ITypedef) t).getType(); - - if (t instanceof ICPPReferenceType) { - t= ((ICPPReferenceType) t).getType(); - while (t instanceof ITypedef) - t= ((ITypedef) t).getType(); - if (t instanceof IQualifierType) { - t= ((IQualifierType) t).getType(); - return ct.isSameType(t); + if (type instanceof IQualifierType) { + type= ((IQualifierType) type).getType(); + if (classType.isSameType(type)) + return refType; } } - return false; + return null; } - private static ICPPMethod getMethodInClass(ICPPClassType ct, int kind, IASTNode point) { + private static ICPPMethod getMethodInClass(ICPPClassType ct, MethodKind kind, IASTNode point) { switch (kind) { - case KIND_DEFAULT_CTOR: - case KIND_COPY_CTOR: + case DEFAULT_CTOR: + case COPY_CTOR: + case MOVE_CTOR: for (ICPPConstructor ctor : getConstructors(ct, point)) { - if (!ctor.isImplicit() && getImplicitMethodKind(ct, ctor) == kind) + if (!ctor.isImplicit() && getMethodKind(ct, ctor) == kind) return ctor; } return null; - case KIND_ASSIGNMENT_OP: + case COPY_ASSIGNMENT_OP: + case MOVE_ASSIGNMENT_OP: for (ICPPMethod method : getDeclaredMethods(ct, point)) { if (method instanceof ICPPConstructor) continue; - if (getImplicitMethodKind(ct, method) == kind) + if (getMethodKind(ct, method) == kind) return method; } return null; - case KIND_DTOR: + case DTOR: for (ICPPMethod method : getDeclaredMethods(ct, point)) { if (method.isDestructor()) return method; } return null; + case OTHER: + break; } return null; } - /** - * 8.5.1 Aggregates [dcl.init.aggr] - * An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), - * no private or protected non-static data members (Clause 11), - * no base classes (Clause 10), and no virtual functions (10.3). - */ - public static boolean isAggregateClass(ICPPClassType classTarget, IASTNode point) { - if (ClassTypeHelper.getBases(classTarget, point).length > 0) - return false; - ICPPMethod[] methods = ClassTypeHelper.getDeclaredMethods(classTarget, point); - for (ICPPMethod m : methods) { - if (m instanceof ICPPConstructor) - return false; - if (m.isVirtual()) { - return false; - } - } - ICPPField[] fields = ClassTypeHelper.getDeclaredFields(classTarget, point); - for (ICPPField field : fields) { - if (!(field.getVisibility() == ICPPMember.v_public || field.isStatic())) { - return false; - } - } - return true; - } - - /** - * Returns true if and only if the given class has a trivial copy constructor. - * A copy constructor is trivial if: - *
    - *
  • it is implicitly defined by the compiler, and
  • - *
  • isPolymorphic(classTarget) == false, and
  • - *
  • the class has no virtual base classes, and
  • - *
  • every direct base class has trivial copy constructor, and
  • - *
  • for every nonstatic data member that has class type or array of class type, that type - * has trivial copy constructor.
  • - *
- * Similar to std::tr1::has_trivial_copy. - * - * @param classTarget the class to check - * @return true if the class has a trivial copy constructor - */ - public static boolean hasTrivialCopyCtor(ICPPClassType classTarget, IASTNode point) { - 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, point)) { - if (!classTarget.isSameType(baseClass) && !hasTrivialCopyCtor(baseClass, point)) - 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, point)) { - return false; - } - } - } - return true; - } - - /** - * Returns the compiler-generated copy constructor for the given class, or null - * 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 null 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 true if and only if the given class has a trivial default constructor. - * A default constructor is trivial if: - *
    - *
  • it is implicitly defined by the compiler, and
  • - *
  • every direct base class has trivial default constructor, and
  • - *
  • for every nonstatic data member that has class type or array of class type, that type - * has trivial default constructor.
  • - *
- * Similar to std::tr1::has_trivial_default_constructor. - * - * @param classTarget the class to check - * @param point - * @return true if the class has a trivial default constructor - */ - public static boolean hasTrivialDefaultConstructor(ICPPClassType classTarget, IASTNode point) { - for (ICPPConstructor ctor : getConstructors(classTarget, point)) { - if (!ctor.isImplicit() && ctor.getParameters().length == 0) - return false; - } - for (ICPPClassType baseClass : getAllBases(classTarget, null)) { - if (!classTarget.isSameType(baseClass) && !hasTrivialDefaultConstructor(baseClass, point)) - return false; - } - for (ICPPField field : getDeclaredFields(classTarget, point)) { - if (!field.isStatic()) { - IType type = field.getType(); - type = SemanticUtil.getNestedType(type, TDEF | CVTYPE | ARRAY); - if (type instanceof ICPPClassType && !classTarget.isSameType(type) && - !hasTrivialDefaultConstructor((ICPPClassType) type, point)) { - return false; - } - } - } - return true; - } - - /** - * Returns true if and only if the given class has a trivial destructor. - * A destructor is trivial if: - *
    - *
  • it is implicitly defined by the compiler, and
  • - *
  • every direct base class has trivial destructor, and
  • - *
  • for every nonstatic data member that has class type or array of class type, that type - * has trivial destructor.
  • - *
- * Similar to std::tr1::has_trivial_destructor. - * - * @param classTarget the class to check - * @return true if the class has a trivial destructor - */ - public static boolean hasTrivialDestructor(ICPPClassType classTarget, IASTNode point) { - for (ICPPMethod method : getDeclaredMethods(classTarget, point)) { - if (method.isDestructor()) - return false; - } - for (ICPPClassType baseClass : getAllBases(classTarget, null)) { - if (!classTarget.isSameType(baseClass) && !hasTrivialDestructor(baseClass, point)) - return false; - } - for (ICPPField field : getDeclaredFields(classTarget, point)) { - if (!field.isStatic()) { - IType type = field.getType(); - type = SemanticUtil.getNestedType(type, TDEF | CVTYPE | ARRAY); - if (type instanceof ICPPClassType && !classTarget.isSameType(type) && - !hasTrivialDestructor((ICPPClassType) type, point)) { - return false; - } - } - } - return true; - } - - /** - * Returns true if and only if the given class declares or inherits a virtual - * function. Similar to std::tr1::is_polymorphic. - * - * @param classTarget the class to check - * @return true 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, null)) { - 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. - * + * * NOTE: The method produces complete results for template instantiations * but doesn't take into account base classes and methods dependent on unspecified * template parameters. */ public static ICPPMethod[] getPureVirtualMethods(ICPPClassType classType, IASTNode point) { - Map> result= collectPureVirtualMethods(classType, + Map> result= collectPureVirtualMethods(classType, new HashMap>>(), point); int resultArraySize = 0; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java index 53b6ff28028..8c2d30ed54c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPEvaluation.java @@ -23,12 +23,9 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; -import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit; import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation; import org.eclipse.cdt.internal.core.dom.parser.ISerializableType; import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; -import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator; -import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment; import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeArgument; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; @@ -250,11 +247,4 @@ public abstract class CPPEvaluation implements ICPPEvaluation { } return args; } - - protected static SizeAndAlignment getSizeAndAlignment(IType type, IASTNode point) { - SizeofCalculator calc = point == null ? - SizeofCalculator.getDefault() : - ((ASTTranslationUnit) point.getTranslationUnit()).getSizeofCalculator(); - return calc.sizeAndAlignment(type); - } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java index 4086f1bd98c..5a07c5e916f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVariableReadWriteFlags.java @@ -32,7 +32,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer; import org.eclipse.cdt.internal.core.dom.parser.VariableReadWriteFlags; -import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; /** @@ -61,7 +60,7 @@ public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags { IType type = CPPVisitor.createType(parent); if (type instanceof ICPPUnknownType || type instanceof ICPPClassType && - !ClassTypeHelper.hasTrivialDefaultConstructor((ICPPClassType) type, parent)) { + !TypeTraits.hasTrivialDefaultConstructor((ICPPClassType) type, parent)) { return WRITE; } return super.rwInDeclarator(parent, indirection); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java index ccf06ec82a4..267b5c018dd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java @@ -368,7 +368,7 @@ public class Conversions { return Cost.NO_CONVERSION; ICPPClassType classTarget= (ICPPClassType) noCVTarget; - if (ClassTypeHelper.isAggregateClass(classTarget, point)) { + if (TypeTraits.isAggregateClass(classTarget, point)) { Cost cost= new Cost(arg.getTypeOrFunctionSet(point), target, Rank.IDENTITY); cost.setUserDefinedConversion(null); return cost; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java index 707e19f45e3..abdbd08a752 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalBinaryTypeId.java @@ -20,14 +20,12 @@ import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation; import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; import org.eclipse.cdt.internal.core.dom.parser.ProblemType; import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; -import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.core.runtime.CoreException; @@ -83,13 +81,7 @@ public class EvalBinaryTypeId extends CPPEvaluation { if (isValueDependent()) return Value.create(this); - switch (fOperator) { - case __is_base_of: - if (!(fType1 instanceof ICPPClassType) || !(fType1 instanceof ICPPClassType)) - return Value.UNKNOWN; - return Value.create(ClassTypeHelper.isSubclass((ICPPClassType) fType2, (ICPPClassType) fType1)); - } - return Value.create(this); + return Value.evaluateBinaryTypeIdExpression(fOperator, fType1, fType2, point); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java index 7a74dc34041..97632357044 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnary.java @@ -49,6 +49,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation; import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; import org.eclipse.cdt.internal.core.dom.parser.ProblemType; +import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator; import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment; import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArithmeticConversion; @@ -219,11 +220,11 @@ public class EvalUnary extends CPPEvaluation { switch (fOperator) { case op_sizeof: { - SizeAndAlignment info = getSizeAndAlignment(fArgument.getTypeOrFunctionSet(point), point); + SizeAndAlignment info = SizeofCalculator.getSizeAndAlignment(fArgument.getTypeOrFunctionSet(point), point); return info == null ? Value.UNKNOWN : Value.create(info.size); } case op_alignOf: { - SizeAndAlignment info = getSizeAndAlignment(fArgument.getTypeOrFunctionSet(point), point); + SizeAndAlignment info = SizeofCalculator.getSizeAndAlignment(fArgument.getTypeOrFunctionSet(point), point); return info == null ? Value.UNKNOWN : Value.create(info.alignment); } case op_noexcept: diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java index 241fb626f72..06eb32de63f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalUnaryTypeID.java @@ -37,8 +37,6 @@ import static org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression.op_typeof; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; -import org.eclipse.cdt.core.dom.ast.ICompositeType; -import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; @@ -46,7 +44,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation; import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; import org.eclipse.cdt.internal.core.dom.parser.ProblemType; -import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator.SizeAndAlignment; import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; @@ -163,55 +160,7 @@ public class EvalUnaryTypeID extends CPPEvaluation { if (isValueDependent()) return Value.create(this); - switch (fOperator) { - case op_sizeof: { - SizeAndAlignment info = getSizeAndAlignment(fOrigType, point); - return info == null ? Value.UNKNOWN : Value.create(info.size); - } - case op_alignof: { - SizeAndAlignment info = getSizeAndAlignment(fOrigType, point); - return info == null ? Value.UNKNOWN : Value.create(info.alignment); - } - case op_typeid: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_has_nothrow_copy: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_has_nothrow_constructor: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_has_trivial_assign: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_has_trivial_constructor: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_has_trivial_copy: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_has_trivial_destructor: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_has_virtual_destructor: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_is_abstract: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_is_class: - return Value.create(fOrigType instanceof ICompositeType && ((ICompositeType) fOrigType).getKey() != ICompositeType.k_union); - case op_is_empty: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_is_enum: - return Value.create(fOrigType instanceof IEnumeration); - case op_is_literal_type: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_is_pod: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_is_polymorphic: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_is_standard_layout: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_is_trivial: - return Value.UNKNOWN; // TODO(sprigogin): Implement - case op_is_union: - return Value.create(fOrigType instanceof ICompositeType && ((ICompositeType) fOrigType).getKey() == ICompositeType.k_union); - case op_typeof: - return Value.UNKNOWN; // TODO(sprigogin): Implement - } - return Value.create(this); + return Value.evaluateUnaryTypeIdExpression(fOperator, fOrigType, point); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeTraits.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeTraits.java new file mode 100644 index 00000000000..71454ab5d6e --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TypeTraits.java @@ -0,0 +1,328 @@ +/******************************************************************************* + * Copyright (c) 2012 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.internal.core.dom.parser.cpp.semantics; + +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 org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IType; +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.dom.ast.cpp.ICPPField; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper.MethodKind; + +/** + * A collection of static methods for determining type traits. + */ +public class TypeTraits { + private TypeTraits() {} + + /** + * C++11: 9-6 + */ + public static boolean isTrivial(ICPPClassType classType, IASTNode point) { + for (ICPPMethod method : ClassTypeHelper.getDeclaredMethods(classType, point)) { + if (method.isVirtual()) + return false; + switch (ClassTypeHelper.getMethodKind(classType, method)) { + case DEFAULT_CTOR: + case COPY_CTOR: + case MOVE_CTOR: + case COPY_ASSIGNMENT_OP: + case MOVE_ASSIGNMENT_OP: + case DTOR: + return false; + default: + break; + } + } + ICPPField[] fields = ClassTypeHelper.getDeclaredFields(classType, point); + for (ICPPField field : fields) { + if (!field.isStatic()) { + IType fieldType = SemanticUtil.getNestedType(field.getType(), TDEF); + if (fieldType instanceof ICPPClassType && !isTrivial((ICPPClassType) fieldType, point)) + return false; + } + } + for (ICPPBase base : ClassTypeHelper.getBases(classType, point)) { + if (base.isVirtual()) + return false; + } + ICPPClassType[] baseClasses = ClassTypeHelper.getAllBases(classType, point); + for (ICPPClassType baseClass : baseClasses) { + if (!isTrivial(baseClass, point)) + return false; + } + return true; + } + + /** + * C++11: 9-7 + */ + public static boolean isStandardLayout(IType type, IASTNode point) { + type = SemanticUtil.getNestedType(type, ARRAY | CVTYPE | TDEF); + if (type instanceof ICPPReferenceType) + return false; + if (!(type instanceof ICPPClassType)) + return true; + ICPPClassType classType = (ICPPClassType) type; + int visibility = 0; + ICPPField firstNonStaticField = null; + ICPPField[] fields = ClassTypeHelper.getDeclaredFields(classType, point); + for (ICPPField field : fields) { + if (!field.isStatic()) { + if (!isStandardLayout(field.getType(), point)) + return false; + int vis = field.getVisibility(); + if (visibility == 0) { + visibility = vis; + } else if (vis != visibility) { + return false; + } + if (firstNonStaticField == null) + firstNonStaticField = field; + } + } + if (hasDeclaredVirtualMethod(classType, point)) + return false; + for (ICPPBase base : ClassTypeHelper.getBases(classType, point)) { + if (base.isVirtual()) + return false; + } + ICPPClassType[] baseClasses = ClassTypeHelper.getAllBases(classType, point); + for (ICPPClassType baseClass : baseClasses) { + if (!isStandardLayout(baseClass, point)) + return false; + if (firstNonStaticField != null) { + if (TypeTraits.hasNonStaticFields(baseClass, point)) + return false; + if (firstNonStaticField.getType().isSameType(baseClass)) + return false; + } + } + return true; + } + + /** + * C++11: 9-10 + */ + public static boolean isPOD(IType type, IASTNode point) { + if (!isStandardLayout(type, point)) + return false; + type = SemanticUtil.getNestedType(type, ARRAY | CVTYPE | TDEF); + if (!(type instanceof ICPPClassType)) + return true; + return isTrivial((ICPPClassType) type, point); + } + + /** + * 8.5.1 Aggregates [dcl.init.aggr] + * An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), + * no private or protected non-static data members (Clause 11), + * no base classes (Clause 10), and no virtual functions (10.3). + */ + public static boolean isAggregateClass(ICPPClassType classType, IASTNode point) { + if (ClassTypeHelper.getBases(classType, point).length > 0) + return false; + ICPPMethod[] methods = ClassTypeHelper.getDeclaredMethods(classType, point); + for (ICPPMethod m : methods) { + if (m instanceof ICPPConstructor) + return false; + if (m.isVirtual()) { + return false; + } + } + ICPPField[] fields = ClassTypeHelper.getDeclaredFields(classType, point); + for (ICPPField field : fields) { + if (!(field.getVisibility() == ICPPMember.v_public || field.isStatic())) { + return false; + } + } + return true; + } + + /** + * Returns true if and only if the given class has a trivial copy constructor. + * A copy constructor is trivial if: + *
    + *
  • it is implicitly defined by the compiler, and
  • + *
  • isPolymorphic(classType) is false, and
  • + *
  • the class has no virtual base classes, and
  • + *
  • every direct base class has trivial copy constructor, and
  • + *
  • for every nonstatic data member that has class type or array of class type, that type + * has trivial copy constructor.
  • + *
+ * Similar to std::tr1::has_trivial_copy. + * + * @param classType the class to check + * @return true if the class has a trivial copy constructor + */ + public static boolean hasTrivialCopyCtor(ICPPClassType classType, IASTNode point) { + if (getImplicitCopyCtor(classType, point) == null) + return false; + if (isPolymorphic(classType, point)) + return false; + for (ICPPBase base : ClassTypeHelper.getBases(classType, point)) { + if (base.isVirtual()) + return false; + } + for (ICPPClassType baseClass : ClassTypeHelper.getAllBases(classType, point)) { + if (!classType.isSameType(baseClass) && !hasTrivialCopyCtor(baseClass, point)) + return false; + } + for (ICPPField field : classType.getDeclaredFields()) { + if (!field.isStatic()) { + IType type = field.getType(); + type = SemanticUtil.getNestedType(type, TDEF | CVTYPE | ARRAY); + if (type instanceof ICPPClassType && !classType.isSameType(type) && + !hasTrivialCopyCtor((ICPPClassType) type, point)) { + return false; + } + } + } + return true; + } + + /** + * Returns true if and only if the given class has a trivial default constructor. + * A default constructor is trivial if: + *
    + *
  • it is implicitly defined by the compiler, and
  • + *
  • every direct base class has trivial default constructor, and
  • + *
  • for every nonstatic data member that has class type or array of class type, that type + * has trivial default constructor.
  • + *
+ * Similar to std::tr1::has_trivial_default_constructor. + * + * @param classType the class to check + * @param point + * @return true if the class has a trivial default constructor + */ + public static boolean hasTrivialDefaultConstructor(ICPPClassType classType, IASTNode point) { + for (ICPPConstructor ctor : ClassTypeHelper.getConstructors(classType, point)) { + if (!ctor.isImplicit() && ctor.getParameters().length == 0) + return false; + } + for (ICPPClassType baseClass : ClassTypeHelper.getAllBases(classType, null)) { + if (!classType.isSameType(baseClass) && !hasTrivialDefaultConstructor(baseClass, point)) + return false; + } + for (ICPPField field : ClassTypeHelper.getDeclaredFields(classType, point)) { + if (!field.isStatic()) { + IType type = field.getType(); + type = SemanticUtil.getNestedType(type, TDEF | CVTYPE | ARRAY); + if (type instanceof ICPPClassType && !classType.isSameType(type) && + !hasTrivialDefaultConstructor((ICPPClassType) type, point)) { + return false; + } + } + } + return true; + } + + /** + * Returns true if and only if the given class has a trivial destructor. + * A destructor is trivial if: + *
    + *
  • it is implicitly defined by the compiler, and
  • + *
  • every direct base class has trivial destructor, and
  • + *
  • for every nonstatic data member that has class type or array of class type, that type + * has trivial destructor.
  • + *
+ * Similar to std::tr1::has_trivial_destructor. + * + * @param classType the class to check + * @return true if the class has a trivial destructor + */ + public static boolean hasTrivialDestructor(ICPPClassType classType, IASTNode point) { + for (ICPPMethod method : ClassTypeHelper.getDeclaredMethods(classType, point)) { + if (method.isDestructor()) + return false; + } + for (ICPPClassType baseClass : ClassTypeHelper.getAllBases(classType, null)) { + if (!classType.isSameType(baseClass) && !hasTrivialDestructor(baseClass, point)) + return false; + } + for (ICPPField field : ClassTypeHelper.getDeclaredFields(classType, point)) { + if (!field.isStatic()) { + IType type = field.getType(); + type = SemanticUtil.getNestedType(type, TDEF | CVTYPE | ARRAY); + if (type instanceof ICPPClassType && !classType.isSameType(type) && + !hasTrivialDestructor((ICPPClassType) type, point)) { + return false; + } + } + } + return true; + } + + /** + * Returns true if and only if the given class declares or inherits a virtual + * function. Similar to std::tr1::is_polymorphic. + * + * @param classType the class to check + * @return true if the class declares or inherits a virtual function. + */ + public static boolean isPolymorphic(ICPPClassType classType, IASTNode point) { + if (hasDeclaredVirtualMethod(classType, point)) + return true; + for (ICPPClassType baseClass : ClassTypeHelper.getAllBases(classType, point)) { + if (hasDeclaredVirtualMethod(baseClass, point)) + return true; + } + return false; + } + + private static boolean hasNonStaticFields(ICPPClassType classType, IASTNode point) { + ICPPField[] fields = ClassTypeHelper.getDeclaredFields(classType, point); + for (ICPPField field : fields) { + if (!field.isStatic()) + return true; + } + return false; + } + + public static boolean isAbstract(ICPPClassType classType, IASTNode point) { + return ClassTypeHelper.getPureVirtualMethods(classType, point).length != 0; + } + + /** + * Returns the compiler-generated copy constructor for the given class, or null + * if the class doesn't have a compiler-generated copy constructor. + * + * @param classType the class to get the copy ctor for. + * @return the compiler-generated copy constructor, or null if the class doesn't + * have a compiler-generated copy constructor. + */ + private static ICPPConstructor getImplicitCopyCtor(ICPPClassType classType, IASTNode point) { + for (ICPPConstructor ctor : ClassTypeHelper.getConstructors(classType, point)) { + if (ctor.isImplicit() && ClassTypeHelper.getMethodKind(classType, ctor) == MethodKind.COPY_CTOR) + return ctor; + } + return null; + } + + private static boolean hasDeclaredVirtualMethod(ICPPClassType classType, IASTNode point) { + for (ICPPMethod method : ClassTypeHelper.getDeclaredMethods(classType, point)) { + if (method.isVirtual()) { + return true; + } + } + return false; + } +} diff --git a/lrparser/org.eclipse.cdt.core.lrparser.tests/src/org/eclipse/cdt/core/lrparser/tests/LRGCCCompleteParseExtensionsTest.java b/lrparser/org.eclipse.cdt.core.lrparser.tests/src/org/eclipse/cdt/core/lrparser/tests/LRGCCCompleteParseExtensionsTest.java index e689324df99..bb6b3535015 100644 --- a/lrparser/org.eclipse.cdt.core.lrparser.tests/src/org/eclipse/cdt/core/lrparser/tests/LRGCCCompleteParseExtensionsTest.java +++ b/lrparser/org.eclipse.cdt.core.lrparser.tests/src/org/eclipse/cdt/core/lrparser/tests/LRGCCCompleteParseExtensionsTest.java @@ -32,7 +32,7 @@ public class LRGCCCompleteParseExtensionsTest extends GCCCompleteParseExtensions //override the test failed case for 342683 @Override - public void testTypetraits_Bug342683() throws Exception {} + public void testTypeTraits_Bug342683() throws Exception {} @Override -- cgit v1.2.3