| /******************************************************************************* |
| * Copyright (c) 2009, 2015 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.CPPTemplates.TypeSelection.PARAMETERS; |
| import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates.TypeSelection.RETURN_TYPE; |
| 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 static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; |
| |
| import java.util.Arrays; |
| |
| import org.eclipse.cdt.core.dom.ast.DOMException; |
| import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; |
| import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; |
| import org.eclipse.cdt.core.dom.ast.IBinding; |
| import org.eclipse.cdt.core.dom.ast.IFunction; |
| 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.ICPPFunctionTemplate; |
| 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.ICPPSpecialization; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates.TypeSelection; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.DeferredUDC; |
| |
| /** |
| * Cost for the entire function call. |
| */ |
| class FunctionCost { |
| private final ICPPFunction fFunction; |
| private final Cost[] fCosts; |
| private final ValueCategory[] fValueCategories; |
| private boolean fIsDirectCopyCtor; |
| |
| public FunctionCost(ICPPFunction fn, int paramCount) { |
| fFunction= fn; |
| fCosts= new Cost[paramCount]; |
| fValueCategories= new ValueCategory[paramCount]; |
| } |
| |
| public FunctionCost(ICPPFunction fn, Cost cost) { |
| fFunction= fn; |
| fCosts= new Cost[] {cost}; |
| fValueCategories= null; // no udc will be performed |
| } |
| |
| public int getLength() { |
| return fCosts.length; |
| } |
| |
| public Cost getCost(int idx) { |
| return fCosts[idx]; |
| } |
| |
| public void setCost(int idx, Cost cost, ValueCategory valueCat) { |
| fCosts[idx]= cost; |
| fValueCategories[idx]= valueCat; |
| } |
| |
| public ICPPFunction getFunction() { |
| return fFunction; |
| } |
| |
| public boolean hasAmbiguousUserDefinedConversion() { |
| for (Cost cost : fCosts) { |
| if (cost.isAmbiguousUDC()) |
| return true; |
| } |
| return false; |
| } |
| |
| public boolean hasDeferredUDC() { |
| for (Cost cost : fCosts) { |
| if (!cost.converts()) |
| return false; |
| if (cost.isDeferredUDC() != DeferredUDC.NONE) |
| return true; |
| } |
| return false; |
| } |
| |
| public boolean performUDC() throws DOMException { |
| for (int i = 0; i < fCosts.length; i++) { |
| Cost cost = fCosts[i]; |
| Cost udcCost= null; |
| switch (cost.isDeferredUDC()) { |
| case NONE: |
| continue; |
| case COPY_INIT_OF_CLASS: |
| udcCost = Conversions.copyInitializationOfClass(fValueCategories[i], cost.source, |
| (ICPPClassType) cost.target, false); |
| break; |
| case INIT_BY_CONVERSION: |
| IType uqSource= getNestedType(cost.source, TDEF | REF | CVTYPE); |
| udcCost = Conversions.initializationByConversion(fValueCategories[i], cost.source, |
| (ICPPClassType) uqSource, cost.target, false, allowsContextualBooleanConversion()); |
| break; |
| case LIST_INIT_OF_CLASS: |
| udcCost = Conversions.listInitializationOfClass(((InitializerListType) cost.source).getEvaluation(), |
| (ICPPClassType) cost.target, false, false); |
| break; |
| case DIRECT_LIST_INIT_OF_CLASS: |
| udcCost = Conversions.listInitializationOfClass(((InitializerListType) cost.source).getEvaluation(), |
| (ICPPClassType) cost.target, true, false); |
| break; |
| default: |
| return false; |
| } |
| fCosts[i] = udcCost; |
| if (!udcCost.converts()) { |
| return false; |
| } |
| udcCost.setReferenceBinding(cost.getReferenceBinding()); |
| } |
| return true; |
| } |
| |
| private boolean allowsContextualBooleanConversion() { |
| char[] functionName = fFunction.getNameCharArray(); |
| return Arrays.equals(functionName, OverloadableOperator.AND.toCharArray()) || |
| Arrays.equals(functionName, OverloadableOperator.OR.toCharArray()) || |
| Arrays.equals(functionName, OverloadableOperator.NOT.toCharArray()); |
| } |
| |
| /** |
| * Compares this function call cost to another one. |
| */ |
| public int compareTo(IASTTranslationUnit tu, FunctionCost other) throws DOMException { |
| if (other == null) |
| return -1; |
| |
| boolean haveWorse = false; |
| boolean haveBetter = false; |
| // In order for this function to be better than the previous best, it must |
| // have at least one parameter match that is better that the corresponding |
| // match for the other function, and none that are worse. |
| int idx= getLength() - 1; |
| int idxOther= other.getLength() - 1; |
| for (; idx >= 0 && idxOther >= 0; idx--, idxOther--) { |
| Cost cost= getCost(idx); |
| if (!cost.converts()) { |
| haveWorse = true; |
| haveBetter = false; |
| break; |
| } |
| |
| int cmp = cost.compareTo(other.getCost(idxOther)); |
| haveWorse |= (cmp > 0); |
| haveBetter |= (cmp < 0); |
| } |
| |
| final ICPPFunction f1 = getFunction(); |
| final ICPPFunction f2 = other.getFunction(); |
| if (!haveWorse && !haveBetter) { |
| // If they are both template functions, we can order them that way |
| ICPPFunctionTemplate asTemplate= asTemplate(f1); |
| ICPPFunctionTemplate otherAsTemplate= asTemplate(f2); |
| final boolean isTemplate = asTemplate != null; |
| final boolean otherIsTemplate = otherAsTemplate != null; |
| |
| // Prefer normal functions over template functions |
| if (isTemplate && !otherIsTemplate) { |
| haveWorse = true; |
| } else if (!isTemplate && otherIsTemplate) { |
| haveBetter = true; |
| } else if (isTemplate && otherIsTemplate) { |
| TypeSelection ts= SemanticUtil.isConversionOperator(f1) ? RETURN_TYPE : PARAMETERS; |
| int order = CPPTemplates.orderFunctionTemplates(otherAsTemplate, asTemplate, ts); |
| if (order < 0) { |
| haveBetter= true; |
| } else if (order > 0) { |
| haveWorse= true; |
| } |
| } |
| } |
| |
| if (haveBetter == haveWorse) { |
| // 7.3.3-15 Using declarations in classes can be overridden |
| int cmp= overridesUsingDeclaration(f1, f2); |
| if (cmp != 0) |
| return cmp; |
| |
| // At this point prefer non-index bindings |
| return -CPPSemantics.compareByRelevance(tu, f1, f2); |
| } |
| |
| if (haveBetter) |
| return -1; |
| |
| return 1; |
| } |
| |
| private int overridesUsingDeclaration(ICPPFunction f1, ICPPFunction f2) { |
| if (f1.takesVarArgs() != f2.takesVarArgs()) |
| return 0; |
| if (!(f1 instanceof ICPPMethod && f2 instanceof ICPPMethod)) |
| return 0; |
| |
| final ICPPMethod m1 = (ICPPMethod) f1; |
| final ICPPMethod m2 = (ICPPMethod) f2; |
| ICPPClassType o1= m1.getClassOwner(); |
| ICPPClassType o2= m2.getClassOwner(); |
| if (o1.isSameType(o2)) |
| return 0; |
| |
| final ICPPFunctionType ft1 = m1.getType(); |
| final ICPPFunctionType ft2 = m2.getType(); |
| if (ft1.isConst() != ft2.isConst() || ft2.isVolatile() != ft2.isVolatile()) |
| return 0; |
| |
| if (!parameterTypesMatch(ft1, ft2)) |
| return 0; |
| |
| int diff= SemanticUtil.calculateInheritanceDepth(o2, o1); |
| if (diff >= 0) |
| return diff; |
| return -SemanticUtil.calculateInheritanceDepth(o1, o2); |
| } |
| |
| private boolean parameterTypesMatch(final ICPPFunctionType ft1, final ICPPFunctionType ft2) { |
| IType[] p1= ft1.getParameterTypes(); |
| IType[] p2= ft2.getParameterTypes(); |
| if (p1.length != p2.length) { |
| if (p1.length == 0) |
| return p2.length == 1 && SemanticUtil.isVoidType(p2[0]); |
| if (p2.length == 0) |
| return p1.length == 1 && SemanticUtil.isVoidType(p1[0]); |
| return false; |
| } |
| |
| for (int i = 0; i < p2.length; i++) { |
| if (!p1[i].isSameType(p2[i])) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public boolean mustBeWorse(FunctionCost other) { |
| if (other == null) |
| return false; |
| |
| boolean haveWorse= false; |
| int idx= getLength() - 1; |
| int idxOther= other.getLength() - 1; |
| for (; idx >= 0 && idxOther >= 0; idx--, idxOther--) { |
| Cost cost= getCost(idx); |
| if (!cost.converts()) |
| return true; |
| |
| Cost otherCost= other.getCost(idxOther); |
| |
| int cmp; |
| if (cost.isDeferredUDC() != DeferredUDC.NONE) { |
| cmp= cost.getRank().compareTo(otherCost.getRank()); |
| } else { |
| cmp= cost.compareTo(otherCost); |
| } |
| |
| if (cmp < 0) |
| return false; |
| if (cmp > 0) |
| haveWorse= true; |
| } |
| |
| return haveWorse; |
| } |
| |
| private static ICPPFunctionTemplate asTemplate(IFunction function) { |
| if (function instanceof ICPPSpecialization) { |
| IBinding original= ((ICPPSpecialization) function).getSpecializedBinding(); |
| if (original instanceof ICPPFunctionTemplate) { |
| return (ICPPFunctionTemplate) original; |
| } |
| } |
| return null; |
| } |
| |
| public void setIsDirectInitWithCopyCtor(boolean val) { |
| fIsDirectCopyCtor= val; |
| } |
| |
| public boolean isDirectInitWithCopyCtor() { |
| return fIsDirectCopyCtor; |
| } |
| } |