kde-extraapps/kdevelop/languages/cpp/cppduchain/overloadresolution.cpp

756 lines
29 KiB
C++
Raw Normal View History

/*
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 "overloadresolution.h"
#include "cppduchain/typeutils.h"
#include <language/duchain/ducontext.h>
#include <language/duchain/declaration.h>
#include <language/duchain/indexedstring.h>
#include <language/duchain/classfunctiondeclaration.h>
#include "cppduchain/cpptypes.h"
#include "viablefunctions.h"
#include "templatedeclaration.h"
#include "templateparameterdeclaration.h"
#include "typeutils.h"
#include <QtAlgorithms>
#include "adlhelper.h"
#include "typeconversion.h"
#include <language/duchain/persistentsymboltable.h>
using namespace Cpp;
using namespace KDevelop;
const bool allowADL = true;
// uncomment to get debugging info on ADL - very expensive on parsing
// #define DEBUG_ADL
#define ifDebugOverloadResolution(x)
// #define ifDebugOverloadResolution(x) x
OverloadResolver::OverloadResolver( DUContextPointer context, TopDUContextPointer topContext, Constness constness, bool forceIsInstance )
: m_context( context )
, m_topContext( topContext )
, m_worstConversionRank( NoMatch )
, m_forceIsInstance( forceIsInstance )
, m_constness(constness)
{
}
Declaration* OverloadResolver::resolveConstructor( const ParameterList& params, bool implicit, bool noUserDefinedConversion )
{
if ( !m_context || !m_topContext )
return 0;
QList<Declaration*> goodDeclarations;
Identifier id = m_context->localScopeIdentifier().last();
id.clearTemplateIdentifiers();
QList<Declaration*> declarations = m_context->findLocalDeclarations( id, CursorInRevision::invalid(), m_topContext.data(), AbstractType::Ptr(), DUContext::OnlyFunctions );
for ( QList<Declaration*>::iterator it = declarations.begin(); it != declarations.end(); ++it )
{
if (( *it )->indexedType() )
{
FunctionType::Ptr function = ( *it )->abstractType().cast<FunctionType>();
ClassFunctionDeclaration* functionDeclaration = dynamic_cast<ClassFunctionDeclaration*>( *it );
//Q_ASSERT();
if ( functionDeclaration /*&& functionDeclaration->isConstructor()*/ ) //Test not needed, because name == classname
{
if ( function->indexedArgumentsSize() >= static_cast<uint>(params.parameters.size()) )
{
if ( !implicit || !functionDeclaration->isExplicit() )
goodDeclarations << *it;
}
}
}
}
// no ADL possible when resolving constructors
return resolveList( params, goodDeclarations, noUserDefinedConversion );
}
Declaration* OverloadResolver::resolve( const ParameterList& params, const QualifiedIdentifier& functionName, bool noUserDefinedConversion )
{
if ( !m_context || !m_topContext )
return 0;
QList<Declaration*> declarations = m_context->findDeclarations( functionName, CursorInRevision::invalid(), AbstractType::Ptr(), m_topContext.data() );
// without ADL findDeclarations may fail so skip ADL there and do it here
Declaration * resolvedDecl = resolveList( params, declarations, noUserDefinedConversion );
if (!resolvedDecl && functionName.count() == 1) {
// start ADL lookup
QList<Declaration*> adlDecls = computeADLCandidates( params, functionName );
resolvedDecl = resolveList( params, adlDecls, noUserDefinedConversion );
#ifdef DEBUG_ADL
if (resolvedDecl)
kDebug() << "ADL found " << resolvedDecl->toString();
else
kDebug() << "ADL failed";
#endif
}
return resolvedDecl;
}
uint OverloadResolver::worstConversionRank()
{
return m_worstConversionRank;
}
void OverloadResolver::expandDeclarations( const QList<Declaration*>& declarations, QSet<Declaration*>& newDeclarations )
{
for ( QList<Declaration*>::const_iterator it = declarations.constBegin(); it != declarations.constEnd(); ++it )
{
Declaration* decl = *it;
if ( CppClassType::Ptr klass = TypeUtils::realType( decl->abstractType(), m_topContext.data() ).cast<CppClassType>() )
{
if ( decl->kind() == Declaration::Instance || m_forceIsInstance )
{
//Instances of classes should be substituted with their operator() members
QList<Declaration*> decls;
TypeUtils::getMemberFunctions( klass, m_topContext.data(), decls, "operator()", klass->modifiers() & AbstractType::ConstModifier );
foreach( Declaration* decl, decls )
newDeclarations.insert( decl );
}
else
{
//Classes should be substituted with their constructors
foreach( Declaration* decl, TypeUtils::getConstructors( klass, m_topContext.data() ) ) {
newDeclarations.insert( decl );
}
}
}
else
{
newDeclarations.insert( *it );
}
}
}
void OverloadResolver::expandDeclarations( const QList<QPair<OverloadResolver::ParameterList, Declaration*> >& declarations, QHash<Declaration*, OverloadResolver::ParameterList>& newDeclarations )
{
for ( QList<QPair<OverloadResolver::ParameterList, Declaration*> >::const_iterator it = declarations.constBegin(); it != declarations.constEnd(); ++it )
{
QPair<OverloadResolver::ParameterList, Declaration*> decl = *it;
if ( CppClassType::Ptr klass = TypeUtils::realType( decl.second->abstractType(), m_topContext.data() ).cast<CppClassType>() )
{
if ( decl.second->kind() == Declaration::Instance || m_forceIsInstance )
{
//Instances of classes should be substituted with their operator() members
QList<Declaration*> functions;
TypeUtils::getMemberFunctions( klass, m_topContext.data(), functions, "operator()", klass->modifiers() & AbstractType::ConstModifier );
foreach( Declaration* f, functions )
newDeclarations.insert( f, decl.first );
}
else
{
//Classes should be substituted with their constructors
foreach( Declaration* f, TypeUtils::getConstructors( klass, m_topContext.data() ) ) {
newDeclarations.insert( f, decl.first );
}
}
}
else
{
newDeclarations.insert( it->second, it->first );
}
}
}
Declaration* OverloadResolver::resolveList( const ParameterList& params, const QList<Declaration*>& declarations, bool noUserDefinedConversion )
{
if ( !m_context || !m_topContext )
return 0;
///Iso c++ draft 13.3.3
m_worstConversionRank = ExactMatch;
///First step: Replace class-instances with operator() functions, and pure classes with their constructors
QSet<Declaration*> newDeclarations;
expandDeclarations( declarations, newDeclarations );
///Second step: Find best viable function
ViableFunction bestViableFunction( m_topContext.data() );
for ( QSet<Declaration*>::const_iterator it = newDeclarations.constBegin(); it != newDeclarations.constEnd(); ++it )
{
Declaration* decl = applyImplicitTemplateParameters( params, *it );
ifDebugOverloadResolution(qDebug() << (*it)->toString() << decl; )
if ( !decl )
continue;
ViableFunction viable( m_topContext.data(), decl, m_constness, noUserDefinedConversion );
viable.matchParameters( params );
ifDebugOverloadResolution(qDebug() << decl->toString() << viable.isBetter(bestViableFunction); )
if ( viable.isBetter( bestViableFunction ) )
{
bestViableFunction = viable;
m_worstConversionRank = bestViableFunction.worstConversion();
}
}
if ( bestViableFunction.isViable() )
return bestViableFunction.declaration().data();
else {
return 0;
}
}
QList< ViableFunction > OverloadResolver::resolveListOffsetted( const ParameterList& params, const QList<QPair<OverloadResolver::ParameterList, Declaration*> >& declarations, bool partial )
{
if ( !m_context || !m_topContext )
return QList<ViableFunction>();
///Iso c++ draft 13.3.3
m_worstConversionRank = ExactMatch;
///First step: Replace class-instances with operator() functions, and pure classes with their constructors
QHash<Declaration*, OverloadResolver::ParameterList> newDeclarations;
expandDeclarations( declarations, newDeclarations );
///Second step: Find best viable function
QList<ViableFunction> viableFunctions;
for ( QHash<Declaration*, OverloadResolver::ParameterList>::const_iterator it = newDeclarations.constBegin(); it != newDeclarations.constEnd(); ++it )
{
ParameterList mergedParams = it.value();
mergedParams.parameters += params.parameters;
Declaration* decl = applyImplicitTemplateParameters( mergedParams, it.key() );
ifDebugOverloadResolution(qDebug() << it.key()->toString() << decl; )
if ( !decl )
continue;
if (decl->isExplicitlyDeleted())
continue;
ViableFunction viable( m_topContext.data(), decl, m_constness );
viable.matchParameters( mergedParams, partial );
viableFunctions << viable;
}
qSort( viableFunctions );
return viableFunctions;
}
ViableFunction OverloadResolver::resolveListViable( const ParameterList& params, const QList<QPair<OverloadResolver::ParameterList, Declaration*> >& declarations, bool partial )
{
if ( !m_context || !m_topContext )
return ViableFunction();
ifDebugOverloadResolution(qDebug() << "resolveListViable" << params; )
///Iso c++ draft 13.3.3
m_worstConversionRank = ExactMatch;
///First step: Replace class-instances with operator() functions, and pure classes with their constructors
QHash<Declaration*, OverloadResolver::ParameterList> newDeclarations;
expandDeclarations( declarations, newDeclarations );
///Second step: Find best viable function
ViableFunction bestViableFunction(m_topContext.data());
for ( QHash<Declaration*, OverloadResolver::ParameterList>::const_iterator it = newDeclarations.constBegin(); it != newDeclarations.constEnd(); ++it )
{
ParameterList mergedParams = it.value();
mergedParams.parameters += params.parameters;
Declaration* decl = applyImplicitTemplateParameters( mergedParams, it.key() );
ifDebugOverloadResolution(qDebug() << it.key()->toString() << decl; )
if ( !decl )
continue;
ViableFunction viable( m_topContext.data(), decl, m_constness );
viable.matchParameters( mergedParams, partial );
ifDebugOverloadResolution(qDebug() << decl->toString() << viable.isBetter(bestViableFunction); )
if ( viable.isBetter( bestViableFunction ) )
{
bestViableFunction = viable;
m_worstConversionRank = bestViableFunction.worstConversion();
}
}
return bestViableFunction;
}
Declaration* OverloadResolver::applyImplicitTemplateParameters( const ParameterList& params, Declaration* declaration ) const
{
TemplateDeclaration* tempDecl = dynamic_cast<TemplateDeclaration*>( declaration );
if ( !tempDecl )
return declaration;
KDevelop::DUContext* templateContext = tempDecl->templateParameterContext();
if ( !templateContext )
{
//May be just within a template, but without own template parameters
return declaration;
}
FunctionType::Ptr functionType = declaration->type<FunctionType>();
if ( !functionType )
{
kDebug( 9007 ) << "Template function has no function type";
return declaration;
}
const IndexedType* arguments( functionType->indexedArguments() );
if ( static_cast<uint>(params.parameters.count()) > functionType->indexedArgumentsSize() )
return declaration;
//templateContext contains the template-parameters that we need to find instantiations for
QMap<IndexedString, AbstractType::Ptr> instantiatedParameters; //Here we store the values assigned to each template-parameter
foreach( Declaration* decl, templateContext->localDeclarations() )
{
CppTemplateParameterType::Ptr paramType = decl->abstractType().cast<CppTemplateParameterType>();
if ( paramType ) //Parameters that are not of type CppTemplateParameterType are already assigned.
{
instantiatedParameters[decl->identifier().identifier()] = AbstractType::Ptr();
}
}
if ( instantiatedParameters.isEmpty() )
return declaration; //All parameters already have a type assigned
for ( int a = 0; a < params.parameters.count(); a++ )
matchParameterTypes( params.parameters[a].type, arguments[a].abstractType(), instantiatedParameters );
bool allInstantiated = true;
for ( QMap<IndexedString, AbstractType::Ptr>::const_iterator it = instantiatedParameters.constBegin(); it != instantiatedParameters.constEnd(); ++it )
if ( !( *it ) )
{
allInstantiated = false;
break;
}
if ( allInstantiated )
{
//We have new template-parameters at hand, we can specialize now.
Cpp::InstantiationInformation instantiateWith( tempDecl->instantiatedWith().information() );
instantiateWith.templateParametersList().clear();
foreach( Declaration* decl, templateContext->localDeclarations() )
{
AbstractType::Ptr type;
CppTemplateParameterType::Ptr paramType = decl->abstractType().cast<CppTemplateParameterType>();
if ( paramType ) //Take the type we have assigned.
type = instantiatedParameters[decl->identifier().identifier()];
else
type = decl->abstractType(); //Take the type that was available already earlier
instantiateWith.addTemplateParameter( type );
}
return tempDecl->instantiate( instantiateWith, m_topContext.data() );
}
return declaration;
}
inline uint incrementIfSuccessful( uint val )
{
if ( val )
return 1 + val;
return 0;
}
uint OverloadResolver::matchParameterTypes( const AbstractType::Ptr& argumentType, const AbstractType::Ptr& parameterType, QMap<IndexedString, AbstractType::Ptr>& instantiatedTypes, bool keepValue ) const
{
if ( !argumentType && !parameterType )
return 1;
if ( !argumentType || !parameterType )
return 0;
ifDebugOverloadResolution( kDebug() << "matching" << argumentType->toString() << "to" << parameterType->toString(); )
if ( instantiatedTypes.isEmpty() )
return 1;
DelayedType::Ptr delayed = parameterType.cast<DelayedType>();
if ( delayed )
return incrementIfSuccessful( matchParameterTypes( argumentType, delayed->identifier(), instantiatedTypes , keepValue ) );
///In case of references on both sides, match the target-types
ReferenceType::Ptr argumentRef = argumentType.cast<ReferenceType>();
ReferenceType::Ptr parameterRef = parameterType.cast<ReferenceType>();
if ( argumentRef && parameterRef )
return incrementIfSuccessful( matchParameterTypes( argumentRef->baseType(), parameterRef->baseType(), instantiatedTypes, keepValue ) );
else if ( argumentRef )
return incrementIfSuccessful( matchParameterTypes( argumentRef->baseType(), parameterType, instantiatedTypes, keepValue ) );
else if ( parameterRef )
return incrementIfSuccessful( matchParameterTypes( argumentType, parameterRef->baseType(), instantiatedTypes, keepValue ) );
///In case of pointers on both sides, match the target-types
PointerType::Ptr argumentPointer = argumentType.cast<PointerType>();
PointerType::Ptr parameterPointer = parameterType.cast<PointerType>();
if ( argumentPointer && parameterPointer && (( argumentPointer->modifiers() & AbstractType::ConstModifier ) == ( parameterPointer->modifiers() & AbstractType::ConstModifier ) ) )
return incrementIfSuccessful( matchParameterTypes( argumentPointer->baseType(), parameterPointer->baseType(), instantiatedTypes, keepValue ) );
///In case of arrays on both sides, match the target-types
ArrayType::Ptr argumentArray = argumentType.cast<ArrayType>();
ArrayType::Ptr parameterArray = parameterType.cast<ArrayType>();
if ( argumentArray && parameterArray && (( argumentArray->modifiers() & AbstractType::ConstModifier ) == ( parameterArray->modifiers() & AbstractType::ConstModifier ) ) ) {
return incrementIfSuccessful( matchParameterTypes( argumentArray->elementType(), parameterArray->elementType(), instantiatedTypes, keepValue ) );
}
if ( CppTemplateParameterType::Ptr templateParam = parameterType.cast<CppTemplateParameterType>() )
{
///@todo Allow template-parameters with even more template-parameters declared
//Directly assign argumentType to the template parameter
Declaration* decl = templateParam->declaration( m_topContext.data() );
if ( decl )
{
IndexedString id = decl->identifier().identifier();
if ( instantiatedTypes[id].isNull() )
{
instantiatedTypes[id] = argumentType;
return 1;
}
else if ( instantiatedTypes[id]->equals( argumentType.unsafeData() ) )
{
return 1;
}
else
{
//Mismatch, another type was already assigned
return 0;
}
}
}
///Match assigned template-parameters, for example when matching QList<int> to QList<T>, assign int to T.
const IdentifiedType* identifiedArgument = dynamic_cast<const IdentifiedType*>( argumentType.unsafeData() );
const IdentifiedType* identifiedParameter = dynamic_cast<const IdentifiedType*>( parameterType.unsafeData() );
if ( identifiedArgument && identifiedParameter )
{
Declaration* argumentDeclaration = identifiedArgument->declaration( m_topContext.data() );
Declaration* parameterDeclaration = identifiedParameter->declaration( m_topContext.data() );
TemplateDeclaration* argumentTemplateDeclaration = dynamic_cast<TemplateDeclaration*>( argumentDeclaration );
TemplateDeclaration* parameterTemplateDeclaration = dynamic_cast<TemplateDeclaration*>( parameterDeclaration );
if ( !argumentTemplateDeclaration || !parameterTemplateDeclaration )
{
return (int)(argumentDeclaration == parameterDeclaration);
}
if ( argumentTemplateDeclaration->instantiatedFrom() == parameterTemplateDeclaration->instantiatedFrom() && argumentTemplateDeclaration->instantiatedFrom() )
{
InstantiationInformation argumentInstantiatedWith = argumentTemplateDeclaration->instantiatedWith().information();
InstantiationInformation parameterInstantiatedWith = parameterTemplateDeclaration->instantiatedWith().information();
if ( argumentInstantiatedWith.templateParametersSize() != parameterInstantiatedWith.templateParametersSize() )
return 0;
uint matchDepth = 1;
for ( uint a = 0; a < argumentInstantiatedWith.templateParametersSize(); ++a )
{
uint localMatchDepth = matchParameterTypes( argumentInstantiatedWith.templateParameters()[a].abstractType(), parameterInstantiatedWith.templateParameters()[a].abstractType(), instantiatedTypes, keepValue );
if ( !localMatchDepth )
return 0;
matchDepth += localMatchDepth;
}
return matchDepth;
}
}
return 1;
}
QList<Declaration *> OverloadResolver::computeADLCandidates( const ParameterList& params, const QualifiedIdentifier& identifier )
{
if(!allowADL || identifier.count() != 1 )
return QList<Declaration *>();
// Don't try to do ADL if there are delayed/unresolved types involved,
// because then we cannot get a proper match as to ViableFunction anyway
foreach( const Parameter & param, params.parameters ) {
if( fastCast<DelayedType*>(param.type.unsafeData()) ) {
ifDebugOverloadResolution(qDebug() << "Skipping ADL due to delayed types" << identifier << params; )
return QList<Declaration *>();
}
}
ADLHelper adlHelper( m_context, m_topContext );
foreach( const Parameter & param, params.parameters )
adlHelper.addArgument( param );
QSet<QualifiedIdentifier> adlNamespaces = adlHelper.associatedNamespaces();
#ifdef DEBUG_ADL
foreach( QualifiedIdentifier ns, adlNamespaces )
{
kDebug() << " ADL found namespace: " << ns.toString();
}
#endif
QList<Declaration*> adlDecls;
#ifdef DEBUG_ADL
kDebug() << " ADL candidates for: " << identifier << params << params.parameters.size();
#endif
foreach( QualifiedIdentifier adlFunctionName, adlNamespaces )
{
adlFunctionName += identifier;
// By using DeclarationId, we prevent a lot of complex logic which we don't require, as we
// already have the fully qualified scope.
PersistentSymbolTable::FilteredDeclarationIterator decls =
PersistentSymbolTable::self().getFilteredDeclarations(IndexedQualifiedIdentifier(adlFunctionName), m_topContext->recursiveImportIndices());
for(; decls; ++decls)
{
Declaration* decl = decls->data();
if(decl && decl->isFunctionDeclaration()) {
adlDecls << decl;
#ifdef DEBUG_ADL
kDebug() << " ADL candidate: " << adlFunctionName << decl->toString();
#endif
}
}
}
return adlDecls;
}
AbstractType::Ptr getContainerType( AbstractType::Ptr type, int depth, TopDUContext* topContext )
{
for ( int a = 0; a < depth; a++ )
{
AbstractType::Ptr real = TypeUtils::realType( type, topContext );
IdentifiedType* idType = dynamic_cast<IdentifiedType*>( real.unsafeData() );
if ( !idType )
return AbstractType::Ptr();
Declaration* decl = idType->declaration(topContext);
if(!decl || !decl->context())
return AbstractType::Ptr();
Declaration* containerDecl = decl->context()->owner();
if ( containerDecl )
type = containerDecl->abstractType();
else
return AbstractType::Ptr();
}
return type;
}
uint OverloadResolver::matchParameterTypes( AbstractType::Ptr argumentType, const IndexedTypeIdentifier& parameterType, QMap<IndexedString, AbstractType::Ptr>& instantiatedTypes, bool keepValue ) const
{
ifDebugOverloadResolution( kDebug() << "1 matching" << argumentType->toString() << "to" << parameterType.toString() << parameterType.pointerDepth(); )
if ( !argumentType )
return 1;
if ( instantiatedTypes.isEmpty() )
return 1;
QualifiedIdentifier parameterQid( parameterType.identifier().identifier() );
if ( parameterQid.isEmpty() )
return 1;
{
ReferenceType::Ptr argumentRef = argumentType.cast<ReferenceType>();
if ( argumentRef && parameterType.isReference() )
argumentType = argumentRef->baseType();
else if ( parameterType.isReference() )
return 0; //Reference on right side, but not on left
}
{
PointerType::Ptr argumentPointer = argumentType.cast<PointerType>();
int cnt = 0; ///@todo correct ordering of the pointers and their constnesses
while ( argumentPointer && cnt < parameterType.pointerDepth() )
{
++cnt;
argumentType = argumentPointer->baseType();
argumentPointer = argumentType.cast<PointerType>();
}
if ( cnt != parameterType.pointerDepth() || !argumentType )
{
return 0; //Do not have the needed count of pointers
}
}
uint matchDepth = 1;
if (( argumentType->modifiers() & AbstractType::ConstModifier ) && parameterType.isConstant() )
++matchDepth;
for ( int a = 0; a < parameterQid.count(); ++a )
{
///@todo Think about this
AbstractType::Ptr pType = getContainerType( argumentType, parameterQid.count() - a - 1, m_topContext.data() );
uint localDepth = matchParameterTypes( pType, parameterQid.at( a ), instantiatedTypes, keepValue );
// if(!localDepth)
// return 0;
matchDepth += localDepth;
}
return matchDepth;
}
uint OverloadResolver::matchParameterTypes( AbstractType::Ptr argumentType, const Identifier& parameterType, QMap<IndexedString, AbstractType::Ptr>& instantiatedTypes, bool keepValue ) const
{
ifDebugOverloadResolution( kDebug() << "2 matching" << argumentType->toString() << "to" << parameterType.toString(); )
if ( !argumentType )
return 1;
if ( instantiatedTypes.isEmpty() )
return 1;
if ( instantiatedTypes.contains( parameterType.identifier() ) )
{
if ( !keepValue ) //Extract the actual type without the value
if ( ConstantIntegralType::Ptr integral = argumentType.cast<ConstantIntegralType>() )
argumentType = AbstractType::Ptr( new IntegralType( *integral ) );
instantiatedTypes[parameterType.identifier()] = argumentType;
return 1;
}
IdentifiedType* identifiedArgument = dynamic_cast<IdentifiedType*>( argumentType.unsafeData() );
if ( !identifiedArgument )
return 0;
if ( identifiedArgument->qualifiedIdentifier().last().identifier() != parameterType.identifier() )
{
return 0;
}
TemplateDeclaration* argumentTemplateDeclaration = dynamic_cast<TemplateDeclaration*>( identifiedArgument->declaration( m_topContext.data() ) );
uint matchDepth = 1;
if ( argumentTemplateDeclaration && parameterType.templateIdentifiersCount() )
{
DUContext* argumentTemplateDeclarationContext = argumentTemplateDeclaration->templateParameterContext();
if ( argumentTemplateDeclarationContext )
{
int matchLength = argumentTemplateDeclarationContext->localDeclarations().count();
if ( parameterType.templateIdentifiersCount() < static_cast<uint>(matchLength) )
matchLength = parameterType.templateIdentifiersCount();
for ( int a = 0; a < matchLength; ++a )
matchDepth += matchParameterTypes( argumentTemplateDeclarationContext->localDeclarations()[a]->abstractType(), parameterType.templateIdentifier( a ), instantiatedTypes, keepValue );
}
else
{
kDebug( 9007 ) << "Template-declaration missing template-parameter context";
}
}
return matchDepth;
}
///Version of matchParameters that would be correct if we used CppTemplateParameterType* instead of DelayedType. Maybe we should doing that some time, it's more correct, and more complicated.
// bool OverloadResolver::matchParameterTypes(AbstractType* _argumentType, AbstractType* _parameterType, QMap<CppTemplateParameterType*, AbstractType::Ptr>& instantiatedTypes) const
// {
// if(!_argumentType || !_parameterType)
// return true;
// if(instantiatedTypes.isEmpty())
// return true;
//
// AbstractType::Ptr argumentType = TypeUtils::resolvedType(_argumentType, m_topContext.data());
// AbstractType::Ptr parameterType = TypeUtils::resolvedType(_parameterType, m_topContext.data());
//
// CppTemplateParameterType* temp = dynamic_cast<CppTemplateParameterType*>(parameterType.data());
// if(temp) {
// if( instantiatedTypes.contains(temp) ) {
// if( instantiatedTypes[temp].data() == 0 ) {
// instantiatedTypes[temp] = argumentType;
// }else{
// ///@todo compare if the type already instantiated for this parameter is the same as argumentType, and else fail.
// }
// }
// return true;
// }
//
// ///Match assigned template-parameters, for example when matching QList<int> to QList<T>, assign int to T.
// IdentifiedType* identifiedArgument = dynamic_cast<IdentifiedType*>(argumentType.data());
// IdentifiedType* identifiedParameter = dynamic_cast<IdentifiedType*>(parameterType.data());
//
// if( identifiedArgument && identifiedParameter )
// {
// if( identifiedArgument->identifier() == identifiedParameter->identifier() )
// {
// TemplateDeclaration* argumentTemplateDeclaration = dynamic_cast<TemplateDeclaration*>(identifiedArgument->declaration());
// TemplateDeclaration* parameterTemplateDeclaration = dynamic_cast<TemplateDeclaration*>(identifiedParameter->declaration());
//
// if( argumentTemplateDeclaration && parameterTemplateDeclaration )
// {
// DUContext* argumentTemplateDeclarationContext = argumentTemplateDeclaration->templateParameterContext();
// DUContext* parameterTemplateDeclarationContext = parameterTemplateDeclaration->templateParameterContext();
//
// if( argumentTemplateDeclarationContext->localDeclarations().count() == parameterTemplateDeclarationContext->localDeclarations().count() ) {
// for( int a = 0; a < argumentTemplateDeclarationContext->localDeclarations().count(); ++a )
// matchParameterTypes( argumentTemplateDeclarationContext->localDeclarations()[a]->abstractType().data(), parameterTemplateDeclarationContext->localDeclarations()[a]->abstractType().data(), instantiatedTypes );
// }
// }
// }
// }
//
// ///In case of references on both sides, match the target-types
// ReferenceType* argumentRef = dynamic_cast<ReferenceType*>(argumentType.data());
// ReferenceType* parameterRef = dynamic_cast<ReferenceType*>(parameterType.data());
//
// if( argumentRef && parameterRef )
// return matchParameterTypes( argumentRef->baseType().data(), parameterRef->baseType().data(), instantiatedTypes );
//
// ///In case of pointers on both sides, match the target-types
// PointerType* argumentPointer = dynamic_cast<PointerType*>(argumentType.data());
// PointerType* parameterPointer = dynamic_cast<PointerType*>(parameterType.data());
//
// if( argumentPointer && parameterPointer )
// return matchParameterTypes( argumentPointer->baseType().data(), parameterPointer->baseType().data(), instantiatedTypes );
//
// return true;
// }
QDebug operator<<(QDebug s, const Cpp::OverloadResolver::Parameter& param)
{
return s << param.toString();
}
QDebug operator<<(QDebug s, const Cpp::OverloadResolver::ParameterList& params)
{
return s << params.parameters;
}