/* This file is part of KDevelop Copyright 2007 David Nolden This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "viablefunctions.h" #include "cppduchain/typeutils.h" #include #include #include #include #include "templatedeclaration.h" #include "typeconversion.h" #define ifDebug(x) // #define ifDebug(x) x using namespace Cpp; ///@todo prefer more specialized template-functions above less specialized ones inline bool ViableFunction::ParameterConversion::operator<(const ParameterConversion& rhs) const { if( rank < rhs.rank ) return true; else if( rank > rhs.rank ) return false; else return baseConversionLevels > rhs.baseConversionLevels; //Conversion-rank is same, so use the base-conversion levels for ranking } ViableFunction::ViableFunction( TopDUContext* topContext, Declaration* decl, OverloadResolver::Constness constness, bool noUserDefinedConversion ) : m_declaration(decl) , m_topContext(topContext) , m_type(0) , m_parameterCountMismatch(true) , m_noUserDefinedConversion(noUserDefinedConversion) , m_constness(constness) { if( decl ) m_type = decl->abstractType().cast(); m_funDecl = dynamic_cast(m_declaration.data()); } KDevelop::DeclarationPointer ViableFunction::declaration() const { return m_declaration; } bool ViableFunction::isValid() const { return m_type && m_declaration && m_funDecl; } void ViableFunction::matchParameters( const OverloadResolver::ParameterList& params, bool partial ) { if( !isValid() || !m_topContext ) return; Q_ASSERT(m_funDecl); uint functionArgumentCount = m_type->indexedArgumentsSize(); bool hasVarArgs = false; if (functionArgumentCount) { hasVarArgs = TypeUtils::isVarArgs(m_type->indexedArguments()[functionArgumentCount-1].abstractType()); } ifDebug(qDebug() << "matchParameters" << params << " to " << m_type->toString() << "partial:" << partial << "varargs" << hasVarArgs;) if (!hasVarArgs) { if( params.parameters.size() + m_funDecl->defaultParametersSize() < functionArgumentCount && !partial ) { return; //Not enough parameters + default-parameters } if( static_cast(params.parameters.size()) > functionArgumentCount ) { return; //Too many parameters } } m_parameterCountMismatch = false; //Match all parameters against the argument-type const IndexedType* arguments = m_type->indexedArguments(); const IndexedType* argumentIt = arguments; TypeConversion conv(m_topContext.data()); for( QList::const_iterator it = params.parameters.begin(); it != params.parameters.end(); ++it ) { ParameterConversion c; c.rank = conv.implicitConversion( (*it).type->indexed(), *argumentIt, (*it).lValue, m_noUserDefinedConversion ); c.baseConversionLevels = conv.baseConversionLevels(); m_parameterConversions << c; if (!hasVarArgs || argumentIt < arguments + functionArgumentCount - 1) { ++argumentIt; } // else keep argumentIt at last argument, i.e. vararg } } bool ViableFunction::operator< ( const ViableFunction& other ) const { return isBetter(other); } bool ViableFunction::isBetter( const ViableFunction& other ) const { if( !isViable() ) return false; if( !other.isViable() ) return true; ///iso c++ 13.3.3 - best viable function //Is one of our conversions worse than one of the other function's? int minParams = m_parameterConversions.size(); if(other.m_parameterConversions.size() < minParams) minParams = other.m_parameterConversions.size(); bool hadBetterConversion = false; for(int a = 0; a < minParams; ++a) { if( m_parameterConversions[a] < other.m_parameterConversions[a] ) return false; //All this function's conversions must not be worse than the other function one's if( other.m_parameterConversions[a] < m_parameterConversions[a] ) hadBetterConversion = true; } ///@todo any special measures when parameter-counts differ? if( hadBetterConversion ) return true; /**Until now both functions have the same match-quality. Iso c++ says this is better when: * - this is a non-template function while other is one * - this is a template-function that is more specialized than other * - we are looking for a const function and we are const or vice-versa */ if((m_constness == Cpp::OverloadResolver::Const && TypeUtils::isConstant(m_declaration->abstractType())) || (m_constness == Cpp::OverloadResolver::NonConst && !TypeUtils::isConstant(m_declaration->abstractType()))) { return true; } if(!dynamic_cast(m_declaration.data()) && dynamic_cast(other.m_declaration.data())) return true; // if( m_type->isMoreSpecialized( other.m_type.data() ) ) // return true; return false; } bool ViableFunction::isViable() const { if( !isValid() || m_parameterCountMismatch ) return false; for( int a = 0; a < m_parameterConversions.size(); ++a ) if( !m_parameterConversions[a].rank ) return false; return true; } uint ViableFunction::worstConversion() const { uint ret = (uint)-1; for( int a = 0; a < m_parameterConversions.size(); ++a ) if( (uint) m_parameterConversions[a].rank < ret ) ret *= m_parameterConversions[a].rank; if( ret == (uint)-1 ) return 0; else return ret; } const KDevVarLengthArray& ViableFunction::parameterConversions() const { return m_parameterConversions; }