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 260ec86a443..58dffcfb95a 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 @@ -6331,7 +6331,7 @@ public class AST2CPPTests extends AST2BaseTest { ICPPFunction f2= ba.assertNonProblem("func(*b)", 4, ICPPFunction.class); assertNotSame(f1, f2); } - + // struct C {int a;}; // void myfunc(C c) { // return c < c.a || @@ -6346,4 +6346,32 @@ public class AST2CPPTests extends AST2BaseTest { final String code= getAboveComment(); parseAndCheckBindings(code); } + + // struct A { + // int a; + // }; + // + // struct B { + // A operator-(B b2); + // A operator+(B& b2); + // A operator*(const B& b2); + // A operator/(B b2) const; + // A operator%(const B& b2) const; + // }; + // + // void test(B p1, B p2) { + // (p1 - p2).a; //1 + // (p1 + p2).a; //2 + // (p1 * p2).a; //3 + // (p1 / p2).a; //4 + // (p1 % p2).a; //5 + // } + public void testOverloadedBinaryOperator_259927() throws Exception { + BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); + ba.assertNonProblem("a; //1", 1, ICPPField.class); + ba.assertNonProblem("a; //2", 1, ICPPField.class); + ba.assertNonProblem("a; //3", 1, ICPPField.class); + ba.assertNonProblem("a; //4", 1, ICPPField.class); + ba.assertNonProblem("a; //5", 1, ICPPField.class); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/OverloadableOperator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/OverloadableOperator.java index bd66683c7b3..23cdb1d0fe2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/OverloadableOperator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/OverloadableOperator.java @@ -7,9 +7,11 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; +import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.parser.IToken; /** @@ -66,7 +68,6 @@ public enum OverloadableOperator { DELETE("delete"), NEW_ARRAY("new[]"); - private final char[] rep; private OverloadableOperator(String rep) { @@ -78,59 +79,110 @@ public enum OverloadableOperator { } /** - * Returns the OverloadableOperator constant that corresponds to the - * given token. Only works for operators that consist of one token. + * Returns the OverloadableOperator constant that corresponds to + * the given token. Only works for operators that consist of one token. * - * @throws NullPointerException if token is null + * @throws NullPointerException if {@code token} is {@code null}. */ public static OverloadableOperator valueOf(IToken token) { - switch(token.getType()) { - case IToken.t_delete: return DELETE; - case IToken.t_new: return NEW; - case IToken.tAMPER: return AMPER; - case IToken.tAMPERASSIGN: return AMPERASSIGN; - case IToken.tARROW: return ARROW; - case IToken.tARROWSTAR: return ARROWSTAR; - case IToken.tBITOR: return BITOR; - case IToken.tBITORASSIGN: return BITORASSIGN; - case IToken.tBITCOMPLEMENT: return BITCOMPLEMENT; - case IToken.tSHIFTL: return SHIFTL; - case IToken.tSHIFTLASSIGN: return SHIFTLASSIGN; - case IToken.tSHIFTR: return SHIFTR; - case IToken.tSHIFTRASSIGN: return SHIFTRASSIGN; - case IToken.tXOR: return XOR; - case IToken.tXORASSIGN: return XORASSIGN; - - // logical operations - case IToken.tNOT: return NOT; - case IToken.tAND: return AND; - case IToken.tOR: return OR; + switch (token.getType()) { + case IToken.t_delete: return DELETE; + case IToken.t_new: return NEW; + case IToken.tAMPER: return AMPER; + case IToken.tAMPERASSIGN: return AMPERASSIGN; + case IToken.tARROW: return ARROW; + case IToken.tARROWSTAR: return ARROWSTAR; + case IToken.tBITOR: return BITOR; + case IToken.tBITORASSIGN: return BITORASSIGN; + case IToken.tBITCOMPLEMENT: return BITCOMPLEMENT; + case IToken.tSHIFTL: return SHIFTL; + case IToken.tSHIFTLASSIGN: return SHIFTLASSIGN; + case IToken.tSHIFTR: return SHIFTR; + case IToken.tSHIFTRASSIGN: return SHIFTRASSIGN; + case IToken.tXOR: return XOR; + case IToken.tXORASSIGN: return XORASSIGN; + + // logical operations + case IToken.tNOT: return NOT; + case IToken.tAND: return AND; + case IToken.tOR: return OR; - // arithmetic - case IToken.tDECR: return DECR; - case IToken.tINCR: return INCR; - case IToken.tDIV: return DIV; - case IToken.tDIVASSIGN: return DIVASSIGN; - case IToken.tMINUS: return MINUS; - case IToken.tMINUSASSIGN: return MINUSASSIGN; - case IToken.tMOD: return MOD; - case IToken.tMODASSIGN: return MODASSIGN; - case IToken.tPLUS: return PLUS; - case IToken.tPLUSASSIGN: return PLUSASSIGN; - case IToken.tSTAR: return STAR; - case IToken.tSTARASSIGN: return STARASSIGN; - - // comparison - case IToken.tEQUAL: return EQUAL; - case IToken.tNOTEQUAL: return NOTEQUAL; - case IToken.tGT: return GT; - case IToken.tGTEQUAL: return GTEQUAL; - case IToken.tLT: return LT; - case IToken.tLTEQUAL: return LTEQUAL; - - // other - case IToken.tASSIGN: return ASSIGN; - case IToken.tCOMMA: return COMMA; + // arithmetic + case IToken.tDECR: return DECR; + case IToken.tINCR: return INCR; + case IToken.tDIV: return DIV; + case IToken.tDIVASSIGN: return DIVASSIGN; + case IToken.tMINUS: return MINUS; + case IToken.tMINUSASSIGN: return MINUSASSIGN; + case IToken.tMOD: return MOD; + case IToken.tMODASSIGN: return MODASSIGN; + case IToken.tPLUS: return PLUS; + case IToken.tPLUSASSIGN: return PLUSASSIGN; + case IToken.tSTAR: return STAR; + case IToken.tSTARASSIGN: return STARASSIGN; + + // comparison + case IToken.tEQUAL: return EQUAL; + case IToken.tNOTEQUAL: return NOTEQUAL; + case IToken.tGT: return GT; + case IToken.tGTEQUAL: return GTEQUAL; + case IToken.tLT: return LT; + case IToken.tLTEQUAL: return LTEQUAL; + + // other + case IToken.tASSIGN: return ASSIGN; + case IToken.tCOMMA: return COMMA; + } + + return null; + } + + /** + * Returns the OverloadableOperator constant that corresponds to + * the given binary expression. + * + * @throws NullPointerException if {@code expression} is {@code null}. + */ + public static OverloadableOperator fromBinaryExpression(IASTBinaryExpression expression) { + switch (expression.getOperator()) { + case IASTBinaryExpression.op_binaryAnd: return AMPER; + case IASTBinaryExpression.op_binaryAndAssign: return AMPERASSIGN; + case IASTBinaryExpression.op_pmarrow: return ARROW; + case IASTBinaryExpression.op_binaryOr: return BITOR; + case IASTBinaryExpression.op_binaryOrAssign: return BITORASSIGN; + case IASTBinaryExpression.op_shiftLeft: return SHIFTL; + case IASTBinaryExpression.op_shiftLeftAssign: return SHIFTLASSIGN; + case IASTBinaryExpression.op_shiftRight: return SHIFTR; + case IASTBinaryExpression.op_shiftRightAssign: return SHIFTRASSIGN; + case IASTBinaryExpression.op_binaryXor: return XOR; + case IASTBinaryExpression.op_binaryXorAssign: return XORASSIGN; + + // logical operations + case IASTBinaryExpression.op_logicalAnd: return AND; + case IASTBinaryExpression.op_logicalOr: return OR; + + // arithmetic + case IASTBinaryExpression.op_divide: return DIV; + case IASTBinaryExpression.op_divideAssign: return DIVASSIGN; + case IASTBinaryExpression.op_minus: return MINUS; + case IASTBinaryExpression.op_minusAssign: return MINUSASSIGN; + case IASTBinaryExpression.op_modulo: return MOD; + case IASTBinaryExpression.op_moduloAssign: return MODASSIGN; + case IASTBinaryExpression.op_plus: return PLUS; + case IASTBinaryExpression.op_plusAssign: return PLUSASSIGN; + case IASTBinaryExpression.op_multiply: return STAR; + case IASTBinaryExpression.op_multiplyAssign: return STARASSIGN; + + // comparison + case IASTBinaryExpression.op_equals: return EQUAL; + case IASTBinaryExpression.op_notequals: return NOTEQUAL; + case IASTBinaryExpression.op_greaterThan: return GT; + case IASTBinaryExpression.op_greaterEqual: return GTEQUAL; + case IASTBinaryExpression.op_lessThan: return LT; + case IASTBinaryExpression.op_lessEqual: return LTEQUAL; + + // other + case IASTBinaryExpression.op_assign: return ASSIGN; } return null; 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 1269166bd46..00db31e1b56 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 @@ -2574,6 +2574,16 @@ public class CPPSemantics { } else { data.functionParameters = new IASTExpression[] {paramExpression}; } + } else if (exp instanceof IASTBinaryExpression) { + final IASTBinaryExpression binary = (IASTBinaryExpression) exp; + OverloadableOperator operator = OverloadableOperator.fromBinaryExpression(binary); + if (operator == null) { + return null; + } + astName.setName(operator.toCharArray()); + data = new LookupData(astName); + data.forceQualified = true; + data.functionParameters = new IASTExpression[] { binary.getOperand2() }; } else { return null; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index efc0da3659b..26aa90d0de1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -1876,6 +1876,33 @@ public class CPPVisitor extends ASTQueries { } } else if (expression instanceof IASTBinaryExpression) { final IASTBinaryExpression binary = (IASTBinaryExpression) expression; + + // Check for overloaded operator. + IType type1 = getExpressionType(binary.getOperand1()); + while (type1 instanceof ITypedef) { + try { + type1 = ((ITypedef) type1).getType(); + } catch (DOMException e) { + break; + } + } + try { + if (type1 instanceof ICPPReferenceType) { + type1 = ((ICPPReferenceType) type1).getType(); + } + if (type1 instanceof IQualifierType) { + type1 = ((IQualifierType) type1).getType(); + } + if (type1 instanceof ICPPClassType) { + ICPPFunction operator= CPPSemantics.findOperator(expression, (ICPPClassType) type1); + if (operator != null) { + return operator.getType().getReturnType(); + } + } + } catch (DOMException e) { + return e.getProblem(); + } + final int op = binary.getOperator(); switch (op) { case IASTBinaryExpression.op_lessEqual: 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 e86ceb42934..e0dec2e33c9 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 @@ -18,26 +18,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; -import org.eclipse.cdt.core.dom.ast.DOMException; -import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; -import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; -import org.eclipse.cdt.core.dom.ast.IASTDeclaration; -import org.eclipse.cdt.core.dom.ast.IASTDeclarator; -import org.eclipse.cdt.core.dom.ast.IASTExpression; -import org.eclipse.cdt.core.dom.ast.IASTFieldReference; -import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; -import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; -import org.eclipse.cdt.core.dom.ast.IASTIdExpression; -import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; -import org.eclipse.cdt.core.dom.ast.IASTNode; -import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; -import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; -import org.eclipse.cdt.core.dom.ast.IASTTypeId; -import org.eclipse.cdt.core.dom.ast.IPointerType; -import org.eclipse.cdt.core.dom.ast.IScope; -import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.*; 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.ICPPASTConstructorChainInitializer; @@ -372,6 +353,9 @@ class LookupData { if (tempNameParent instanceof IASTFunctionCallExpression) { return CPPVisitor.getExpressionType(((IASTFunctionCallExpression) tempNameParent).getFunctionNameExpression()); } + if (tempNameParent instanceof IASTBinaryExpression) { + return CPPVisitor.getExpressionType(((IASTBinaryExpression) tempNameParent).getOperand1()); + } return null; } if (prop == IASTFieldReference.FIELD_NAME) {