/* 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 "overloadresolutionhelper.h" #include #include #include #include #include #include "typeutils.h" #include "viablefunctions.h" #include "cppduchain.h" #include "adlhelper.h" using namespace KDevelop; using namespace Cpp; ///@todo Decide whether this should be enabled or disabled (by performance considerations) bool useADLForOperators = true; OverloadResolutionFunction::OverloadResolutionFunction() : matchedArguments(0) { } OverloadResolutionFunction::OverloadResolutionFunction( int _matchedArguments, const ViableFunction& _viable ) : matchedArguments(_matchedArguments), function(_viable) { } OverloadResolutionHelper::OverloadResolutionHelper(const KDevelop::DUContextPointer& context, const KDevelop::TopDUContextPointer& topContext) : m_context(context) , m_topContext(topContext) , m_isOperator(false) , m_constness(OverloadResolver::Unknown) { } void OverloadResolutionHelper::setFunctionNameForADL(const KDevelop::QualifiedIdentifier& identifierForADL) { m_identifierForADL = identifierForADL; } void OverloadResolutionHelper::setOperator( const OverloadResolver::Parameter& base ) { m_baseType = base; m_isOperator = true; } void OverloadResolutionHelper::setFunctions( const QList& functions ) { foreach( Declaration* decl, functions ) m_declarations << DeclarationWithArgument( OverloadResolver::ParameterList(), decl ); //Insert with argument-offset zero } void OverloadResolutionHelper::setKnownParameters( const OverloadResolver::ParameterList& parameters ) { m_knownParameters = parameters; } void OverloadResolutionHelper::setConstness( OverloadResolver::Constness constness ) { m_constness = constness; } void OverloadResolutionHelper::initializeResolver(OverloadResolver& resolv) { if( m_isOperator ) { Q_ASSERT(!m_identifierForADL.isEmpty()); ///Search for member operators AbstractType::Ptr real( TypeUtils::realType(m_baseType.type, m_context->topContext()) ); if( dynamic_cast( real.unsafeData() ) ) { IdentifiedType* idType = dynamic_cast( real.unsafeData() ); if( idType && idType->declaration(m_context->topContext()) ) { DUContext* ctx = idType->declaration(m_context->topContext())->logicalInternalContext(m_context->topContext()); if( ctx ) { QList decls = Cpp::findLocalDeclarations( ctx, m_identifierForADL.first(), m_context->topContext() ); foreach( Declaration* decl, decls ) m_declarations << DeclarationWithArgument( OverloadResolver::ParameterList(), decl ); } else { log( "no internal context found" ); } } else { log( "type is not identified" ); } } ///Search for static global operators QList decls = m_context->findDeclarations(m_identifierForADL); foreach( Declaration* decl, decls ) { FunctionType::Ptr fun = decl->abstractType().cast(); if( fun && (fun->arguments().size() == 1 || fun->arguments().size() == 2) ) m_declarations << DeclarationWithArgument( m_baseType, decl ); } ///If no global or class member operators found try ADL for namespaced operators if (m_declarations.isEmpty() && useADLForOperators) { OverloadResolver::ParameterList params; params.parameters << m_baseType; params.parameters += m_knownParameters.parameters; foreach( Declaration* decl, resolv.computeADLCandidates( params, m_identifierForADL ) ) { FunctionType::Ptr fun = decl->abstractType().cast(); if( fun && (fun->arguments().size() == 1 || fun->arguments().size() == 2) ) m_declarations << DeclarationWithArgument( m_baseType, decl ); } } }else{ //m_declarations should already be set by setFunctions(..) } foreach( const DeclarationWithArgument& decl, m_declarations ) m_argumentCountMap[decl.second] = decl.first.parameters.size(); // log( "functions given to overload-resolution:" ); // foreach( const DeclarationWithArgument& declaration, m_declarations ) // log( declaration.second->toString() ); // log("parameters given to overload-resolution:"); // lock.unlock(); // foreach( const ExpressionEvaluationResult& result, m_knownArgumentTypes ) { // log( result.toString() ); // } // lock.lock(); } QList OverloadResolutionHelper::resolveToList(bool partial) { OverloadResolver resolv( m_context, m_topContext, m_constness ); QList< ViableFunction > viableFunctions; viableFunctions = resolv.resolveListOffsetted( m_knownParameters, m_declarations, partial ); // also retrieve names by ADL if partial argument list (only used by code completion) // and even in strict mode if normal lookup failed if (partial || viableFunctions.empty() || !viableFunctions[0].isViable()) { QList adlDecls = resolv.computeADLCandidates( m_knownParameters, m_identifierForADL ); if (!adlDecls.empty()) { QList< DeclarationWithArgument > adlDeclsWithArguments; foreach(Declaration * decl, adlDecls) { adlDeclsWithArguments << DeclarationWithArgument( OverloadResolver::ParameterList(), decl ); // see setFunctions } viableFunctions += resolv.resolveListOffsetted( m_knownParameters, adlDeclsWithArguments, partial ); } } qSort( viableFunctions ); QList ret; foreach( const ViableFunction& function, viableFunctions ) { if( function.declaration() && function.declaration()->abstractType() ) ret << OverloadResolutionFunction( m_argumentCountMap[function.declaration().data()] + m_knownParameters.parameters.size(), function ); } return ret; } ViableFunction OverloadResolutionHelper::resolve(bool forceInstance) { OverloadResolver resolv( m_context, m_topContext, m_constness, forceInstance ); initializeResolver(resolv); ViableFunction ret = resolv.resolveListViable( m_knownParameters, m_declarations ); // also retrieve names by ADL if partial argument list (only used by code completion) // and even in strict mode if normal lookup failed if (!ret.isViable()) { QList adlDecls = resolv.computeADLCandidates( m_knownParameters, m_identifierForADL ); if (!adlDecls.empty()) { QList< DeclarationWithArgument > adlDeclsWithArguments; foreach(Declaration * decl, adlDecls) adlDeclsWithArguments << DeclarationWithArgument( OverloadResolver::ParameterList(), decl ); // see setFunctions ret = resolv.resolveListViable( m_knownParameters, adlDeclsWithArguments ); } } return ret; } void OverloadResolutionHelper::log(const QString& str) const { kDebug(9007) << "OverloadResolutionHelper: " << str; }