| /******************************************************************************* |
| * Copyright (c) 2010, 2016 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.ALLCVQ; |
| import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE; |
| 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 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.IASTNode; |
| 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.IFunction; |
| 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.ISemanticProblem; |
| 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.ICPPEnumeration; |
| 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.core.parser.util.ArrayUtil; |
| 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.CPPScope; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; |
| 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 PTR_DIFF = new CPPBasicType(Kind.eInt, 0); |
| |
| public static ICPPFunction[] create(OverloadableOperator operator, ICPPEvaluation[] args, |
| Object[] globCandidates) { |
| if (operator == null || args == null || args.length == 0) |
| return EMPTY; |
| |
| return new BuiltinOperators(operator, args, globCandidates).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<ICPPFunction> fResult; |
| private Set<String> fSignatures; |
| private Object[] fGlobalCandidates; |
| |
| BuiltinOperators(OverloadableOperator operator, ICPPEvaluation[] args, |
| Object[] globCandidates) { |
| IASTNode point = CPPSemantics.getCurrentLookupPoint(); |
| fFileScope= point == null ? |
| new CPPScope.CPPScopeProblem(null, IProblemBinding.SEMANTIC_BAD_SCOPE) : |
| point.getTranslationUnit().getScope(); |
| fOperator= operator; |
| fUnary= args.length < 2; |
| fGlobalCandidates= globCandidates; |
| if (args.length > 0) { |
| IType type= args[0].getType(); |
| if (!(type instanceof ISemanticProblem)) |
| fType1= type; |
| } |
| if (args.length > 1) { |
| IType type= args[1].getType(); |
| if (!(type instanceof ISemanticProblem)) |
| 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, Assignment.WITHOUT_OPERATION); |
| break; |
| |
| case MINUSASSIGN: |
| case PLUSASSIGN: |
| arithmeticAssignement(true, Assignment.WITH_POINTER_OPERATION); |
| break; |
| |
| case DIVASSIGN: |
| case STARASSIGN: |
| arithmeticAssignement(true, Assignment.WITH_OPERATION); |
| break; |
| |
| case AMPERASSIGN: |
| case BITORASSIGN: |
| case MODASSIGN: |
| case SHIFTLASSIGN: |
| case SHIFTRASSIGN: |
| case XORASSIGN: |
| arithmeticAssignement(false, Assignment.WITH_OPERATION); |
| break; |
| |
| case AND: |
| case OR: |
| addFunction(CPPBasicType.BOOLEAN, CPPBasicType.BOOLEAN, CPPBasicType.BOOLEAN); |
| break; |
| |
| case NOT: |
| addFunction(CPPBasicType.BOOLEAN, CPPBasicType.BOOLEAN); |
| break; |
| |
| case CONDITIONAL_OPERATOR: |
| binaryPromotedArithmetic(true, ReturnType.CONVERT); |
| conditional(); |
| 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|REF); |
| 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<IPointerType> classPointers= null; |
| List<ICPPPointerToMemberType> 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; |
| if (SemanticUtil.calculateInheritanceDepth(c1, c2) >= 0) { |
| IType cvt= SemanticUtil.getNestedType(memPtr.getType(), TDEF); |
| IType rt= new CPPReferenceType( |
| SemanticUtil.addQualifiers(cvt, cv1.isConst(), cv1.isVolatile(), cv1.isRestrict()), false); |
| addFunction(rt, clsPtr, memPtr); |
| } |
| } |
| } |
| } |
| } |
| |
| // 13.6-12, 13.6-17 |
| private static enum ReturnType {CONVERT, USE_FIRST, USE_BOOL} |
| private void binaryPromotedArithmetic(boolean fltPt, ReturnType rstrat) { |
| List<IType> 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= CPPBasicType.BOOLEAN; |
| break; |
| case USE_FIRST: |
| rt= t1; |
| break; |
| case CONVERT: |
| rt= CPPArithmeticConversion.convertCppOperandTypes(IASTBinaryExpression.op_plus, t1, t2); |
| break; |
| } |
| addFunction(rt, t1, t2); |
| } |
| } |
| } |
| |
| private List<IType> addPromotedArithmetic(IType t, boolean fltPt, List<IType> 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(CPPBasicType.BOOLEAN, type, type); |
| } |
| } |
| } |
| } |
| |
| // 13.6-18, 13.6-29, 13.6-20, 13.6-22 |
| private static enum Assignment {WITHOUT_OPERATION, WITH_POINTER_OPERATION, WITH_OPERATION} |
| private void arithmeticAssignement(boolean fltPt, Assignment assign) { |
| IType[] types2= getClassConversionTypes(SECOND); |
| if (types2.length == 0) |
| return; |
| |
| IType refType= SemanticUtil.getNestedType(fType1, TDEF); |
| if (refType instanceof ICPPReferenceType) { |
| IType t= SemanticUtil.getNestedType(((ICPPReferenceType) refType).getType(), TDEF); |
| if (!SemanticUtil.getCVQualifier(t).isConst()) { |
| switch (assign) { |
| case WITHOUT_OPERATION: |
| if (isEnumeration(t) || isPointerToMember(t) || isPointer(t)) { |
| addFunction(refType, refType, SemanticUtil.getNestedType(t, TDEF|ALLCVQ)); |
| return; |
| } |
| break; |
| case WITH_POINTER_OPERATION: |
| if (isPointer(t)) { |
| addFunction(refType, refType, PTR_DIFF); |
| return; |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| if (fltPt ? isArithmetic(t) : isIntegral(t)) { |
| List<IType> p2= null; |
| for (IType t2 : types2) { |
| p2 = addPromotedArithmetic(t2, fltPt, p2); |
| } |
| if (p2 != null) { |
| for (IType t2 : p2) { |
| addFunction(refType, refType, t2); |
| } |
| } |
| } |
| } |
| } |
| |
| // 13.6-25 |
| private void conditional() { |
| 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) || isScopedEnumeration(type) || isPointerToMember(type)) { |
| addFunction(type, type, type); |
| } |
| } |
| } |
| } |
| |
| 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 (fGlobalCandidates != null) { |
| for (Object cand : fGlobalCandidates) { |
| if (cand instanceof IFunction && !(cand instanceof ICPPMethod)) { |
| fSignatures.add(ASTTypeUtil.getType(((IFunction) cand).getType(), true)); |
| } |
| } |
| } |
| } |
| 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, true, false)); |
| } |
| } |
| |
| private boolean isEnumeration(IType type) { |
| return type instanceof IEnumeration; |
| } |
| |
| private boolean isScopedEnumeration(IType type) { |
| return type instanceof ICPPEnumeration && ((ICPPEnumeration) type).isScoped(); |
| } |
| |
| private boolean isPointer(IType type) { |
| return type instanceof IPointerType && !(type instanceof ICPPPointerToMemberType); |
| } |
| |
| private boolean isPointerToMember(IType type) { |
| return type instanceof ICPPPointerToMemberType; |
| } |
| |
| private static boolean isBoolean(IType type) { |
| return type instanceof IBasicType && ((IBasicType) type).getKind() == Kind.eBoolean; |
| } |
| |
| public static boolean isFloatingPoint(IType type) { |
| if (type instanceof IBasicType) { |
| IBasicType.Kind kind= ((IBasicType) type).getKind(); |
| switch (kind) { |
| case eDouble: |
| case eFloat: |
| case eFloat128: |
| case eDecimal32: |
| case eDecimal64: |
| case eDecimal128: |
| return true; |
| case eBoolean: |
| case eChar: |
| case eChar16: |
| case eChar32: |
| case eInt: |
| case eInt128: |
| case eWChar: |
| case eUnspecified: |
| case eVoid: |
| case eNullPtr: |
| return false; |
| } |
| } |
| return false; |
| } |
| |
| private static 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 eFloat128: |
| case eDecimal32: |
| case eDecimal64: |
| case eDecimal128: |
| case eInt: |
| case eInt128: |
| case eWChar: |
| return true; |
| case eUnspecified: |
| case eNullPtr: |
| case eVoid: |
| return false; |
| } |
| } |
| return false; |
| } |
| |
| public static 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 eInt128: |
| case eWChar: |
| return true; |
| case eDouble: |
| case eFloat: |
| case eFloat128: |
| case eDecimal32: |
| case eDecimal64: |
| case eDecimal128: |
| case eUnspecified: |
| case eVoid: |
| case eNullPtr: |
| 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]; |
| int j= -1; |
| for (ICPPMethod op : ops) { |
| if (op.isExplicit()) |
| continue; |
| final ICPPFunctionType functionType = op.getType(); |
| if (functionType != null) { |
| IType retType= functionType.getReturnType(); |
| if (retType != null) { |
| result[++j]= retType; |
| } |
| } |
| } |
| result= ArrayUtil.trimAt(IType.class, result, j); |
| } catch (DOMException e) { |
| } |
| } |
| } |
| fClassConversionTypes[idx]= result; |
| } |
| return result; |
| } |
| } |