2
Copyright 2007 David Nolden <david.nolden.kdevelop@art-master.de>
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License version 2 as published by the Free Software Foundation.
8
This library is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
Library General Public License for more details.
13
You should have received a copy of the GNU Library General Public License
14
along with this library; see the file COPYING.LIB. If not, write to
15
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16
Boston, MA 02110-1301, USA.
19
#include "typeconversion.h"
20
#include "cppduchain/typeutils.h"
21
#include "cppduchain/cpptypes.h"
22
#include "overloadresolution.h"
23
#include <language/duchain/ducontext.h>
24
#include <language/duchain/topducontext.h>
26
#include <language/duchain/duchainlock.h>
27
#include <language/duchain/duchain.h>
29
#include <language/duchain/classfunctiondeclaration.h>
30
#include <language/duchain/types/typeutils.h>
34
using namespace KDevelop;
35
using namespace TypeUtils;
37
struct ImplicitConversionParams {
39
bool fromLValue, noUserDefinedConversion;
41
bool operator==(const ImplicitConversionParams& rhs) const {
42
return from == rhs.from && to == rhs.to && fromLValue == rhs.fromLValue && noUserDefinedConversion == rhs.noUserDefinedConversion;
46
uint qHash(const ImplicitConversionParams& params) {
47
return (params.from.hash() * 36109 + params.to.hash()) * (params.fromLValue ? 111 : 53) * (params.noUserDefinedConversion ? 317293 : 1);
51
class TypeConversionCache
55
QHash<ImplicitConversionParams, int> m_implicitConversionResults;
56
/* QHash<QPair<IndexedType, IndexedType>, uint> m_standardConversionResults;
57
QHash<QPair<IndexedType, IndexedType>, uint> m_userDefinedConversionResults;*/
58
// QHash<QPair<IndexedType, IndexedType>, bool> m_isPublicBaseCache;
62
QHash<Qt::HANDLE, TypeConversionCache*> typeConversionCaches;
63
QMutex typeConversionCacheMutex;
65
void TypeConversion::startCache() {
66
QMutexLocker lock(&typeConversionCacheMutex);
67
if(!typeConversionCaches.contains(QThread::currentThreadId()))
68
typeConversionCaches[QThread::currentThreadId()] = new TypeConversionCache;
71
void TypeConversion::stopCache() {
72
QMutexLocker lock(&typeConversionCacheMutex);
73
if(typeConversionCaches.contains(QThread::currentThreadId())) {
74
delete typeConversionCaches[QThread::currentThreadId()];
75
typeConversionCaches.remove(QThread::currentThreadId());
79
TypeConversion::TypeConversion(const TopDUContext* topContext) : m_topContext(topContext) {
81
QMutexLocker lock(&typeConversionCacheMutex);
82
QHash<Qt::HANDLE, TypeConversionCache*>::iterator it = typeConversionCaches.find(QThread::currentThreadId());
83
if(it != typeConversionCaches.end())
90
TypeConversion::~TypeConversion() {
94
* All information taken from iso c++ draft
96
* Standard-conversion-sequence:
97
* - zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, function-to-pointer conversion
98
* - zero or one conversion from the following set: integral promotions, floating point promotions, integral conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to member conversions, and boolean conversions.
100
* Standard-conversion-sequence will be applied to expression when it needs to be converted to another type.
102
* Note: lvalue = reference to existing object
103
* rvalue = copied object
105
* When is an expression implicitly converted? :
106
* - When used as operands of operators.
107
* - When used in a condition statement(destination type is bool)
108
* - When used in the expression of a switch statement
109
* - When used as the source expression for an initialization(includes argument in function-call and return-statement)
111
* User-defined conversions:
112
* - Constructors and conversion-functions.
113
* - At most one such conversion is applied when doing implicit type-conversion
117
* An implicit conversion-sequence is one of the following:
118
* - a standard conversion sequence
119
* - a user-defined conversion sequence
120
* - an ellipsis conversion sequence
123
uint TypeConversion::implicitConversion( IndexedType _from, IndexedType _to, bool fromLValue, bool noUserDefinedConversion ) {
124
m_baseConversionLevels = 0;
128
ImplicitConversionParams params;
131
params.fromLValue = fromLValue;
132
params.noUserDefinedConversion = noUserDefinedConversion;
135
QHash<ImplicitConversionParams, int>::const_iterator it = m_cache->m_implicitConversionResults.constFind(params);
136
if(it != m_cache->m_implicitConversionResults.constEnd())
140
AbstractType::Ptr to = unAliasedType(_to.abstractType());
141
AbstractType::Ptr from = unAliasedType(_from.abstractType());
144
problem( from, to, "one type is invalid" );
148
//kDebug(9007) << "Checking conversion from " << from->toString() << " to " << to->toString();
149
ReferenceType::Ptr fromReference = from.cast<ReferenceType>();
153
///iso c++ draft 13.3.3.1.4 reference-binding, modeled roughly
154
ReferenceType::Ptr toReference = to.cast<ReferenceType>();
156
AbstractType::Ptr realFrom = realType(from, m_topContext);
157
AbstractType::Ptr realTo = realType(to, m_topContext);
158
if(!realFrom || !realTo) {
159
problem( from, to, "one type is invalid" );
162
if( fromLValue && ((realTo->modifiers() & AbstractType::ConstModifier) || (realTo->modifiers() & AbstractType::ConstModifier) == isConstant(from)) ) {
163
///Since from is an lvalue, and the constant-specification matches, we can maybe directly create a reference
164
//Either identity-conversion:
165
if( identityConversion( realFrom, realTo ) ) {
166
conv = ExactMatch + 2*ConversionRankOffset;
169
//Or realType(toReference) is a public base-class of realType(fromReference)
170
CppClassType::Ptr fromClass = realFrom.cast<CppClassType>();
171
CppClassType::Ptr toClass = realTo.cast<CppClassType>();
173
if( fromClass && toClass && isPublicBaseClass( fromClass, toClass, m_topContext, &m_baseConversionLevels ) ) {
174
conv = ExactMatch + 2*ConversionRankOffset;
179
//We cannot directly create a reference, but maybe there is a user-defined conversion that creates a compatible reference, as in iso c++ 13.3.3.1.4.1
180
if( !noUserDefinedConversion ) {
181
if( int rank = userDefinedConversion( from, to, fromLValue, true ) ) {
182
conv = rank + ConversionRankOffset;
187
if( realTo->modifiers() & AbstractType::ConstModifier ) {
188
//For constant references, the compiler can create a temporary object holding the converted value. So just forget whether the types are references.
189
conv = implicitConversion( realType(from, m_topContext)->indexed(), realType(to, m_topContext)->indexed(), fromLValue, noUserDefinedConversion );
197
//This is very simplified, see iso c++ draft 13.3.3.1
199
if( (tempConv = standardConversion(from,to)) ) {
200
tempConv += 2*ConversionRankOffset;
201
if( tempConv > conv )
205
if( !noUserDefinedConversion ) {
206
if( (tempConv = userDefinedConversion(from, to, fromLValue)) ) {
207
tempConv += ConversionRankOffset;
208
if( tempConv > conv )
213
if( (tempConv = ellipsisConversion(from, to)) && tempConv > conv )
221
m_cache->m_implicitConversionResults.insert(params, conv);
226
int TypeConversion::baseConversionLevels() const {
227
return m_baseConversionLevels;
230
///Helper for standardConversion(..) that makes sure that when one category is taken out of the possible ones, the earlier are taken out too, because categories must be checked in order.
231
int removeCategories( int categories, ConversionCategories remove ) {
232
for( int a = 1; a <= remove; a*=2 ) {
238
///if myRank is better than rank, rank will be set to myRank
239
void maximizeRank( ConversionRank& rank, ConversionRank myRank ) {
244
///Returns the worse of the both given ranks
245
ConversionRank worseRank( ConversionRank rank1, ConversionRank rank2 ) {
246
return rank1 > rank2 ? rank2 : rank1;
249
ConversionRank TypeConversion::pointerConversion( PointerType::Ptr from, PointerType::Ptr to ) {
251
//We can convert non-const -> const, but not const -> non-const
252
// if(to->modifiers() & AbstractType::ConstModifier || !(from->modifiers()& AbstractType::ConstModifier)) {
257
AbstractType::Ptr nextFrom = unAliasedType(from->baseType());
258
AbstractType::Ptr nextTo = unAliasedType(to->baseType());
260
if(!nextTo || !nextFrom)
263
if((nextFrom->modifiers() & AbstractType::ConstModifier) && !(nextTo->modifiers() & AbstractType::ConstModifier))
264
return NoMatch; //Cannot convert const -> non-const
266
PointerType::Ptr pointerFrom = nextFrom.cast<PointerType>();
267
PointerType::Ptr pointerTo = nextTo.cast<PointerType>();
268
if(pointerFrom && pointerTo)
269
return pointerConversion(pointerFrom, pointerTo);
271
CppClassType::Ptr fromClass = nextFrom.cast<CppClassType>();
272
CppClassType::Ptr toClass = nextTo.cast<CppClassType>();
273
if( toClass && fromClass )
274
if(toClass->modifiers() & AbstractType::ConstModifier || !(fromClass->modifiers()& AbstractType::ConstModifier))
275
if( isPublicBaseClass( fromClass, toClass, m_topContext, &m_baseConversionLevels ) )
276
return ((toClass->modifiers() & AbstractType::ConstModifier) != (fromClass->modifiers() & AbstractType::ConstModifier)) ? Conversion : ExactMatch;
278
bool changed = false;
279
//Change the constness matches, so they are equal if compatible
280
if(nextTo->modifiers() & AbstractType::ConstModifier) {
281
nextFrom->setModifiers(nextFrom->modifiers() | AbstractType::ConstModifier);
285
if(identityConversion(nextFrom, nextTo))
286
return changed ? Conversion : ExactMatch;
297
ConversionRank TypeConversion::standardConversion( AbstractType::Ptr from, AbstractType::Ptr to, int categories, int maxCategories ) {
299
/** Lowest conversion-rank of all sub-conversions is returned
300
* See iso c++ draft 13.3.3.1.1
302
* Conversions from up to 3 different categories are allowed
304
* Table about category and rank:
306
* Conversion Category Rank iso c++ clause
307
* -----------------------------------------------------------------------------------------------------
308
* No conversion Identity Exact Match
309
* Lvalue-to-rvalue conv. Lvalue Transformation Exact Match 4.1
310
* Array-to-pointer conv. Lvalue Transformation Exact Match 4.2
311
* Function-to-pointer conv. Lvalue Transformation Exact Match 4.3
312
* Qualification conversion Qualification Adjustment Exact Match 4.4
313
* Integral promotions Promotion Promotion 4.5
314
* Floating point promotion Promotion Promotion 4.6
315
* Integral conversions Conversion Conversion 4.7
316
* Floating point conversions Conversion Conversion 4.8
317
* Floating-integral conversions Conversion Conversion 4.9
318
* Pointer conversions Conversion Conversion 4.10
319
* Pointer to member conversions Conversion Conversion 4.11
320
* Boolean conversions Conversion Conversion 4.12
322
* A standard-conversion may consist of up to 3 conversions from different categories
325
* This function achieves the rules recursively. Performance-wise that may not be perfect, because sometimes many different paths can are followed.
327
from = unAliasedType(from);
328
to = unAliasedType(to);
330
if( (categories & IdentityCategory) && identityConversion( from, to ) )
336
ConversionRank bestRank = NoMatch;
338
///Try lvalue-transformation category
339
if( (categories & LValueTransformationCategory) ) {
341
bool constRef = false;
342
if( isReferenceType(from) ) {
343
///Transform lvalue to rvalue. Iso c++ draft 4.1 modeled roughly
345
AbstractType::Ptr fromNonConstant = realType(from, m_topContext)->indexed().abstractType();
347
//When copying, the type becomes non-constant
348
if(fromNonConstant && fromNonConstant->modifiers() & AbstractType::ConstModifier)
349
fromNonConstant->setModifiers(fromNonConstant->modifiers() & ~(AbstractType::ConstModifier));
351
ConversionRank ret = standardConversion( fromNonConstant, to, removeCategories(categories,LValueTransformationCategory), maxCategories-1 );
352
maximizeRank( bestRank, ret );
353
}else if( ArrayType::Ptr array = realType(from, m_topContext, &constRef).cast<ArrayType>() ) { //realType(from) is used here so reference-to-array can be transformed to a pointer. This does not exactly follow the standard I think, check that.
354
///Transform array to pointer. Iso c++ draft 4.2 modeled roughly.
355
PointerType::Ptr p( new PointerType() );
357
p->setModifiers(AbstractType::ConstModifier);
358
p->setBaseType(array->elementType());
359
ConversionRank rank = standardConversion( p.cast<AbstractType>(), to, removeCategories(categories,LValueTransformationCategory), maxCategories-1 );
361
maximizeRank( bestRank, worseRank(rank, ExactMatch ) );
362
} else if( FunctionType::Ptr function = realType(from, m_topContext, &constRef).cast<FunctionType>() ) {
363
///Transform lvalue-function. Iso c++ draft 4.3
364
//This code is nearly the same as the above array-to-pointer conversion. Maybe it should be merged.
366
PointerType::Ptr p( new PointerType() );
368
p->setModifiers(AbstractType::ConstModifier);
369
p->setBaseType( function.cast<AbstractType>() );
371
ConversionRank rank = standardConversion( p.cast<AbstractType>(), to, removeCategories(categories,LValueTransformationCategory), maxCategories-1 );
373
maximizeRank( bestRank, worseRank(rank, ExactMatch ) );
374
}else if(from->modifiers() & AbstractType::ConstModifier) {
375
///We can transform a constant lvalue to a non-constant rvalue
376
AbstractType::Ptr fromNonConstant = from->indexed().abstractType();
377
fromNonConstant->setModifiers(fromNonConstant->modifiers() & ~(AbstractType::ConstModifier));
378
ConversionRank ret = standardConversion( fromNonConstant, to, removeCategories(categories,LValueTransformationCategory), maxCategories-1 );
379
maximizeRank( bestRank, ret );
383
// if( categories & QualificationAdjustmentCategory ) {
384
// PointerType::Ptr pnt = from.cast<PointerType>();
386
// ///@todo iso c++ 4.4.2 etc: pointer to member
389
EnumerationType::Ptr toEnumeration = to.cast<EnumerationType>();
392
//Eventually convert enumerator -> enumeration if the enumeration equals
393
EnumeratorType::Ptr fromEnumerator = from.cast<EnumeratorType>();
395
Declaration* enumeratorDecl = fromEnumerator->declaration(m_topContext);
396
Declaration* enumerationDecl = toEnumeration->declaration(m_topContext);
397
if(enumeratorDecl && enumerationDecl && enumeratorDecl->context()->owner() == enumerationDecl)
398
return ExactMatch; //Converting an enumeration value into its own enumerator type, perfect match.
400
///iso c++ 7.2.9: No conversion or promotion to enumerator types is possible
404
if( categories & PromotionCategory ) {
406
IntegralType::Ptr integral = from.cast<IntegralType>();
409
///Integral promotions, iso c++ 4.5
410
if( integerConversionRank(integral) < unsignedIntConversionRank && integral->dataType() != IntegralType::TypeBoolean && integral->dataType() != IntegralType::TypeWchar_t && integral->dataType() != IntegralType::TypeVoid ) {
412
///@todo re-create a mini repository for fast lookup of such integral types, so we don't have to do allocations here
413
AbstractType::Ptr newFrom( new IntegralType(IntegralType::TypeInt) );
414
newFrom->setModifiers((integral->modifiers() & AbstractType::UnsignedModifier) ? AbstractType::UnsignedModifier : AbstractType::NoModifiers);
415
ConversionRank rank = standardConversion( newFrom, to, removeCategories(categories,PromotionCategory), maxCategories-1 );
417
maximizeRank( bestRank, worseRank(rank, Promotion ) );
420
///Floating point promotion, iso c++ 4.6
421
if( integral->dataType() == IntegralType::TypeDouble ) {
422
AbstractType::Ptr newFrom( new IntegralType(IntegralType::TypeDouble) );
423
ConversionRank rank = standardConversion( newFrom, to, removeCategories(categories,PromotionCategory), maxCategories-1 );
425
maximizeRank( bestRank, worseRank(rank, Promotion ) );
430
if( categories & ConversionCategory )
432
IntegralType::Ptr fromIntegral = from.cast<IntegralType>();
433
EnumerationType::Ptr fromEnumeration = fromIntegral.cast<EnumerationType>();
434
EnumeratorType::Ptr fromEnumerator = fromIntegral.cast<EnumeratorType>();
436
IntegralType::Ptr toIntegral = to.cast<IntegralType>();
438
if( fromIntegral && toIntegral ) {
439
///iso c++ 4.7 integral conversion: we can convert from any integer type to any other integer type, and from enumeration-type to integer-type
440
if( (fromEnumeration || fromEnumerator || isIntegerType(fromIntegral)) && isIntegerType(toIntegral) )
442
maximizeRank( bestRank, Conversion );
445
///iso c++ 4.8 floating point conversion: any floating-point to any other floating-point
446
if( isFloatingPointType(fromIntegral) && isFloatingPointType(toIntegral) )
448
maximizeRank( bestRank, Conversion );
451
///iso c++ 4.9 floating-integral conversion: floating point can be converted to integral, enumeration and integral can be converted to floating point
452
if( ( ( fromEnumeration || fromEnumerator || isIntegerType(fromIntegral) ) && isFloatingPointType(toIntegral) ) ||
453
( isFloatingPointType(fromIntegral) && isIntegerType(toIntegral) ) )
456
maximizeRank( bestRank, Conversion );
460
///iso c++ 4.10 pointer conversion: null-type con be converted to pointer
461
PointerType::Ptr fromPointer = from.cast<PointerType>();
462
PointerType::Ptr toPointer = to.cast<PointerType>();
464
if( isNullType(from) && toPointer )
466
maximizeRank( bestRank, Conversion );
469
///Pointer can be converted to void*
470
if( fromPointer && toPointer && isVoidType(toPointer->baseType()) )
472
maximizeRank( bestRank, Conversion );
475
///iso c++ 4.10.3 - class-pointer conversion
476
if( fromPointer && toPointer /*&& fromPointer->cv() == toPointer->cv()*/ )
477
maximizeRank( bestRank, pointerConversion(fromPointer, toPointer) );
479
///@todo pointer-to-member conversion
481
///iso c++ 4.12 Boolean conversions
482
if( toIntegral && toIntegral->dataType() == IntegralType::TypeBoolean ) {
483
//We are converting to a boolean value
484
if( fromPointer || fromEnumeration || fromEnumerator || (fromIntegral && (isIntegerType(fromIntegral) || isFloatingPointType(fromIntegral))) ) {
485
maximizeRank( bestRank, Conversion );
493
bool TypeConversion::identityConversion( AbstractType::Ptr from, AbstractType::Ptr to ) {
495
from = TypeUtils::unAliasedType(from);
496
to = TypeUtils::unAliasedType(to);
500
else if( !from || !to )
503
//ConstantIntegralType::equals does not return true on equals in this case, but the type is compatible.
504
if(from.cast<ConstantIntegralType>() && typeid(*to) == typeid(IntegralType))
507
return from->equals(to.unsafeData());
510
void TypeConversion::problem( AbstractType::Ptr from, AbstractType::Ptr to, const QString& desc ) {
516
ConversionRank TypeConversion::userDefinedConversion( AbstractType::Ptr from, AbstractType::Ptr to, bool fromLValue, bool secondConversionIsIdentity ) {
518
* Two possible cases:
519
* - from is a class, that has a conversion-function
520
* - to is a class that has a converting(non-explicit) matching constructor
522
ConversionRank bestRank = NoMatch;
524
bool fromConst = false;
525
AbstractType::Ptr realFrom( realType(from, m_topContext, &fromConst) );
526
CppClassType::Ptr fromClass = realFrom.cast<CppClassType>();
528
///Try user-defined conversion using a conversion-function, iso c++ 12.3
532
///Search for a conversion-function that has a compatible output
533
QHash<FunctionType::Ptr, ClassFunctionDeclaration*> conversionFunctions;
534
getMemberFunctions(fromClass, m_topContext, conversionFunctions, "operator{...cast...}", fromConst);
536
for( QHash<FunctionType::Ptr, ClassFunctionDeclaration*>::const_iterator it = conversionFunctions.constBegin(); it != conversionFunctions.constEnd(); ++it )
538
if(isAccessible(it.value())) {
539
AbstractType::Ptr convertedType( it.key()->returnType() );
540
ConversionRank rank = standardConversion( convertedType, to );
542
if( rank != NoMatch && (!secondConversionIsIdentity || rank == ExactMatch) )
544
//We have found a matching conversion-function
545
if( identityConversion(realType(convertedType, m_topContext), to) )
546
maximizeRank( bestRank, ExactMatch );
548
maximizeRank( bestRank, Conversion );
555
AbstractType::Ptr realTo( realType(to, m_topContext) );
558
///Try conversion using constructor
559
CppClassType::Ptr toClass = realTo.cast<CppClassType>(); //@todo think whether the realType(..) is ok
560
if( toClass && toClass->declaration(m_topContext) )
563
if( isPublicBaseClass(fromClass, toClass, m_topContext, &m_baseConversionLevels ) ) {
564
///@todo check whether this is correct
565
//There is a default-constructor in toClass that initializes from const toClass&, which fromClass can be converted to
566
maximizeRank( bestRank, Conversion );
570
DUContextPointer ptr(toClass->declaration(m_topContext)->logicalInternalContext(m_topContext));
571
OverloadResolver resolver( ptr, TopDUContextPointer( const_cast<TopDUContext*>(m_topContext) ) );
572
Declaration* function = resolver.resolveConstructor( OverloadResolver::Parameter( from, fromLValue ), true, true );
574
if( function && isAccessible(dynamic_cast<ClassMemberDeclaration*>(function)) )
576
//We've successfully located an overloaded constructor that accepts the argument
578
maximizeRank( bestRank, ExactMatch );
580
maximizeRank( bestRank, Conversion );
588
bool TypeConversion::isAccessible(const ClassMemberDeclaration* decl) {
589
///@todo Use Cpp::isAccessible here
592
return decl->accessPolicy() == Declaration::Public;
595
ConversionRank TypeConversion::ellipsisConversion( AbstractType::Ptr from, AbstractType::Ptr to ) {