1 /*
2 SPDX-FileCopyrightText: 2012 Olivier de Gaalon <olivier.jg@gmail.com>
3
4 SPDX-License-Identifier: LGPL-2.0-only
5 */
6
7 #ifndef KDEVPLATFORM_JSONDECLARATIONTESTS_H
8 #define KDEVPLATFORM_JSONDECLARATIONTESTS_H
9
10 #include "language/duchain/ducontext.h"
11 #include "language/duchain/declaration.h"
12 #include "language/duchain/indexeddeclaration.h"
13 #include "language/duchain/identifier.h"
14 #include "language/duchain/abstractfunctiondeclaration.h"
15 #include "language/duchain/types/typeutils.h"
16 #include "language/duchain/types/identifiedtype.h"
17 #include <language/duchain/types/functiontype.h>
18 #include "language/duchain/duchain.h"
19 #include "language/duchain/functiondefinition.h"
20 #include "language/duchain/definitions.h"
21 #include <language/duchain/classfunctiondeclaration.h>
22 #include "jsontesthelpers.h"
23
24 /**
25 * JSON Object Specification:
26 * DeclTestObject: Mapping of (string) declaration test names to values
27 * TypeTestObject: Mapping of (string) type test names to values
28 * CtxtTestObject: Mapping of (string) context test names to values
29 *
30 * Quick Reference:
31 * useCount : int
32 * useRanges : string array
33 * identifier : string
34 * qualifiedIdentifier : string
35 * internalContext : CtxtTestObject
36 * internalFunctionContext : CtxtTestObject
37 * type : TypeTestObject
38 * unaliasedType : TypeTestObject
39 * targetType : TypeTestObject
40 * returnType : TypeTestObject
41 * isAbstract : bool
42 * isMutable : bool
43 * isVirtual : bool
44 * isStatic : bool
45 * declaration : DeclTestObject
46 * definition : DeclTestObject
47 * identifiedTypeDeclaration : DeclTestObject
48 * null : bool
49 * defaultParameter : string
50 * toString : string
51 * range : string
52 * kind : string
53 * isDeprecated : bool
54 * isDefinition : bool
55 * isExplicitlyTyped : bool
56 */
57
58 namespace KDevelop {
59 template<>
objectInformation(Declaration * decl)60 QString TestSuite<Declaration*>::objectInformation(Declaration* decl)
61 {
62 VERIFY_NOT_NULL(decl);
63 return QStringLiteral("(Declaration on line %1 in %2)")
64 .arg(decl->range().start.line + 1)
65 .arg(decl->topContext()->url().str());
66 }
67
68 namespace DeclarationTests {
69 using namespace JsonTestHelpers;
70
71 ///JSON type: int
72 ///@returns whether the declaration's number of uses matches the given value
DeclarationTest(useCount)73 DeclarationTest(useCount)
74 {
75 int uses = 0;
76 const auto declarationUses = decl->uses();
77 for (const auto& useRanges : declarationUses) {
78 uses += useRanges.size();
79 }
80
81 return compareValues(uses, value, QStringLiteral("Declaration's use count "));
82 }
83 ///JSON type: string array
84 ///@returns whether the declaration's ranges match the given value
DeclarationTest(useRanges)85 DeclarationTest(useRanges)
86 {
87 QStringList ranges;
88 const auto declarationUses = decl->uses();
89 for (const auto& useRanges : declarationUses) {
90 for (const RangeInRevision range : useRanges) {
91 ranges << rangeStr(range);
92 }
93 }
94
95 const QStringList testValues = value.toStringList();
96 return ranges == testValues ? SUCCESS()
97 : QStringLiteral("Declaration's use ranges (\"%1\") don't match test data (\"%2\").").arg(ranges.join(
98 QStringLiteral(
99 ", ")),
100 testValues.join(
101 QStringLiteral(
102 ", ")));
103 }
104 ///JSON type: string
105 ///@returns whether the declaration's identifier matches the given value
DeclarationTest(identifier)106 DeclarationTest(identifier)
107 {
108 VERIFY_NOT_NULL(decl);
109 return compareValues(decl->identifier().toString(), value, QStringLiteral("Declaration's identifier"));
110 }
111 ///JSON type: string
112 ///@returns whether the declaration's qualified identifier matches the given value
DeclarationTest(qualifiedIdentifier)113 DeclarationTest(qualifiedIdentifier)
114 {
115 VERIFY_NOT_NULL(decl);
116 return compareValues(decl->qualifiedIdentifier().toString(), value,
117 QStringLiteral("Declaration's qualified identifier"));
118 }
119 ///JSON type: CtxtTestObject
120 ///@returns whether the tests for the declaration's internal context pass
DeclarationTest(internalContext)121 DeclarationTest(internalContext)
122 {
123 VERIFY_NOT_NULL(decl);
124 return testObject(decl->internalContext(), value, QStringLiteral("Declaration's internal context"));
125 }
126 ///JSON type: CtxtTestObject
127 ///@returns whether the tests for the declaration's internal function context pass
DeclarationTest(internalFunctionContext)128 DeclarationTest(internalFunctionContext)
129 {
130 const QString NO_INTERNAL_CTXT = QStringLiteral("%1 has no internal function context.");
131 auto* absFuncDecl = dynamic_cast<AbstractFunctionDeclaration*>(decl);
132 if (!absFuncDecl || !absFuncDecl->internalFunctionContext())
133 return NO_INTERNAL_CTXT.arg(decl->qualifiedIdentifier().toString());
134 return testObject(absFuncDecl->internalFunctionContext(), value,
135 QStringLiteral("Declaration's internal function context"));
136 }
137 /*FIXME: The type functions need some renaming and moving around
138 * Some (all?) functions from cpp's TypeUtils should be moved to the kdevplatform type utils
139 * targetType is exactly like realType except it also tosses pointers
140 * 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)
141 * UnaliasedType seems to be unable to understand aliases involving templates, perhaps a cpp version is in order
142 */
143 ///JSON type: TypeTestObject
144 ///@returns whether the tests for the declaration's type pass
DeclarationTest(type)145 DeclarationTest(type)
146 {
147 VERIFY_NOT_NULL(decl);
148 return testObject(decl->abstractType(), value, QStringLiteral("Declaration's type"));
149 }
150 ///JSON type: TypeTestObject
151 ///@returns whether the tests for the declaration's unaliased type pass (TypeUtils::unaliasedType)
DeclarationTest(unaliasedType)152 DeclarationTest(unaliasedType)
153 {
154 VERIFY_NOT_NULL(decl);
155 return testObject(TypeUtils::unAliasedType(decl->abstractType()), value,
156 QStringLiteral("Declaration's unaliased type"));
157 }
158 ///JSON type: TypeTestObject
159 ///@returns whether the tests for the declaration's target type pass (TypeUtils::targetType)
DeclarationTest(targetType)160 DeclarationTest(targetType)
161 {
162 VERIFY_NOT_NULL(decl);
163 return testObject(TypeUtils::targetType(decl->abstractType(), decl->topContext()), value,
164 QStringLiteral("Declaration's target type"));
165 }
166 ///JSON type: TestTypeObject
167 ///@returns the
DeclarationTest(returnType)168 DeclarationTest(returnType)
169 {
170 FunctionType::Ptr functionType = decl->abstractType().cast<FunctionType>();
171 AbstractType::Ptr returnType;
172 if (functionType) {
173 returnType = functionType->returnType();
174 }
175 return testObject(returnType, value, QStringLiteral("Declaration's return type"));
176 }
177 ///JSON type: DeclTestObject
178 ///@returns The IdentifiedType's declaration
DeclarationTest(identifiedTypeDeclaration)179 DeclarationTest(identifiedTypeDeclaration)
180 {
181 const QString UN_ID_ERROR = QStringLiteral("Unable to identify declaration of type \"%1\".");
182 AbstractType::Ptr type = TypeUtils::targetType(decl->abstractType(), decl->topContext());
183 auto* idType = dynamic_cast<IdentifiedType*>(type.data());
184 Declaration* idDecl = idType ? idType->declaration(decl->topContext()) : nullptr;
185 if (!idDecl)
186 return UN_ID_ERROR.arg(type->toString());
187
188 return testObject(idDecl, value, QStringLiteral("IdentifiedType's declaration"));
189 }
190 ///JSON type: bool
191 ///@returns whether the (function) declaration's isVirtual matches the given value
DeclarationTest(isVirtual)192 DeclarationTest(isVirtual)
193 {
194 const QString NOT_A_FUNCTION = QStringLiteral("Non-function declaration cannot be virtual.");
195 auto* absFuncDecl = dynamic_cast<AbstractFunctionDeclaration*>(decl);
196 if (!absFuncDecl)
197 return NOT_A_FUNCTION;
198
199 return compareValues(absFuncDecl->isVirtual(), value, QStringLiteral("Declaration's isVirtual"));
200 }
201
202 ///JSON type: bool
203 ///@returns whether the (function) declaration's isAbstract matches the given value
DeclarationTest(isAbstract)204 DeclarationTest(isAbstract)
205 {
206 const QString NOT_A_FUNCTION = QStringLiteral("Non-class-function declaration cannot be abstract.");
207 auto* absFuncDecl = dynamic_cast<ClassFunctionDeclaration*>(decl);
208 if (!absFuncDecl)
209 return NOT_A_FUNCTION;
210
211 return compareValues(absFuncDecl->isAbstract(), value, QStringLiteral("Declaration's isAbstract"));
212 }
213 ///JSON type: bool
214 ///@returns whether the (function) declaration's isAbstract matches the given value
DeclarationTest(isFinal)215 DeclarationTest(isFinal)
216 {
217 const QString NOT_A_FUNCTION = QStringLiteral("Non-class-function declaration cannot be final.");
218 auto* classFuncDecl = dynamic_cast<ClassFunctionDeclaration*>(decl);
219 if (!classFuncDecl)
220 return NOT_A_FUNCTION;
221
222 return compareValues(classFuncDecl->isFinal(), value, QStringLiteral("Declaration's isFinal"));
223 }
224 ///JSON type: bool
225 ///@returns whether the (class-member) declaration's isStatic matches the given value
DeclarationTest(isStatic)226 DeclarationTest(isStatic)
227 {
228 const QString NOT_A_MEMBER = QStringLiteral("Non-class-member declaration cannot be static.");
229 auto memberDecl = dynamic_cast<ClassMemberDeclaration*>(decl);
230 if (!memberDecl)
231 return NOT_A_MEMBER;
232
233 return compareValues(memberDecl->isStatic(), value, QStringLiteral("Declaration's isStatic"));
234 }
235 ///JSON type: bool
236 ///@returns whether the (class-member) declaration's isMutable matches the given value
DeclarationTest(isMutable)237 DeclarationTest(isMutable)
238 {
239 const QString NOT_A_MEMBER = QStringLiteral("Non-class-member declaration cannot be mutable.");
240 auto memberDecl = dynamic_cast<ClassMemberDeclaration*>(decl);
241 if (!memberDecl)
242 return NOT_A_MEMBER;
243
244 return compareValues(memberDecl->isMutable(), value, QStringLiteral("Declaration's isMutable"));
245 }
246 ///JSON type: DeclTestObject
247 ///@returns whether the tests for the function declaration's definition pass
DeclarationTest(definition)248 DeclarationTest(definition)
249 {
250 KDevVarLengthArray<IndexedDeclaration> definitions = DUChain::definitions()->definitions(decl->id());
251 Declaration* declDef = nullptr;
252 if (!definitions.isEmpty())
253 declDef = definitions.at(0).declaration();
254 return testObject(declDef, value, QStringLiteral("Declaration's definition"));
255 }
256 ///JSON type: DeclTestObject
257 ///@returns whether the tests for the function definition's declaration pass
DeclarationTest(declaration)258 DeclarationTest(declaration)
259 {
260 auto* def = dynamic_cast<FunctionDefinition*>(decl);
261 Declaration* defDecl = nullptr;
262 if (def)
263 defDecl = def->declaration(decl->topContext());
264 return testObject(defDecl, value, QStringLiteral("Definition's declaration"));
265 }
266 ///JSON type: bool
267 ///@returns whether the declaration's nullity matches the given value
DeclarationTest(null)268 DeclarationTest(null)
269 {
270 return compareValues(decl == nullptr, value, QStringLiteral("Declaration's nullity"));
271 }
272 ///JSON type: bool
273 ///@returns whether the declaration's default parameter matches the given value
DeclarationTest(defaultParameter)274 DeclarationTest(defaultParameter)
275 {
276 const QString NOT_IN_FUNC_CTXT = QStringLiteral(
277 "Asked for a default parameter for a declaration outside of a function context.");
278 const QString OWNER_NOT_FUNC = QStringLiteral(
279 "Function context not owned by function declaration (what on earth did you do?).");
280 DUContext* context = decl->context();
281 if (!context || context->type() != DUContext::Function)
282 return NOT_IN_FUNC_CTXT;
283 auto* funcDecl = dynamic_cast<AbstractFunctionDeclaration*>(context->owner());
284 if (!funcDecl)
285 return OWNER_NOT_FUNC;
286 int argIndex = context->localDeclarations().indexOf(decl);
287 return compareValues(funcDecl->defaultParameterForArgument(argIndex).str(), value,
288 QStringLiteral("Declaration's default parameter"));
289 }
290
291 ///JSON type: string
292 ///@returns stringified declaration
DeclarationTest(toString)293 DeclarationTest(toString)
294 {
295 VERIFY_NOT_NULL(decl);
296 return compareValues(decl->toString(), value, QStringLiteral("Declaration's toString"));
297 }
298
299 ///JSON type: string
300 ///@returns stringified declaration range
DeclarationTest(range)301 DeclarationTest(range)
302 {
303 VERIFY_NOT_NULL(decl);
304 return compareValues(rangeStr(decl->range()), value, QStringLiteral("Declaration's range"));
305 }
306
307 ///JSON type: string
308 ///@returns stringified declaration kind
DeclarationTest(kind)309 DeclarationTest(kind)
310 {
311 VERIFY_NOT_NULL(decl);
312 QString kind;
313 switch (decl->kind()) {
314 case KDevelop::Declaration::Alias:
315 kind = QStringLiteral("Alias");
316 break;
317 case KDevelop::Declaration::Import:
318 kind = QStringLiteral("Import");
319 break;
320 case KDevelop::Declaration::Instance:
321 kind = QStringLiteral("Instance");
322 break;
323 case KDevelop::Declaration::Namespace:
324 kind = QStringLiteral("Namespace");
325 break;
326 case KDevelop::Declaration::NamespaceAlias:
327 kind = QStringLiteral("NamespaceAlias");
328 break;
329 case KDevelop::Declaration::Type:
330 kind = QStringLiteral("Type");
331 break;
332 case KDevelop::Declaration::Macro:
333 kind = QStringLiteral("Macro");
334 break;
335 }
336 return compareValues(kind, value, QStringLiteral("Declaration's kind"));
337 }
338
339 ///JSON type: bool
340 ///@returns whether the declaration's isDeprecated matches the given value
DeclarationTest(isDeprecated)341 DeclarationTest(isDeprecated)
342 {
343 VERIFY_NOT_NULL(decl);
344 return compareValues(decl->isDeprecated(), value, QStringLiteral("Declaration's isDeprecated"));
345 }
346
347 ///JSON type: bool
348 ///@returns whether the declaration's isDefinition matches the given value
DeclarationTest(isDefinition)349 DeclarationTest(isDefinition)
350 {
351 VERIFY_NOT_NULL(decl);
352 return compareValues(decl->isDefinition(), value, QStringLiteral("Declaration's isDefinition"));
353 }
354
355 ///JSON type: bool
356 ///@returns whether the declaration's isExplicitlyTyped matches the given value
DeclarationTest(isExplicitlyTyped)357 DeclarationTest(isExplicitlyTyped)
358 {
359 VERIFY_NOT_NULL(decl);
360 return compareValues(decl->isExplicitlyTyped(), value, QStringLiteral("Declaration's isExplicitlyTyped"));
361 }
362 }
363 }
364
365 #endif //KDEVPLATFORM_JSONDECLARATIONTESTS_H
366