1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-31 21:05:37 +02:00

Bug 460741 - Type of conditional expression in C

Change-Id: I64f4fded197b31e60d81e2fbd5a2728aa8d8d8ce
Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
This commit is contained in:
Nathan Ridge 2015-02-27 04:04:06 -05:00 committed by Gerrit Code Review @ Eclipse.org
parent de3c23df86
commit 8607866e33
10 changed files with 271 additions and 34 deletions

View file

@ -11052,8 +11052,8 @@ public class AST2CPPTests extends AST2TestBase {
ICPPVariable waldo1 = helper.assertNonProblem("waldo1"); ICPPVariable waldo1 = helper.assertNonProblem("waldo1");
ICPPVariable waldo2 = helper.assertNonProblem("waldo2"); ICPPVariable waldo2 = helper.assertNonProblem("waldo2");
// constexpr on a variable *should* make it const // constexpr on a variable *should* make it const
assertSameType(waldo1.getType(), CommonTypes.constInt); assertSameType(waldo1.getType(), CommonCPPTypes.constInt);
assertSameType(waldo2.getType(), CommonTypes.constInt); assertSameType(waldo2.getType(), CommonCPPTypes.constInt);
} }
// constexpr int waldo1(); // constexpr int waldo1();
@ -11065,11 +11065,11 @@ public class AST2CPPTests extends AST2TestBase {
ICPPFunction waldo2 = helper.assertNonProblem("waldo2"); ICPPFunction waldo2 = helper.assertNonProblem("waldo2");
ICPPFunction waldo3 = helper.assertNonProblem("waldo3"); ICPPFunction waldo3 = helper.assertNonProblem("waldo3");
// constexpr on a function *should not* make its return type const // 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(), 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 // 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; // void waldo() noexcept;

View file

@ -11,6 +11,7 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2; package org.eclipse.cdt.core.parser.tests.ast2;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.core.parser.ParserLanguage;
/** /**
@ -314,16 +315,35 @@ public class AST2CSpecTest extends AST2SpecTestBase {
} }
// /* Start Example(C 6.5.15-8) */ // /* Start Example(C 6.5.15-8) */
// int f() { // int f(bool cond) {
// const void *c_vp; // const void *c_vp;
// void *vp; // void *vp;
// const int *c_ip; // const int *c_ip;
// volatile int *v_ip; // volatile int *v_ip;
// int *ip; // int *ip;
// const char *c_cp; // 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 { 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) */ // /* Start Example(C 6.5.16.1-5) */

View file

@ -3280,7 +3280,7 @@ public class AST2TemplateTests extends AST2TestBase {
public void testDependentBaseLookup_408314a() throws Exception { public void testDependentBaseLookup_408314a() throws Exception {
BindingAssertionHelper bh = getAssertionHelper(); BindingAssertionHelper bh = getAssertionHelper();
ITypedef waldo = bh.assertNonProblem("waldo"); ITypedef waldo = bh.assertNonProblem("waldo");
assertSameType(waldo.getType(), CommonTypes.int_); assertSameType(waldo.getType(), CommonCPPTypes.int_);
} }
// template <typename T> // template <typename T>
@ -3302,7 +3302,7 @@ public class AST2TemplateTests extends AST2TestBase {
public void testDependentBaseLookup_408314b() throws Exception { public void testDependentBaseLookup_408314b() throws Exception {
BindingAssertionHelper bh = getAssertionHelper(); BindingAssertionHelper bh = getAssertionHelper();
ITypedef waldo = bh.assertNonProblem("waldo"); ITypedef waldo = bh.assertNonProblem("waldo");
assertSameType(waldo.getType(), CommonTypes.int_); assertSameType(waldo.getType(), CommonCPPTypes.int_);
} }
// template <typename T> // template <typename T>
@ -3324,7 +3324,7 @@ public class AST2TemplateTests extends AST2TestBase {
public void testDependentBaseLookup_408314c() throws Exception { public void testDependentBaseLookup_408314c() throws Exception {
BindingAssertionHelper bh = getAssertionHelper(); BindingAssertionHelper bh = getAssertionHelper();
ITypedef waldo = bh.assertNonProblem("waldo"); ITypedef waldo = bh.assertNonProblem("waldo");
assertSameType(waldo.getType(), CommonTypes.int_); assertSameType(waldo.getType(), CommonCPPTypes.int_);
} }
// template <class T> // template <class T>
@ -6139,8 +6139,8 @@ public class AST2TemplateTests extends AST2TestBase {
// auto x2 = begin2(v); // auto x2 = begin2(v);
public void testResolvingAutoTypeWithDependentExpression_402409a() throws Exception { public void testResolvingAutoTypeWithDependentExpression_402409a() throws Exception {
BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), true); BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), true);
helper.assertVariableType("x1", CommonTypes.pointerToInt); helper.assertVariableType("x1", CommonCPPTypes.pointerToInt);
helper.assertVariableType("x2", CommonTypes.pointerToInt); helper.assertVariableType("x2", CommonCPPTypes.pointerToInt);
} }
// struct vector { // struct vector {
@ -6314,7 +6314,7 @@ public class AST2TemplateTests extends AST2TestBase {
public void testSpecializationOfBaseClass_409078() throws Exception { public void testSpecializationOfBaseClass_409078() throws Exception {
BindingAssertionHelper bh = getAssertionHelper(); BindingAssertionHelper bh = getAssertionHelper();
ITypedef waldo = bh.assertNonProblem("waldo"); ITypedef waldo = bh.assertNonProblem("waldo");
assertSameType(waldo.getType(), CommonTypes.int_); assertSameType(waldo.getType(), CommonCPPTypes.int_);
} }
//struct A { //struct A {
@ -7836,7 +7836,7 @@ public class AST2TemplateTests extends AST2TestBase {
public void testInstantiationOfConstMemberAccess_409107() throws Exception { public void testInstantiationOfConstMemberAccess_409107() throws Exception {
BindingAssertionHelper bh = getAssertionHelper(); BindingAssertionHelper bh = getAssertionHelper();
IType waldo = bh.assertNonProblem("waldo"); IType waldo = bh.assertNonProblem("waldo");
assertSameType(waldo, CommonTypes.int_); assertSameType(waldo, CommonCPPTypes.int_);
} }
// template <typename _Tp> // template <typename _Tp>
@ -8253,7 +8253,7 @@ public class AST2TemplateTests extends AST2TestBase {
// auto x = foo(N::A()); // auto x = foo(N::A());
// } // }
public void testUnqualifiedFunctionCallInTemplate_402498b() throws Exception { public void testUnqualifiedFunctionCallInTemplate_402498b() throws Exception {
new BindingAssertionHelper(getAboveComment(), true).assertVariableType("x", CommonTypes.int_); new BindingAssertionHelper(getAboveComment(), true).assertVariableType("x", CommonCPPTypes.int_);
} }
// template <typename T> // template <typename T>
@ -8275,7 +8275,7 @@ public class AST2TemplateTests extends AST2TestBase {
// analyzer is too lenient and makes it a TypeOfDependentExpression if it // analyzer is too lenient and makes it a TypeOfDependentExpression if it
// can't instantiate the return type of foo() properly. // can't instantiate the return type of foo() properly.
// That's another bug for another day. // That's another bug for another day.
assertFalse(x.getType().isSameType(CommonTypes.int_)); assertFalse(x.getType().isSameType(CommonCPPTypes.int_));
} }
// void bar(); // void bar();
@ -8326,7 +8326,7 @@ public class AST2TemplateTests extends AST2TestBase {
// auto b = foo(a); // auto b = foo(a);
public void testQualifiedNameLookupInTemplate_402854() throws Exception { public void testQualifiedNameLookupInTemplate_402854() throws Exception {
BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), true); BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), true);
helper.assertVariableType("b", CommonTypes.int_); helper.assertVariableType("b", CommonCPPTypes.int_);
} }
// template<typename T> struct A { // template<typename T> struct A {
@ -8504,7 +8504,7 @@ public class AST2TemplateTests extends AST2TestBase {
public void testDependentDecltypeInNameQualifier_415198() throws Exception { public void testDependentDecltypeInNameQualifier_415198() throws Exception {
BindingAssertionHelper helper = getAssertionHelper(); BindingAssertionHelper helper = getAssertionHelper();
helper.assertNonProblem("decltype(foo(T()))::type"); helper.assertNonProblem("decltype(foo(T()))::type");
assertSameType((ITypedef) helper.assertNonProblem("U<S>::type"), CommonTypes.int_); assertSameType((ITypedef) helper.assertNonProblem("U<S>::type"), CommonCPPTypes.int_);
} }
// template <typename T> // template <typename T>
@ -8519,7 +8519,7 @@ public class AST2TemplateTests extends AST2TestBase {
// decltype(B::c)::type x; // decltype(B::c)::type x;
public void testDependentDecltypeInNameQualifier_429837() throws Exception { public void testDependentDecltypeInNameQualifier_429837() throws Exception {
BindingAssertionHelper helper = getAssertionHelper(); 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 { // namespace N {

View file

@ -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.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; 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.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType; import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IField; 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.core.testplugin.util.TestSourceReader;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode; 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.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.CVisitor;
import org.eclipse.cdt.internal.core.dom.parser.c.GNUCSourceParser; import org.eclipse.cdt.internal.core.dom.parser.c.GNUCSourceParser;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; 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 final IParserLogService NULL_LOG = new NullLogService();
protected static boolean sValidateCopy; protected static boolean sValidateCopy;
protected static class CommonTypes { protected static class CommonCTypes {
public static IType int_ = new CPPBasicType(Kind.eInt, 0); 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 pointerToInt = new CPPPointerType(int_);
public static IType constInt = new CPPQualifierType(int_, true, false); public static IType constInt = new CPPQualifierType(int_, true, false);
} }

View file

@ -7582,4 +7582,17 @@ public class AST2Tests extends AST2TestBase {
IFunction waldo = bh.assertNonProblem("waldo"); IFunction waldo = bh.assertNonProblem("waldo");
assertTrue(waldo.getType().takesVarArgs()); 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);
}
} }

View file

@ -13,13 +13,18 @@
package org.eclipse.cdt.internal.core.dom.parser.c; package org.eclipse.cdt.internal.core.dom.parser.c;
import org.eclipse.cdt.core.dom.ast.ASTVisitor; 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.IASTConditionalExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTNode; 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.IPointerType;
import org.eclipse.cdt.core.dom.ast.IType; 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.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent; 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 * Conditional expression in C
@ -151,13 +156,76 @@ public class CASTConditionalExpression extends ASTNode implements
if (positiveExpression == null) { if (positiveExpression == null) {
positiveExpression= getLogicalConditionExpression(); positiveExpression= getLogicalConditionExpression();
} }
IType t2 = positiveExpression.getExpressionType(); IASTExpression negativeExpression = getNegativeResultExpression();
IType t3 = getNegativeResultExpression().getExpressionType(); IType originalPositiveType = positiveExpression.getExpressionType();
if (t3 instanceof IPointerType || t2 == null) IType originalNegativeType = getNegativeResultExpression().getExpressionType();
return t3; IType positiveType = CVisitor.unwrapTypedefs(originalPositiveType);
return t2; 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 @Override
public boolean isLValue() { public boolean isLValue() {
return false; return false;

View file

@ -23,6 +23,9 @@ import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
public class CBasicType implements ICBasicType, ISerializableType { 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 final Kind fKind;
private int fModifiers; private int fModifiers;
private IASTExpression value; private IASTExpression value;

View file

@ -20,6 +20,8 @@ import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
public class CPointerType implements ICPointerType, ITypeContainer, ISerializableType { 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_CONST = 1;
static public final int IS_RESTRICT = 1 << 1; static public final int IS_RESTRICT = 1 << 1;
static public final int IS_VOLATILE = 1 << 2; static public final int IS_VOLATILE = 1 << 2;

View file

@ -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.IASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.IASTAttribute; import org.eclipse.cdt.core.dom.ast.IASTAttribute;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; 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.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; 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.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId; 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.IArrayType;
import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; 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.IFunctionType;
import org.eclipse.cdt.core.dom.ast.ILabel; import org.eclipse.cdt.core.dom.ast.ILabel;
import org.eclipse.cdt.core.dom.ast.IParameter; 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.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;
import org.eclipse.cdt.core.dom.ast.IScope.ScopeLookupData; import org.eclipse.cdt.core.dom.ast.IScope.ScopeLookupData;
import org.eclipse.cdt.core.dom.ast.ISemanticProblem; import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef; 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.IVariable;
import org.eclipse.cdt.core.dom.ast.c.ICASTArrayModifier; import org.eclipse.cdt.core.dom.ast.c.ICASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.c.ICASTCompositeTypeSpecifier; 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.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.ProblemType; 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;
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.dom.parser.cpp.semantics.SemanticUtil;
import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory; import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory;
@ -714,6 +720,16 @@ public class CVisitor extends ASTQueries {
} }
return type; 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 * @param parent
@ -1278,6 +1294,9 @@ public class CVisitor extends ASTQueries {
return type; return type;
} }
private static IType createType(IASTTypeId typeId) {
return createType(typeId.getAbstractDeclarator());
}
public static IType createType(IType baseType, IASTDeclarator declarator) { public static IType createType(IType baseType, IASTDeclarator declarator) {
if (declarator instanceof IASTFunctionDeclarator) if (declarator instanceof IASTFunctionDeclarator)
@ -1742,4 +1761,39 @@ public class CVisitor extends ASTQueries {
return name.resolveBinding(); 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;
}
} }

View file

@ -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.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IFunctionType; 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.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.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; 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. * Methods for computing the type of an expression.
@ -89,4 +93,54 @@ public class ExpressionTypes {
} }
return type; 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);
}
} }