blob: 25d969bf22b51b5c47b46dc601f02d0ae4f75801 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}