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 }