From 49891dac3a89657decc13017fd05cbacb0949283 Mon Sep 17 00:00:00 2001 From: Mike Kucera Date: Tue, 24 Feb 2009 17:49:37 +0000 Subject: [PATCH] bug 265982, support for overloaded unary operators --- .../core/parser/tests/ast2/AST2CPPTests.java | 102 +++++++++++++++++ .../parser/cpp/CPPASTLiteralExpression.java | 3 + .../dom/parser/cpp/CPPASTUnaryExpression.java | 107 ++++++++++++------ .../dom/parser/cpp/OverloadableOperator.java | 20 +++- .../parser/cpp/semantics/CPPSemantics.java | 64 ++++++++--- 5 files changed, 241 insertions(+), 55 deletions(-) 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 24b7409ed7c..d107834246e 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 @@ -6425,6 +6425,108 @@ public class AST2CPPTests extends AST2BaseTest { ba.assertProblem("a; //6", 1); } + + // struct A { + // int x; + // }; + // + // struct B { + // A& operator++(); // prefix + // A operator++(int); // postfix + // }; + // + // void test(B p1, B p2) { + // (p1++).x; //1 + // (++p1).x; //2 + // } + public void testOverloadedUnaryOperator_259927_3() throws Exception { + BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); + ba.assertNonProblem("x; //1", 1, ICPPField.class); + ba.assertNonProblem("x; //2", 1, ICPPField.class); + } + + + // struct A { + // int x; + // }; + // struct B { }; + // A& operator++(B); // prefix + // A operator++(B, int); // postfix + // + // void test(B p1, B p2) { + // (p1++).x; //1 + // (++p1).x; //2 + // } + public void testOverloadedUnaryOperator_259927_4() throws Exception { + BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); + ba.assertNonProblem("x; //1", 1, ICPPField.class); + ba.assertNonProblem("x; //2", 1, ICPPField.class); + } + + + // struct A { + // int xx; + // }; + // + // + // struct B { + // A operator*(); + // A operator&(); + // A operator+(); + // A operator-(); + // A operator!(); + // A operator~(); + // }; + // + // int main() { + // B b; + // + // (*b).xx; // 1 + // (&b).xx; // 2 + // (+b).xx; // 3 + // (-b).xx; // 4 + // (!b).xx; // 5 + // (~b).xx; // 6 + // } + public void testOverloadedUnaryOperator_259927_5() throws Exception { + BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); + for(int i = 1; i <=6; i++) + ba.assertNonProblem("xx; // "+i, 2, ICPPField.class); + } + + // struct A { + // int xx; + // }; + // + // + // struct B { + // }; + // + // A operator*(B); + // A operator&(B); + // A operator+(B); + // A operator-(B); + // A operator!(B); + // A operator~(B); + // + // int main() { + // B b; + // + // (*b).xx; // 1 + // (&b).xx; // 2 + // (+b).xx; // 3 + // (-b).xx; // 4 + // (!b).xx; // 5 + // (~b).xx; // 6 + //} + public void testOverloadedUnaryOperator_259927_6() throws Exception { + BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); + for(int i = 1; i <=6; i++) + ba.assertNonProblem("xx; // "+i, 2, ICPPField.class); + } + + + // int a,b,c,d ; // class X { // void m() { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLiteralExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLiteralExpression.java index e07124890a2..9965e5ecd89 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLiteralExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTLiteralExpression.java @@ -26,6 +26,9 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; */ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralExpression { + public static final CPPASTLiteralExpression INT_ZERO = new CPPASTLiteralExpression(lk_integer_constant, new char[] {'0'} ); + + private int kind; private char[] value = CharArrayUtils.EMPTY; 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 2df9894d268..cab01d70547 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 @@ -1,6 +1,6 @@ /******************************************************************************* * Copyright (c) 2004, 2009 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials + * All rights reserved. This program and the accompanying masterials * 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 @@ -8,12 +8,11 @@ * Contributors: * John Camelon (IBM) - Initial API and implementation * Sergey Prigogin (Google) + * Mike Kucera (IBM) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVQ; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; +import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.DOMException; @@ -122,39 +121,14 @@ public class CPPASTUnaryExpression extends ASTNode implements ICPPASTUnaryExpres return CPPVisitor.get_SIZE_T(this); case IASTUnaryExpression.op_typeid: return CPPVisitor.get_type_info(this); - case IASTUnaryExpression.op_not: - return new CPPBasicType(ICPPBasicType.t_bool, 0); } final IASTExpression operand = getOperand(); - if (op == IASTUnaryExpression.op_star) { - IType type= operand.getExpressionType(); - type = SemanticUtil.getNestedType(type, TDEF | REF | CVQ); - if (type instanceof IProblemBinding) { - return type; - } - try { - if (type instanceof ICPPClassType) { - ICPPFunction operator= CPPSemantics.findOperator(this, (ICPPClassType) type); - if (operator != null) { - return operator.getType().getReturnType(); - } - } else if (type instanceof IPointerType || type instanceof IArrayType) { - return ((ITypeContainer) type).getType(); - } else if (type instanceof ICPPUnknownType) { - return CPPUnknownClass.createUnnamedInstance(); - } - } catch (DOMException e) { - return e.getProblem(); - } - return new ProblemBinding(this, IProblemBinding.SEMANTIC_INVALID_TYPE, - this.getRawSignature().toCharArray()); - } - if (op == IASTUnaryExpression.op_amper) { + + if (op == IASTUnaryExpression.op_amper) { // check for pointer to member IASTNode child= operand; boolean inParenthesis= false; - while (child instanceof IASTUnaryExpression && - ((IASTUnaryExpression) child).getOperator() == IASTUnaryExpression.op_bracketedPrimary) { + while (child instanceof IASTUnaryExpression && ((IASTUnaryExpression) child).getOperator() == IASTUnaryExpression.op_bracketedPrimary) { child= ((IASTUnaryExpression) child).getOperand(); inParenthesis= true; } @@ -165,13 +139,11 @@ public class CPPASTUnaryExpression extends ASTNode implements ICPPASTUnaryExpres ICPPMember member= (ICPPMember) b; try { if (name instanceof ICPPASTQualifiedName) { - if (!member.isStatic()) { + if (!member.isStatic()) { // so if the member is static it will fall through if (!inParenthesis) { - return new CPPPointerToMemberType(member.getType(), member.getClassOwner(), - false, false); + return new CPPPointerToMemberType(member.getType(), member.getClassOwner(), false, false); } else if (member instanceof IFunction) { - return new ProblemBinding(operand, IProblemBinding.SEMANTIC_INVALID_TYPE, - operand.getRawSignature().toCharArray()); + return new ProblemBinding(operand, IProblemBinding.SEMANTIC_INVALID_TYPE, operand.getRawSignature().toCharArray()); } } } @@ -183,14 +155,75 @@ public class CPPASTUnaryExpression extends ASTNode implements ICPPASTUnaryExpres IType type= operand.getExpressionType(); type = SemanticUtil.getNestedType(type, TDEF | REF); + + IType operator = findOperatorReturnType(type); + if(operator != null) + return operator; + return new CPPPointerType(type); } + + + if (op == IASTUnaryExpression.op_star) { + IType type= operand.getExpressionType(); + type = SemanticUtil.getNestedType(type, TDEF | REF | CVQ); + if (type instanceof IProblemBinding) { + return type; + } + try { + IType operator = findOperatorReturnType(type); + if(operator != null) { + return operator; + } else if (type instanceof IPointerType || type instanceof IArrayType) { + return ((ITypeContainer) type).getType(); + } else if (type instanceof ICPPUnknownType) { + return CPPUnknownClass.createUnnamedInstance(); + } + } catch (DOMException e) { + return e.getProblem(); + } + return new ProblemBinding(this, IProblemBinding.SEMANTIC_INVALID_TYPE, this.getRawSignature().toCharArray()); + } + IType type= operand.getExpressionType(); type = SemanticUtil.getNestedType(type, TDEF | REF); + IType operator = findOperatorReturnType(type); + if(operator != null) { + return operator; + } + + if(op == IASTUnaryExpression.op_not) { + return new CPPBasicType(ICPPBasicType.t_bool, 0); + } if (type instanceof CPPBasicType) { ((CPPBasicType) type).setFromExpression(this); } return type; } + + + private IType findOperatorReturnType(IType type) { + ICPPFunction operatorFunction = findOperatorFunction(type); + if(operatorFunction != null) { + try { + return operatorFunction.getType().getReturnType(); + } catch (DOMException e) { + return e.getProblem(); + } + } + return null; + } + + + private ICPPFunction findOperatorFunction(IType type) { + if(type instanceof ICPPClassType) { + ICPPFunction operator = CPPSemantics.findOperator(this, (ICPPClassType) type); + if(operator != null) + return operator; + return CPPSemantics.findOverloadedOperator(this); + } + + return null; + } } 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 23cdb1d0fe2..bd8330d3650 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,11 +7,13 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Mike Kucera (IBM) * 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.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.parser.IToken; /** @@ -19,8 +21,6 @@ import org.eclipse.cdt.core.parser.IToken; * * Note: toString() has not been overridden, use toCharArray() to get * a character representation of the operator. - * - * @author Mike Kucera */ @SuppressWarnings("nls") public enum OverloadableOperator { @@ -187,4 +187,20 @@ public enum OverloadableOperator { return null; } + + public static OverloadableOperator fromUnaryExpression(IASTUnaryExpression expression) { + switch(expression.getOperator()) { + case IASTUnaryExpression.op_prefixIncr: return INCR; + case IASTUnaryExpression.op_prefixDecr: return DECR; + case IASTUnaryExpression.op_plus: return PLUS; + case IASTUnaryExpression.op_minus: return MINUS; + case IASTUnaryExpression.op_star: return STAR; + case IASTUnaryExpression.op_amper: return AMPER; + case IASTUnaryExpression.op_tilde: return BITCOMPLEMENT; + case IASTUnaryExpression.op_not: return NOT; + case IASTUnaryExpression.op_postFixIncr: return INCR; + case IASTUnaryExpression.op_postFixDecr: return DECR; + } + 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 ccfd7754d60..54fd01ee445 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 @@ -11,13 +11,11 @@ * Bryan Wilkinson (QNX) * Andrew Ferguson (Symbian) * Sergey Prigogin (Google) + * Mike Kucera (IBM) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateType; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateTypeUptoPointers; +import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*; import java.util.ArrayList; import java.util.HashMap; @@ -142,6 +140,7 @@ import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit; @@ -2493,12 +2492,7 @@ public class CPPSemantics { astName.setPropertyInParent(STRING_LOOKUP_PROPERTY); LookupData data; - if (exp instanceof IASTUnaryExpression) { - astName.setName(OverloadableOperator.STAR.toCharArray()); - data = new LookupData(astName); - data.forceQualified = true; - data.setFunctionArguments(IASTExpression.EMPTY_EXPRESSION_ARRAY); - } else if (exp instanceof IASTArraySubscriptExpression) { + if (exp instanceof IASTArraySubscriptExpression) { astName.setName(OverloadableOperator.BRACKET.toCharArray()); data = new LookupData(astName); data.forceQualified = true; @@ -2523,6 +2517,20 @@ public class CPPSemantics { data = new LookupData(astName); data.forceQualified = true; data.setFunctionArguments(new IASTExpression[] { binary.getOperand2() }); + } else if (exp instanceof IASTUnaryExpression) { + IASTUnaryExpression unary = (IASTUnaryExpression) exp; + OverloadableOperator operator = OverloadableOperator.fromUnaryExpression(unary); + if(operator == null) { + return null; + } + astName.setName(operator.toCharArray()); + data = new LookupData(astName); + data.forceQualified = true; + int op = unary.getOperator(); + if(op == IASTUnaryExpression.op_postFixDecr || op == IASTUnaryExpression.op_postFixIncr) + data.setFunctionArguments(new IASTExpression[] { CPPASTLiteralExpression.INT_ZERO }); + else + data.setFunctionArguments(IASTExpression.EMPTY_EXPRESSION_ARRAY); } else { return null; } @@ -2545,6 +2553,30 @@ public class CPPSemantics { */ public static ICPPFunction findOverloadedOperator(IASTBinaryExpression exp) { OverloadableOperator operator = OverloadableOperator.fromBinaryExpression(exp); + IASTExpression[] args = { exp.getOperand1(), exp.getOperand2() }; + return findOverloadedOperator(exp, operator, args); + } + + + /** + * Returns the overloaded operator corresponding to a unary expression, or {@code null} + * if no such operator is found. + */ + public static ICPPFunction findOverloadedOperator(IASTUnaryExpression exp) { + OverloadableOperator operator = OverloadableOperator.fromUnaryExpression(exp); + + IASTExpression[] args = null; + int op = exp.getOperator(); + if(op == IASTUnaryExpression.op_postFixDecr || op == IASTUnaryExpression.op_postFixIncr) + args = new IASTExpression[] { exp.getOperand(), CPPASTLiteralExpression.INT_ZERO }; + else + args = new IASTExpression[] { exp.getOperand() }; + + return findOverloadedOperator(exp, operator, args); + } + + + private static ICPPFunction findOverloadedOperator(IASTExpression exp, OverloadableOperator operator, IASTExpression[] args) { if (operator == null) { return null; } @@ -2558,18 +2590,18 @@ public class CPPSemantics { astName.setPropertyInParent(STRING_LOOKUP_PROPERTY); astName.setName(operator.toCharArray()); LookupData data = new LookupData(astName); - data.setFunctionArguments(new IASTExpression[] {exp.getOperand1(), exp.getOperand2()}); - + data.setFunctionArguments(args); + try { lookup(data, scope); IBinding binding = resolveAmbiguities(data, astName); if (binding instanceof ICPPFunction) return (ICPPFunction) binding; - } catch (DOMException e) { - } + } catch (DOMException e) {} return null; - } - + } + + public static IBinding[] findBindings(IScope scope, String name, boolean qualified) throws DOMException { return findBindings(scope, name.toCharArray(), qualified, null); }