File indexing completed on 2024-05-12 04:38:43

0001 /*
0002     SPDX-FileCopyrightText: 2012 Olivier de Gaalon <olivier.jg@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #ifndef KDEVPLATFORM_JSONDECLARATIONTESTS_H
0008 #define KDEVPLATFORM_JSONDECLARATIONTESTS_H
0009 
0010 #include "language/duchain/ducontext.h"
0011 #include "language/duchain/declaration.h"
0012 #include "language/duchain/indexeddeclaration.h"
0013 #include "language/duchain/identifier.h"
0014 #include "language/duchain/abstractfunctiondeclaration.h"
0015 #include "language/duchain/types/typeutils.h"
0016 #include "language/duchain/types/identifiedtype.h"
0017 #include <language/duchain/types/functiontype.h>
0018 #include "language/duchain/duchain.h"
0019 #include "language/duchain/functiondefinition.h"
0020 #include "language/duchain/definitions.h"
0021 #include <language/duchain/classfunctiondeclaration.h>
0022 #include "jsontesthelpers.h"
0023 
0024 /**
0025  * JSON Object Specification:
0026  *   DeclTestObject: Mapping of (string) declaration test names to values
0027  *   TypeTestObject: Mapping of (string) type test names to values
0028  *   CtxtTestObject: Mapping of (string) context test names to values
0029  *
0030  * Quick Reference:
0031  *   useCount : int
0032  *   useRanges : string array
0033  *   identifier : string
0034  *   qualifiedIdentifier : string
0035  *   internalContext : CtxtTestObject
0036  *   internalFunctionContext : CtxtTestObject
0037  *   type : TypeTestObject
0038  *   unaliasedType : TypeTestObject
0039  *   targetType : TypeTestObject
0040  *   returnType : TypeTestObject
0041  *   isAtomic : bool
0042  *   isAbstract : bool
0043  *   isMutable : bool
0044  *   isVirtual : bool
0045  *   isStatic : bool
0046  *   declaration : DeclTestObject
0047  *   definition : DeclTestObject
0048  *   identifiedTypeDeclaration : DeclTestObject
0049  *   null : bool
0050  *   defaultParameter : string
0051  *   toString : string
0052  *   range : string
0053  *   kind : string
0054  *   isDeprecated : bool
0055  *   isDefinition : bool
0056  *   isExplicitlyTyped : bool
0057  */
0058 
0059 namespace KDevelop {
0060 template<>
0061 QString TestSuite<Declaration*>::objectInformation(Declaration* decl)
0062 {
0063     VERIFY_NOT_NULL(decl);
0064     return QStringLiteral("(Declaration on line %1 in %2)")
0065            .arg(decl->range().start.line + 1)
0066            .arg(decl->topContext()->url().str());
0067 }
0068 
0069 namespace DeclarationTests {
0070 using namespace JsonTestHelpers;
0071 
0072 ///JSON type: int
0073 ///@returns whether the declaration's number of uses matches the given value
0074 DeclarationTest(useCount)
0075 {
0076     int uses = 0;
0077     const auto declarationUses = decl->uses();
0078     for (const auto& useRanges : declarationUses) {
0079         uses += useRanges.size();
0080     }
0081 
0082     return compareValues(uses, value, QStringLiteral("Declaration's use count "));
0083 }
0084 ///JSON type: string array
0085 ///@returns whether the declaration's ranges match the given value
0086 DeclarationTest(useRanges)
0087 {
0088     QStringList ranges;
0089     const auto declarationUses = decl->uses();
0090     for (const auto& useRanges : declarationUses) {
0091         for (const RangeInRevision range : useRanges) {
0092             ranges << rangeStr(range);
0093         }
0094     }
0095 
0096     const QStringList testValues = value.toStringList();
0097     return ranges == testValues ? SUCCESS()
0098            : QStringLiteral("Declaration's use ranges (\"%1\") don't match test data (\"%2\").").arg(ranges.join(
0099                                                                                                          QStringLiteral(
0100                                                                                                              ", ")),
0101                                                                                                      testValues.join(
0102                                                                                                          QStringLiteral(
0103                                                                                                              ", ")));
0104 }
0105 ///JSON type: string
0106 ///@returns whether the declaration's identifier matches the given value
0107 DeclarationTest(identifier)
0108 {
0109     VERIFY_NOT_NULL(decl);
0110     return compareValues(decl->identifier().toString(), value, QStringLiteral("Declaration's identifier"));
0111 }
0112 ///JSON type: string
0113 ///@returns whether the declaration's qualified identifier matches the given value
0114 DeclarationTest(qualifiedIdentifier)
0115 {
0116     VERIFY_NOT_NULL(decl);
0117     return compareValues(decl->qualifiedIdentifier().toString(), value,
0118                          QStringLiteral("Declaration's qualified identifier"));
0119 }
0120 ///JSON type: CtxtTestObject
0121 ///@returns whether the tests for the declaration's internal context pass
0122 DeclarationTest(internalContext)
0123 {
0124     VERIFY_NOT_NULL(decl);
0125     return testObject(decl->internalContext(), value, QStringLiteral("Declaration's internal context"));
0126 }
0127 ///JSON type: CtxtTestObject
0128 ///@returns whether the tests for the declaration's internal function context pass
0129 DeclarationTest(internalFunctionContext)
0130 {
0131     const QString NO_INTERNAL_CTXT = QStringLiteral("%1 has no internal function context.");
0132     auto* absFuncDecl = dynamic_cast<AbstractFunctionDeclaration*>(decl);
0133     if (!absFuncDecl || !absFuncDecl->internalFunctionContext())
0134         return NO_INTERNAL_CTXT.arg(decl->qualifiedIdentifier().toString());
0135     return testObject(absFuncDecl->internalFunctionContext(), value,
0136                       QStringLiteral("Declaration's internal function context"));
0137 }
0138 /*FIXME: The type functions need some renaming and moving around
0139  * Some (all?) functions from cpp's TypeUtils should be moved to the kdevplatform type utils
0140  * targetType is exactly like realType except it also tosses pointers
0141  * shortenTypeForViewing should go to type utils (and it's broken, it places const to the left of all *'s when it should be left or right of the type)
0142  * UnaliasedType seems to be unable to understand aliases involving templates, perhaps a cpp version is in order
0143  */
0144 ///JSON type: TypeTestObject
0145 ///@returns whether the tests for the declaration's type pass
0146 DeclarationTest(type)
0147 {
0148     VERIFY_NOT_NULL(decl);
0149     return testObject(decl->abstractType(), value, QStringLiteral("Declaration's type"));
0150 }
0151 ///JSON type: TypeTestObject
0152 ///@returns whether the tests for the declaration's unaliased type pass (TypeUtils::unaliasedType)
0153 DeclarationTest(unaliasedType)
0154 {
0155     VERIFY_NOT_NULL(decl);
0156     return testObject(TypeUtils::unAliasedType(decl->abstractType()), value,
0157                       QStringLiteral("Declaration's unaliased type"));
0158 }
0159 ///JSON type: TypeTestObject
0160 ///@returns whether the tests for the declaration's target type pass (TypeUtils::targetType)
0161 DeclarationTest(targetType)
0162 {
0163     VERIFY_NOT_NULL(decl);
0164     return testObject(TypeUtils::targetType(decl->abstractType(), decl->topContext()), value,
0165                       QStringLiteral("Declaration's target type"));
0166 }
0167 ///JSON type: TestTypeObject
0168 ///@returns the
0169 DeclarationTest(returnType)
0170 {
0171     AbstractType::Ptr returnType;
0172     if (auto functionType = decl->abstractType().dynamicCast<FunctionType>()) {
0173         returnType = functionType->returnType();
0174     }
0175     return testObject(returnType, value, QStringLiteral("Declaration's return type"));
0176 }
0177 ///JSON type: DeclTestObject
0178 ///@returns The IdentifiedType's declaration
0179 DeclarationTest(identifiedTypeDeclaration)
0180 {
0181     const QString UN_ID_ERROR = QStringLiteral("Unable to identify declaration of type \"%1\".");
0182     AbstractType::Ptr type = TypeUtils::targetType(decl->abstractType(), decl->topContext());
0183     auto* idType = dynamic_cast<IdentifiedType*>(type.data());
0184     Declaration* idDecl = idType ? idType->declaration(decl->topContext()) : nullptr;
0185     if (!idDecl)
0186         return UN_ID_ERROR.arg(type->toString());
0187 
0188     return testObject(idDecl, value, QStringLiteral("IdentifiedType's declaration"));
0189 }
0190 
0191 ///JSON type: bool
0192 ///@returns whether the declaration's isAtomic matches the given value
0193 DeclarationTest(isAtomic)
0194 {
0195     AbstractType::Ptr type = TypeUtils::targetType(decl->abstractType(), decl->topContext());
0196 
0197     return compareValues((type->modifiers() & AbstractType::AtomicModifier) != 0, value, QStringLiteral("Declaration's atomic modifier"));
0198 }
0199 
0200 ///JSON type: bool
0201 ///@returns whether the (function) declaration's isVirtual matches the given value
0202 DeclarationTest(isVirtual)
0203 {
0204     const QString NOT_A_FUNCTION = QStringLiteral("Non-function declaration cannot be virtual.");
0205     auto* absFuncDecl = dynamic_cast<AbstractFunctionDeclaration*>(decl);
0206     if (!absFuncDecl)
0207         return NOT_A_FUNCTION;
0208 
0209     return compareValues(absFuncDecl->isVirtual(), value, QStringLiteral("Declaration's isVirtual"));
0210 }
0211 
0212 ///JSON type: bool
0213 ///@returns whether the (function) declaration's isAbstract matches the given value
0214 DeclarationTest(isAbstract)
0215 {
0216     const QString NOT_A_FUNCTION = QStringLiteral("Non-class-function declaration cannot be abstract.");
0217     auto* absFuncDecl = dynamic_cast<ClassFunctionDeclaration*>(decl);
0218     if (!absFuncDecl)
0219         return NOT_A_FUNCTION;
0220 
0221     return compareValues(absFuncDecl->isAbstract(), value, QStringLiteral("Declaration's isAbstract"));
0222 }
0223 ///JSON type: bool
0224 ///@returns whether the (function) declaration's isAbstract matches the given value
0225 DeclarationTest(isFinal)
0226 {
0227     const QString NOT_A_FUNCTION = QStringLiteral("Non-class-function declaration cannot be final.");
0228     auto* classFuncDecl = dynamic_cast<ClassFunctionDeclaration*>(decl);
0229     if (!classFuncDecl)
0230         return NOT_A_FUNCTION;
0231 
0232     return compareValues(classFuncDecl->isFinal(), value, QStringLiteral("Declaration's isFinal"));
0233 }
0234 ///JSON type: bool
0235 ///@returns whether the (class-member) declaration's isStatic matches the given value
0236 DeclarationTest(isStatic)
0237 {
0238     const QString NOT_A_MEMBER = QStringLiteral("Non-class-member declaration cannot be static.");
0239     auto memberDecl = dynamic_cast<ClassMemberDeclaration*>(decl);
0240     if (!memberDecl)
0241         return NOT_A_MEMBER;
0242 
0243     return compareValues(memberDecl->isStatic(), value, QStringLiteral("Declaration's isStatic"));
0244 }
0245 ///JSON type: bool
0246 ///@returns whether the (class-member) declaration's isMutable matches the given value
0247 DeclarationTest(isMutable)
0248 {
0249     const QString NOT_A_MEMBER = QStringLiteral("Non-class-member declaration cannot be mutable.");
0250     auto memberDecl = dynamic_cast<ClassMemberDeclaration*>(decl);
0251     if (!memberDecl)
0252         return NOT_A_MEMBER;
0253 
0254     return compareValues(memberDecl->isMutable(), value, QStringLiteral("Declaration's isMutable"));
0255 }
0256 ///JSON type: DeclTestObject
0257 ///@returns whether the tests for the function declaration's definition pass
0258 DeclarationTest(definition)
0259 {
0260     KDevVarLengthArray<IndexedDeclaration> definitions = DUChain::definitions()->definitions(decl->id());
0261     Declaration* declDef = nullptr;
0262     if (!definitions.isEmpty())
0263         declDef = definitions.at(0).declaration();
0264     return testObject(declDef, value, QStringLiteral("Declaration's definition"));
0265 }
0266 ///JSON type: DeclTestObject
0267 ///@returns whether the tests for the function definition's declaration pass
0268 DeclarationTest(declaration)
0269 {
0270     auto* def = dynamic_cast<FunctionDefinition*>(decl);
0271     Declaration* defDecl = nullptr;
0272     if (def)
0273         defDecl = def->declaration(decl->topContext());
0274     return testObject(defDecl, value, QStringLiteral("Definition's declaration"));
0275 }
0276 ///JSON type: bool
0277 ///@returns whether the declaration's nullity matches the given value
0278 DeclarationTest(null)
0279 {
0280     return compareValues(decl == nullptr, value, QStringLiteral("Declaration's nullity"));
0281 }
0282 ///JSON type: bool
0283 ///@returns whether the declaration's default parameter matches the given value
0284 DeclarationTest(defaultParameter)
0285 {
0286     const QString NOT_IN_FUNC_CTXT = QStringLiteral(
0287         "Asked for a default parameter for a declaration outside of a function context.");
0288     const QString OWNER_NOT_FUNC = QStringLiteral(
0289         "Function context not owned by function declaration (what on earth did you do?).");
0290     DUContext* context = decl->context();
0291     if (!context || context->type() != DUContext::Function)
0292         return NOT_IN_FUNC_CTXT;
0293     auto* funcDecl = dynamic_cast<AbstractFunctionDeclaration*>(context->owner());
0294     if (!funcDecl)
0295         return OWNER_NOT_FUNC;
0296     int argIndex = context->localDeclarations().indexOf(decl);
0297     return compareValues(funcDecl->defaultParameterForArgument(argIndex).str(), value,
0298                          QStringLiteral("Declaration's default parameter"));
0299 }
0300 
0301 ///JSON type: string
0302 ///@returns stringified declaration
0303 DeclarationTest(toString)
0304 {
0305     VERIFY_NOT_NULL(decl);
0306     return compareValues(decl->toString(), value, QStringLiteral("Declaration's toString"));
0307 }
0308 
0309 ///JSON type: string
0310 ///@returns stringified declaration range
0311 DeclarationTest(range)
0312 {
0313     VERIFY_NOT_NULL(decl);
0314     return compareValues(rangeStr(decl->range()), value, QStringLiteral("Declaration's range"));
0315 }
0316 
0317 ///JSON type: string
0318 ///@returns stringified declaration kind
0319 DeclarationTest(kind)
0320 {
0321     VERIFY_NOT_NULL(decl);
0322     QString kind;
0323     switch (decl->kind()) {
0324     case KDevelop::Declaration::Alias:
0325         kind = QStringLiteral("Alias");
0326         break;
0327     case KDevelop::Declaration::Import:
0328         kind = QStringLiteral("Import");
0329         break;
0330     case KDevelop::Declaration::Instance:
0331         kind = QStringLiteral("Instance");
0332         break;
0333     case KDevelop::Declaration::Namespace:
0334         kind = QStringLiteral("Namespace");
0335         break;
0336     case KDevelop::Declaration::NamespaceAlias:
0337         kind = QStringLiteral("NamespaceAlias");
0338         break;
0339     case KDevelop::Declaration::Type:
0340         kind = QStringLiteral("Type");
0341         break;
0342     case KDevelop::Declaration::Macro:
0343         kind = QStringLiteral("Macro");
0344         break;
0345     }
0346     return compareValues(kind, value, QStringLiteral("Declaration's kind"));
0347 }
0348 
0349 ///JSON type: bool
0350 ///@returns whether the declaration's isDeprecated matches the given value
0351 DeclarationTest(isDeprecated)
0352 {
0353     VERIFY_NOT_NULL(decl);
0354     return compareValues(decl->isDeprecated(), value, QStringLiteral("Declaration's isDeprecated"));
0355 }
0356 
0357 ///JSON type: bool
0358 ///@returns whether the declaration's isDefinition matches the given value
0359 DeclarationTest(isDefinition)
0360 {
0361     VERIFY_NOT_NULL(decl);
0362     return compareValues(decl->isDefinition(), value, QStringLiteral("Declaration's isDefinition"));
0363 }
0364 
0365 ///JSON type: bool
0366 ///@returns whether the declaration's isExplicitlyTyped matches the given value
0367 DeclarationTest(isExplicitlyTyped)
0368 {
0369     VERIFY_NOT_NULL(decl);
0370     return compareValues(decl->isExplicitlyTyped(), value, QStringLiteral("Declaration's isExplicitlyTyped"));
0371 }
0372 }
0373 }
0374 
0375 #endif //KDEVPLATFORM_JSONDECLARATIONTESTS_H