Warning, file /kdevelop/kdev-python/duchain/types/unsuretype.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2011 Sven Brauch <svenbrauch@googlemail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "unsuretype.h" 0008 #include "helpers.h" 0009 #include "indexedcontainer.h" 0010 0011 #include <duchaindebug.h> 0012 0013 #include <language/duchain/types/typeregister.h> 0014 #include <language/duchain/types/typesystem.h> 0015 #include <language/duchain/types/typealiastype.h> 0016 #include <language/duchain/types/containertypes.h> 0017 #include <language/duchain/types/unsuretype.h> 0018 #include <language/duchain/parsingenvironment.h> 0019 #include <language/duchain/duchainlock.h> 0020 0021 #include <KLocalizedString> 0022 0023 namespace Python { 0024 0025 REGISTER_TYPE(UnsureType); 0026 0027 UnsureType::UnsureType() : KDevelop::UnsureType(createData<UnsureType>()) 0028 { 0029 } 0030 0031 UnsureType::UnsureType(const UnsureType& rhs) 0032 : KDevelop::UnsureType(copyData<UnsureType>(*rhs.d_func())) 0033 { 0034 0035 } 0036 0037 UnsureType::UnsureType(KDevelop::UnsureTypeData& data) 0038 : KDevelop::UnsureType(data) 0039 { 0040 0041 } 0042 0043 const QList<AbstractType::Ptr> UnsureType::typesRecursive() const 0044 { 0045 QList<AbstractType::Ptr> results; 0046 FOREACH_FUNCTION ( const IndexedType& type, d_func()->m_types ) { 0047 AbstractType::Ptr current = type.abstractType(); 0048 AbstractType::Ptr resolved = Helper::resolveAliasType(current); 0049 if ( resolved->whichType() == AbstractType::TypeUnsure ) { 0050 results.append(resolved.staticCast<UnsureType>()->typesRecursive()); 0051 } 0052 else 0053 results.append(current); 0054 } 0055 return results; 0056 } 0057 0058 QString UnsureType::toString() const 0059 { 0060 QString typeList; 0061 QVector<AbstractType::Ptr> types; 0062 auto is_new_type = [&types](const IndexedType newType) { 0063 foreach ( const auto& type, types ) { 0064 if ( type->indexed() == newType ) { 0065 return false; 0066 } 0067 } 0068 return true; 0069 }; 0070 0071 foreach ( AbstractType::Ptr type, typesRecursive() ) { 0072 if ( ! type ) { 0073 qCWarning(KDEV_PYTHON_DUCHAIN) << "Invalid type: " << type.data(); 0074 continue; 0075 } 0076 0077 const auto new_type = Helper::resolveAliasType(type); 0078 if ( is_new_type(new_type->indexed()) ) { 0079 types.append(new_type); 0080 } 0081 } 0082 0083 auto count_and_remove = [&types](std::function<bool(AbstractType::Ptr)> match) -> bool { 0084 auto count = std::count_if(types.begin(), types.end(), match); 0085 if ( count < 3 ) { 0086 // nothing worth collapsing 0087 return false; 0088 } 0089 auto end = std::remove_if(types.begin(), types.end(), match); 0090 types.erase(end, types.end()); 0091 return true; 0092 }; 0093 0094 QStringList collapsedTypes; 0095 if ( types.size() > 2 ) { 0096 // try to collapse the list, if possible 0097 using T = const AbstractType::Ptr&; 0098 auto have_callable = count_and_remove([](T t) { return t->whichType() == AbstractType::TypeFunction; }); 0099 if ( have_callable ) { 0100 // TODO collapse arguments / return type 0101 collapsedTypes.append(i18nc("some object that can be called, in programming", "<callable>")); 0102 } 0103 auto have_iterable = count_and_remove([](T t) { return t.dynamicCast<IndexedContainer>() || t.dynamicCast<ListType>(); }); 0104 if ( have_iterable ) { 0105 // TODO collapse element count / types 0106 collapsedTypes.append(i18nc("a set with some elements", "<iterable>")); 0107 } 0108 } 0109 0110 int count = 0; 0111 foreach ( const auto& type, types ) { 0112 if ( count ) 0113 typeList += ", "; 0114 count += 1; 0115 0116 typeList += type->toString(); 0117 } 0118 foreach ( const auto& collapsed, collapsedTypes ) { 0119 if ( count ) 0120 typeList += ", "; 0121 count += 1; 0122 0123 typeList += collapsed; 0124 } 0125 0126 if ( count == 0 || count > 7 ) 0127 return i18nc("refers to a type (in program code) which is not known", "mixed"); 0128 if ( count == 1 ) 0129 return typeList; 0130 return i18nc("refers to a type (in program code) which can have multiple values", "unsure (%1)", typeList); 0131 } 0132 0133 KDevelop::AbstractType* UnsureType::clone() const 0134 { 0135 UnsureType* n = new UnsureType(*this); 0136 return n; 0137 } 0138 0139 AbstractType::WhichType UnsureType::whichType() const 0140 { 0141 return AbstractType::TypeUnsure; 0142 } 0143 0144 void UnsureType::addType(const IndexedType& indexed) { 0145 auto type = indexed.abstractType(); 0146 auto hinted = type.dynamicCast<HintedType>(); // XXX: do we need a read locker here? 0147 if ( ! hinted ) { 0148 // if we aren't adding a HintedType the default implementation works 0149 KDevelop::UnsureType::addType(indexed); 0150 return; 0151 } 0152 auto& list = d_func_dynamic()->m_typesList(); 0153 DUChainReadLocker lock; 0154 if (!hinted->isValid()) { // needs a read lock (as does most of the rest of the function) 0155 // can happen if the user saves the currently open document again before parsing has finished 0156 return; 0157 } 0158 // If there is already a HintedType in the list referring to the underlying type 0159 // we only add it if the context it was created in is the same. 0160 // Additionally, we also remove all HintedType instances that are no longer valid 0161 // to make sure the list doesn't grow infinitely large 0162 const auto newHintedTarget = hinted->type()->indexed(); 0163 bool alreadyExists = false; 0164 for ( int j = 0; j < list.size(); j++ ) { 0165 const IndexedType oldIndexed = list.at(j); 0166 if (oldIndexed == indexed) { 0167 alreadyExists = true; 0168 } 0169 const auto& old = oldIndexed.abstractType(); 0170 if ( auto oldHinted = old.dynamicCast<HintedType>() ) { 0171 if ( !alreadyExists ) { 0172 // only do these checks if we haven't already determined that it is a duplicate 0173 auto oldHintedTarget = oldHinted->type()->indexed(); 0174 if ( oldHintedTarget == newHintedTarget ) { 0175 if ( hinted->createdBy() == oldHinted->createdBy()) { 0176 alreadyExists = true; 0177 } 0178 } 0179 } 0180 if ( ! oldHinted->isValid() ) { 0181 // std::remove_if + erase() would be faster than remove() but this list won't have many entries 0182 // and the memcpy() cost is probably massively offset by the IndexedType -> AbstractType 0183 // lookup that we would have to duplicated if we had a separate check for duplicates loop 0184 list.remove(j); 0185 j--; 0186 continue; 0187 } 0188 } 0189 } 0190 if ( !alreadyExists ) { 0191 list.append(indexed); 0192 } 0193 // #define CHECK_DUPLICATES 0194 #ifdef CHECK_DUPLICATES 0195 if (list.size() > 1) { 0196 QString types; 0197 bool foundDuplicates = false; 0198 QStringList checkDuplicates; 0199 FOREACH_FUNCTION(const IndexedType& type2, d_func()->m_types) { 0200 auto t = type2.abstractType(); 0201 auto str = t->toString(); 0202 types += "\n " + QString::number(type2.index()); 0203 auto hinted = t.dynamicCast<HintedType>(); 0204 while (hinted) { 0205 auto target = hinted->type(); 0206 types += " (aka " + QString::number(target->indexed().index()) + ": " + target->toString() 0207 + " and context " + QString::number(hinted->createdBy().index()) + ")"; 0208 hinted = target.dynamicCast<HintedType>(); 0209 } 0210 types += " - " + t->toString() + " of type " + typeid(*t).name(); 0211 if (!foundDuplicates) { 0212 if (checkDuplicates.contains(str)) { 0213 foundDuplicates = true; 0214 } else { 0215 checkDuplicates.append(str); 0216 } 0217 } 0218 } 0219 if (foundDuplicates) { 0220 qWarning().nospace().noquote() << "found potential duplicates when adding " << typeid(*type).name() 0221 << " " << type->toString() 0222 << "(index = " << indexed.index() << ") ->" << types; 0223 } 0224 } 0225 #endif 0226 } 0227 0228 bool UnsureType::equals(const AbstractType* rhs) const 0229 { 0230 if ( this == rhs ) { 0231 return true; 0232 } 0233 if ( ! dynamic_cast<const UnsureType*>(rhs) ) { 0234 return false; 0235 } 0236 if ( ! KDevelop::UnsureType::equals(rhs) ) { 0237 return false; 0238 } 0239 return true; 0240 } 0241 0242 uint UnsureType::hash() const 0243 { 0244 return KDevelop::UnsureType::hash() + 1; 0245 } 0246 0247 }