File: | build/source/clang/lib/ExtractAPI/DeclarationFragments.cpp |
Warning: | line 167, column 9 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- ExtractAPI/DeclarationFragments.cpp ----------------------*- C++ -*-===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | /// | |||
9 | /// \file | |||
10 | /// This file implements Declaration Fragments related classes. | |||
11 | /// | |||
12 | //===----------------------------------------------------------------------===// | |||
13 | ||||
14 | #include "clang/ExtractAPI/DeclarationFragments.h" | |||
15 | #include "TypedefUnderlyingTypeResolver.h" | |||
16 | #include "clang/Index/USRGeneration.h" | |||
17 | #include "llvm/ADT/StringSwitch.h" | |||
18 | ||||
19 | using namespace clang::extractapi; | |||
20 | using namespace llvm; | |||
21 | ||||
22 | DeclarationFragments &DeclarationFragments::appendSpace() { | |||
23 | if (!Fragments.empty()) { | |||
24 | Fragment &Last = Fragments.back(); | |||
25 | if (Last.Kind == FragmentKind::Text) { | |||
26 | // Merge the extra space into the last fragment if the last fragment is | |||
27 | // also text. | |||
28 | if (Last.Spelling.back() != ' ') { // avoid extra trailing spaces. | |||
29 | Last.Spelling.push_back(' '); | |||
30 | } | |||
31 | } else { | |||
32 | append(" ", FragmentKind::Text); | |||
33 | } | |||
34 | } | |||
35 | ||||
36 | return *this; | |||
37 | } | |||
38 | ||||
39 | StringRef DeclarationFragments::getFragmentKindString( | |||
40 | DeclarationFragments::FragmentKind Kind) { | |||
41 | switch (Kind) { | |||
42 | case DeclarationFragments::FragmentKind::None: | |||
43 | return "none"; | |||
44 | case DeclarationFragments::FragmentKind::Keyword: | |||
45 | return "keyword"; | |||
46 | case DeclarationFragments::FragmentKind::Attribute: | |||
47 | return "attribute"; | |||
48 | case DeclarationFragments::FragmentKind::NumberLiteral: | |||
49 | return "number"; | |||
50 | case DeclarationFragments::FragmentKind::StringLiteral: | |||
51 | return "string"; | |||
52 | case DeclarationFragments::FragmentKind::Identifier: | |||
53 | return "identifier"; | |||
54 | case DeclarationFragments::FragmentKind::TypeIdentifier: | |||
55 | return "typeIdentifier"; | |||
56 | case DeclarationFragments::FragmentKind::GenericParameter: | |||
57 | return "genericParameter"; | |||
58 | case DeclarationFragments::FragmentKind::ExternalParam: | |||
59 | return "externalParam"; | |||
60 | case DeclarationFragments::FragmentKind::InternalParam: | |||
61 | return "internalParam"; | |||
62 | case DeclarationFragments::FragmentKind::Text: | |||
63 | return "text"; | |||
64 | } | |||
65 | ||||
66 | llvm_unreachable("Unhandled FragmentKind")::llvm::llvm_unreachable_internal("Unhandled FragmentKind", "clang/lib/ExtractAPI/DeclarationFragments.cpp" , 66); | |||
67 | } | |||
68 | ||||
69 | DeclarationFragments::FragmentKind | |||
70 | DeclarationFragments::parseFragmentKindFromString(StringRef S) { | |||
71 | return llvm::StringSwitch<FragmentKind>(S) | |||
72 | .Case("keyword", DeclarationFragments::FragmentKind::Keyword) | |||
73 | .Case("attribute", DeclarationFragments::FragmentKind::Attribute) | |||
74 | .Case("number", DeclarationFragments::FragmentKind::NumberLiteral) | |||
75 | .Case("string", DeclarationFragments::FragmentKind::StringLiteral) | |||
76 | .Case("identifier", DeclarationFragments::FragmentKind::Identifier) | |||
77 | .Case("typeIdentifier", | |||
78 | DeclarationFragments::FragmentKind::TypeIdentifier) | |||
79 | .Case("genericParameter", | |||
80 | DeclarationFragments::FragmentKind::GenericParameter) | |||
81 | .Case("internalParam", DeclarationFragments::FragmentKind::InternalParam) | |||
82 | .Case("externalParam", DeclarationFragments::FragmentKind::ExternalParam) | |||
83 | .Case("text", DeclarationFragments::FragmentKind::Text) | |||
84 | .Default(DeclarationFragments::FragmentKind::None); | |||
85 | } | |||
86 | ||||
87 | // NNS stores C++ nested name specifiers, which are prefixes to qualified names. | |||
88 | // Build declaration fragments for NNS recursively so that we have the USR for | |||
89 | // every part in a qualified name, and also leaves the actual underlying type | |||
90 | // cleaner for its own fragment. | |||
91 | DeclarationFragments | |||
92 | DeclarationFragmentsBuilder::getFragmentsForNNS(const NestedNameSpecifier *NNS, | |||
93 | ASTContext &Context, | |||
94 | DeclarationFragments &After) { | |||
95 | DeclarationFragments Fragments; | |||
96 | if (NNS->getPrefix()) | |||
97 | Fragments.append(getFragmentsForNNS(NNS->getPrefix(), Context, After)); | |||
98 | ||||
99 | switch (NNS->getKind()) { | |||
100 | case NestedNameSpecifier::Identifier: | |||
101 | Fragments.append(NNS->getAsIdentifier()->getName(), | |||
102 | DeclarationFragments::FragmentKind::Identifier); | |||
103 | break; | |||
104 | ||||
105 | case NestedNameSpecifier::Namespace: { | |||
106 | const NamespaceDecl *NS = NNS->getAsNamespace(); | |||
107 | if (NS->isAnonymousNamespace()) | |||
108 | return Fragments; | |||
109 | SmallString<128> USR; | |||
110 | index::generateUSRForDecl(NS, USR); | |||
111 | Fragments.append(NS->getName(), | |||
112 | DeclarationFragments::FragmentKind::Identifier, USR, NS); | |||
113 | break; | |||
114 | } | |||
115 | ||||
116 | case NestedNameSpecifier::NamespaceAlias: { | |||
117 | const NamespaceAliasDecl *Alias = NNS->getAsNamespaceAlias(); | |||
118 | SmallString<128> USR; | |||
119 | index::generateUSRForDecl(Alias, USR); | |||
120 | Fragments.append(Alias->getName(), | |||
121 | DeclarationFragments::FragmentKind::Identifier, USR, | |||
122 | Alias); | |||
123 | break; | |||
124 | } | |||
125 | ||||
126 | case NestedNameSpecifier::Global: | |||
127 | // The global specifier `::` at the beginning. No stored value. | |||
128 | break; | |||
129 | ||||
130 | case NestedNameSpecifier::Super: | |||
131 | // Microsoft's `__super` specifier. | |||
132 | Fragments.append("__super", DeclarationFragments::FragmentKind::Keyword); | |||
133 | break; | |||
134 | ||||
135 | case NestedNameSpecifier::TypeSpecWithTemplate: | |||
136 | // A type prefixed by the `template` keyword. | |||
137 | Fragments.append("template", DeclarationFragments::FragmentKind::Keyword); | |||
138 | Fragments.appendSpace(); | |||
139 | // Fallthrough after adding the keyword to handle the actual type. | |||
140 | [[fallthrough]]; | |||
141 | ||||
142 | case NestedNameSpecifier::TypeSpec: { | |||
143 | const Type *T = NNS->getAsType(); | |||
144 | // FIXME: Handle C++ template specialization type | |||
145 | Fragments.append(getFragmentsForType(T, Context, After)); | |||
146 | break; | |||
147 | } | |||
148 | } | |||
149 | ||||
150 | // Add the separator text `::` for this segment. | |||
151 | return Fragments.append("::", DeclarationFragments::FragmentKind::Text); | |||
152 | } | |||
153 | ||||
154 | // Recursively build the declaration fragments for an underlying `Type` with | |||
155 | // qualifiers removed. | |||
156 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType( | |||
157 | const Type *T, ASTContext &Context, DeclarationFragments &After) { | |||
158 | assert(T && "invalid type")(static_cast <bool> (T && "invalid type") ? void (0) : __assert_fail ("T && \"invalid type\"", "clang/lib/ExtractAPI/DeclarationFragments.cpp" , 158, __extension__ __PRETTY_FUNCTION__)); | |||
159 | ||||
160 | DeclarationFragments Fragments; | |||
161 | ||||
162 | // Declaration fragments of a pointer type is the declaration fragments of | |||
163 | // the pointee type followed by a `*`, except for Objective-C `id` and `Class` | |||
164 | // pointers, where we do not spell out the `*`. | |||
165 | if (T->isPointerType() || | |||
166 | (T->isObjCObjectPointerType() && | |||
167 | !T->getAs<ObjCObjectPointerType>()->isObjCIdOrClassType())) { | |||
| ||||
168 | return Fragments | |||
169 | .append(getFragmentsForType(T->getPointeeType(), Context, After)) | |||
170 | .append(" *", DeclarationFragments::FragmentKind::Text); | |||
171 | } | |||
172 | ||||
173 | // Declaration fragments of a lvalue reference type is the declaration | |||
174 | // fragments of the underlying type followed by a `&`. | |||
175 | if (const LValueReferenceType *LRT = dyn_cast<LValueReferenceType>(T)) | |||
176 | return Fragments | |||
177 | .append( | |||
178 | getFragmentsForType(LRT->getPointeeTypeAsWritten(), Context, After)) | |||
179 | .append(" &", DeclarationFragments::FragmentKind::Text); | |||
180 | ||||
181 | // Declaration fragments of a rvalue reference type is the declaration | |||
182 | // fragments of the underlying type followed by a `&&`. | |||
183 | if (const RValueReferenceType *RRT = dyn_cast<RValueReferenceType>(T)) | |||
184 | return Fragments | |||
185 | .append( | |||
186 | getFragmentsForType(RRT->getPointeeTypeAsWritten(), Context, After)) | |||
187 | .append(" &&", DeclarationFragments::FragmentKind::Text); | |||
188 | ||||
189 | // Declaration fragments of an array-typed variable have two parts: | |||
190 | // 1. the element type of the array that appears before the variable name; | |||
191 | // 2. array brackets `[(0-9)?]` that appear after the variable name. | |||
192 | if (const ArrayType *AT = T->getAsArrayTypeUnsafe()) { | |||
193 | // Build the "after" part first because the inner element type might also | |||
194 | // be an array-type. For example `int matrix[3][4]` which has a type of | |||
195 | // "(array 3 of (array 4 of ints))." | |||
196 | // Push the array size part first to make sure they are in the right order. | |||
197 | After.append("[", DeclarationFragments::FragmentKind::Text); | |||
198 | ||||
199 | switch (AT->getSizeModifier()) { | |||
200 | case ArrayType::Normal: | |||
201 | break; | |||
202 | case ArrayType::Static: | |||
203 | Fragments.append("static", DeclarationFragments::FragmentKind::Keyword); | |||
204 | break; | |||
205 | case ArrayType::Star: | |||
206 | Fragments.append("*", DeclarationFragments::FragmentKind::Text); | |||
207 | break; | |||
208 | } | |||
209 | ||||
210 | if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) { | |||
211 | // FIXME: right now this would evaluate any expressions/macros written in | |||
212 | // the original source to concrete values. For example | |||
213 | // `int nums[MAX]` -> `int nums[100]` | |||
214 | // `char *str[5 + 1]` -> `char *str[6]` | |||
215 | SmallString<128> Size; | |||
216 | CAT->getSize().toStringUnsigned(Size); | |||
217 | After.append(Size, DeclarationFragments::FragmentKind::NumberLiteral); | |||
218 | } | |||
219 | ||||
220 | After.append("]", DeclarationFragments::FragmentKind::Text); | |||
221 | ||||
222 | return Fragments.append( | |||
223 | getFragmentsForType(AT->getElementType(), Context, After)); | |||
224 | } | |||
225 | ||||
226 | // An ElaboratedType is a sugar for types that are referred to using an | |||
227 | // elaborated keyword, e.g., `struct S`, `enum E`, or (in C++) via a | |||
228 | // qualified name, e.g., `N::M::type`, or both. | |||
229 | if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(T)) { | |||
230 | ElaboratedTypeKeyword Keyword = ET->getKeyword(); | |||
231 | if (Keyword != ETK_None) { | |||
232 | Fragments | |||
233 | .append(ElaboratedType::getKeywordName(Keyword), | |||
234 | DeclarationFragments::FragmentKind::Keyword) | |||
235 | .appendSpace(); | |||
236 | } | |||
237 | ||||
238 | if (const NestedNameSpecifier *NNS = ET->getQualifier()) | |||
239 | Fragments.append(getFragmentsForNNS(NNS, Context, After)); | |||
240 | ||||
241 | // After handling the elaborated keyword or qualified name, build | |||
242 | // declaration fragments for the desugared underlying type. | |||
243 | return Fragments.append(getFragmentsForType(ET->desugar(), Context, After)); | |||
244 | } | |||
245 | ||||
246 | // If the type is a typedefed type, get the underlying TypedefNameDecl for a | |||
247 | // direct reference to the typedef instead of the wrapped type. | |||
248 | ||||
249 | // 'id' type is a typedef for an ObjCObjectPointerType | |||
250 | // we treat it as a typedef | |||
251 | if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(T)) { | |||
252 | const TypedefNameDecl *Decl = TypedefTy->getDecl(); | |||
253 | TypedefUnderlyingTypeResolver TypedefResolver(Context); | |||
254 | std::string USR = TypedefResolver.getUSRForType(QualType(T, 0)); | |||
255 | ||||
256 | if (T->isObjCIdType()) { | |||
257 | return Fragments.append(Decl->getName(), | |||
258 | DeclarationFragments::FragmentKind::Keyword); | |||
259 | } | |||
260 | ||||
261 | return Fragments.append( | |||
262 | Decl->getName(), DeclarationFragments::FragmentKind::TypeIdentifier, | |||
263 | USR, TypedefResolver.getUnderlyingTypeDecl(QualType(T, 0))); | |||
264 | } | |||
265 | ||||
266 | // Everything we care about has been handled now, reduce to the canonical | |||
267 | // unqualified base type. | |||
268 | QualType Base = T->getCanonicalTypeUnqualified(); | |||
269 | ||||
270 | // If the base type is a TagType (struct/interface/union/class/enum), let's | |||
271 | // get the underlying Decl for better names and USRs. | |||
272 | if (const TagType *TagTy = dyn_cast<TagType>(Base)) { | |||
273 | const TagDecl *Decl = TagTy->getDecl(); | |||
274 | // Anonymous decl, skip this fragment. | |||
275 | if (Decl->getName().empty()) | |||
276 | return Fragments; | |||
277 | SmallString<128> TagUSR; | |||
278 | clang::index::generateUSRForDecl(Decl, TagUSR); | |||
279 | return Fragments.append(Decl->getName(), | |||
280 | DeclarationFragments::FragmentKind::TypeIdentifier, | |||
281 | TagUSR, Decl); | |||
282 | } | |||
283 | ||||
284 | // If the base type is an ObjCInterfaceType, use the underlying | |||
285 | // ObjCInterfaceDecl for the true USR. | |||
286 | if (const auto *ObjCIT = dyn_cast<ObjCInterfaceType>(Base)) { | |||
287 | const auto *Decl = ObjCIT->getDecl(); | |||
288 | SmallString<128> USR; | |||
289 | index::generateUSRForDecl(Decl, USR); | |||
290 | return Fragments.append(Decl->getName(), | |||
291 | DeclarationFragments::FragmentKind::TypeIdentifier, | |||
292 | USR, Decl); | |||
293 | } | |||
294 | ||||
295 | // Default fragment builder for other kinds of types (BuiltinType etc.) | |||
296 | SmallString<128> USR; | |||
297 | clang::index::generateUSRForType(Base, Context, USR); | |||
298 | Fragments.append(Base.getAsString(), | |||
299 | DeclarationFragments::FragmentKind::TypeIdentifier, USR); | |||
300 | ||||
301 | return Fragments; | |||
302 | } | |||
303 | ||||
304 | DeclarationFragments | |||
305 | DeclarationFragmentsBuilder::getFragmentsForQualifiers(const Qualifiers Quals) { | |||
306 | DeclarationFragments Fragments; | |||
307 | if (Quals.hasConst()) | |||
308 | Fragments.append("const", DeclarationFragments::FragmentKind::Keyword); | |||
309 | if (Quals.hasVolatile()) | |||
310 | Fragments.append("volatile", DeclarationFragments::FragmentKind::Keyword); | |||
311 | if (Quals.hasRestrict()) | |||
312 | Fragments.append("restrict", DeclarationFragments::FragmentKind::Keyword); | |||
313 | ||||
314 | return Fragments; | |||
315 | } | |||
316 | ||||
317 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType( | |||
318 | const QualType QT, ASTContext &Context, DeclarationFragments &After) { | |||
319 | assert(!QT.isNull() && "invalid type")(static_cast <bool> (!QT.isNull() && "invalid type" ) ? void (0) : __assert_fail ("!QT.isNull() && \"invalid type\"" , "clang/lib/ExtractAPI/DeclarationFragments.cpp", 319, __extension__ __PRETTY_FUNCTION__)); | |||
320 | ||||
321 | if (const ParenType *PT
| |||
322 | After.append(")", DeclarationFragments::FragmentKind::Text); | |||
323 | return getFragmentsForType(PT->getInnerType(), Context, After) | |||
324 | .append("(", DeclarationFragments::FragmentKind::Text); | |||
325 | } | |||
326 | ||||
327 | const SplitQualType SQT = QT.split(); | |||
328 | DeclarationFragments QualsFragments = getFragmentsForQualifiers(SQT.Quals), | |||
329 | TypeFragments = | |||
330 | getFragmentsForType(SQT.Ty, Context, After); | |||
331 | if (QualsFragments.getFragments().empty()) | |||
332 | return TypeFragments; | |||
333 | ||||
334 | // Use east qualifier for pointer types | |||
335 | // For example: | |||
336 | // ``` | |||
337 | // int * const | |||
338 | // ^---- ^---- | |||
339 | // type qualifier | |||
340 | // ^----------------- | |||
341 | // const pointer to int | |||
342 | // ``` | |||
343 | // should not be reconstructed as | |||
344 | // ``` | |||
345 | // const int * | |||
346 | // ^---- ^-- | |||
347 | // qualifier type | |||
348 | // ^---------------- ^ | |||
349 | // pointer to const int | |||
350 | // ``` | |||
351 | if (SQT.Ty->isAnyPointerType()) | |||
352 | return TypeFragments.appendSpace().append(std::move(QualsFragments)); | |||
353 | ||||
354 | return QualsFragments.appendSpace().append(std::move(TypeFragments)); | |||
355 | } | |||
356 | ||||
357 | DeclarationFragments | |||
358 | DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) { | |||
359 | DeclarationFragments Fragments; | |||
360 | StorageClass SC = Var->getStorageClass(); | |||
361 | if (SC != SC_None) | |||
362 | Fragments | |||
363 | .append(VarDecl::getStorageClassSpecifierString(SC), | |||
364 | DeclarationFragments::FragmentKind::Keyword) | |||
365 | .appendSpace(); | |||
366 | QualType T = | |||
367 | Var->getTypeSourceInfo() | |||
368 | ? Var->getTypeSourceInfo()->getType() | |||
369 | : Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType()); | |||
370 | ||||
371 | // Capture potential fragments that needs to be placed after the variable name | |||
372 | // ``` | |||
373 | // int nums[5]; | |||
374 | // char (*ptr_to_array)[6]; | |||
375 | // ``` | |||
376 | DeclarationFragments After; | |||
377 | return Fragments.append(getFragmentsForType(T, Var->getASTContext(), After)) | |||
378 | .appendSpace() | |||
379 | .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) | |||
380 | .append(std::move(After)); | |||
381 | } | |||
382 | ||||
383 | DeclarationFragments | |||
384 | DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) { | |||
385 | DeclarationFragments Fragments, After; | |||
386 | ||||
387 | QualType T = Param->getTypeSourceInfo() | |||
388 | ? Param->getTypeSourceInfo()->getType() | |||
389 | : Param->getASTContext().getUnqualifiedObjCPointerType( | |||
390 | Param->getType()); | |||
391 | ||||
392 | DeclarationFragments TypeFragments = | |||
393 | getFragmentsForType(T, Param->getASTContext(), After); | |||
394 | ||||
395 | if (Param->isObjCMethodParameter()) | |||
396 | Fragments.append("(", DeclarationFragments::FragmentKind::Text) | |||
397 | .append(std::move(TypeFragments)) | |||
398 | .append(") ", DeclarationFragments::FragmentKind::Text); | |||
399 | else | |||
400 | Fragments.append(std::move(TypeFragments)).appendSpace(); | |||
401 | ||||
402 | return Fragments | |||
403 | .append(Param->getName(), | |||
404 | DeclarationFragments::FragmentKind::InternalParam) | |||
405 | .append(std::move(After)); | |||
406 | } | |||
407 | ||||
408 | DeclarationFragments | |||
409 | DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { | |||
410 | DeclarationFragments Fragments; | |||
411 | // FIXME: Handle template specialization | |||
412 | switch (Func->getStorageClass()) { | |||
413 | case SC_None: | |||
414 | case SC_PrivateExtern: | |||
415 | break; | |||
416 | case SC_Extern: | |||
417 | Fragments.append("extern", DeclarationFragments::FragmentKind::Keyword) | |||
418 | .appendSpace(); | |||
419 | break; | |||
420 | case SC_Static: | |||
421 | Fragments.append("static", DeclarationFragments::FragmentKind::Keyword) | |||
422 | .appendSpace(); | |||
423 | break; | |||
424 | case SC_Auto: | |||
425 | case SC_Register: | |||
426 | llvm_unreachable("invalid for functions")::llvm::llvm_unreachable_internal("invalid for functions", "clang/lib/ExtractAPI/DeclarationFragments.cpp" , 426); | |||
427 | } | |||
428 | // FIXME: Handle C++ function specifiers: constexpr, consteval, explicit, etc. | |||
429 | ||||
430 | // FIXME: Is `after` actually needed here? | |||
431 | DeclarationFragments After; | |||
432 | Fragments | |||
433 | .append(getFragmentsForType(Func->getReturnType(), Func->getASTContext(), | |||
434 | After)) | |||
435 | .appendSpace() | |||
436 | .append(Func->getName(), DeclarationFragments::FragmentKind::Identifier) | |||
437 | .append(std::move(After)); | |||
438 | ||||
439 | Fragments.append("(", DeclarationFragments::FragmentKind::Text); | |||
440 | for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) { | |||
441 | if (i) | |||
442 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
443 | Fragments.append(getFragmentsForParam(Func->getParamDecl(i))); | |||
444 | } | |||
445 | Fragments.append(")", DeclarationFragments::FragmentKind::Text); | |||
446 | ||||
447 | // FIXME: Handle exception specifiers: throw, noexcept | |||
448 | return Fragments; | |||
449 | } | |||
450 | ||||
451 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForEnumConstant( | |||
452 | const EnumConstantDecl *EnumConstDecl) { | |||
453 | DeclarationFragments Fragments; | |||
454 | return Fragments.append(EnumConstDecl->getName(), | |||
455 | DeclarationFragments::FragmentKind::Identifier); | |||
456 | } | |||
457 | ||||
458 | DeclarationFragments | |||
459 | DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) { | |||
460 | if (const auto *TypedefNameDecl = EnumDecl->getTypedefNameForAnonDecl()) | |||
461 | return getFragmentsForTypedef(TypedefNameDecl); | |||
462 | ||||
463 | DeclarationFragments Fragments, After; | |||
464 | Fragments.append("enum", DeclarationFragments::FragmentKind::Keyword); | |||
465 | ||||
466 | if (!EnumDecl->getName().empty()) | |||
467 | Fragments.appendSpace().append( | |||
468 | EnumDecl->getName(), DeclarationFragments::FragmentKind::Identifier); | |||
469 | ||||
470 | QualType IntegerType = EnumDecl->getIntegerType(); | |||
471 | if (!IntegerType.isNull()) | |||
472 | Fragments.append(": ", DeclarationFragments::FragmentKind::Text) | |||
473 | .append( | |||
474 | getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After)) | |||
475 | .append(std::move(After)); | |||
476 | ||||
477 | return Fragments.append(";", DeclarationFragments::FragmentKind::Text); | |||
478 | } | |||
479 | ||||
480 | DeclarationFragments | |||
481 | DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) { | |||
482 | DeclarationFragments After; | |||
483 | return getFragmentsForType(Field->getType(), Field->getASTContext(), After) | |||
484 | .appendSpace() | |||
485 | .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier) | |||
486 | .append(std::move(After)); | |||
487 | } | |||
488 | ||||
489 | DeclarationFragments | |||
490 | DeclarationFragmentsBuilder::getFragmentsForStruct(const RecordDecl *Record) { | |||
491 | if (const auto *TypedefNameDecl = Record->getTypedefNameForAnonDecl()) | |||
492 | return getFragmentsForTypedef(TypedefNameDecl); | |||
493 | ||||
494 | DeclarationFragments Fragments; | |||
495 | Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword); | |||
496 | ||||
497 | if (!Record->getName().empty()) | |||
498 | Fragments.appendSpace().append( | |||
499 | Record->getName(), DeclarationFragments::FragmentKind::Identifier); | |||
500 | ||||
501 | return Fragments.append(";", DeclarationFragments::FragmentKind::Text); | |||
502 | } | |||
503 | ||||
504 | DeclarationFragments | |||
505 | DeclarationFragmentsBuilder::getFragmentsForMacro(StringRef Name, | |||
506 | const MacroDirective *MD) { | |||
507 | DeclarationFragments Fragments; | |||
508 | Fragments.append("#define", DeclarationFragments::FragmentKind::Keyword) | |||
509 | .appendSpace(); | |||
510 | Fragments.append(Name, DeclarationFragments::FragmentKind::Identifier); | |||
511 | ||||
512 | auto *MI = MD->getMacroInfo(); | |||
513 | ||||
514 | if (MI->isFunctionLike()) { | |||
515 | Fragments.append("(", DeclarationFragments::FragmentKind::Text); | |||
516 | unsigned numParameters = MI->getNumParams(); | |||
517 | if (MI->isC99Varargs()) | |||
518 | --numParameters; | |||
519 | for (unsigned i = 0; i < numParameters; ++i) { | |||
520 | if (i) | |||
521 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
522 | Fragments.append(MI->params()[i]->getName(), | |||
523 | DeclarationFragments::FragmentKind::InternalParam); | |||
524 | } | |||
525 | if (MI->isVariadic()) { | |||
526 | if (numParameters && MI->isC99Varargs()) | |||
527 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
528 | Fragments.append("...", DeclarationFragments::FragmentKind::Text); | |||
529 | } | |||
530 | Fragments.append(")", DeclarationFragments::FragmentKind::Text); | |||
531 | } | |||
532 | return Fragments; | |||
533 | } | |||
534 | ||||
535 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCCategory( | |||
536 | const ObjCCategoryDecl *Category) { | |||
537 | DeclarationFragments Fragments; | |||
538 | ||||
539 | auto *Interface = Category->getClassInterface(); | |||
540 | SmallString<128> InterfaceUSR; | |||
541 | index::generateUSRForDecl(Interface, InterfaceUSR); | |||
542 | ||||
543 | Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword) | |||
544 | .appendSpace() | |||
545 | .append(Category->getClassInterface()->getName(), | |||
546 | DeclarationFragments::FragmentKind::TypeIdentifier, InterfaceUSR, | |||
547 | Interface) | |||
548 | .append(" (", DeclarationFragments::FragmentKind::Text) | |||
549 | .append(Category->getName(), | |||
550 | DeclarationFragments::FragmentKind::Identifier) | |||
551 | .append(")", DeclarationFragments::FragmentKind::Text); | |||
552 | ||||
553 | return Fragments; | |||
554 | } | |||
555 | ||||
556 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCInterface( | |||
557 | const ObjCInterfaceDecl *Interface) { | |||
558 | DeclarationFragments Fragments; | |||
559 | // Build the base of the Objective-C interface declaration. | |||
560 | Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword) | |||
561 | .appendSpace() | |||
562 | .append(Interface->getName(), | |||
563 | DeclarationFragments::FragmentKind::Identifier); | |||
564 | ||||
565 | // Build the inheritance part of the declaration. | |||
566 | if (const ObjCInterfaceDecl *SuperClass = Interface->getSuperClass()) { | |||
567 | SmallString<128> SuperUSR; | |||
568 | index::generateUSRForDecl(SuperClass, SuperUSR); | |||
569 | Fragments.append(" : ", DeclarationFragments::FragmentKind::Text) | |||
570 | .append(SuperClass->getName(), | |||
571 | DeclarationFragments::FragmentKind::TypeIdentifier, SuperUSR, | |||
572 | SuperClass); | |||
573 | } | |||
574 | ||||
575 | return Fragments; | |||
576 | } | |||
577 | ||||
578 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCMethod( | |||
579 | const ObjCMethodDecl *Method) { | |||
580 | DeclarationFragments Fragments, After; | |||
581 | // Build the instance/class method indicator. | |||
582 | if (Method->isClassMethod()) | |||
583 | Fragments.append("+ ", DeclarationFragments::FragmentKind::Text); | |||
584 | else if (Method->isInstanceMethod()) | |||
585 | Fragments.append("- ", DeclarationFragments::FragmentKind::Text); | |||
586 | ||||
587 | // Build the return type. | |||
588 | Fragments.append("(", DeclarationFragments::FragmentKind::Text) | |||
589 | .append(getFragmentsForType(Method->getReturnType(), | |||
590 | Method->getASTContext(), After)) | |||
591 | .append(std::move(After)) | |||
592 | .append(")", DeclarationFragments::FragmentKind::Text); | |||
593 | ||||
594 | // Build the selector part. | |||
595 | Selector Selector = Method->getSelector(); | |||
596 | if (Selector.getNumArgs() == 0) | |||
597 | // For Objective-C methods that don't take arguments, the first (and only) | |||
598 | // slot of the selector is the method name. | |||
599 | Fragments.appendSpace().append( | |||
600 | Selector.getNameForSlot(0), | |||
601 | DeclarationFragments::FragmentKind::Identifier); | |||
602 | ||||
603 | // For Objective-C methods that take arguments, build the selector slots. | |||
604 | for (unsigned i = 0, end = Method->param_size(); i != end; ++i) { | |||
605 | // Objective-C method selector parts are considered as identifiers instead | |||
606 | // of "external parameters" as in Swift. This is because Objective-C method | |||
607 | // symbols are referenced with the entire selector, instead of just the | |||
608 | // method name in Swift. | |||
609 | SmallString<32> ParamID(Selector.getNameForSlot(i)); | |||
610 | ParamID.append(":"); | |||
611 | Fragments.appendSpace().append( | |||
612 | ParamID, DeclarationFragments::FragmentKind::Identifier); | |||
613 | ||||
614 | // Build the internal parameter. | |||
615 | const ParmVarDecl *Param = Method->getParamDecl(i); | |||
616 | Fragments.append(getFragmentsForParam(Param)); | |||
617 | } | |||
618 | ||||
619 | return Fragments.append(";", DeclarationFragments::FragmentKind::Text); | |||
620 | } | |||
621 | ||||
622 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( | |||
623 | const ObjCPropertyDecl *Property) { | |||
624 | DeclarationFragments Fragments, After; | |||
625 | ||||
626 | // Build the Objective-C property keyword. | |||
627 | Fragments.append("@property", DeclarationFragments::FragmentKind::Keyword); | |||
628 | ||||
629 | const auto Attributes = Property->getPropertyAttributes(); | |||
630 | // Build the attributes if there is any associated with the property. | |||
631 | if (Attributes != ObjCPropertyAttribute::kind_noattr) { | |||
| ||||
632 | // No leading comma for the first attribute. | |||
633 | bool First = true; | |||
634 | Fragments.append(" (", DeclarationFragments::FragmentKind::Text); | |||
635 | // Helper function to render the attribute. | |||
636 | auto RenderAttribute = | |||
637 | [&](ObjCPropertyAttribute::Kind Kind, StringRef Spelling, | |||
638 | StringRef Arg = "", | |||
639 | DeclarationFragments::FragmentKind ArgKind = | |||
640 | DeclarationFragments::FragmentKind::Identifier) { | |||
641 | // Check if the `Kind` attribute is set for this property. | |||
642 | if ((Attributes & Kind) && !Spelling.empty()) { | |||
643 | // Add a leading comma if this is not the first attribute rendered. | |||
644 | if (!First) | |||
645 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
646 | // Render the spelling of this attribute `Kind` as a keyword. | |||
647 | Fragments.append(Spelling, | |||
648 | DeclarationFragments::FragmentKind::Keyword); | |||
649 | // If this attribute takes in arguments (e.g. `getter=getterName`), | |||
650 | // render the arguments. | |||
651 | if (!Arg.empty()) | |||
652 | Fragments.append("=", DeclarationFragments::FragmentKind::Text) | |||
653 | .append(Arg, ArgKind); | |||
654 | First = false; | |||
655 | } | |||
656 | }; | |||
657 | ||||
658 | // Go through all possible Objective-C property attributes and render set | |||
659 | // ones. | |||
660 | RenderAttribute(ObjCPropertyAttribute::kind_class, "class"); | |||
661 | RenderAttribute(ObjCPropertyAttribute::kind_direct, "direct"); | |||
662 | RenderAttribute(ObjCPropertyAttribute::kind_nonatomic, "nonatomic"); | |||
663 | RenderAttribute(ObjCPropertyAttribute::kind_atomic, "atomic"); | |||
664 | RenderAttribute(ObjCPropertyAttribute::kind_assign, "assign"); | |||
665 | RenderAttribute(ObjCPropertyAttribute::kind_retain, "retain"); | |||
666 | RenderAttribute(ObjCPropertyAttribute::kind_strong, "strong"); | |||
667 | RenderAttribute(ObjCPropertyAttribute::kind_copy, "copy"); | |||
668 | RenderAttribute(ObjCPropertyAttribute::kind_weak, "weak"); | |||
669 | RenderAttribute(ObjCPropertyAttribute::kind_unsafe_unretained, | |||
670 | "unsafe_unretained"); | |||
671 | RenderAttribute(ObjCPropertyAttribute::kind_readwrite, "readwrite"); | |||
672 | RenderAttribute(ObjCPropertyAttribute::kind_readonly, "readonly"); | |||
673 | RenderAttribute(ObjCPropertyAttribute::kind_getter, "getter", | |||
674 | Property->getGetterName().getAsString()); | |||
675 | RenderAttribute(ObjCPropertyAttribute::kind_setter, "setter", | |||
676 | Property->getSetterName().getAsString()); | |||
677 | ||||
678 | // Render nullability attributes. | |||
679 | if (Attributes & ObjCPropertyAttribute::kind_nullability) { | |||
680 | QualType Type = Property->getType(); | |||
681 | if (const auto Nullability = | |||
682 | AttributedType::stripOuterNullability(Type)) { | |||
683 | if (!First) | |||
684 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
685 | if (*Nullability == NullabilityKind::Unspecified && | |||
686 | (Attributes & ObjCPropertyAttribute::kind_null_resettable)) | |||
687 | Fragments.append("null_resettable", | |||
688 | DeclarationFragments::FragmentKind::Keyword); | |||
689 | else | |||
690 | Fragments.append( | |||
691 | getNullabilitySpelling(*Nullability, /*isContextSensitive=*/true), | |||
692 | DeclarationFragments::FragmentKind::Keyword); | |||
693 | First = false; | |||
694 | } | |||
695 | } | |||
696 | ||||
697 | Fragments.append(")", DeclarationFragments::FragmentKind::Text); | |||
698 | } | |||
699 | ||||
700 | // Build the property type and name, and return the completed fragments. | |||
701 | return Fragments.appendSpace() | |||
702 | .append(getFragmentsForType(Property->getType(), | |||
703 | Property->getASTContext(), After)) | |||
704 | .appendSpace() | |||
705 | .append(Property->getName(), | |||
706 | DeclarationFragments::FragmentKind::Identifier) | |||
707 | .append(std::move(After)); | |||
708 | } | |||
709 | ||||
710 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol( | |||
711 | const ObjCProtocolDecl *Protocol) { | |||
712 | DeclarationFragments Fragments; | |||
713 | // Build basic protocol declaration. | |||
714 | Fragments.append("@protocol", DeclarationFragments::FragmentKind::Keyword) | |||
715 | .appendSpace() | |||
716 | .append(Protocol->getName(), | |||
717 | DeclarationFragments::FragmentKind::Identifier); | |||
718 | ||||
719 | // If this protocol conforms to other protocols, build the conformance list. | |||
720 | if (!Protocol->protocols().empty()) { | |||
721 | Fragments.append(" <", DeclarationFragments::FragmentKind::Text); | |||
722 | for (ObjCProtocolDecl::protocol_iterator It = Protocol->protocol_begin(); | |||
723 | It != Protocol->protocol_end(); It++) { | |||
724 | // Add a leading comma if this is not the first protocol rendered. | |||
725 | if (It != Protocol->protocol_begin()) | |||
726 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
727 | ||||
728 | SmallString<128> USR; | |||
729 | index::generateUSRForDecl(*It, USR); | |||
730 | Fragments.append((*It)->getName(), | |||
731 | DeclarationFragments::FragmentKind::TypeIdentifier, USR, | |||
732 | *It); | |||
733 | } | |||
734 | Fragments.append(">", DeclarationFragments::FragmentKind::Text); | |||
735 | } | |||
736 | ||||
737 | return Fragments; | |||
738 | } | |||
739 | ||||
740 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForTypedef( | |||
741 | const TypedefNameDecl *Decl) { | |||
742 | DeclarationFragments Fragments, After; | |||
743 | Fragments.append("typedef", DeclarationFragments::FragmentKind::Keyword) | |||
744 | .appendSpace() | |||
745 | .append(getFragmentsForType(Decl->getUnderlyingType(), | |||
746 | Decl->getASTContext(), After)) | |||
747 | .append(std::move(After)) | |||
748 | .appendSpace() | |||
749 | .append(Decl->getName(), DeclarationFragments::FragmentKind::Identifier); | |||
750 | ||||
751 | return Fragments.append(";", DeclarationFragments::FragmentKind::Text); | |||
752 | } | |||
753 | ||||
754 | template <typename FunctionT> | |||
755 | FunctionSignature | |||
756 | DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) { | |||
757 | FunctionSignature Signature; | |||
758 | ||||
759 | DeclarationFragments ReturnType, After; | |||
760 | ReturnType | |||
761 | .append(getFragmentsForType(Function->getReturnType(), | |||
762 | Function->getASTContext(), After)) | |||
763 | .append(std::move(After)); | |||
764 | Signature.setReturnType(ReturnType); | |||
765 | ||||
766 | for (const auto *Param : Function->parameters()) | |||
767 | Signature.addParameter(Param->getName(), getFragmentsForParam(Param)); | |||
768 | ||||
769 | return Signature; | |||
770 | } | |||
771 | ||||
772 | // Instantiate template for FunctionDecl. | |||
773 | template FunctionSignature | |||
774 | DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *); | |||
775 | ||||
776 | // Instantiate template for ObjCMethodDecl. | |||
777 | template FunctionSignature | |||
778 | DeclarationFragmentsBuilder::getFunctionSignature(const ObjCMethodDecl *); | |||
779 | ||||
780 | // Subheading of a symbol defaults to its name. | |||
781 | DeclarationFragments | |||
782 | DeclarationFragmentsBuilder::getSubHeading(const NamedDecl *Decl) { | |||
783 | DeclarationFragments Fragments; | |||
784 | if (!Decl->getName().empty()) | |||
785 | Fragments.append(Decl->getName(), | |||
786 | DeclarationFragments::FragmentKind::Identifier); | |||
787 | return Fragments; | |||
788 | } | |||
789 | ||||
790 | // Subheading of an Objective-C method is a `+` or `-` sign indicating whether | |||
791 | // it's a class method or an instance method, followed by the selector name. | |||
792 | DeclarationFragments | |||
793 | DeclarationFragmentsBuilder::getSubHeading(const ObjCMethodDecl *Method) { | |||
794 | DeclarationFragments Fragments; | |||
795 | if (Method->isClassMethod()) | |||
796 | Fragments.append("+ ", DeclarationFragments::FragmentKind::Text); | |||
797 | else if (Method->isInstanceMethod()) | |||
798 | Fragments.append("- ", DeclarationFragments::FragmentKind::Text); | |||
799 | ||||
800 | return Fragments.append(Method->getNameAsString(), | |||
801 | DeclarationFragments::FragmentKind::Identifier); | |||
802 | } | |||
803 | ||||
804 | // Subheading of a symbol defaults to its name. | |||
805 | DeclarationFragments | |||
806 | DeclarationFragmentsBuilder::getSubHeadingForMacro(StringRef Name) { | |||
807 | DeclarationFragments Fragments; | |||
808 | Fragments.append(Name, DeclarationFragments::FragmentKind::Identifier); | |||
809 | return Fragments; | |||
810 | } |