Bug Summary

File:build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/clang/lib/ExtractAPI/DeclarationFragments.cpp
Warning:line 166, column 9
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name DeclarationFragments.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm -resource-dir /usr/lib/llvm-16/lib/clang/16.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/clang/lib/ExtractAPI -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/clang/lib/ExtractAPI -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/clang/include -I tools/clang/include -I include -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-16/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-10-03-140002-15933-1 -x c++ /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/clang/lib/ExtractAPI/DeclarationFragments.cpp
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
19using namespace clang::extractapi;
20using namespace llvm;
21
22DeclarationFragments &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
39StringRef 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
69DeclarationFragments::FragmentKind
70DeclarationFragments::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.
91DeclarationFragments
92DeclarationFragmentsBuilder::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);
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 break;
123 }
124
125 case NestedNameSpecifier::Global:
126 // The global specifier `::` at the beginning. No stored value.
127 break;
128
129 case NestedNameSpecifier::Super:
130 // Microsoft's `__super` specifier.
131 Fragments.append("__super", DeclarationFragments::FragmentKind::Keyword);
132 break;
133
134 case NestedNameSpecifier::TypeSpecWithTemplate:
135 // A type prefixed by the `template` keyword.
136 Fragments.append("template", DeclarationFragments::FragmentKind::Keyword);
137 Fragments.appendSpace();
138 // Fallthrough after adding the keyword to handle the actual type.
139 [[fallthrough]];
140
141 case NestedNameSpecifier::TypeSpec: {
142 const Type *T = NNS->getAsType();
143 // FIXME: Handle C++ template specialization type
144 Fragments.append(getFragmentsForType(T, Context, After));
145 break;
146 }
147 }
148
149 // Add the separator text `::` for this segment.
150 return Fragments.append("::", DeclarationFragments::FragmentKind::Text);
151}
152
153// Recursively build the declaration fragments for an underlying `Type` with
154// qualifiers removed.
155DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
156 const Type *T, ASTContext &Context, DeclarationFragments &After) {
157 assert(T && "invalid type")(static_cast <bool> (T && "invalid type") ? void
(0) : __assert_fail ("T && \"invalid type\"", "clang/lib/ExtractAPI/DeclarationFragments.cpp"
, 157, __extension__ __PRETTY_FUNCTION__))
;
7
Assuming 'T' is non-null
8
'?' condition is true
158
159 DeclarationFragments Fragments;
160
161 // Declaration fragments of a pointer type is the declaration fragments of
162 // the pointee type followed by a `*`, except for Objective-C `id` and `Class`
163 // pointers, where we do not spell out the `*`.
164 if (T->isPointerType() ||
165 (T->isObjCObjectPointerType() &&
166 !T->getAs<ObjCObjectPointerType>()->isObjCIdOrClassType())) {
9
Assuming 'T' is not a 'const class clang::ObjCObjectPointerType *'
10
Called C++ object pointer is null
167 return Fragments
168 .append(getFragmentsForType(T->getPointeeType(), Context, After))
169 .append(" *", DeclarationFragments::FragmentKind::Text);
170 }
171
172 // Declaration fragments of a lvalue reference type is the declaration
173 // fragments of the underlying type followed by a `&`.
174 if (const LValueReferenceType *LRT = dyn_cast<LValueReferenceType>(T))
175 return Fragments
176 .append(
177 getFragmentsForType(LRT->getPointeeTypeAsWritten(), Context, After))
178 .append(" &", DeclarationFragments::FragmentKind::Text);
179
180 // Declaration fragments of a rvalue reference type is the declaration
181 // fragments of the underlying type followed by a `&&`.
182 if (const RValueReferenceType *RRT = dyn_cast<RValueReferenceType>(T))
183 return Fragments
184 .append(
185 getFragmentsForType(RRT->getPointeeTypeAsWritten(), Context, After))
186 .append(" &&", DeclarationFragments::FragmentKind::Text);
187
188 // Declaration fragments of an array-typed variable have two parts:
189 // 1. the element type of the array that appears before the variable name;
190 // 2. array brackets `[(0-9)?]` that appear after the variable name.
191 if (const ArrayType *AT = T->getAsArrayTypeUnsafe()) {
192 // Build the "after" part first because the inner element type might also
193 // be an array-type. For example `int matrix[3][4]` which has a type of
194 // "(array 3 of (array 4 of ints))."
195 // Push the array size part first to make sure they are in the right order.
196 After.append("[", DeclarationFragments::FragmentKind::Text);
197
198 switch (AT->getSizeModifier()) {
199 case ArrayType::Normal:
200 break;
201 case ArrayType::Static:
202 Fragments.append("static", DeclarationFragments::FragmentKind::Keyword);
203 break;
204 case ArrayType::Star:
205 Fragments.append("*", DeclarationFragments::FragmentKind::Text);
206 break;
207 }
208
209 if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
210 // FIXME: right now this would evaluate any expressions/macros written in
211 // the original source to concrete values. For example
212 // `int nums[MAX]` -> `int nums[100]`
213 // `char *str[5 + 1]` -> `char *str[6]`
214 SmallString<128> Size;
215 CAT->getSize().toStringUnsigned(Size);
216 After.append(Size, DeclarationFragments::FragmentKind::NumberLiteral);
217 }
218
219 After.append("]", DeclarationFragments::FragmentKind::Text);
220
221 return Fragments.append(
222 getFragmentsForType(AT->getElementType(), Context, After));
223 }
224
225 // An ElaboratedType is a sugar for types that are referred to using an
226 // elaborated keyword, e.g., `struct S`, `enum E`, or (in C++) via a
227 // qualified name, e.g., `N::M::type`, or both.
228 if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(T)) {
229 ElaboratedTypeKeyword Keyword = ET->getKeyword();
230 if (Keyword != ETK_None) {
231 Fragments
232 .append(ElaboratedType::getKeywordName(Keyword),
233 DeclarationFragments::FragmentKind::Keyword)
234 .appendSpace();
235 }
236
237 if (const NestedNameSpecifier *NNS = ET->getQualifier())
238 Fragments.append(getFragmentsForNNS(NNS, Context, After));
239
240 // After handling the elaborated keyword or qualified name, build
241 // declaration fragments for the desugared underlying type.
242 return Fragments.append(getFragmentsForType(ET->desugar(), Context, After));
243 }
244
245 // Everything we care about has been handled now, reduce to the canonical
246 // unqualified base type.
247 QualType Base = T->getCanonicalTypeUnqualified();
248
249 // Render Objective-C `id`/`instancetype` as keywords.
250 if (T->isObjCIdType())
251 return Fragments.append(Base.getAsString(),
252 DeclarationFragments::FragmentKind::Keyword);
253
254 // If the type is a typedefed type, get the underlying TypedefNameDecl for a
255 // direct reference to the typedef instead of the wrapped type.
256 if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(T)) {
257 const TypedefNameDecl *Decl = TypedefTy->getDecl();
258 std::string USR =
259 TypedefUnderlyingTypeResolver(Context).getUSRForType(QualType(T, 0));
260 return Fragments.append(Decl->getName(),
261 DeclarationFragments::FragmentKind::TypeIdentifier,
262 USR);
263 }
264
265 // If the base type is a TagType (struct/interface/union/class/enum), let's
266 // get the underlying Decl for better names and USRs.
267 if (const TagType *TagTy = dyn_cast<TagType>(Base)) {
268 const TagDecl *Decl = TagTy->getDecl();
269 // Anonymous decl, skip this fragment.
270 if (Decl->getName().empty())
271 return Fragments;
272 SmallString<128> TagUSR;
273 clang::index::generateUSRForDecl(Decl, TagUSR);
274 return Fragments.append(Decl->getName(),
275 DeclarationFragments::FragmentKind::TypeIdentifier,
276 TagUSR);
277 }
278
279 // If the base type is an ObjCInterfaceType, use the underlying
280 // ObjCInterfaceDecl for the true USR.
281 if (const auto *ObjCIT = dyn_cast<ObjCInterfaceType>(Base)) {
282 const auto *Decl = ObjCIT->getDecl();
283 SmallString<128> USR;
284 index::generateUSRForDecl(Decl, USR);
285 return Fragments.append(Decl->getName(),
286 DeclarationFragments::FragmentKind::TypeIdentifier,
287 USR);
288 }
289
290 // Default fragment builder for other kinds of types (BuiltinType etc.)
291 SmallString<128> USR;
292 clang::index::generateUSRForType(Base, Context, USR);
293 Fragments.append(Base.getAsString(),
294 DeclarationFragments::FragmentKind::TypeIdentifier, USR);
295
296 return Fragments;
297}
298
299DeclarationFragments
300DeclarationFragmentsBuilder::getFragmentsForQualifiers(const Qualifiers Quals) {
301 DeclarationFragments Fragments;
302 if (Quals.hasConst())
303 Fragments.append("const", DeclarationFragments::FragmentKind::Keyword);
304 if (Quals.hasVolatile())
305 Fragments.append("volatile", DeclarationFragments::FragmentKind::Keyword);
306 if (Quals.hasRestrict())
307 Fragments.append("restrict", DeclarationFragments::FragmentKind::Keyword);
308
309 return Fragments;
310}
311
312DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
313 const QualType QT, ASTContext &Context, DeclarationFragments &After) {
314 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", 314, __extension__
__PRETTY_FUNCTION__))
;
4
'?' condition is true
315
316 if (const ParenType *PT
4.1
'PT' is null
= dyn_cast<ParenType>(QT)) {
5
Taking false branch
317 After.append(")", DeclarationFragments::FragmentKind::Text);
318 return getFragmentsForType(PT->getInnerType(), Context, After)
319 .append("(", DeclarationFragments::FragmentKind::Text);
320 }
321
322 const SplitQualType SQT = QT.split();
323 DeclarationFragments QualsFragments = getFragmentsForQualifiers(SQT.Quals),
324 TypeFragments =
325 getFragmentsForType(SQT.Ty, Context, After);
6
Calling 'DeclarationFragmentsBuilder::getFragmentsForType'
326 if (QualsFragments.getFragments().empty())
327 return TypeFragments;
328
329 // Use east qualifier for pointer types
330 // For example:
331 // ```
332 // int * const
333 // ^---- ^----
334 // type qualifier
335 // ^-----------------
336 // const pointer to int
337 // ```
338 // should not be reconstructed as
339 // ```
340 // const int *
341 // ^---- ^--
342 // qualifier type
343 // ^---------------- ^
344 // pointer to const int
345 // ```
346 if (SQT.Ty->isAnyPointerType())
347 return TypeFragments.appendSpace().append(std::move(QualsFragments));
348
349 return QualsFragments.appendSpace().append(std::move(TypeFragments));
350}
351
352DeclarationFragments
353DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) {
354 DeclarationFragments Fragments;
355 StorageClass SC = Var->getStorageClass();
356 if (SC != SC_None)
357 Fragments
358 .append(VarDecl::getStorageClassSpecifierString(SC),
359 DeclarationFragments::FragmentKind::Keyword)
360 .appendSpace();
361 QualType T =
362 Var->getTypeSourceInfo()
363 ? Var->getTypeSourceInfo()->getType()
364 : Var->getASTContext().getUnqualifiedObjCPointerType(Var->getType());
365
366 // Capture potential fragments that needs to be placed after the variable name
367 // ```
368 // int nums[5];
369 // char (*ptr_to_array)[6];
370 // ```
371 DeclarationFragments After;
372 return Fragments.append(getFragmentsForType(T, Var->getASTContext(), After))
373 .appendSpace()
374 .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier)
375 .append(std::move(After));
376}
377
378DeclarationFragments
379DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) {
380 DeclarationFragments Fragments, After;
381
382 QualType T = Param->getTypeSourceInfo()
383 ? Param->getTypeSourceInfo()->getType()
384 : Param->getASTContext().getUnqualifiedObjCPointerType(
385 Param->getType());
386
387 DeclarationFragments TypeFragments =
388 getFragmentsForType(T, Param->getASTContext(), After);
389
390 if (Param->isObjCMethodParameter())
391 Fragments.append("(", DeclarationFragments::FragmentKind::Text)
392 .append(std::move(TypeFragments))
393 .append(") ", DeclarationFragments::FragmentKind::Text);
394 else
395 Fragments.append(std::move(TypeFragments)).appendSpace();
396
397 return Fragments
398 .append(Param->getName(),
399 DeclarationFragments::FragmentKind::InternalParam)
400 .append(std::move(After));
401}
402
403DeclarationFragments
404DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) {
405 DeclarationFragments Fragments;
406 // FIXME: Handle template specialization
407 switch (Func->getStorageClass()) {
408 case SC_None:
409 case SC_PrivateExtern:
410 break;
411 case SC_Extern:
412 Fragments.append("extern", DeclarationFragments::FragmentKind::Keyword)
413 .appendSpace();
414 break;
415 case SC_Static:
416 Fragments.append("static", DeclarationFragments::FragmentKind::Keyword)
417 .appendSpace();
418 break;
419 case SC_Auto:
420 case SC_Register:
421 llvm_unreachable("invalid for functions")::llvm::llvm_unreachable_internal("invalid for functions", "clang/lib/ExtractAPI/DeclarationFragments.cpp"
, 421)
;
422 }
423 // FIXME: Handle C++ function specifiers: constexpr, consteval, explicit, etc.
424
425 // FIXME: Is `after` actually needed here?
426 DeclarationFragments After;
427 Fragments
428 .append(getFragmentsForType(Func->getReturnType(), Func->getASTContext(),
429 After))
430 .appendSpace()
431 .append(Func->getName(), DeclarationFragments::FragmentKind::Identifier)
432 .append(std::move(After));
433
434 Fragments.append("(", DeclarationFragments::FragmentKind::Text);
435 for (unsigned i = 0, end = Func->getNumParams(); i != end; ++i) {
436 if (i)
437 Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
438 Fragments.append(getFragmentsForParam(Func->getParamDecl(i)));
439 }
440 Fragments.append(")", DeclarationFragments::FragmentKind::Text);
441
442 // FIXME: Handle exception specifiers: throw, noexcept
443 return Fragments;
444}
445
446DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForEnumConstant(
447 const EnumConstantDecl *EnumConstDecl) {
448 DeclarationFragments Fragments;
449 return Fragments.append(EnumConstDecl->getName(),
450 DeclarationFragments::FragmentKind::Identifier);
451}
452
453DeclarationFragments
454DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) {
455 if (const auto *TypedefNameDecl = EnumDecl->getTypedefNameForAnonDecl())
456 return getFragmentsForTypedef(TypedefNameDecl);
457
458 DeclarationFragments Fragments, After;
459 Fragments.append("enum", DeclarationFragments::FragmentKind::Keyword);
460
461 if (!EnumDecl->getName().empty())
462 Fragments.appendSpace().append(
463 EnumDecl->getName(), DeclarationFragments::FragmentKind::Identifier);
464
465 QualType IntegerType = EnumDecl->getIntegerType();
466 if (!IntegerType.isNull())
467 Fragments.append(": ", DeclarationFragments::FragmentKind::Text)
468 .append(
469 getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After))
470 .append(std::move(After));
471
472 return Fragments;
473}
474
475DeclarationFragments
476DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) {
477 DeclarationFragments After;
478 return getFragmentsForType(Field->getType(), Field->getASTContext(), After)
479 .appendSpace()
480 .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier)
481 .append(std::move(After));
482}
483
484DeclarationFragments
485DeclarationFragmentsBuilder::getFragmentsForStruct(const RecordDecl *Record) {
486 if (const auto *TypedefNameDecl = Record->getTypedefNameForAnonDecl())
487 return getFragmentsForTypedef(TypedefNameDecl);
488
489 DeclarationFragments Fragments;
490 Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword);
491
492 if (!Record->getName().empty())
493 Fragments.appendSpace().append(
494 Record->getName(), DeclarationFragments::FragmentKind::Identifier);
495 return Fragments;
496}
497
498DeclarationFragments
499DeclarationFragmentsBuilder::getFragmentsForMacro(StringRef Name,
500 const MacroDirective *MD) {
501 DeclarationFragments Fragments;
502 Fragments.append("#define", DeclarationFragments::FragmentKind::Keyword)
503 .appendSpace();
504 Fragments.append(Name, DeclarationFragments::FragmentKind::Identifier);
505
506 auto *MI = MD->getMacroInfo();
507
508 if (MI->isFunctionLike()) {
509 Fragments.append("(", DeclarationFragments::FragmentKind::Text);
510 unsigned numParameters = MI->getNumParams();
511 if (MI->isC99Varargs())
512 --numParameters;
513 for (unsigned i = 0; i < numParameters; ++i) {
514 if (i)
515 Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
516 Fragments.append(MI->params()[i]->getName(),
517 DeclarationFragments::FragmentKind::InternalParam);
518 }
519 if (MI->isVariadic()) {
520 if (numParameters && MI->isC99Varargs())
521 Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
522 Fragments.append("...", DeclarationFragments::FragmentKind::Text);
523 }
524 Fragments.append(")", DeclarationFragments::FragmentKind::Text);
525 }
526 return Fragments;
527}
528
529DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCCategory(
530 const ObjCCategoryDecl *Category) {
531 DeclarationFragments Fragments;
532
533 SmallString<128> InterfaceUSR;
534 index::generateUSRForDecl(Category->getClassInterface(), InterfaceUSR);
535
536 Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword)
537 .appendSpace()
538 .append(Category->getClassInterface()->getName(),
539 DeclarationFragments::FragmentKind::TypeIdentifier, InterfaceUSR)
540 .append(" (", DeclarationFragments::FragmentKind::Text)
541 .append(Category->getName(),
542 DeclarationFragments::FragmentKind::Identifier)
543 .append(")", DeclarationFragments::FragmentKind::Text);
544
545 return Fragments;
546}
547
548DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCInterface(
549 const ObjCInterfaceDecl *Interface) {
550 DeclarationFragments Fragments;
551 // Build the base of the Objective-C interface declaration.
552 Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword)
553 .appendSpace()
554 .append(Interface->getName(),
555 DeclarationFragments::FragmentKind::Identifier);
556
557 // Build the inheritance part of the declaration.
558 if (const ObjCInterfaceDecl *SuperClass = Interface->getSuperClass()) {
559 SmallString<128> SuperUSR;
560 index::generateUSRForDecl(SuperClass, SuperUSR);
561 Fragments.append(" : ", DeclarationFragments::FragmentKind::Text)
562 .append(SuperClass->getName(),
563 DeclarationFragments::FragmentKind::TypeIdentifier, SuperUSR);
564 }
565
566 return Fragments;
567}
568
569DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCMethod(
570 const ObjCMethodDecl *Method) {
571 DeclarationFragments Fragments, After;
572 // Build the instance/class method indicator.
573 if (Method->isClassMethod())
574 Fragments.append("+ ", DeclarationFragments::FragmentKind::Text);
575 else if (Method->isInstanceMethod())
576 Fragments.append("- ", DeclarationFragments::FragmentKind::Text);
577
578 // Build the return type.
579 Fragments.append("(", DeclarationFragments::FragmentKind::Text)
580 .append(getFragmentsForType(Method->getReturnType(),
581 Method->getASTContext(), After))
582 .append(std::move(After))
583 .append(")", DeclarationFragments::FragmentKind::Text);
584
585 // Build the selector part.
586 Selector Selector = Method->getSelector();
587 if (Selector.getNumArgs() == 0)
588 // For Objective-C methods that don't take arguments, the first (and only)
589 // slot of the selector is the method name.
590 Fragments.appendSpace().append(
591 Selector.getNameForSlot(0),
592 DeclarationFragments::FragmentKind::Identifier);
593
594 // For Objective-C methods that take arguments, build the selector slots.
595 for (unsigned i = 0, end = Method->param_size(); i != end; ++i) {
596 // Objective-C method selector parts are considered as identifiers instead
597 // of "external parameters" as in Swift. This is because Objective-C method
598 // symbols are referenced with the entire selector, instead of just the
599 // method name in Swift.
600 SmallString<32> ParamID(Selector.getNameForSlot(i));
601 ParamID.append(":");
602 Fragments.appendSpace().append(
603 ParamID, DeclarationFragments::FragmentKind::Identifier);
604
605 // Build the internal parameter.
606 const ParmVarDecl *Param = Method->getParamDecl(i);
607 Fragments.append(getFragmentsForParam(Param));
608 }
609
610 return Fragments.append(";", DeclarationFragments::FragmentKind::Text);
611}
612
613DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty(
614 const ObjCPropertyDecl *Property) {
615 DeclarationFragments Fragments, After;
616
617 // Build the Objective-C property keyword.
618 Fragments.append("@property", DeclarationFragments::FragmentKind::Keyword);
619
620 const auto Attributes = Property->getPropertyAttributes();
621 // Build the attributes if there is any associated with the property.
622 if (Attributes != ObjCPropertyAttribute::kind_noattr) {
1
Assuming 'Attributes' is equal to kind_noattr
2
Taking false branch
623 // No leading comma for the first attribute.
624 bool First = true;
625 Fragments.append(" (", DeclarationFragments::FragmentKind::Text);
626 // Helper function to render the attribute.
627 auto RenderAttribute =
628 [&](ObjCPropertyAttribute::Kind Kind, StringRef Spelling,
629 StringRef Arg = "",
630 DeclarationFragments::FragmentKind ArgKind =
631 DeclarationFragments::FragmentKind::Identifier) {
632 // Check if the `Kind` attribute is set for this property.
633 if ((Attributes & Kind) && !Spelling.empty()) {
634 // Add a leading comma if this is not the first attribute rendered.
635 if (!First)
636 Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
637 // Render the spelling of this attribute `Kind` as a keyword.
638 Fragments.append(Spelling,
639 DeclarationFragments::FragmentKind::Keyword);
640 // If this attribute takes in arguments (e.g. `getter=getterName`),
641 // render the arguments.
642 if (!Arg.empty())
643 Fragments.append("=", DeclarationFragments::FragmentKind::Text)
644 .append(Arg, ArgKind);
645 First = false;
646 }
647 };
648
649 // Go through all possible Objective-C property attributes and render set
650 // ones.
651 RenderAttribute(ObjCPropertyAttribute::kind_class, "class");
652 RenderAttribute(ObjCPropertyAttribute::kind_direct, "direct");
653 RenderAttribute(ObjCPropertyAttribute::kind_nonatomic, "nonatomic");
654 RenderAttribute(ObjCPropertyAttribute::kind_atomic, "atomic");
655 RenderAttribute(ObjCPropertyAttribute::kind_assign, "assign");
656 RenderAttribute(ObjCPropertyAttribute::kind_retain, "retain");
657 RenderAttribute(ObjCPropertyAttribute::kind_strong, "strong");
658 RenderAttribute(ObjCPropertyAttribute::kind_copy, "copy");
659 RenderAttribute(ObjCPropertyAttribute::kind_weak, "weak");
660 RenderAttribute(ObjCPropertyAttribute::kind_unsafe_unretained,
661 "unsafe_unretained");
662 RenderAttribute(ObjCPropertyAttribute::kind_readwrite, "readwrite");
663 RenderAttribute(ObjCPropertyAttribute::kind_readonly, "readonly");
664 RenderAttribute(ObjCPropertyAttribute::kind_getter, "getter",
665 Property->getGetterName().getAsString());
666 RenderAttribute(ObjCPropertyAttribute::kind_setter, "setter",
667 Property->getSetterName().getAsString());
668
669 // Render nullability attributes.
670 if (Attributes & ObjCPropertyAttribute::kind_nullability) {
671 QualType Type = Property->getType();
672 if (const auto Nullability =
673 AttributedType::stripOuterNullability(Type)) {
674 if (!First)
675 Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
676 if (*Nullability == NullabilityKind::Unspecified &&
677 (Attributes & ObjCPropertyAttribute::kind_null_resettable))
678 Fragments.append("null_resettable",
679 DeclarationFragments::FragmentKind::Keyword);
680 else
681 Fragments.append(
682 getNullabilitySpelling(*Nullability, /*isContextSensitive=*/true),
683 DeclarationFragments::FragmentKind::Keyword);
684 First = false;
685 }
686 }
687
688 Fragments.append(")", DeclarationFragments::FragmentKind::Text);
689 }
690
691 // Build the property type and name, and return the completed fragments.
692 return Fragments.appendSpace()
693 .append(getFragmentsForType(Property->getType(),
3
Calling 'DeclarationFragmentsBuilder::getFragmentsForType'
694 Property->getASTContext(), After))
695 .appendSpace()
696 .append(Property->getName(),
697 DeclarationFragments::FragmentKind::Identifier)
698 .append(std::move(After));
699}
700
701DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(
702 const ObjCProtocolDecl *Protocol) {
703 DeclarationFragments Fragments;
704 // Build basic protocol declaration.
705 Fragments.append("@protocol", DeclarationFragments::FragmentKind::Keyword)
706 .appendSpace()
707 .append(Protocol->getName(),
708 DeclarationFragments::FragmentKind::Identifier);
709
710 // If this protocol conforms to other protocols, build the conformance list.
711 if (!Protocol->protocols().empty()) {
712 Fragments.append(" <", DeclarationFragments::FragmentKind::Text);
713 for (ObjCProtocolDecl::protocol_iterator It = Protocol->protocol_begin();
714 It != Protocol->protocol_end(); It++) {
715 // Add a leading comma if this is not the first protocol rendered.
716 if (It != Protocol->protocol_begin())
717 Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
718
719 SmallString<128> USR;
720 index::generateUSRForDecl(*It, USR);
721 Fragments.append((*It)->getName(),
722 DeclarationFragments::FragmentKind::TypeIdentifier, USR);
723 }
724 Fragments.append(">", DeclarationFragments::FragmentKind::Text);
725 }
726
727 return Fragments;
728}
729
730DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForTypedef(
731 const TypedefNameDecl *Decl) {
732 DeclarationFragments Fragments, After;
733 Fragments.append("typedef", DeclarationFragments::FragmentKind::Keyword)
734 .appendSpace()
735 .append(getFragmentsForType(Decl->getUnderlyingType(),
736 Decl->getASTContext(), After))
737 .append(std::move(After))
738 .appendSpace()
739 .append(Decl->getName(), DeclarationFragments::FragmentKind::Identifier);
740
741 return Fragments;
742}
743
744template <typename FunctionT>
745FunctionSignature
746DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) {
747 FunctionSignature Signature;
748
749 DeclarationFragments ReturnType, After;
750 ReturnType
751 .append(getFragmentsForType(Function->getReturnType(),
752 Function->getASTContext(), After))
753 .append(std::move(After));
754 Signature.setReturnType(ReturnType);
755
756 for (const auto *Param : Function->parameters())
757 Signature.addParameter(Param->getName(), getFragmentsForParam(Param));
758
759 return Signature;
760}
761
762// Instantiate template for FunctionDecl.
763template FunctionSignature
764DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *);
765
766// Instantiate template for ObjCMethodDecl.
767template FunctionSignature
768DeclarationFragmentsBuilder::getFunctionSignature(const ObjCMethodDecl *);
769
770// Subheading of a symbol defaults to its name.
771DeclarationFragments
772DeclarationFragmentsBuilder::getSubHeading(const NamedDecl *Decl) {
773 DeclarationFragments Fragments;
774 if (!Decl->getName().empty())
775 Fragments.append(Decl->getName(),
776 DeclarationFragments::FragmentKind::Identifier);
777 return Fragments;
778}
779
780// Subheading of an Objective-C method is a `+` or `-` sign indicating whether
781// it's a class method or an instance method, followed by the selector name.
782DeclarationFragments
783DeclarationFragmentsBuilder::getSubHeading(const ObjCMethodDecl *Method) {
784 DeclarationFragments Fragments;
785 if (Method->isClassMethod())
786 Fragments.append("+ ", DeclarationFragments::FragmentKind::Text);
787 else if (Method->isInstanceMethod())
788 Fragments.append("- ", DeclarationFragments::FragmentKind::Text);
789
790 return Fragments.append(Method->getNameAsString(),
791 DeclarationFragments::FragmentKind::Identifier);
792}
793
794// Subheading of a symbol defaults to its name.
795DeclarationFragments
796DeclarationFragmentsBuilder::getSubHeadingForMacro(StringRef Name) {
797 DeclarationFragments Fragments;
798 Fragments.append(Name, DeclarationFragments::FragmentKind::Identifier);
799 return Fragments;
800}