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 | // Everything we care about has been handled now, reduce to the canonical | |||
247 | // unqualified base type. | |||
248 | QualType Base = T->getCanonicalTypeUnqualified(); | |||
249 | ||||
250 | // Render Objective-C `id`/`instancetype` as keywords. | |||
251 | if (T->isObjCIdType()) | |||
252 | return Fragments.append(Base.getAsString(), | |||
253 | DeclarationFragments::FragmentKind::Keyword); | |||
254 | ||||
255 | // If the type is a typedefed type, get the underlying TypedefNameDecl for a | |||
256 | // direct reference to the typedef instead of the wrapped type. | |||
257 | if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(T)) { | |||
258 | const TypedefNameDecl *Decl = TypedefTy->getDecl(); | |||
259 | TypedefUnderlyingTypeResolver TypedefResolver(Context); | |||
260 | std::string USR = TypedefResolver.getUSRForType(QualType(T, 0)); | |||
261 | return Fragments.append( | |||
262 | Decl->getName(), DeclarationFragments::FragmentKind::TypeIdentifier, | |||
263 | USR, TypedefResolver.getUnderlyingTypeDecl(QualType(T, 0))); | |||
264 | } | |||
265 | ||||
266 | // If the base type is a TagType (struct/interface/union/class/enum), let's | |||
267 | // get the underlying Decl for better names and USRs. | |||
268 | if (const TagType *TagTy = dyn_cast<TagType>(Base)) { | |||
269 | const TagDecl *Decl = TagTy->getDecl(); | |||
270 | // Anonymous decl, skip this fragment. | |||
271 | if (Decl->getName().empty()) | |||
272 | return Fragments; | |||
273 | SmallString<128> TagUSR; | |||
274 | clang::index::generateUSRForDecl(Decl, TagUSR); | |||
275 | return Fragments.append(Decl->getName(), | |||
276 | DeclarationFragments::FragmentKind::TypeIdentifier, | |||
277 | TagUSR, Decl); | |||
278 | } | |||
279 | ||||
280 | // If the base type is an ObjCInterfaceType, use the underlying | |||
281 | // ObjCInterfaceDecl for the true USR. | |||
282 | if (const auto *ObjCIT = dyn_cast<ObjCInterfaceType>(Base)) { | |||
283 | const auto *Decl = ObjCIT->getDecl(); | |||
284 | SmallString<128> USR; | |||
285 | index::generateUSRForDecl(Decl, USR); | |||
286 | return Fragments.append(Decl->getName(), | |||
287 | DeclarationFragments::FragmentKind::TypeIdentifier, | |||
288 | USR, Decl); | |||
289 | } | |||
290 | ||||
291 | // Default fragment builder for other kinds of types (BuiltinType etc.) | |||
292 | SmallString<128> USR; | |||
293 | clang::index::generateUSRForType(Base, Context, USR); | |||
294 | Fragments.append(Base.getAsString(), | |||
295 | DeclarationFragments::FragmentKind::TypeIdentifier, USR); | |||
296 | ||||
297 | return Fragments; | |||
298 | } | |||
299 | ||||
300 | DeclarationFragments | |||
301 | DeclarationFragmentsBuilder::getFragmentsForQualifiers(const Qualifiers Quals) { | |||
302 | DeclarationFragments Fragments; | |||
303 | if (Quals.hasConst()) | |||
304 | Fragments.append("const", DeclarationFragments::FragmentKind::Keyword); | |||
305 | if (Quals.hasVolatile()) | |||
306 | Fragments.append("volatile", DeclarationFragments::FragmentKind::Keyword); | |||
307 | if (Quals.hasRestrict()) | |||
308 | Fragments.append("restrict", DeclarationFragments::FragmentKind::Keyword); | |||
309 | ||||
310 | return Fragments; | |||
311 | } | |||
312 | ||||
313 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType( | |||
314 | const QualType QT, ASTContext &Context, DeclarationFragments &After) { | |||
315 | 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", 315, __extension__ __PRETTY_FUNCTION__)); | |||
316 | ||||
317 | if (const ParenType *PT
| |||
318 | After.append(")", DeclarationFragments::FragmentKind::Text); | |||
319 | return getFragmentsForType(PT->getInnerType(), Context, After) | |||
320 | .append("(", DeclarationFragments::FragmentKind::Text); | |||
321 | } | |||
322 | ||||
323 | const SplitQualType SQT = QT.split(); | |||
324 | DeclarationFragments QualsFragments = getFragmentsForQualifiers(SQT.Quals), | |||
325 | TypeFragments = | |||
326 | getFragmentsForType(SQT.Ty, Context, After); | |||
327 | if (QualsFragments.getFragments().empty()) | |||
328 | return TypeFragments; | |||
329 | ||||
330 | // Use east qualifier for pointer types | |||
331 | // For example: | |||
332 | // ``` | |||
333 | // int * const | |||
334 | // ^---- ^---- | |||
335 | // type qualifier | |||
336 | // ^----------------- | |||
337 | // const pointer to int | |||
338 | // ``` | |||
339 | // should not be reconstructed as | |||
340 | // ``` | |||
341 | // const int * | |||
342 | // ^---- ^-- | |||
343 | // qualifier type | |||
344 | // ^---------------- ^ | |||
345 | // pointer to const int | |||
346 | // ``` | |||
347 | if (SQT.Ty->isAnyPointerType()) | |||
348 | return TypeFragments.appendSpace().append(std::move(QualsFragments)); | |||
349 | ||||
350 | return QualsFragments.appendSpace().append(std::move(TypeFragments)); | |||
351 | } | |||
352 | ||||
353 | DeclarationFragments | |||
354 | DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) { | |||
355 | DeclarationFragments Fragments; | |||
356 | StorageClass SC = Var->getStorageClass(); | |||
357 | if (SC != SC_None) | |||
358 | Fragments | |||
359 | .append(VarDecl::getStorageClassSpecifierString(SC), | |||
360 | DeclarationFragments::FragmentKind::Keyword) | |||
361 | .appendSpace(); | |||
362 | QualType T = | |||
363 | Var->getTypeSourceInfo() | |||
364 | ? Var->getTypeSourceInfo()->getType() | |||
365 | : Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType()); | |||
366 | ||||
367 | // Capture potential fragments that needs to be placed after the variable name | |||
368 | // ``` | |||
369 | // int nums[5]; | |||
370 | // char (*ptr_to_array)[6]; | |||
371 | // ``` | |||
372 | DeclarationFragments After; | |||
373 | return Fragments.append(getFragmentsForType(T, Var->getASTContext(), After)) | |||
374 | .appendSpace() | |||
375 | .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) | |||
376 | .append(std::move(After)); | |||
377 | } | |||
378 | ||||
379 | DeclarationFragments | |||
380 | DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) { | |||
381 | DeclarationFragments Fragments, After; | |||
382 | ||||
383 | QualType T = Param->getTypeSourceInfo() | |||
384 | ? Param->getTypeSourceInfo()->getType() | |||
385 | : Param->getASTContext().getUnqualifiedObjCPointerType( | |||
386 | Param->getType()); | |||
387 | ||||
388 | DeclarationFragments TypeFragments = | |||
389 | getFragmentsForType(T, Param->getASTContext(), After); | |||
390 | ||||
391 | if (Param->isObjCMethodParameter()) | |||
392 | Fragments.append("(", DeclarationFragments::FragmentKind::Text) | |||
393 | .append(std::move(TypeFragments)) | |||
394 | .append(") ", DeclarationFragments::FragmentKind::Text); | |||
395 | else | |||
396 | Fragments.append(std::move(TypeFragments)).appendSpace(); | |||
397 | ||||
398 | return Fragments | |||
399 | .append(Param->getName(), | |||
400 | DeclarationFragments::FragmentKind::InternalParam) | |||
401 | .append(std::move(After)); | |||
402 | } | |||
403 | ||||
404 | DeclarationFragments | |||
405 | DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { | |||
406 | DeclarationFragments Fragments; | |||
407 | // FIXME: Handle template specialization | |||
408 | switch (Func->getStorageClass()) { | |||
409 | case SC_None: | |||
410 | case SC_PrivateExtern: | |||
411 | break; | |||
412 | case SC_Extern: | |||
413 | Fragments.append("extern", DeclarationFragments::FragmentKind::Keyword) | |||
414 | .appendSpace(); | |||
415 | break; | |||
416 | case SC_Static: | |||
417 | Fragments.append("static", DeclarationFragments::FragmentKind::Keyword) | |||
418 | .appendSpace(); | |||
419 | break; | |||
420 | case SC_Auto: | |||
421 | case SC_Register: | |||
422 | llvm_unreachable("invalid for functions")::llvm::llvm_unreachable_internal("invalid for functions", "clang/lib/ExtractAPI/DeclarationFragments.cpp" , 422); | |||
423 | } | |||
424 | // FIXME: Handle C++ function specifiers: constexpr, consteval, explicit, etc. | |||
425 | ||||
426 | // FIXME: Is `after` actually needed here? | |||
427 | DeclarationFragments After; | |||
428 | Fragments | |||
429 | .append(getFragmentsForType(Func->getReturnType(), Func->getASTContext(), | |||
430 | After)) | |||
431 | .appendSpace() | |||
432 | .append(Func->getName(), DeclarationFragments::FragmentKind::Identifier) | |||
433 | .append(std::move(After)); | |||
434 | ||||
435 | Fragments.append("(", DeclarationFragments::FragmentKind::Text); | |||
436 | for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) { | |||
437 | if (i) | |||
438 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
439 | Fragments.append(getFragmentsForParam(Func->getParamDecl(i))); | |||
440 | } | |||
441 | Fragments.append(")", DeclarationFragments::FragmentKind::Text); | |||
442 | ||||
443 | // FIXME: Handle exception specifiers: throw, noexcept | |||
444 | return Fragments; | |||
445 | } | |||
446 | ||||
447 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForEnumConstant( | |||
448 | const EnumConstantDecl *EnumConstDecl) { | |||
449 | DeclarationFragments Fragments; | |||
450 | return Fragments.append(EnumConstDecl->getName(), | |||
451 | DeclarationFragments::FragmentKind::Identifier); | |||
452 | } | |||
453 | ||||
454 | DeclarationFragments | |||
455 | DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) { | |||
456 | if (const auto *TypedefNameDecl = EnumDecl->getTypedefNameForAnonDecl()) | |||
457 | return getFragmentsForTypedef(TypedefNameDecl); | |||
458 | ||||
459 | DeclarationFragments Fragments, After; | |||
460 | Fragments.append("enum", DeclarationFragments::FragmentKind::Keyword); | |||
461 | ||||
462 | if (!EnumDecl->getName().empty()) | |||
463 | Fragments.appendSpace().append( | |||
464 | EnumDecl->getName(), DeclarationFragments::FragmentKind::Identifier); | |||
465 | ||||
466 | QualType IntegerType = EnumDecl->getIntegerType(); | |||
467 | if (!IntegerType.isNull()) | |||
468 | Fragments.append(": ", DeclarationFragments::FragmentKind::Text) | |||
469 | .append( | |||
470 | getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After)) | |||
471 | .append(std::move(After)); | |||
472 | ||||
473 | return Fragments.append(";", DeclarationFragments::FragmentKind::Text); | |||
474 | } | |||
475 | ||||
476 | DeclarationFragments | |||
477 | DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) { | |||
478 | DeclarationFragments After; | |||
479 | return getFragmentsForType(Field->getType(), Field->getASTContext(), After) | |||
480 | .appendSpace() | |||
481 | .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier) | |||
482 | .append(std::move(After)); | |||
483 | } | |||
484 | ||||
485 | DeclarationFragments | |||
486 | DeclarationFragmentsBuilder::getFragmentsForStruct(const RecordDecl *Record) { | |||
487 | if (const auto *TypedefNameDecl = Record->getTypedefNameForAnonDecl()) | |||
488 | return getFragmentsForTypedef(TypedefNameDecl); | |||
489 | ||||
490 | DeclarationFragments Fragments; | |||
491 | Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword); | |||
492 | ||||
493 | if (!Record->getName().empty()) | |||
494 | Fragments.appendSpace().append( | |||
495 | Record->getName(), DeclarationFragments::FragmentKind::Identifier); | |||
496 | ||||
497 | return Fragments.append(";", DeclarationFragments::FragmentKind::Text); | |||
498 | } | |||
499 | ||||
500 | DeclarationFragments | |||
501 | DeclarationFragmentsBuilder::getFragmentsForMacro(StringRef Name, | |||
502 | const MacroDirective *MD) { | |||
503 | DeclarationFragments Fragments; | |||
504 | Fragments.append("#define", DeclarationFragments::FragmentKind::Keyword) | |||
505 | .appendSpace(); | |||
506 | Fragments.append(Name, DeclarationFragments::FragmentKind::Identifier); | |||
507 | ||||
508 | auto *MI = MD->getMacroInfo(); | |||
509 | ||||
510 | if (MI->isFunctionLike()) { | |||
511 | Fragments.append("(", DeclarationFragments::FragmentKind::Text); | |||
512 | unsigned numParameters = MI->getNumParams(); | |||
513 | if (MI->isC99Varargs()) | |||
514 | --numParameters; | |||
515 | for (unsigned i = 0; i < numParameters; ++i) { | |||
516 | if (i) | |||
517 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
518 | Fragments.append(MI->params()[i]->getName(), | |||
519 | DeclarationFragments::FragmentKind::InternalParam); | |||
520 | } | |||
521 | if (MI->isVariadic()) { | |||
522 | if (numParameters && MI->isC99Varargs()) | |||
523 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
524 | Fragments.append("...", DeclarationFragments::FragmentKind::Text); | |||
525 | } | |||
526 | Fragments.append(")", DeclarationFragments::FragmentKind::Text); | |||
527 | } | |||
528 | return Fragments; | |||
529 | } | |||
530 | ||||
531 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCCategory( | |||
532 | const ObjCCategoryDecl *Category) { | |||
533 | DeclarationFragments Fragments; | |||
534 | ||||
535 | auto *Interface = Category->getClassInterface(); | |||
536 | SmallString<128> InterfaceUSR; | |||
537 | index::generateUSRForDecl(Interface, InterfaceUSR); | |||
538 | ||||
539 | Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword) | |||
540 | .appendSpace() | |||
541 | .append(Category->getClassInterface()->getName(), | |||
542 | DeclarationFragments::FragmentKind::TypeIdentifier, InterfaceUSR, | |||
543 | Interface) | |||
544 | .append(" (", DeclarationFragments::FragmentKind::Text) | |||
545 | .append(Category->getName(), | |||
546 | DeclarationFragments::FragmentKind::Identifier) | |||
547 | .append(")", DeclarationFragments::FragmentKind::Text); | |||
548 | ||||
549 | return Fragments; | |||
550 | } | |||
551 | ||||
552 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCInterface( | |||
553 | const ObjCInterfaceDecl *Interface) { | |||
554 | DeclarationFragments Fragments; | |||
555 | // Build the base of the Objective-C interface declaration. | |||
556 | Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword) | |||
557 | .appendSpace() | |||
558 | .append(Interface->getName(), | |||
559 | DeclarationFragments::FragmentKind::Identifier); | |||
560 | ||||
561 | // Build the inheritance part of the declaration. | |||
562 | if (const ObjCInterfaceDecl *SuperClass = Interface->getSuperClass()) { | |||
563 | SmallString<128> SuperUSR; | |||
564 | index::generateUSRForDecl(SuperClass, SuperUSR); | |||
565 | Fragments.append(" : ", DeclarationFragments::FragmentKind::Text) | |||
566 | .append(SuperClass->getName(), | |||
567 | DeclarationFragments::FragmentKind::TypeIdentifier, SuperUSR, | |||
568 | SuperClass); | |||
569 | } | |||
570 | ||||
571 | return Fragments; | |||
572 | } | |||
573 | ||||
574 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCMethod( | |||
575 | const ObjCMethodDecl *Method) { | |||
576 | DeclarationFragments Fragments, After; | |||
577 | // Build the instance/class method indicator. | |||
578 | if (Method->isClassMethod()) | |||
579 | Fragments.append("+ ", DeclarationFragments::FragmentKind::Text); | |||
580 | else if (Method->isInstanceMethod()) | |||
581 | Fragments.append("- ", DeclarationFragments::FragmentKind::Text); | |||
582 | ||||
583 | // Build the return type. | |||
584 | Fragments.append("(", DeclarationFragments::FragmentKind::Text) | |||
585 | .append(getFragmentsForType(Method->getReturnType(), | |||
586 | Method->getASTContext(), After)) | |||
587 | .append(std::move(After)) | |||
588 | .append(")", DeclarationFragments::FragmentKind::Text); | |||
589 | ||||
590 | // Build the selector part. | |||
591 | Selector Selector = Method->getSelector(); | |||
592 | if (Selector.getNumArgs() == 0) | |||
593 | // For Objective-C methods that don't take arguments, the first (and only) | |||
594 | // slot of the selector is the method name. | |||
595 | Fragments.appendSpace().append( | |||
596 | Selector.getNameForSlot(0), | |||
597 | DeclarationFragments::FragmentKind::Identifier); | |||
598 | ||||
599 | // For Objective-C methods that take arguments, build the selector slots. | |||
600 | for (unsigned i = 0, end = Method->param_size(); i != end; ++i) { | |||
601 | // Objective-C method selector parts are considered as identifiers instead | |||
602 | // of "external parameters" as in Swift. This is because Objective-C method | |||
603 | // symbols are referenced with the entire selector, instead of just the | |||
604 | // method name in Swift. | |||
605 | SmallString<32> ParamID(Selector.getNameForSlot(i)); | |||
606 | ParamID.append(":"); | |||
607 | Fragments.appendSpace().append( | |||
608 | ParamID, DeclarationFragments::FragmentKind::Identifier); | |||
609 | ||||
610 | // Build the internal parameter. | |||
611 | const ParmVarDecl *Param = Method->getParamDecl(i); | |||
612 | Fragments.append(getFragmentsForParam(Param)); | |||
613 | } | |||
614 | ||||
615 | return Fragments.append(";", DeclarationFragments::FragmentKind::Text); | |||
616 | } | |||
617 | ||||
618 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( | |||
619 | const ObjCPropertyDecl *Property) { | |||
620 | DeclarationFragments Fragments, After; | |||
621 | ||||
622 | // Build the Objective-C property keyword. | |||
623 | Fragments.append("@property", DeclarationFragments::FragmentKind::Keyword); | |||
624 | ||||
625 | const auto Attributes = Property->getPropertyAttributes(); | |||
626 | // Build the attributes if there is any associated with the property. | |||
627 | if (Attributes != ObjCPropertyAttribute::kind_noattr) { | |||
| ||||
628 | // No leading comma for the first attribute. | |||
629 | bool First = true; | |||
630 | Fragments.append(" (", DeclarationFragments::FragmentKind::Text); | |||
631 | // Helper function to render the attribute. | |||
632 | auto RenderAttribute = | |||
633 | [&](ObjCPropertyAttribute::Kind Kind, StringRef Spelling, | |||
634 | StringRef Arg = "", | |||
635 | DeclarationFragments::FragmentKind ArgKind = | |||
636 | DeclarationFragments::FragmentKind::Identifier) { | |||
637 | // Check if the `Kind` attribute is set for this property. | |||
638 | if ((Attributes & Kind) && !Spelling.empty()) { | |||
639 | // Add a leading comma if this is not the first attribute rendered. | |||
640 | if (!First) | |||
641 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
642 | // Render the spelling of this attribute `Kind` as a keyword. | |||
643 | Fragments.append(Spelling, | |||
644 | DeclarationFragments::FragmentKind::Keyword); | |||
645 | // If this attribute takes in arguments (e.g. `getter=getterName`), | |||
646 | // render the arguments. | |||
647 | if (!Arg.empty()) | |||
648 | Fragments.append("=", DeclarationFragments::FragmentKind::Text) | |||
649 | .append(Arg, ArgKind); | |||
650 | First = false; | |||
651 | } | |||
652 | }; | |||
653 | ||||
654 | // Go through all possible Objective-C property attributes and render set | |||
655 | // ones. | |||
656 | RenderAttribute(ObjCPropertyAttribute::kind_class, "class"); | |||
657 | RenderAttribute(ObjCPropertyAttribute::kind_direct, "direct"); | |||
658 | RenderAttribute(ObjCPropertyAttribute::kind_nonatomic, "nonatomic"); | |||
659 | RenderAttribute(ObjCPropertyAttribute::kind_atomic, "atomic"); | |||
660 | RenderAttribute(ObjCPropertyAttribute::kind_assign, "assign"); | |||
661 | RenderAttribute(ObjCPropertyAttribute::kind_retain, "retain"); | |||
662 | RenderAttribute(ObjCPropertyAttribute::kind_strong, "strong"); | |||
663 | RenderAttribute(ObjCPropertyAttribute::kind_copy, "copy"); | |||
664 | RenderAttribute(ObjCPropertyAttribute::kind_weak, "weak"); | |||
665 | RenderAttribute(ObjCPropertyAttribute::kind_unsafe_unretained, | |||
666 | "unsafe_unretained"); | |||
667 | RenderAttribute(ObjCPropertyAttribute::kind_readwrite, "readwrite"); | |||
668 | RenderAttribute(ObjCPropertyAttribute::kind_readonly, "readonly"); | |||
669 | RenderAttribute(ObjCPropertyAttribute::kind_getter, "getter", | |||
670 | Property->getGetterName().getAsString()); | |||
671 | RenderAttribute(ObjCPropertyAttribute::kind_setter, "setter", | |||
672 | Property->getSetterName().getAsString()); | |||
673 | ||||
674 | // Render nullability attributes. | |||
675 | if (Attributes & ObjCPropertyAttribute::kind_nullability) { | |||
676 | QualType Type = Property->getType(); | |||
677 | if (const auto Nullability = | |||
678 | AttributedType::stripOuterNullability(Type)) { | |||
679 | if (!First) | |||
680 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
681 | if (*Nullability == NullabilityKind::Unspecified && | |||
682 | (Attributes & ObjCPropertyAttribute::kind_null_resettable)) | |||
683 | Fragments.append("null_resettable", | |||
684 | DeclarationFragments::FragmentKind::Keyword); | |||
685 | else | |||
686 | Fragments.append( | |||
687 | getNullabilitySpelling(*Nullability, /*isContextSensitive=*/true), | |||
688 | DeclarationFragments::FragmentKind::Keyword); | |||
689 | First = false; | |||
690 | } | |||
691 | } | |||
692 | ||||
693 | Fragments.append(")", DeclarationFragments::FragmentKind::Text); | |||
694 | } | |||
695 | ||||
696 | // Build the property type and name, and return the completed fragments. | |||
697 | return Fragments.appendSpace() | |||
698 | .append(getFragmentsForType(Property->getType(), | |||
699 | Property->getASTContext(), After)) | |||
700 | .appendSpace() | |||
701 | .append(Property->getName(), | |||
702 | DeclarationFragments::FragmentKind::Identifier) | |||
703 | .append(std::move(After)); | |||
704 | } | |||
705 | ||||
706 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol( | |||
707 | const ObjCProtocolDecl *Protocol) { | |||
708 | DeclarationFragments Fragments; | |||
709 | // Build basic protocol declaration. | |||
710 | Fragments.append("@protocol", DeclarationFragments::FragmentKind::Keyword) | |||
711 | .appendSpace() | |||
712 | .append(Protocol->getName(), | |||
713 | DeclarationFragments::FragmentKind::Identifier); | |||
714 | ||||
715 | // If this protocol conforms to other protocols, build the conformance list. | |||
716 | if (!Protocol->protocols().empty()) { | |||
717 | Fragments.append(" <", DeclarationFragments::FragmentKind::Text); | |||
718 | for (ObjCProtocolDecl::protocol_iterator It = Protocol->protocol_begin(); | |||
719 | It != Protocol->protocol_end(); It++) { | |||
720 | // Add a leading comma if this is not the first protocol rendered. | |||
721 | if (It != Protocol->protocol_begin()) | |||
722 | Fragments.append(", ", DeclarationFragments::FragmentKind::Text); | |||
723 | ||||
724 | SmallString<128> USR; | |||
725 | index::generateUSRForDecl(*It, USR); | |||
726 | Fragments.append((*It)->getName(), | |||
727 | DeclarationFragments::FragmentKind::TypeIdentifier, USR, | |||
728 | *It); | |||
729 | } | |||
730 | Fragments.append(">", DeclarationFragments::FragmentKind::Text); | |||
731 | } | |||
732 | ||||
733 | return Fragments; | |||
734 | } | |||
735 | ||||
736 | DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForTypedef( | |||
737 | const TypedefNameDecl *Decl) { | |||
738 | DeclarationFragments Fragments, After; | |||
739 | Fragments.append("typedef", DeclarationFragments::FragmentKind::Keyword) | |||
740 | .appendSpace() | |||
741 | .append(getFragmentsForType(Decl->getUnderlyingType(), | |||
742 | Decl->getASTContext(), After)) | |||
743 | .append(std::move(After)) | |||
744 | .appendSpace() | |||
745 | .append(Decl->getName(), DeclarationFragments::FragmentKind::Identifier); | |||
746 | ||||
747 | return Fragments.append(";", DeclarationFragments::FragmentKind::Text); | |||
748 | } | |||
749 | ||||
750 | template <typename FunctionT> | |||
751 | FunctionSignature | |||
752 | DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) { | |||
753 | FunctionSignature Signature; | |||
754 | ||||
755 | DeclarationFragments ReturnType, After; | |||
756 | ReturnType | |||
757 | .append(getFragmentsForType(Function->getReturnType(), | |||
758 | Function->getASTContext(), After)) | |||
759 | .append(std::move(After)); | |||
760 | Signature.setReturnType(ReturnType); | |||
761 | ||||
762 | for (const auto *Param : Function->parameters()) | |||
763 | Signature.addParameter(Param->getName(), getFragmentsForParam(Param)); | |||
764 | ||||
765 | return Signature; | |||
766 | } | |||
767 | ||||
768 | // Instantiate template for FunctionDecl. | |||
769 | template FunctionSignature | |||
770 | DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *); | |||
771 | ||||
772 | // Instantiate template for ObjCMethodDecl. | |||
773 | template FunctionSignature | |||
774 | DeclarationFragmentsBuilder::getFunctionSignature(const ObjCMethodDecl *); | |||
775 | ||||
776 | // Subheading of a symbol defaults to its name. | |||
777 | DeclarationFragments | |||
778 | DeclarationFragmentsBuilder::getSubHeading(const NamedDecl *Decl) { | |||
779 | DeclarationFragments Fragments; | |||
780 | if (!Decl->getName().empty()) | |||
781 | Fragments.append(Decl->getName(), | |||
782 | DeclarationFragments::FragmentKind::Identifier); | |||
783 | return Fragments; | |||
784 | } | |||
785 | ||||
786 | // Subheading of an Objective-C method is a `+` or `-` sign indicating whether | |||
787 | // it's a class method or an instance method, followed by the selector name. | |||
788 | DeclarationFragments | |||
789 | DeclarationFragmentsBuilder::getSubHeading(const ObjCMethodDecl *Method) { | |||
790 | DeclarationFragments Fragments; | |||
791 | if (Method->isClassMethod()) | |||
792 | Fragments.append("+ ", DeclarationFragments::FragmentKind::Text); | |||
793 | else if (Method->isInstanceMethod()) | |||
794 | Fragments.append("- ", DeclarationFragments::FragmentKind::Text); | |||
795 | ||||
796 | return Fragments.append(Method->getNameAsString(), | |||
797 | DeclarationFragments::FragmentKind::Identifier); | |||
798 | } | |||
799 | ||||
800 | // Subheading of a symbol defaults to its name. | |||
801 | DeclarationFragments | |||
802 | DeclarationFragmentsBuilder::getSubHeadingForMacro(StringRef Name) { | |||
803 | DeclarationFragments Fragments; | |||
804 | Fragments.append(Name, DeclarationFragments::FragmentKind::Identifier); | |||
805 | return Fragments; | |||
806 | } |