diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index 37b54bb528b..cac2a3abdbe 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -11052,8 +11052,8 @@ public class AST2CPPTests extends AST2TestBase { ICPPVariable waldo1 = helper.assertNonProblem("waldo1"); ICPPVariable waldo2 = helper.assertNonProblem("waldo2"); // constexpr on a variable *should* make it const - assertSameType(waldo1.getType(), CommonTypes.constInt); - assertSameType(waldo2.getType(), CommonTypes.constInt); + assertSameType(waldo1.getType(), CommonCPPTypes.constInt); + assertSameType(waldo2.getType(), CommonCPPTypes.constInt); } // constexpr int waldo1(); @@ -11065,11 +11065,11 @@ public class AST2CPPTests extends AST2TestBase { ICPPFunction waldo2 = helper.assertNonProblem("waldo2"); ICPPFunction waldo3 = helper.assertNonProblem("waldo3"); // constexpr on a function *should not* make its return type const - assertSameType(waldo1.getType().getReturnType(), CommonTypes.int_); + assertSameType(waldo1.getType().getReturnType(), CommonCPPTypes.int_); assertSameType(waldo2.getType().getReturnType(), - new CPPPointerType(new CPPFunctionType(CommonTypes.int_, new IType[]{ CommonTypes.int_ }))); + new CPPPointerType(new CPPFunctionType(CommonCPPTypes.int_, new IType[]{ CommonCPPTypes.int_ }))); // constexpr on a method *should not* make the method const - assertSameType(waldo3.getType(), new CPPFunctionType(CommonTypes.int_, new IType[]{})); + assertSameType(waldo3.getType(), new CPPFunctionType(CommonCPPTypes.int_, new IType[]{})); } // void waldo() noexcept; diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CSpecTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CSpecTest.java index 18ce62dbb52..be062a3f4db 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CSpecTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CSpecTest.java @@ -11,6 +11,7 @@ *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.ast2; +import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.parser.ParserLanguage; /** @@ -314,16 +315,35 @@ public class AST2CSpecTest extends AST2SpecTestBase { } // /* Start Example(C 6.5.15-8) */ - // int f() { - // const void *c_vp; - // void *vp; - // const int *c_ip; - // volatile int *v_ip; - // int *ip; - // const char *c_cp; - // } + // int f(bool cond) { + // const void *c_vp; + // void *vp; + // const int *c_ip; + // volatile int *v_ip; + // int *ip; + // const char *c_cp; + // + // cond ? c_vp : c_ip; + // cond ? v_ip : 0; + // cond ? c_ip : v_ip; + // cond ? vp : c_cp; + // cond ? ip : c_ip; + // cond ? vp : ip; + // } public void test6_5_15s8() throws Exception { - parseCandCPP(getAboveComment(), true, 0); + BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), ParserLanguage.C); + IASTExpression c1 = helper.assertNode("cond ? c_vp : c_ip"); + IASTExpression c2 = helper.assertNode("cond ? v_ip : 0"); + IASTExpression c3 = helper.assertNode("cond ? c_ip : v_ip"); + IASTExpression c4 = helper.assertNode("cond ? vp : c_cp"); + IASTExpression c5 = helper.assertNode("cond ? ip : c_ip"); + IASTExpression c6 = helper.assertNode("cond ? vp : ip"); + assertSameType(CommonCTypes.pointerToConstVoid, c1.getExpressionType()); + assertSameType(CommonCTypes.pointerToVolatileInt, c2.getExpressionType()); + assertSameType(CommonCTypes.pointerToConstVolatileInt, c3.getExpressionType()); + assertSameType(CommonCTypes.pointerToConstVoid, c4.getExpressionType()); + assertSameType(CommonCTypes.pointerToConstInt, c5.getExpressionType()); + assertSameType(CommonCTypes.pointerToVoid, c6.getExpressionType()); } // /* Start Example(C 6.5.16.1-5) */ 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 63044426531..2049fc6a01d 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 @@ -3280,7 +3280,7 @@ public class AST2TemplateTests extends AST2TestBase { public void testDependentBaseLookup_408314a() throws Exception { BindingAssertionHelper bh = getAssertionHelper(); ITypedef waldo = bh.assertNonProblem("waldo"); - assertSameType(waldo.getType(), CommonTypes.int_); + assertSameType(waldo.getType(), CommonCPPTypes.int_); } // template @@ -3302,7 +3302,7 @@ public class AST2TemplateTests extends AST2TestBase { public void testDependentBaseLookup_408314b() throws Exception { BindingAssertionHelper bh = getAssertionHelper(); ITypedef waldo = bh.assertNonProblem("waldo"); - assertSameType(waldo.getType(), CommonTypes.int_); + assertSameType(waldo.getType(), CommonCPPTypes.int_); } // template @@ -3324,7 +3324,7 @@ public class AST2TemplateTests extends AST2TestBase { public void testDependentBaseLookup_408314c() throws Exception { BindingAssertionHelper bh = getAssertionHelper(); ITypedef waldo = bh.assertNonProblem("waldo"); - assertSameType(waldo.getType(), CommonTypes.int_); + assertSameType(waldo.getType(), CommonCPPTypes.int_); } // template @@ -6139,8 +6139,8 @@ public class AST2TemplateTests extends AST2TestBase { // auto x2 = begin2(v); public void testResolvingAutoTypeWithDependentExpression_402409a() throws Exception { BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), true); - helper.assertVariableType("x1", CommonTypes.pointerToInt); - helper.assertVariableType("x2", CommonTypes.pointerToInt); + helper.assertVariableType("x1", CommonCPPTypes.pointerToInt); + helper.assertVariableType("x2", CommonCPPTypes.pointerToInt); } // struct vector { @@ -6314,7 +6314,7 @@ public class AST2TemplateTests extends AST2TestBase { public void testSpecializationOfBaseClass_409078() throws Exception { BindingAssertionHelper bh = getAssertionHelper(); ITypedef waldo = bh.assertNonProblem("waldo"); - assertSameType(waldo.getType(), CommonTypes.int_); + assertSameType(waldo.getType(), CommonCPPTypes.int_); } //struct A { @@ -7836,7 +7836,7 @@ public class AST2TemplateTests extends AST2TestBase { public void testInstantiationOfConstMemberAccess_409107() throws Exception { BindingAssertionHelper bh = getAssertionHelper(); IType waldo = bh.assertNonProblem("waldo"); - assertSameType(waldo, CommonTypes.int_); + assertSameType(waldo, CommonCPPTypes.int_); } // template @@ -8253,7 +8253,7 @@ public class AST2TemplateTests extends AST2TestBase { // auto x = foo(N::A()); // } public void testUnqualifiedFunctionCallInTemplate_402498b() throws Exception { - new BindingAssertionHelper(getAboveComment(), true).assertVariableType("x", CommonTypes.int_); + new BindingAssertionHelper(getAboveComment(), true).assertVariableType("x", CommonCPPTypes.int_); } // template @@ -8275,7 +8275,7 @@ public class AST2TemplateTests extends AST2TestBase { // analyzer is too lenient and makes it a TypeOfDependentExpression if it // can't instantiate the return type of foo() properly. // That's another bug for another day. - assertFalse(x.getType().isSameType(CommonTypes.int_)); + assertFalse(x.getType().isSameType(CommonCPPTypes.int_)); } // void bar(); @@ -8326,7 +8326,7 @@ public class AST2TemplateTests extends AST2TestBase { // auto b = foo(a); public void testQualifiedNameLookupInTemplate_402854() throws Exception { BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), true); - helper.assertVariableType("b", CommonTypes.int_); + helper.assertVariableType("b", CommonCPPTypes.int_); } // template struct A { @@ -8504,7 +8504,7 @@ public class AST2TemplateTests extends AST2TestBase { public void testDependentDecltypeInNameQualifier_415198() throws Exception { BindingAssertionHelper helper = getAssertionHelper(); helper.assertNonProblem("decltype(foo(T()))::type"); - assertSameType((ITypedef) helper.assertNonProblem("U::type"), CommonTypes.int_); + assertSameType((ITypedef) helper.assertNonProblem("U::type"), CommonCPPTypes.int_); } // template @@ -8519,7 +8519,7 @@ public class AST2TemplateTests extends AST2TestBase { // decltype(B::c)::type x; public void testDependentDecltypeInNameQualifier_429837() throws Exception { BindingAssertionHelper helper = getAssertionHelper(); - assertSameType((ITypedef) helper.assertNonProblem("decltype(B::c)::type"), CommonTypes.int_); + assertSameType((ITypedef) helper.assertNonProblem("decltype(B::c)::type"), CommonCPPTypes.int_); } // namespace N { diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java index 40794207cd5..ebf995b598e 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TestBase.java @@ -53,7 +53,6 @@ import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; -import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.IField; @@ -90,6 +89,9 @@ import org.eclipse.cdt.core.testplugin.util.BaseTestCase; import org.eclipse.cdt.core.testplugin.util.TestSourceReader; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser; +import org.eclipse.cdt.internal.core.dom.parser.c.CBasicType; +import org.eclipse.cdt.internal.core.dom.parser.c.CPointerType; +import org.eclipse.cdt.internal.core.dom.parser.c.CQualifierType; import org.eclipse.cdt.internal.core.dom.parser.c.CVisitor; import org.eclipse.cdt.internal.core.dom.parser.c.GNUCSourceParser; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; @@ -109,8 +111,29 @@ public class AST2TestBase extends BaseTestCase { protected static final IParserLogService NULL_LOG = new NullLogService(); protected static boolean sValidateCopy; - protected static class CommonTypes { - public static IType int_ = new CPPBasicType(Kind.eInt, 0); + protected static class CommonCTypes { + public static IType pointerToVoid = pointerTo(CBasicType.VOID); + public static IType pointerToConstVoid = pointerTo(constOf(CBasicType.VOID)); + public static IType pointerToConstInt = pointerTo(constOf(CBasicType.INT)); + public static IType pointerToVolatileInt = pointerTo(volatileOf(CBasicType.INT)); + public static IType pointerToConstVolatileInt = pointerTo(constVolatileOf(CBasicType.INT)); + + private static IType pointerTo(IType type) { + return new CPointerType(type, 0); + } + private static IType constOf(IType type) { + return new CQualifierType(type, true, false, false); + } + private static IType volatileOf(IType type) { + return new CQualifierType(type, false, true, false); + } + private static IType constVolatileOf(IType type) { + return new CQualifierType(type, true, true, false); + } + } + + protected static class CommonCPPTypes { + public static IType int_ = CPPBasicType.INT; public static IType pointerToInt = new CPPPointerType(int_); public static IType constInt = new CPPQualifierType(int_, true, false); } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java index 2a8c6c41fdf..418d8a5b4c1 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java @@ -7582,4 +7582,17 @@ public class AST2Tests extends AST2TestBase { IFunction waldo = bh.assertNonProblem("waldo"); assertTrue(waldo.getType().takesVarArgs()); } + + // struct Foo { + // struct Foo* a; + // }; + // + // int main() { + // struct Foo * f = 0; + // (f ? f->a : ((void*) 0))->a; // second 'a' cannot be resolved + // return 0; + // } + public void testVoidPointerInTernaryOperator_460741() throws Exception { + parseAndCheckBindings(getAboveComment(), C); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTConditionalExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTConditionalExpression.java index 9c414454434..b56ebca239c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTConditionalExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CASTConditionalExpression.java @@ -13,13 +13,18 @@ package org.eclipse.cdt.internal.core.dom.parser.c; import org.eclipse.cdt.core.dom.ast.ASTVisitor; +import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IBasicType; +import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent; +import org.eclipse.cdt.internal.core.dom.parser.ProblemType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes; /** * Conditional expression in C @@ -151,13 +156,76 @@ public class CASTConditionalExpression extends ASTNode implements if (positiveExpression == null) { positiveExpression= getLogicalConditionExpression(); } - IType t2 = positiveExpression.getExpressionType(); - IType t3 = getNegativeResultExpression().getExpressionType(); - if (t3 instanceof IPointerType || t2 == null) - return t3; - return t2; + IASTExpression negativeExpression = getNegativeResultExpression(); + IType originalPositiveType = positiveExpression.getExpressionType(); + IType originalNegativeType = getNegativeResultExpression().getExpressionType(); + IType positiveType = CVisitor.unwrapTypedefs(originalPositiveType); + IType negativeType = CVisitor.unwrapTypedefs(originalNegativeType); + IType resultType = computeResultType(positiveExpression, negativeExpression, + positiveType, negativeType); + if (resultType == null) { + return ProblemType.UNKNOWN_FOR_EXPRESSION; + } + return ExpressionTypes.restoreTypedefs(resultType, originalPositiveType, originalPositiveType); } + + private IType computeResultType(IASTExpression positiveExpression, IASTExpression negativeExpression, + IType positiveType, IType negativeType) { + // [6.5.15] p5: If both the second and third operands have arithmetic type, the result type + // that would be determined by the usual arithmetic conversions, were they applied to those + // two operands, is the type of the result. If both operands have void type, the result has + // void type. + if (positiveType instanceof IBasicType && negativeType instanceof IBasicType) { + if (((IBasicType) positiveType).getKind() == IBasicType.Kind.eVoid + && ((IBasicType) negativeType).getKind() == IBasicType.Kind.eVoid) { + return CBasicType.VOID; + } + + // It doesn't really matter which operator we use here, so we'll use op_plus. + return CArithmeticConversion.convertCOperandTypes(IASTBinaryExpression.op_plus, + positiveType, negativeType); + } + + // If both the operands have structure or union type, the result has that type. + if (positiveType instanceof ICompositeType && negativeType instanceof ICompositeType) { + // Both operands must have the same structure or union type as per p3. + if (positiveType.isSameType(negativeType)) { + return positiveType; + } + } + + // [6.5.15] p6: If both the second and third operands are pointers or one is a null pointer + // constant and the other is a pointer, the result type is a pointer to a type qualified with + // all the type qualifiers of the types referenced by both operands. Furthermore, if both + // operands are pointers to compatible types or to differently qualified versions of compatible + // types, the result type is a pointer to an appropriately qualified version of the composite + // type; if one operand is a null pointer constant, the result has the type of the other operand; + // otherwise, one operand is a pointer to void or a qualified version of void, in which case the + // result type is a pointer to an appropriately qualified version of void. + if (CVisitor.isNullPointerConstant(positiveExpression) && negativeType instanceof IPointerType) { + return negativeType; + } else if (CVisitor.isNullPointerConstant(negativeExpression) && positiveType instanceof IPointerType) { + return positiveType; + } else if (positiveType instanceof IPointerType && negativeType instanceof IPointerType) { + IType positivePointeeCV = ((IPointerType) positiveType).getType(); + IType negativePointeeCV = ((IPointerType) negativeType).getType(); + IType positivePointee = CVisitor.unwrapCV(positivePointeeCV); + IType negativePointee = CVisitor.unwrapCV(negativePointeeCV); + IType resultPointee; + if (positivePointee.isSameType(CBasicType.VOID) || negativePointee.isSameType(CBasicType.VOID)) { + resultPointee = CBasicType.VOID; + } else { + // TODO: Implement checking for compatible types and computing the composite type. + resultPointee = negativePointee; + } + return new CPointerType( + ExpressionTypes.restoreCV(resultPointee, positivePointeeCV, negativePointeeCV), 0); + } + + return null; + } + @Override public boolean isLValue() { return false; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CBasicType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CBasicType.java index 0ac2f77d745..e30b0ac1c68 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CBasicType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CBasicType.java @@ -23,6 +23,9 @@ import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; import org.eclipse.core.runtime.CoreException; public class CBasicType implements ICBasicType, ISerializableType { + public static final CBasicType VOID = new CBasicType(Kind.eVoid, 0, null); + public static final CBasicType INT = new CBasicType(Kind.eInt, 0, null); + private final Kind fKind; private int fModifiers; private IASTExpression value; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CPointerType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CPointerType.java index 89477b01764..98c66d390c1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CPointerType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CPointerType.java @@ -20,6 +20,8 @@ import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; import org.eclipse.core.runtime.CoreException; public class CPointerType implements ICPointerType, ITypeContainer, ISerializableType { + static public final CPointerType VOID_POINTER = new CPointerType(CBasicType.VOID, 0); + static public final int IS_CONST = 1; static public final int IS_RESTRICT = 1 << 1; static public final int IS_VOLATILE = 1 << 2; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java index bd76dcc387e..38814e9f111 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java @@ -27,6 +27,7 @@ import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator; import org.eclipse.cdt.core.dom.ast.IASTArrayModifier; import org.eclipse.cdt.core.dom.ast.IASTAttribute; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; +import org.eclipse.cdt.core.dom.ast.IASTCastExpression; import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; @@ -58,6 +59,7 @@ import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; +import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IArrayType; import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; @@ -70,12 +72,15 @@ import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.ILabel; import org.eclipse.cdt.core.dom.ast.IParameter; +import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; +import org.eclipse.cdt.core.dom.ast.IQualifierType; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.IScope.ScopeLookupData; import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; +import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.c.ICASTArrayModifier; import org.eclipse.cdt.core.dom.ast.c.ICASTCompositeTypeSpecifier; @@ -105,6 +110,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; 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.Value; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory; @@ -714,6 +720,16 @@ public class CVisitor extends ASTQueries { } return type; } + + static IType unwrapCV(IType type) { + while (type instanceof IQualifierType) { + type = ((IQualifierType) type).getType(); + } + if (type instanceof IPointerType) { + type = new CPointerType(((IPointerType) type).getType(), 0 /* no qualifiers */); + } + return type; + } /** * @param parent @@ -1278,6 +1294,9 @@ public class CVisitor extends ASTQueries { return type; } + private static IType createType(IASTTypeId typeId) { + return createType(typeId.getAbstractDeclarator()); + } public static IType createType(IType baseType, IASTDeclarator declarator) { if (declarator instanceof IASTFunctionDeclarator) @@ -1742,4 +1761,39 @@ public class CVisitor extends ASTQueries { return name.resolveBinding(); } + + /** + * Determine whether an expression is a null pointer constant. + */ + public static boolean isNullPointerConstant(IASTExpression expression) { + // [6.3.2.3] p3: An integer constant expression with the value 0, or such an expression cast + // to void*, is called a null pointer constant. + + // Unwrap extra parentheses. + if (expression instanceof IASTUnaryExpression) { + IASTUnaryExpression unaryExpression = (IASTUnaryExpression) expression; + if (unaryExpression.getOperator() == IASTUnaryExpression.op_bracketedPrimary) { + return isNullPointerConstant(unaryExpression.getOperand()); + } + } + + if (expression instanceof IASTCastExpression) { + IASTCastExpression castExpression = (IASTCastExpression) expression; + IType castType = createType(castExpression.getTypeId()); + if (castType.isSameType(CPointerType.VOID_POINTER)) { + return isNullPointerConstant(castExpression.getOperand()); + } + } + + IType expressionType = expression.getExpressionType(); + if (expressionType instanceof IBasicType) { + IValue value = Value.create(expression); + if (value != null && value.numericalValue() != null) { + return value.numericalValue().longValue() == 0; + } + } + + return false; + } + } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java index a4e0443e607..31ec1852809 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExpressionTypes.java @@ -15,10 +15,14 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IFunctionType; +import org.eclipse.cdt.core.dom.ast.IPointerType; +import org.eclipse.cdt.core.dom.ast.IQualifierType; import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.c.ICQualifierType; 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.ICPPReferenceType; +import org.eclipse.cdt.internal.core.dom.parser.c.CQualifierType; /** * Methods for computing the type of an expression. @@ -89,4 +93,54 @@ public class ExpressionTypes { } return type; } + + private static boolean isConst(IType type) { + if (type instanceof IQualifierType) { + return ((IQualifierType) type).isConst(); + } else if (type instanceof IPointerType) { + return ((IPointerType) type).isConst(); + } + return false; + } + + private static boolean isVolatile(IType type) { + if (type instanceof IQualifierType) { + return ((IQualifierType) type).isVolatile(); + } else if (type instanceof IPointerType) { + return ((IPointerType) type).isVolatile(); + } + return false; + } + + private static IType makeConst(IType type) { + if (type instanceof ICQualifierType) { + ICQualifierType qualifierType = ((ICQualifierType) type); + return new CQualifierType(qualifierType.getType(), + true, qualifierType.isVolatile(), qualifierType.isRestrict()); + } + return new CQualifierType(type, true, false, false); + } + + private static IType makeVolatile(IType type) { + if (type instanceof ICQualifierType) { + ICQualifierType qualifierType = ((ICQualifierType) type); + return new CQualifierType(qualifierType.getType(), + qualifierType.isConst(), true, qualifierType.isRestrict()); + } + return new CQualifierType(type, false, true, false); + } + + private static IType restoreCV(IType type, IType originalType) { + if (isConst(originalType)) { + type = makeConst(type); + } + if (isVolatile(originalType)) { + type = makeVolatile(type); + } + return type; + } + + public static IType restoreCV(IType type, IType originalType1, IType originalType2) { + return restoreCV(restoreCV(type, originalType1), originalType2); + } }