File indexing completed on 2024-05-12 04:39:09
0001 /* 0002 SPDX-FileCopyrightText: 2007 David Nolden <david.nolden.kdevelop@art-master.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #include "codegenhelper.h" 0008 0009 #include "adaptsignatureaction.h" 0010 0011 #include <language/duchain/classmemberdeclaration.h> 0012 #include <language/duchain/types/arraytype.h> 0013 #include <language/duchain/types/functiontype.h> 0014 #include <language/duchain/types/typealiastype.h> 0015 #include <language/duchain/types/typesystem.h> 0016 #include <language/duchain/types/referencetype.h> 0017 #include <language/duchain/types/pointertype.h> 0018 #include <language/duchain/ducontext.h> 0019 0020 using namespace KDevelop; 0021 0022 namespace { 0023 IndexedTypeIdentifier stripPrefixIdentifiers(const IndexedTypeIdentifier& id, const QualifiedIdentifier& strip); 0024 0025 Identifier stripPrefixIdentifiers(const Identifier& id, const QualifiedIdentifier& strip) 0026 { 0027 Identifier ret(id); 0028 ret.clearTemplateIdentifiers(); 0029 for (unsigned int a = 0; a < id.templateIdentifiersCount(); ++a) { 0030 ret.appendTemplateIdentifier(stripPrefixIdentifiers(id.templateIdentifier(a), strip)); 0031 } 0032 0033 return ret; 0034 } 0035 0036 IndexedTypeIdentifier stripPrefixIdentifiers(const IndexedTypeIdentifier& id, const QualifiedIdentifier& strip) 0037 { 0038 QualifiedIdentifier oldId(id.identifier().identifier()); 0039 QualifiedIdentifier qid; 0040 0041 int commonPrefix = 0; 0042 for (; commonPrefix < oldId.count() - 1 && commonPrefix < strip.count(); ++commonPrefix) { 0043 if (strip.at(commonPrefix).toString() != oldId.at(commonPrefix).toString()) { 0044 break; 0045 } 0046 } 0047 0048 for (int a = commonPrefix; a < oldId.count(); ++a) { 0049 qid.push(stripPrefixIdentifiers(oldId.at(a), strip)); 0050 } 0051 0052 IndexedTypeIdentifier ret(id); 0053 ret.setIdentifier(qid); 0054 return ret; 0055 } 0056 0057 int reservedIdentifierCount(const QString &name) 0058 { 0059 const QStringList l = name.split(QStringLiteral("::")); 0060 int ret = 0; 0061 for (const QString& s : l) { 0062 if (s.startsWith(QLatin1Char('_'))) { 0063 ++ret; 0064 } 0065 } 0066 return ret; 0067 } 0068 0069 uint buildIdentifierForType(const AbstractType::Ptr& type, IndexedTypeIdentifier& id, uint pointerLevel, TopDUContext* top) 0070 { 0071 if (!type) { 0072 return pointerLevel; 0073 } 0074 if (auto refType = type.dynamicCast<ReferenceType>()) { 0075 id.setIsReference(true); 0076 if (refType->modifiers() & AbstractType::ConstModifier) { 0077 id.setIsConstant(true); 0078 } 0079 0080 return buildIdentifierForType(refType->baseType(), id, pointerLevel, top); 0081 } 0082 0083 if (auto pointerType = type.dynamicCast<PointerType>()) { 0084 ++pointerLevel; 0085 uint maxPointerLevel = buildIdentifierForType(pointerType->baseType(), id, pointerLevel, top); 0086 if (type->modifiers() & AbstractType::ConstModifier) { 0087 id.setIsConstPointer(maxPointerLevel - pointerLevel, true); 0088 } 0089 if (static_cast<uint>(id.pointerDepth()) < pointerLevel) { 0090 id.setPointerDepth(pointerLevel); 0091 } 0092 0093 return maxPointerLevel; 0094 } 0095 0096 AbstractType::Ptr useTypeText = type; 0097 if (type->modifiers() & AbstractType::ConstModifier) { 0098 //Remove the 'const' modifier, as it will be added to the type-identifier below 0099 useTypeText = IndexedType(type).abstractType(); 0100 useTypeText->setModifiers(useTypeText->modifiers() & (~AbstractType::ConstModifier)); 0101 } 0102 id.setIdentifier(QualifiedIdentifier(useTypeText->toString(), true)); 0103 0104 if (type->modifiers() & AbstractType::ConstModifier) { 0105 id.setIsConstant(true); 0106 } 0107 if (type->modifiers() & AbstractType::VolatileModifier) { 0108 id.setIsVolatile(true); 0109 } 0110 return pointerLevel; 0111 } 0112 0113 IndexedTypeIdentifier identifierForType(const AbstractType::Ptr& type, TopDUContext* top) 0114 { 0115 IndexedTypeIdentifier ret; 0116 buildIdentifierForType(type, ret, 0, top); 0117 return ret; 0118 } 0119 0120 IndexedTypeIdentifier removeTemplateParameters(const IndexedTypeIdentifier& identifier, int behindPosition); 0121 0122 Identifier removeTemplateParameters(const Identifier& id, int behindPosition) 0123 { 0124 Identifier ret(id); 0125 0126 ret.clearTemplateIdentifiers(); 0127 for (unsigned int a = 0; a < id.templateIdentifiersCount(); ++a) { 0128 IndexedTypeIdentifier replacement = removeTemplateParameters(id.templateIdentifier(a), behindPosition); 0129 if (( int ) a < behindPosition) { 0130 ret.appendTemplateIdentifier(replacement); 0131 } else { 0132 ret.appendTemplateIdentifier(IndexedTypeIdentifier(QualifiedIdentifier(QStringLiteral("...")))); 0133 break; 0134 } 0135 } 0136 0137 return ret; 0138 } 0139 0140 IndexedTypeIdentifier removeTemplateParameters(const IndexedTypeIdentifier& identifier, int behindPosition) { 0141 IndexedTypeIdentifier ret(identifier); 0142 0143 QualifiedIdentifier oldId(identifier.identifier().identifier()); 0144 QualifiedIdentifier qid; 0145 0146 for (int a = 0; a < oldId.count(); ++a) { 0147 qid.push(removeTemplateParameters(oldId.at(a), behindPosition)); 0148 } 0149 0150 ret.setIdentifier(qid); 0151 0152 return ret; 0153 } 0154 0155 IndexedType removeConstModifier(const IndexedType& indexedType) 0156 { 0157 AbstractType::Ptr type = indexedType.abstractType(); 0158 type->setModifiers(type->modifiers() & (~AbstractType::ConstModifier)); 0159 return type->indexed(); 0160 } 0161 0162 AbstractType::Ptr shortenTypeForViewing(const AbstractType::Ptr& type) 0163 { 0164 struct ShortenAliasExchanger 0165 : public TypeExchanger 0166 { 0167 AbstractType::Ptr exchange(const AbstractType::Ptr& type) override { 0168 if (!type) { 0169 return type; 0170 } 0171 0172 AbstractType::Ptr newType(type->clone()); 0173 0174 if (auto alias = type.dynamicCast<TypeAliasType>()) { 0175 //If the aliased type has less involved template arguments, prefer it 0176 AbstractType::Ptr shortenedTarget = exchange(alias->type()); 0177 if (shortenedTarget && shortenedTarget->toString().count(QLatin1Char('<')) < alias->toString().count(QLatin1Char('<')) 0178 && reservedIdentifierCount(shortenedTarget->toString()) <= reservedIdentifierCount(alias->toString())) 0179 { 0180 shortenedTarget->setModifiers(shortenedTarget->modifiers() | alias->modifiers()); 0181 return shortenedTarget; 0182 } 0183 } 0184 0185 newType->exchangeTypes(this); 0186 0187 return newType; 0188 } 0189 }; 0190 0191 ShortenAliasExchanger exchanger; 0192 return exchanger.exchange(type); 0193 } 0194 0195 ///Returns a type that has all template types replaced with DelayedType's that have their template default parameters stripped away, 0196 ///and all scope prefixes removed that are redundant within the given context 0197 ///The returned type should not actively be used in the type-system, but rather only for displaying. 0198 AbstractType::Ptr stripType(const AbstractType::Ptr& type, DUContext* ctx) 0199 { 0200 if (!type) { 0201 return AbstractType::Ptr(); 0202 } 0203 0204 struct ShortenTemplateDefaultParameter 0205 : public TypeExchanger 0206 { 0207 DUContext* ctx; 0208 explicit ShortenTemplateDefaultParameter(DUContext* _ctx) 0209 : ctx(_ctx) { 0210 Q_ASSERT(ctx); 0211 } 0212 0213 AbstractType::Ptr exchange(const AbstractType::Ptr& type) override { 0214 if (!type) { 0215 return type; 0216 } 0217 0218 AbstractType::Ptr newType(type->clone()); 0219 0220 if (const auto * idType = dynamic_cast<const IdentifiedType*>(type.data())) { 0221 Declaration* decl = idType->declaration(ctx->topContext()); 0222 if (!decl) { 0223 return type; 0224 } 0225 0226 QualifiedIdentifier newTypeName; 0227 0228 #if 0 // from oldcpp 0229 if (TemplateDeclaration * tempDecl = dynamic_cast<TemplateDeclaration*>(decl)) { 0230 if (decl->context()->type() == DUContext::Class && decl->context()->owner()) { 0231 //Strip template default-parameters from the parent class 0232 AbstractType::Ptr parentType = stripType(decl->context()->owner()->abstractType(), ctx); 0233 if (parentType) { 0234 newTypeName = QualifiedIdentifier(parentType->toString(), true); 0235 } 0236 } 0237 if (newTypeName.isEmpty()) { 0238 newTypeName = decl->context()->scopeIdentifier(true); 0239 } 0240 0241 Identifier currentId; 0242 if (!idType->qualifiedIdentifier().isEmpty()) { 0243 currentId = idType->qualifiedIdentifier().last(); 0244 } 0245 currentId.clearTemplateIdentifiers(); 0246 0247 InstantiationInformation instantiationInfo = tempDecl->instantiatedWith().information(); 0248 InstantiationInformation newInformation(instantiationInfo); 0249 newInformation.templateParametersList().clear(); 0250 0251 for (uint neededParameters = 0; neededParameters < instantiationInfo.templateParametersSize(); ++neededParameters) { 0252 newInformation.templateParametersList().append(instantiationInfo.templateParameters()[neededParameters]); 0253 AbstractType::Ptr niceParam = stripType(instantiationInfo.templateParameters()[neededParameters].abstractType(), ctx); 0254 if (niceParam) { 0255 currentId.appendTemplateIdentifier(IndexedTypeIdentifier(niceParam->toString(), true)); 0256 // debug() << "testing param" << niceParam->toString(); 0257 } 0258 0259 if (tempDecl->instantiate(newInformation, ctx->topContext()) == decl) { 0260 // debug() << "got full instantiation"; 0261 break; 0262 } 0263 } 0264 0265 newTypeName.push(currentId); 0266 } else { 0267 newTypeName = decl->qualifiedIdentifier(); 0268 } 0269 #endif 0270 0271 newTypeName = decl->qualifiedIdentifier(); 0272 0273 //Strip unneeded prefixes of the scope 0274 QualifiedIdentifier candidate = newTypeName; 0275 while (candidate.count() > 1) { 0276 candidate = candidate.mid(1); 0277 QList<Declaration*> decls = ctx->findDeclarations(candidate); 0278 if (decls.isEmpty()) { 0279 continue; // type aliases might be available for nested sub scopes, hence we must not break early 0280 } 0281 if (decls[0]->kind() != Declaration::Type || removeConstModifier(decls[0]->indexedType()) != removeConstModifier(IndexedType(type))) { 0282 break; 0283 } 0284 newTypeName = candidate; 0285 } 0286 if (newTypeName == decl->qualifiedIdentifier()) { 0287 return type; 0288 } 0289 0290 DelayedType::Ptr ret(new DelayedType); 0291 IndexedTypeIdentifier ti(newTypeName); 0292 ti.setIsConstant(type->modifiers() & AbstractType::ConstModifier); 0293 ret->setIdentifier(ti); 0294 return ret; 0295 } 0296 newType->exchangeTypes(this); 0297 0298 return newType; 0299 } 0300 }; 0301 0302 ShortenTemplateDefaultParameter exchanger(ctx); 0303 return exchanger.exchange(type); 0304 } 0305 } 0306 0307 namespace CodegenHelper { 0308 AbstractType::Ptr typeForShortenedString(Declaration* decl) 0309 { 0310 AbstractType::Ptr type = decl->abstractType(); 0311 if (decl->isTypeAlias()) { 0312 if (auto alias = type.dynamicCast<TypeAliasType>()) { 0313 type = alias->type(); 0314 } 0315 } 0316 0317 if (decl->isFunctionDeclaration()) { 0318 FunctionType::Ptr funType = decl->type<FunctionType>(); 0319 if (!funType) { 0320 return AbstractType::Ptr(); 0321 } 0322 type = funType->returnType(); 0323 } 0324 return type; 0325 } 0326 0327 QString shortenedTypeString(Declaration* decl, DUContext* ctx, int desiredLength, const QualifiedIdentifier& stripPrefix) 0328 { 0329 return shortenedTypeString(typeForShortenedString(decl), ctx, desiredLength, stripPrefix); 0330 } 0331 0332 QString simplifiedTypeString(const AbstractType::Ptr& type, DUContext* visibilityFrom) 0333 { 0334 return shortenedTypeString(type, visibilityFrom, 100000); 0335 } 0336 0337 QString shortenedTypeString(const AbstractType::Ptr& type, DUContext* ctx, int desiredLength, const QualifiedIdentifier& stripPrefix) 0338 { 0339 return shortenedTypeIdentifier(type, ctx, desiredLength, stripPrefix).toString(); 0340 } 0341 0342 IndexedTypeIdentifier shortenedTypeIdentifier(const AbstractType::Ptr& type_, DUContext* ctx, int desiredLength, 0343 const QualifiedIdentifier& stripPrefix) 0344 { 0345 bool isReference = false; 0346 bool isRValue = false; 0347 0348 auto type = type_; 0349 if (auto refType = type.dynamicCast<ReferenceType>()) { 0350 isReference = true; 0351 type = refType->baseType(); 0352 isRValue = refType->isRValue(); 0353 } 0354 0355 type = shortenTypeForViewing(type); 0356 0357 if (ctx) { 0358 type = stripType(type, ctx); 0359 } 0360 if (!type) { 0361 return IndexedTypeIdentifier(); 0362 } 0363 0364 IndexedTypeIdentifier identifier = identifierForType(type, ctx ? ctx->topContext() : nullptr); 0365 0366 identifier = stripPrefixIdentifiers(identifier, stripPrefix); 0367 0368 if (isReference) { 0369 identifier.setIsReference(true); 0370 } 0371 if (isRValue) { 0372 identifier.setIsRValue(true); 0373 } 0374 0375 int removeTemplateParametersFrom = 10; 0376 0377 while (identifier.toString().length() > desiredLength * 3 && removeTemplateParametersFrom >= 0) { 0378 --removeTemplateParametersFrom; 0379 identifier = removeTemplateParameters(identifier, removeTemplateParametersFrom); 0380 } 0381 return identifier; 0382 } 0383 0384 QString makeSignatureString(const KDevelop::Declaration* functionDecl, const Signature& signature, const bool editingDefinition) 0385 { 0386 if (!functionDecl || !functionDecl->internalContext()) { 0387 return {}; 0388 } 0389 const auto visibilityFrom = functionDecl->internalContext()->parentContext(); 0390 if (!visibilityFrom) { 0391 return {}; 0392 } 0393 0394 QString ret; 0395 0396 if (!editingDefinition) { 0397 auto classMember = dynamic_cast<const ClassMemberDeclaration*>(functionDecl); 0398 if (classMember && classMember->isStatic()) { 0399 ret += QLatin1String("static "); 0400 } 0401 } 0402 0403 // constructors don't have a return type 0404 if (signature.returnType.isValid()) { 0405 ret += CodegenHelper::simplifiedTypeString(signature.returnType.abstractType(), 0406 visibilityFrom) 0407 + QLatin1Char(' '); 0408 } 0409 0410 ret += editingDefinition ? functionDecl->qualifiedIdentifier().toString() : functionDecl->identifier().toString(); 0411 int pos = 0; 0412 0413 QStringList parameters; 0414 parameters.reserve(signature.parameters.size()); 0415 for (const ParameterItem& item : signature.parameters) { 0416 QString parameter; 0417 AbstractType::Ptr type = item.first.abstractType(); 0418 0419 QString arrayAppendix; 0420 while (auto arrayType = type.dynamicCast<ArrayType>()) { 0421 type = arrayType->elementType(); 0422 //note: we have to prepend since we iterate from outside, i.e. from right to left. 0423 if (arrayType->dimension()) { 0424 arrayAppendix.prepend(QStringLiteral("[%1]").arg(arrayType->dimension())); 0425 } else { 0426 // dimensionless 0427 arrayAppendix.prepend(QLatin1String("[]")); 0428 } 0429 } 0430 parameter += CodegenHelper::simplifiedTypeString(type, visibilityFrom); 0431 0432 if (!item.second.isEmpty()) { 0433 parameter += QLatin1Char(' ') + item.second; 0434 } 0435 parameter += arrayAppendix; 0436 if (signature.defaultParams.size() > pos && !signature.defaultParams[pos].isEmpty()) { 0437 parameter += QLatin1String(" = ") + signature.defaultParams[pos]; 0438 } 0439 parameters.append(parameter); 0440 ++pos; 0441 } 0442 ret += QLatin1Char('(') + parameters.join(QLatin1String(", ")) + QLatin1Char(')'); 0443 if (signature.isConst) { 0444 ret += QLatin1String(" const"); 0445 } 0446 return ret; 0447 } 0448 0449 }