kde-extraapps/kdevelop/languages/cpp/cppduchain/overloadresolutionhelper.cpp
2015-07-26 14:23:17 +03:00

205 lines
7.5 KiB
C++

/*
Copyright 2007 David Nolden <david.nolden.kdevelop@art-master.de>
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 <kdebug.h>
#include <language/duchain/declaration.h>
#include <language/duchain/ducontext.h>
#include <language/duchain/types/identifiedtype.h>
#include <cpptypes.h>
#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<Declaration*>& 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<CppClassType*>( real.unsafeData() ) )
{
IdentifiedType* idType = dynamic_cast<IdentifiedType*>( real.unsafeData() );
if( idType && idType->declaration(m_context->topContext()) ) {
DUContext* ctx = idType->declaration(m_context->topContext())->logicalInternalContext(m_context->topContext());
if( ctx ) {
QList<Declaration*> 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<Declaration*> decls = m_context->findDeclarations(m_identifierForADL);
foreach( Declaration* decl, decls ) {
FunctionType::Ptr fun = decl->abstractType().cast<FunctionType>();
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<FunctionType>();
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<OverloadResolutionFunction> 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<Declaration*> 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<OverloadResolutionFunction> 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<Declaration*> 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;
}