diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPImplicitNameTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPImplicitNameTests.java index cdbb29226ca..0ca7cea5bd4 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPImplicitNameTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPImplicitNameTests.java @@ -402,10 +402,10 @@ public class AST2CPPImplicitNameTests extends AST2BaseTest { // X* xs = new X[5]; // delete[] x; // } - public void _testImplicitNewAndDelete() throws Exception { + public void testImplicitNewAndDelete() throws Exception { BindingAssertionHelper ba = new BindingAssertionHelper(getAboveComment(), true); ba.assertNoImplicitName("new X", 3); - ba.assertNoImplicitName("delete[]", 6); // fails because its picking up the implicit global delete[] + ba.assertNoImplicitName("delete[]", 6); } // typedef long unsigned int size_t 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 350fe623b3e..a11985d0718 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 @@ -8562,4 +8562,25 @@ public class AST2CPPTests extends AST2BaseTest { String code= getAboveComment(); parseAndCheckBindings(code); } + + // struct D {}; + // struct C { + // operator D(); + // operator char(); + // }; + // long operator+(D d, char a); + // void f(long); + // void f(int); + // void xx() { + // C c; + // f(c+1); // converts c to a char and calls operator+(int, int) + // } + public void testBuiltinOperators_294543() throws Exception { + String code= getAboveComment(); + parseAndCheckBindings(code); + BindingAssertionHelper bh= new BindingAssertionHelper(code, true); + IFunction fint= bh.assertNonProblem("f(int)", 1); + IFunction f= bh.assertNonProblem("f(c+1)", 1); + assertSame(fint, f); + } } diff --git a/core/org.eclipse.cdt.core/.settings/.api_filters b/core/org.eclipse.cdt.core/.settings/.api_filters deleted file mode 100644 index 2aae30a0706..00000000000 --- a/core/org.eclipse.cdt.core/.settings/.api_filters +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTArraySubscriptExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTArraySubscriptExpression.java index f12c5b4d292..afa4b5270a8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTArraySubscriptExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTArraySubscriptExpression.java @@ -96,7 +96,7 @@ public class CPPASTArraySubscriptExpression extends ASTNode implements ICPPASTAr public IASTImplicitName[] getImplicitNames() { if (implicitNames == null) { ICPPFunction overload = getOverload(); - if (overload == null) + if (overload == null || overload instanceof CPPImplicitFunction) return implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; // create separate implicit names for the two brackets diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java index c76dc48ea4d..fa2275f6834 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTBinaryExpression.java @@ -21,12 +21,13 @@ import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IArrayType; +import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IType; -import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent; @@ -113,7 +114,7 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr public IASTImplicitName[] getImplicitNames() { if (implicitNames == null) { ICPPFunction overload = getOverload(); - if (overload == null) { + if (overload == null || (overload instanceof CPPImplicitFunction && !(overload instanceof ICPPMethod))) { implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; } else { CPPASTImplicitName operatorName = new CPPASTImplicitName(overload.getNameCharArray(), this); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeleteExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeleteExpression.java index 7b91cacf894..9d7a6e06bca 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeleteExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeleteExpression.java @@ -100,7 +100,7 @@ public class CPPASTDeleteExpression extends ASTNode implements ICPPASTDeleteExpr if (!isGlobal) { ICPPFunction deleteOperator = CPPSemantics.findOverloadedOperator(this); - if (deleteOperator != null) { + if (deleteOperator != null && !(deleteOperator instanceof CPPImplicitFunction)) { CPPASTImplicitName deleteName = new CPPASTImplicitName(deleteOperator.getNameCharArray(), this); deleteName.setOperator(true); deleteName.setBinding(deleteOperator); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTExpressionList.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTExpressionList.java index e81d93f125b..c59cb91b50c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTExpressionList.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTExpressionList.java @@ -120,7 +120,7 @@ public class CPPASTExpressionList extends ASTNode implements ICPPASTExpressionLi ICPPFunction[] overloads = getOverloads(); for(int i = 0; i < overloads.length; i++) { ICPPFunction overload = overloads[i]; - if(overload != null) { + if(overload != null && !(overload instanceof CPPImplicitFunction)) { CPPASTImplicitName operatorName = new CPPASTImplicitName(OverloadableOperator.COMMA, this); operatorName.setBinding(overload); operatorName.computeOperatorOffsets(exprs[i], true); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFieldReference.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFieldReference.java index ecf2753c3db..2e530f87eb2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFieldReference.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFieldReference.java @@ -38,6 +38,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; 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.core.parser.util.ArrayUtil; 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.cpp.semantics.CPPSemantics; @@ -133,12 +134,16 @@ public class CPPASTFieldReference extends ASTNode implements ICPPASTFieldReferen // create a name to wrap each binding implicitNames = new IASTImplicitName[functionBindings.size()]; - for(int i = 0, n = functionBindings.size(); i < n; i++) { - CPPASTImplicitName operatorName = new CPPASTImplicitName(OverloadableOperator.ARROW, this); - operatorName.setBinding(functionBindings.get(i)); - operatorName.computeOperatorOffsets(owner, true); - implicitNames[i] = operatorName; + int i=-1; + for (ICPPFunction op : functionBindings) { + if (op != null && !(op instanceof CPPImplicitFunction)) { + CPPASTImplicitName operatorName = new CPPASTImplicitName(OverloadableOperator.ARROW, this); + operatorName.setBinding(op); + operatorName.computeOperatorOffsets(owner, true); + implicitNames[++i] = operatorName; + } } + implicitNames= ArrayUtil.trimAt(IASTImplicitName.class, implicitNames, i); } return implicitNames; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java index 6fcddc24a0d..7b6bc969e8d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java @@ -109,7 +109,7 @@ public class CPPASTFunctionCallExpression extends ASTNode implements public IASTImplicitName[] getImplicitNames() { if (implicitNames == null) { ICPPFunction overload = getOperator(); - if (overload == null) + if (overload == null || overload instanceof CPPImplicitFunction) return implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; // create separate implicit names for the two brackets @@ -246,13 +246,9 @@ public class CPPASTFunctionCallExpression extends ASTNode implements if (t instanceof IFunctionType) { return ((IFunctionType) t).getReturnType(); } else if (t instanceof ICPPClassType) { - ICPPFunction op = CPPSemantics.findOverloadedOperator(this, (ICPPClassType)t); - if (op != null) { - // overload can be a surrogate function call, which consists of a conversion and a call to - // a dynamically computed function pointer. - if (!(op instanceof CPPImplicitFunction)) - overload = op; - return op.getType().getReturnType(); + overload = CPPSemantics.findOverloadedOperator(this, (ICPPClassType)t); + if (overload != null) { + return overload.getType().getReturnType(); } } else if (t instanceof IPointerType) { t= SemanticUtil.getUltimateTypeUptoPointers(((IPointerType) t).getType()); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTNewExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTNewExpression.java index c55c2bd5ed2..b96c0bcca1c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTNewExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTNewExpression.java @@ -139,7 +139,7 @@ public class CPPASTNewExpression extends ASTNode implements ICPPASTNewExpression public IASTImplicitName[] getImplicitNames() { if (implicitNames == null) { ICPPFunction operatorFunction = CPPSemantics.findOverloadedOperator(this); - if (operatorFunction == null) { + if (operatorFunction == null || operatorFunction instanceof CPPImplicitFunction) { implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; } else { CPPASTImplicitName operatorName = new CPPASTImplicitName(operatorFunction.getNameCharArray(), this); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java index 69d0e2386f2..c699a1da229 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTUnaryExpression.java @@ -26,12 +26,12 @@ import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IArrayType; +import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IType; -import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; @@ -100,7 +100,7 @@ public class CPPASTUnaryExpression extends ASTNode implements ICPPASTUnaryExpres public IASTImplicitName[] getImplicitNames() { if (implicitNames == null) { ICPPFunction overload = getOverload(); - if (overload == null) { + if (overload == null || overload instanceof CPPImplicitFunction) { implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; } else { CPPASTImplicitName operatorName = new CPPASTImplicitName(overload.getNameCharArray(), this); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java new file mode 100644 index 00000000000..b4f097574f2 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java @@ -0,0 +1,658 @@ +/******************************************************************************* + * Copyright (c) 2010 Wind River Systems, 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: + * Markus Schorn - 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.*; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; +import org.eclipse.cdt.core.dom.ast.DOMException; +import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; +import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IBasicType; +import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; +import org.eclipse.cdt.core.dom.ast.IEnumeration; +import org.eclipse.cdt.core.dom.ast.IFunctionType; +import org.eclipse.cdt.core.dom.ast.IPointerType; +import org.eclipse.cdt.core.dom.ast.IProblemBinding; +import org.eclipse.cdt.core.dom.ast.IScope; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +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.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArithmeticConversion; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBuiltinParameter; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitFunction; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; + +/** + * Generates built-in operators according to 13.6 + */ +class BuiltinOperators { + private static final ICPPFunction[] EMPTY = {}; + private static final int FIRST = 0; + private static final int SECOND = 1; + private static final IType BOOL = new CPPBasicType(Kind.eBoolean, 0); + private static final IType PTR_DIFF = new CPPBasicType(Kind.eInt, 0); + + public static ICPPFunction[] create(OverloadableOperator operator, IASTInitializerClause[] args, IASTTranslationUnit tu) { + if (operator == null || args == null || args.length == 0) + return EMPTY; + + return new BuiltinOperators(operator, args, tu.getScope()).create(); + } + + private final OverloadableOperator fOperator; + private final boolean fUnary; + private IType fType1; + private IType fType2; + private IType[][] fClassConversionTypes= {null, null}; + private boolean[] fIsClass= {false,false}; + private IScope fFileScope; + private List fResult; + private Set fSignatures; + + BuiltinOperators(OverloadableOperator operator, IASTInitializerClause[] args, IScope fileScope) { + fFileScope= fileScope; + fOperator= operator; + fUnary= args.length<2; + if (args.length > 0 && args[0] instanceof IASTExpression) { + IType type= ((IASTExpression) args[0]).getExpressionType(); + if (!(type instanceof IProblemBinding)) + fType1= type; + + } + if (args.length > 1 && args[1] instanceof IASTExpression) { + IType type= ((IASTExpression) args[1]).getExpressionType(); + if (!(type instanceof IProblemBinding)) + fType2= type; + } + } + + + private ICPPFunction[] create() { + switch(fOperator) { + case ARROW: + case COMMA: + case DELETE: + case DELETE_ARRAY: + case NEW: + case NEW_ARRAY: + case PAREN: + return EMPTY; + + case INCR: + case DECR: + opIncOrDec(); + break; + + case STAR: + if (fUnary) { + opDeref(); + } else { + binaryPromotedArithmetic(true, ReturnType.CONVERT); + } + break; + + case DIV: + binaryPromotedArithmetic(true, ReturnType.CONVERT); + break; + + case PLUS: + if (fUnary) { + unaryPointer(); + unaryPromotedArithmetic(true); + } else { + binaryPromotedArithmetic(true, ReturnType.CONVERT); + pointerArithmetic(false, false); + } + break; + + case BRACKET: + pointerArithmetic(true, false); + break; + + case MINUS: + if (fUnary) { + unaryPromotedArithmetic(true); + } else { + binaryPromotedArithmetic(true, ReturnType.CONVERT); + pointerArithmetic(false, true); + } + break; + + case BITCOMPLEMENT: + unaryPromotedArithmetic(false); + break; + + case ARROWSTAR: + opArrowStar(); + break; + + case EQUAL: + case NOTEQUAL: + binaryPromotedArithmetic(true, ReturnType.USE_BOOL); + comparison(true); + break; + + case GT: + case GTEQUAL: + case LT: + case LTEQUAL: + binaryPromotedArithmetic(true, ReturnType.USE_BOOL); + comparison(false); + break; + + case AMPER: + if (fUnary) + return EMPTY; + + binaryPromotedArithmetic(false, ReturnType.CONVERT); + break; + + case BITOR: + case XOR: + case MOD: + binaryPromotedArithmetic(false, ReturnType.CONVERT); + break; + + case SHIFTL: + case SHIFTR: + binaryPromotedArithmetic(false, ReturnType.USE_FIRST); + break; + + case ASSIGN: + arithmeticAssignement(true, true, false); + break; + + case MINUSASSIGN: + case PLUSASSIGN: + arithmeticAssignement(true, false, true); + break; + + case DIVASSIGN: + case STARASSIGN: + arithmeticAssignement(true, false, false); + break; + + case AMPERASSIGN: + case BITORASSIGN: + case MODASSIGN: + case SHIFTLASSIGN: + case SHIFTRASSIGN: + case XORASSIGN: + arithmeticAssignement(false, false, false); + break; + + case AND: + case OR: + addFunction(BOOL, BOOL, BOOL); + break; + + case NOT: + addFunction(BOOL, BOOL); + break; + } + + if (fResult == null) + return EMPTY; + + return fResult.toArray(new ICPPFunction[fResult.size()]); + } + + + + // 13.6-3, 13.6-4, 13.6-5 + private void opIncOrDec() { + IType[] types= getClassConversionTypes(FIRST); + for (IType type : types) { + type= SemanticUtil.getNestedType(type, TDEF); + if (type instanceof ICPPReferenceType) { + IType nested= ((ICPPReferenceType) type).getType(); + CVQualifier cvq= SemanticUtil.getCVQualifier(nested); + if (!cvq.isConst()) { + nested= SemanticUtil.getNestedType(nested, TDEF | CVTYPE); + boolean ok= false; + if (isArithmetic(nested)) { + // 13.6-3 and 1.3.6-4 + if (fOperator == OverloadableOperator.INCR || !isBoolean(type)) { + ok= true; + } + } else if (isPointer(nested)) { + // 13.6-5 + nested= ((IPointerType) nested).getType(); + if (!(SemanticUtil.getNestedType(nested, TDEF) instanceof IFunctionType)) { + ok= true; + } + } + if (ok) { + if (fType2 != null) { + addFunction(type, type, fType2); + } else { + addFunction(type, type); + } + } + } + } + } + } + + // 13.6-6, 13.6-7 + private void opDeref() { + IType[] types= getClassConversionTypes(FIRST); + for (IType type : types) { + type= SemanticUtil.getNestedType(type, TDEF); + if (isPointer(type)) { + IType nested= SemanticUtil.getNestedType(((IPointerType) type).getType(), TDEF); + if (nested instanceof ICPPFunctionType) { + ICPPFunctionType ft= (ICPPFunctionType) nested; + if (ft.isConst() || ft.isVolatile()) + return; + } + addFunction(new CPPReferenceType(nested, false), type); + } + } + } + + // 13.6-8 + private void unaryPointer() { + IType[] types= getClassConversionTypes(FIRST); + for (IType type : types) { + type= SemanticUtil.getNestedType(type, TDEF|REF); + if (isPointer(type)) { + addFunction(type, type); + } + } + } + + // 13.6-9, 13.6-10 + private void unaryPromotedArithmetic(boolean includeFloatingPoint) { + IType[] types= getClassConversionTypes(FIRST); + for (IType type : types) { + type= SemanticUtil.getNestedType(type, TDEF|REF|CVTYPE); + if (isFloatingPoint(type)) { + if (includeFloatingPoint) { + addFunction(type, type); + } + } else { + type= CPPArithmeticConversion.promoteCppType(type); + if (type != null) { + addFunction(type, type); + } + } + } + } + + // 13.6-11 + private void opArrowStar() { + List classPointers= null; + List memberPointers= null; + IType[] types= getClassConversionTypes(FIRST); + for (IType type : types) { + type= SemanticUtil.getNestedType(type, TDEF | REF); + if (isPointer(type)) { + final IPointerType ptrType = (IPointerType) type; + if (SemanticUtil.getNestedType(ptrType.getType(), TDEF | CVTYPE) instanceof ICPPClassType) { + if (classPointers == null) { + classPointers= new ArrayList(); + } + classPointers.add(ptrType); + } + } + } + if (classPointers == null) + return; + + types= getClassConversionTypes(SECOND); + for (IType type : types) { + type= SemanticUtil.getNestedType(type, TDEF | REF); + if (type instanceof ICPPPointerToMemberType) { + if (memberPointers == null) { + memberPointers= new ArrayList(); + } + memberPointers.add((ICPPPointerToMemberType) type); + } + } + if (memberPointers == null) + return; + + for (IPointerType clsPtr : classPointers) { + IType cvClass= SemanticUtil.getNestedType(clsPtr.getType(), TDEF); + CVQualifier cv1= SemanticUtil.getCVQualifier(cvClass); + ICPPClassType c1= (ICPPClassType) SemanticUtil.getNestedType(cvClass, TDEF | CVTYPE); + for (ICPPPointerToMemberType memPtr : memberPointers) { + IType t2= SemanticUtil.getNestedType(memPtr.getMemberOfClass(), TDEF); + if (t2 instanceof ICPPClassType) { + ICPPClassType c2= (ICPPClassType) t2; + try { + if (SemanticUtil.calculateInheritanceDepth(c1, c2) >= 0) { + IType cvt= SemanticUtil.getNestedType(memPtr.getType(), TDEF); + IType rt= new CPPReferenceType( + SemanticUtil.addQualifiers(cvt, cv1.isConst(), cv1.isVolatile()), false); + addFunction(rt, clsPtr, memPtr); + } + } catch (DOMException e) { + } + } + } + } + } + + // 13.6-12, 13.6-17 + private static enum ReturnType {CONVERT, USE_FIRST, USE_BOOL} + private void binaryPromotedArithmetic(boolean fltPt, ReturnType rstrat) { + List p1= null, p2= null; + + IType[] types1= getClassConversionTypes(FIRST); + IType[] types2= getClassConversionTypes(SECOND); + if (types1.length == 0 && types2.length == 0) + return; + + for (IType t : types1) { + p1 = addPromotedArithmetic(t, fltPt, p1); + } + for (IType t : types2) { + p2 = addPromotedArithmetic(t, fltPt, p2); + } + p1= addPromotedArithmetic(fType1, fltPt, p1); + p2= addPromotedArithmetic(fType2, fltPt, p2); + if (p1 == null || p2 == null) + return; + + for (IType t1 : p1) { + for (IType t2 : p2) { + IType rt= null; + switch(rstrat) { + case USE_BOOL: + rt= BOOL; + break; + case USE_FIRST: + rt= t1; + break; + case CONVERT: + rt= CPPArithmeticConversion.convertCppOperandTypes(IASTBinaryExpression.op_plus, t1, t2); + break; + } + addFunction(rt, t1, t2); + } + } + } + + private List addPromotedArithmetic(IType t, boolean fltPt, List p1) { + IType type= SemanticUtil.getNestedType(t, TDEF|REF|CVTYPE); + if (isFloatingPoint(type)) { + if (!fltPt) { + type= null; + } + } else { + type= CPPArithmeticConversion.promoteCppType(type); + } + if (type != null) { + if (p1 == null) { + p1= new ArrayList(); + } + p1.add(type); + } + return p1; + } + + + // 13.6-13, 13.6.14 + private void pointerArithmetic(boolean useRef, boolean isDiff) { + IType[] types= getClassConversionTypes(FIRST); + if (types.length == 0 && !fIsClass[FIRST]) { + types= new IType[] {fType1}; + } + for (IType type : types) { + type= SemanticUtil.getNestedType(type, TDEF|REF); + if (isPointer(type)) { + final IType ptrTarget = ((IPointerType) type).getType(); + final IType uqPtrTarget = SemanticUtil.getNestedType(ptrTarget, TDEF|CVTYPE); + if (!(uqPtrTarget instanceof IFunctionType)) { + final IType retType= useRef ? new CPPReferenceType(ptrTarget, false) : type; + addFunction(retType, type, PTR_DIFF); + if (isDiff) { + addFunction(PTR_DIFF, type, type); + } + } + } + } + + types= getClassConversionTypes(SECOND); + if (types.length == 0 && !fIsClass[SECOND]) { + types= new IType[] {fType2}; + } + for (IType type : types) { + type= SemanticUtil.getNestedType(type, TDEF|REF); + if (isPointer(type)) { + final IType ptrTarget = ((IPointerType) type).getType(); + final IType uqPtrTarget = SemanticUtil.getNestedType(ptrTarget, TDEF|CVTYPE); + if (!(uqPtrTarget instanceof IFunctionType)) { + if (isDiff) { + addFunction(PTR_DIFF, type, type); + } else { + final IType retType= useRef ? new CPPReferenceType(ptrTarget, false) : type; + addFunction(retType, PTR_DIFF, type); + } + } + } + } + } + + // 13.6-15, 13.6.16 + private void comparison(boolean ordered) { + for (int i = FIRST; i <= SECOND; i++) { + IType[] types= getClassConversionTypes(i); + for (IType type : types) { + type= SemanticUtil.getNestedType(type, TDEF|REF|CVTYPE); + if (isPointer(type) || isEnumeration(type) || (!ordered && isPointerToMember(type))) { + addFunction(BOOL, type, type); + } + } + } + } + + // 13.6-18, 13.6-29, 13.6-20, 13.6-22 + private void arithmeticAssignement(boolean fltPt, boolean self, boolean ptr) { + List p1= null, p2= null; + + IType[] types1= getClassConversionTypes(FIRST); + IType[] types2= getClassConversionTypes(SECOND); + if (types1.length == 0 && types2.length == 0) + return; + + for (IType t : types1) { + p1 = addArithmeticRef(t, fltPt, p1, self, ptr); + } + p1= addArithmeticRef(fType1, fltPt, p1, false, false); + for (IType t : types2) { + p2 = addPromotedArithmetic(t, fltPt, p2); + } + p2= addPromotedArithmetic(fType2, fltPt, p2); + if (p1 == null || p2 == null) + return; + + for (IType t1 : p1) { + for (IType t2 : p2) { + addFunction(t1, t1, t2); + } + } + } + + private List addArithmeticRef(IType t, boolean fltPt, List p1, boolean self, boolean ptr) { + final IType type= t= SemanticUtil.getNestedType(t, TDEF); + if (type instanceof ICPPReferenceType) { + t= SemanticUtil.getNestedType(((ICPPReferenceType) t).getType(), TDEF); + if (!SemanticUtil.getCVQualifier(t).isConst()) { + t = SemanticUtil.getNestedType(t, TDEF|CVTYPE); + if (fltPt ? isArithmetic(t) : isIntegral(t)) { + if (p1 == null) { + p1= new ArrayList(); + } + p1.add(type); + } + if (self && (isEnumeration(t) || isPointerToMember(t) || isPointer(t))) { + addFunction(type, type, SemanticUtil.getNestedType(t, TDEF|ALLCVQ)); + } + if (ptr && isPointer(t)) { + addFunction(type, type, PTR_DIFF); + } + } + } + return p1; + } + + private void addFunction(IType returnType, IType p1) { + addFunction(returnType, new IType[] {p1}); + } + + private void addFunction(IType returnType, IType p1, IType p2) { + addFunction(returnType, new IType[] {p1, p2}); + } + + private void addFunction(IType returnType, IType[] parameterTypes) { + ICPPParameter[] parameter = new ICPPParameter[parameterTypes.length]; + ICPPFunctionType functionType = new CPPFunctionType(returnType, parameterTypes); + String sig= ASTTypeUtil.getType(functionType, true); + if (fSignatures == null) { + fSignatures= new HashSet(); + } + if (fSignatures.add(sig)) { + for (int i = 0; i < parameterTypes.length; i++) { + IType t = parameterTypes[i]; + parameter[i]= new CPPBuiltinParameter(t); + } + if (fResult == null) { + fResult= new ArrayList(); + } + fResult.add(new CPPImplicitFunction(fOperator.toCharArray(), fFileScope, functionType, parameter, false)); + } + } + + private boolean isEnumeration(IType type) { + return type instanceof IEnumeration; + } + + private boolean isPointer(IType type) { + return type instanceof IPointerType && !(type instanceof ICPPPointerToMemberType); + } + + private boolean isPointerToMember(IType type) { + return type instanceof ICPPPointerToMemberType; + } + + private boolean isBoolean(IType type) { + return type instanceof IBasicType && ((IBasicType) type).getKind() == Kind.eBoolean; + } + + private boolean isFloatingPoint(IType type) { + if (type instanceof IBasicType) { + IBasicType.Kind kind= ((IBasicType) type).getKind(); + switch(kind) { + case eDouble: + case eFloat: + return true; + case eBoolean: + case eChar: + case eChar16: + case eChar32: + case eInt: + case eWChar: + case eUnspecified: + case eVoid: + return false; + } + } + return false; + } + + private boolean isArithmetic(IType type) { + if (type instanceof IBasicType) { + IBasicType.Kind kind= ((IBasicType) type).getKind(); + switch(kind) { + case eBoolean: + case eChar: + case eChar16: + case eChar32: + case eDouble: + case eFloat: + case eInt: + case eWChar: + return true; + case eUnspecified: + case eVoid: + return false; + } + } + return false; + } + + private boolean isIntegral(IType type) { + if (type instanceof IBasicType) { + IBasicType.Kind kind= ((IBasicType) type).getKind(); + switch(kind) { + case eBoolean: + case eChar: + case eChar16: + case eChar32: + case eInt: + case eWChar: + return true; + case eDouble: + case eFloat: + case eUnspecified: + case eVoid: + return false; + } + } + return false; + } + + private IType[] getClassConversionTypes(int idx) { + IType[] result = fClassConversionTypes[idx]; + if (result == null) { + result= IType.EMPTY_TYPE_ARRAY; + IType type= idx == 0 ? fType1 : fType2; + if (type != null) { + type= SemanticUtil.getNestedType(type, TDEF | REF | CVTYPE); + if (type instanceof ICPPClassType) { + fIsClass[idx]= true; + try { + ICPPMethod[] ops = SemanticUtil.getConversionOperators((ICPPClassType) type); + result= new IType[ops.length]; + for (int i = 0; i < result.length; i++) { + final ICPPFunctionType functionType = ops[i].getType(); + if (functionType != null) { + result[i]= functionType.getReturnType(); + } + } + } catch (DOMException e) { + } + } + } + fClassConversionTypes[idx]= result; + } + return result; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index ac84b781b63..76ce81c9c0d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -2662,7 +2662,6 @@ public class CPPSemantics { if (!fieldReference.isPointerDereference()) return type; - char[] operatorName = OverloadableOperator.ARROW.toCharArray(); IASTExpression[] args = {owner}; // bug 205964: as long as the type is a class type, recurse. @@ -2700,7 +2699,7 @@ public class CPPSemantics { IASTFieldReference innerFR= new CPPASTFieldReference(arw, new CPPASTIdExpression(x)); innerFR.setParent(fieldReference); // connect to the AST - ICPPFunction op = findOverloadedOperator(innerFR, args, uTemp, operatorName, NonMemberMode.none); + ICPPFunction op = findOverloadedOperator(innerFR, args, uTemp, OverloadableOperator.ARROW, NonMemberMode.none); if (op == null) break; @@ -2723,15 +2722,13 @@ public class CPPSemantics { } public static ICPPFunction findOverloadedOperator(IASTArraySubscriptExpression exp) { - char[] name = OverloadableOperator.BRACKET.toCharArray(); IASTInitializerClause[] args = {exp.getArrayExpression(), exp.getArgument()}; IType type = exp.getArrayExpression().getExpressionType(); type = SemanticUtil.getUltimateTypeUptoPointers(type); - return findOverloadedOperator(exp, args, type, name, NonMemberMode.none); + return findOverloadedOperator(exp, args, type, OverloadableOperator.BRACKET, NonMemberMode.none); } public static ICPPFunction findOverloadedOperator(IASTFunctionCallExpression exp, ICPPClassType type) { - char[] name = OverloadableOperator.PAREN.toCharArray(); IASTInitializerClause[] args = exp.getArguments(); ArrayList argsToPass = new ArrayList(args.length + 1); argsToPass.add(exp.getFunctionNameExpression()); @@ -2740,7 +2737,7 @@ public class CPPSemantics { } args = argsToPass.toArray(new IASTInitializerClause[argsToPass.size()]); - return findOverloadedOperator(exp, args, type, name, NonMemberMode.none); + return findOverloadedOperator(exp, args, type, OverloadableOperator.PAREN, NonMemberMode.none); } public static ICPPFunction findOverloadedOperator(ICPPASTNewExpression exp) { @@ -2764,14 +2761,14 @@ public class CPPSemantics { } } IASTInitializerClause[] argArray = args.toArray(new IASTInitializerClause[args.size()]); - return findOverloadedOperator(exp, argArray, type, op.toCharArray(), NonMemberMode.all); + return findOverloadedOperator(exp, argArray, type, op, NonMemberMode.all); } public static ICPPFunction findOverloadedOperator(ICPPASTDeleteExpression exp) { OverloadableOperator op = OverloadableOperator.fromDeleteExpression(exp); IASTExpression[] args = { exp.getOperand() }; IType classType = getNestedClassType(exp); - return findOverloadedOperator(exp, args, classType, op.toCharArray(), NonMemberMode.all); + return findOverloadedOperator(exp, args, classType, op, NonMemberMode.all); } private static ICPPClassType getNestedClassType(ICPPASTDeleteExpression exp) { @@ -2907,7 +2904,7 @@ public class CPPSemantics { if (!isUserDefined(type)) return null; - return findOverloadedOperator(exp, args, type, op.toCharArray(), NonMemberMode.limited); + return findOverloadedOperator(exp, args, type, op, NonMemberMode.limited); } public static ICPPFunction findOverloadedOperator(IASTBinaryExpression exp) { @@ -2928,7 +2925,7 @@ public class CPPSemantics { lookupNonMember= NonMemberMode.limited; } - return findOverloadedOperator(exp, args, op1type, op.toCharArray(), lookupNonMember); + return findOverloadedOperator(exp, args, op1type, op, lookupNonMember); } /** @@ -2946,16 +2943,23 @@ public class CPPSemantics { }; dummy.setParent(first); - char[] name = OverloadableOperator.COMMA.toCharArray(); IASTExpression[] args = new IASTExpression[] { dummy , second }; - return findOverloadedOperator(dummy, args, lookupType, name, NonMemberMode.limited); + return findOverloadedOperator(dummy, args, lookupType, OverloadableOperator.COMMA, NonMemberMode.limited); } - enum NonMemberMode {none, limited, all} + private static enum NonMemberMode {none, limited, all} private static ICPPFunction findOverloadedOperator(IASTExpression parent, IASTInitializerClause[] args, IType methodLookupType, - char[] operatorName, NonMemberMode mode) { + OverloadableOperator operator, NonMemberMode mode) { ICPPClassType callToObjectOfClassType= null; - + IType type2= null; + if (args.length >= 2 && args[1] instanceof IASTExpression) { + type2= getUltimateTypeUptoPointers(((IASTExpression) args[1]).getExpressionType()); + } + + if (methodLookupType instanceof ICPPUnknownType || type2 instanceof ICPPUnknownType) { + return new CPPUnknownFunction(null, operator.toCharArray()); + } + // Find a method LookupData methodData = null; CPPASTName methodName = null; @@ -2964,7 +2968,7 @@ public class CPPSemantics { if (methodLookupType instanceof ICPPClassType) { ICPPClassType classType = (ICPPClassType) methodLookupType; - methodName = new CPPASTName(operatorName); + methodName = new CPPASTName(operator.toCharArray()); methodName.setParent(parent); methodName.setPropertyInParent(STRING_LOOKUP_PROPERTY); methodData = new LookupData(methodName); @@ -2986,16 +2990,13 @@ public class CPPSemantics { } // Find a function - LookupData funcData = null; - CPPASTName funcName = null; + CPPASTName funcName = new CPPASTName(operator.toCharArray()); + funcName.setParent(parent); + funcName.setPropertyInParent(STRING_LOOKUP_PROPERTY); + LookupData funcData = new LookupData(funcName); + funcData.setFunctionArguments(args); + funcData.ignoreMembers = true; // (13.3.1.2.3) if (mode != NonMemberMode.none || callToObjectOfClassType != null) { - funcName = new CPPASTName(operatorName); - funcName.setParent(parent); - funcName.setPropertyInParent(STRING_LOOKUP_PROPERTY); - funcData = new LookupData(funcName); - funcData.setFunctionArguments(args); - funcData.ignoreMembers = true; // (13.3.1.2.3) - try { if (mode != NonMemberMode.none) { IScope scope = CPPVisitor.getContainingScope(parent); @@ -3033,10 +3034,6 @@ public class CPPSemantics { // 13.3.1.2.3 // However, if no operand type has class type, only those non-member functions ... if (mode == NonMemberMode.limited) { - IType type2= null; - if (args.length >= 2 && args[1] instanceof IASTExpression) { - type2= getUltimateTypeUptoPointers(((IASTExpression) args[1]).getExpressionType()); - } if (funcData.foundItems != null && !(methodLookupType instanceof ICPPClassType) && !(type2 instanceof ICPPClassType)) { IEnumeration enum1= null; IEnumeration enum2= null; @@ -3092,14 +3089,19 @@ public class CPPSemantics { } } + if (methodLookupType instanceof ICPPClassType || type2 instanceof ICPPClassType) { + ICPPFunction[] builtins= BuiltinOperators.create(operator, args, parent.getTranslationUnit()); + mergeResults(funcData, builtins, false); + } + try { IBinding binding = null; - if (methodData != null && funcData != null) { + if (methodData != null && funcData.hasResults()) { // if there was two lookups then merge the results mergeResults(funcData, methodData.foundItems, false); funcData.firstArgIsImpliedMethodArg = true; binding = resolveAmbiguities(funcData, funcName); - } else if (funcData != null) { + } else if (funcData.hasResults()) { binding = resolveAmbiguities(funcData, funcName); } else if (methodData != null) { binding = resolveAmbiguities(methodData, methodName); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java index 3717aa99091..865de1d4003 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java @@ -43,6 +43,7 @@ import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.c.ICASTFieldDesignator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression; @@ -65,7 +66,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; @@ -625,17 +625,4 @@ public class LookupData { } return IBinding.EMPTY_BINDING_ARRAY; } - - public int getFoundItemCount() { - if (foundItems instanceof Object[]) { - Object[] items = (Object[]) foundItems; - int len; - for (len= items.length-1; len >=0; len--) { - if (items[len] != null) - break; - } - return len+1; - } - return 0; - } }