Bug Summary

File:build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/clang-tools-extra/clangd/refactor/tweaks/ObjCMemberwiseInitializer.cpp
Warning:line 111, column 27
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 ObjCMemberwiseInitializer.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/tools/clang/stage2-bins -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/tools/extra/clangd/refactor/tweaks -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/clang-tools-extra/clangd/refactor/tweaks -I tools/clang/tools/extra/clangd/../clang-tidy -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 -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/clang-tools-extra/clangd -I tools/clang/tools/extra/clangd -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/clang-tools-extra/clangd/refactor/tweaks/../.. -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/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -O2 -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/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -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-tools-extra/clangd/refactor/tweaks/ObjCMemberwiseInitializer.cpp

/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/clang-tools-extra/clangd/refactor/tweaks/ObjCMemberwiseInitializer.cpp

1//===--- ObjCMemberwiseInitializer.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#include "ParsedAST.h"
10#include "SourceCode.h"
11#include "refactor/InsertionPoint.h"
12#include "refactor/Tweak.h"
13#include "support/Logger.h"
14#include "clang/AST/DeclObjC.h"
15#include "clang/AST/PrettyPrinter.h"
16#include "clang/Basic/LLVM.h"
17#include "clang/Basic/LangOptions.h"
18#include "clang/Basic/SourceLocation.h"
19#include "clang/Basic/SourceManager.h"
20#include "clang/Tooling/Core/Replacement.h"
21#include "llvm/ADT/None.h"
22#include "llvm/ADT/Optional.h"
23#include "llvm/ADT/StringRef.h"
24#include "llvm/ADT/iterator_range.h"
25#include "llvm/Support/Casting.h"
26#include "llvm/Support/Error.h"
27
28namespace clang {
29namespace clangd {
30namespace {
31
32static std::string capitalize(std::string Message) {
33 if (!Message.empty())
34 Message[0] = llvm::toUpper(Message[0]);
35 return Message;
36}
37
38static std::string getTypeStr(const QualType &OrigT, const Decl &D,
39 unsigned PropertyAttributes) {
40 QualType T = OrigT;
41 PrintingPolicy Policy(D.getASTContext().getLangOpts());
42 Policy.SuppressStrongLifetime = true;
43 std::string Prefix;
44 // If the nullability is specified via a property attribute, use the shorter
45 // `nullable` form for the method parameter.
46 if (PropertyAttributes & ObjCPropertyAttribute::kind_nullability) {
47 if (auto Kind = AttributedType::stripOuterNullability(T)) {
48 switch (*Kind) {
49 case NullabilityKind::Nullable:
50 Prefix = "nullable ";
51 break;
52 case NullabilityKind::NonNull:
53 Prefix = "nonnull ";
54 break;
55 case NullabilityKind::Unspecified:
56 Prefix = "null_unspecified ";
57 break;
58 case NullabilityKind::NullableResult:
59 T = OrigT;
60 break;
61 }
62 }
63 }
64 return Prefix + T.getAsString(Policy);
65}
66
67struct MethodParameter {
68 // Parameter name.
69 llvm::StringRef Name;
70
71 // Type of the parameter.
72 std::string Type;
73
74 // Assignment target (LHS).
75 std::string Assignee;
76
77 MethodParameter(const ObjCIvarDecl &ID) {
78 // Convention maps `@property int foo` to ivar `int _foo`, so drop the
79 // leading `_` if there is one.
80 Name = ID.getName();
81 Name.consume_front("_");
82 Type = getTypeStr(ID.getType(), ID, ObjCPropertyAttribute::kind_noattr);
83 Assignee = ID.getName().str();
84 }
85 MethodParameter(const ObjCPropertyDecl &PD) {
86 Name = PD.getName();
87 Type = getTypeStr(PD.getType(), PD, PD.getPropertyAttributes());
88 if (const auto *ID = PD.getPropertyIvarDecl())
89 Assignee = ID->getName().str();
90 else // Could be a dynamic property or a property in a header.
91 Assignee = ("self." + Name).str();
92 }
93 static llvm::Optional<MethodParameter> parameterFor(const Decl &D) {
94 if (const auto *ID = dyn_cast<ObjCIvarDecl>(&D))
95 return MethodParameter(*ID);
96 if (const auto *PD = dyn_cast<ObjCPropertyDecl>(&D))
97 if (PD->isInstanceProperty())
98 return MethodParameter(*PD);
99 return llvm::None;
100 }
101};
102
103static SmallVector<MethodParameter, 8>
104getAllParams(const ObjCInterfaceDecl *ID) {
105 SmallVector<MethodParameter, 8> Params;
106 // Currently we only generate based on the ivars and properties declared
107 // in the interface. We could consider expanding this to include visible
108 // categories + class extensions in the future (see
109 // all_declared_ivar_begin).
110 llvm::DenseSet<llvm::StringRef> Names;
111 for (const auto *Ivar : ID->ivars()) {
19
Called C++ object pointer is null
112 MethodParameter P(*Ivar);
113 if (Names.insert(P.Name).second)
114 Params.push_back(P);
115 }
116 for (const auto *Prop : ID->properties()) {
117 MethodParameter P(*Prop);
118 if (Names.insert(P.Name).second)
119 Params.push_back(P);
120 }
121 return Params;
122}
123
124static std::string
125initializerForParams(const SmallVector<MethodParameter, 8> &Params,
126 bool GenerateImpl) {
127 std::string Code;
128 llvm::raw_string_ostream Stream(Code);
129
130 if (Params.empty()) {
131 if (GenerateImpl) {
132 Stream <<
133 R"cpp(- (instancetype)init {
134 self = [super init];
135 if (self) {
136
137 }
138 return self;
139})cpp";
140 } else {
141 Stream << "- (instancetype)init;";
142 }
143 } else {
144 const auto &First = Params.front();
145 Stream << llvm::formatv("- (instancetype)initWith{0}:({1}){2}",
146 capitalize(First.Name.trim().str()), First.Type,
147 First.Name);
148 for (const auto &It : llvm::drop_begin(Params))
149 Stream << llvm::formatv(" {0}:({1}){0}", It.Name, It.Type);
150
151 if (GenerateImpl) {
152 Stream <<
153 R"cpp( {
154 self = [super init];
155 if (self) {)cpp";
156 for (const auto &Param : Params)
157 Stream << llvm::formatv("\n {0} = {1};", Param.Assignee, Param.Name);
158 Stream <<
159 R"cpp(
160 }
161 return self;
162})cpp";
163 } else {
164 Stream << ";";
165 }
166 }
167 Stream << "\n\n";
168 return Code;
169}
170
171/// Generate an initializer for an Objective-C class based on selected
172/// properties and instance variables.
173class ObjCMemberwiseInitializer : public Tweak {
174public:
175 const char *id() const final;
176 llvm::StringLiteral kind() const override {
177 return CodeAction::REFACTOR_KIND;
178 }
179
180 bool prepare(const Selection &Inputs) override;
181 Expected<Tweak::Effect> apply(const Selection &Inputs) override;
182 std::string title() const override;
183
184private:
185 SmallVector<MethodParameter, 8>
186 paramsForSelection(const SelectionTree::Node *N);
187
188 const ObjCInterfaceDecl *Interface = nullptr;
189
190 // Will be nullptr if running on an interface.
191 const ObjCImplementationDecl *Impl = nullptr;
192};
193
194REGISTER_TWEAK(ObjCMemberwiseInitializer)::llvm::Registry<::clang::clangd::Tweak>::Add<ObjCMemberwiseInitializer
> TweakRegistrationForObjCMemberwiseInitializer("ObjCMemberwiseInitializer"
, ""); const char *ObjCMemberwiseInitializer::id() const { return
"ObjCMemberwiseInitializer"; }
195
196bool ObjCMemberwiseInitializer::prepare(const Selection &Inputs) {
197 const SelectionTree::Node *N = Inputs.ASTSelection.commonAncestor();
198 if (!N)
199 return false;
200 const Decl *D = N->ASTNode.get<Decl>();
201 if (!D)
202 return false;
203 const auto &LangOpts = Inputs.AST->getLangOpts();
204 // Require ObjC w/ arc enabled since we don't emit retains.
205 if (!LangOpts.ObjC || !LangOpts.ObjCAutoRefCount)
206 return false;
207
208 // We support the following selected decls:
209 // - ObjCInterfaceDecl/ObjCImplementationDecl only - generate for all
210 // properties and ivars
211 //
212 // - Specific ObjCPropertyDecl(s)/ObjCIvarDecl(s) - generate only for those
213 // selected. Note that if only one is selected, the common ancestor will be
214 // the ObjCPropertyDecl/ObjCIvarDecl itself instead of the container.
215 if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
216 // Ignore forward declarations (@class Name;).
217 if (!ID->isThisDeclarationADefinition())
218 return false;
219 Interface = ID;
220 } else if (const auto *ID = dyn_cast<ObjCImplementationDecl>(D)) {
221 Interface = ID->getClassInterface();
222 Impl = ID;
223 } else if (isa<ObjCPropertyDecl, ObjCIvarDecl>(D)) {
224 const auto *DC = D->getDeclContext();
225 if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(DC)) {
226 Interface = ID;
227 } else if (const auto *ID = dyn_cast<ObjCImplementationDecl>(DC)) {
228 Interface = ID->getClassInterface();
229 Impl = ID;
230 }
231 }
232 return Interface != nullptr;
233}
234
235SmallVector<MethodParameter, 8>
236ObjCMemberwiseInitializer::paramsForSelection(const SelectionTree::Node *N) {
237 SmallVector<MethodParameter, 8> Params;
238 // Base case: selected a single ivar or property.
239 if (const auto *D
11.1
'D' is null
11.1
'D' is null
= N->ASTNode.get<Decl>()) {
4
Calling 'DynTypedNode::get'
11
Returning from 'DynTypedNode::get'
240 if (auto Param = MethodParameter::parameterFor(*D)) {
241 Params.push_back(*Param);
242 return Params;
243 }
244 }
245 const ObjCContainerDecl *Container =
12
Taking false branch
246 Impl ? static_cast<const ObjCContainerDecl *>(Impl)
13
Assuming field 'Impl' is null
14
'?' condition is false
247 : static_cast<const ObjCContainerDecl *>(Interface);
248 if (Container == N->ASTNode.get<ObjCContainerDecl>() && N->Children.empty())
15
Assuming pointer value is null
16
Taking true branch
249 return getAllParams(Interface);
17
Passing null pointer value via 1st parameter 'ID'
18
Calling 'getAllParams'
250
251 llvm::DenseSet<llvm::StringRef> Names;
252 // Check for selecting multiple ivars/properties.
253 for (const auto *CNode : N->Children) {
254 const Decl *D = CNode->ASTNode.get<Decl>();
255 if (!D)
256 continue;
257 if (auto P = MethodParameter::parameterFor(*D))
258 if (Names.insert(P->Name).second)
259 Params.push_back(*P);
260 }
261 return Params;
262}
263
264Expected<Tweak::Effect>
265ObjCMemberwiseInitializer::apply(const Selection &Inputs) {
266 const auto &SM = Inputs.AST->getASTContext().getSourceManager();
267 const SelectionTree::Node *N = Inputs.ASTSelection.commonAncestor();
268 if (!N)
1
Assuming 'N' is non-null
2
Taking false branch
269 return error("Invalid selection");
270
271 SmallVector<MethodParameter, 8> Params = paramsForSelection(N);
3
Calling 'ObjCMemberwiseInitializer::paramsForSelection'
272
273 // Insert before the first non-init instance method.
274 std::vector<Anchor> Anchors = {
275 {[](const Decl *D) {
276 if (const auto *MD = llvm::dyn_cast<ObjCMethodDecl>(D)) {
277 return MD->getMethodFamily() != OMF_init && MD->isInstanceMethod();
278 }
279 return false;
280 },
281 Anchor::Above}};
282 Effect E;
283
284 auto InterfaceReplacement =
285 insertDecl(initializerForParams(Params, /*GenerateImpl=*/false),
286 *Interface, Anchors);
287 if (!InterfaceReplacement)
288 return InterfaceReplacement.takeError();
289 auto FE = Effect::fileEdit(SM, SM.getFileID(Interface->getLocation()),
290 tooling::Replacements(*InterfaceReplacement));
291 if (!FE)
292 return FE.takeError();
293 E.ApplyEdits.insert(std::move(*FE));
294
295 if (Impl) {
296 // If we see the class implementation, add the initializer there too.
297 // FIXME: merging the edits is awkward, do this elsewhere.
298 auto ImplReplacement = insertDecl(
299 initializerForParams(Params, /*GenerateImpl=*/true), *Impl, Anchors);
300 if (!ImplReplacement)
301 return ImplReplacement.takeError();
302
303 if (SM.isWrittenInSameFile(Interface->getLocation(), Impl->getLocation())) {
304 // Merge with previous edit if they are in the same file.
305 if (auto Err =
306 E.ApplyEdits.begin()->second.Replacements.add(*ImplReplacement))
307 return std::move(Err);
308 } else {
309 // Generate a new edit if the interface and implementation are in
310 // different files.
311 auto FE = Effect::fileEdit(SM, SM.getFileID(Impl->getLocation()),
312 tooling::Replacements(*ImplReplacement));
313 if (!FE)
314 return FE.takeError();
315 E.ApplyEdits.insert(std::move(*FE));
316 }
317 }
318 return E;
319}
320
321std::string ObjCMemberwiseInitializer::title() const {
322 if (Impl)
323 return "Generate memberwise initializer";
324 return "Declare memberwise initializer";
325}
326
327} // namespace
328} // namespace clangd
329} // namespace clang

/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/clang/include/clang/AST/ASTTypeTraits.h

1//===--- ASTTypeTraits.h ----------------------------------------*- 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// Provides a dynamic type identifier and a dynamically typed node container
10// that can be used to store an AST base node at runtime in the same storage in
11// a type safe way.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_AST_ASTTYPETRAITS_H
16#define LLVM_CLANG_AST_ASTTYPETRAITS_H
17
18#include "clang/AST/ASTFwd.h"
19#include "clang/AST/DeclCXX.h"
20#include "clang/AST/LambdaCapture.h"
21#include "clang/AST/NestedNameSpecifier.h"
22#include "clang/AST/TemplateBase.h"
23#include "clang/AST/TypeLoc.h"
24#include "clang/Basic/LLVM.h"
25#include "llvm/ADT/DenseMapInfo.h"
26#include "llvm/Support/AlignOf.h"
27
28namespace llvm {
29class raw_ostream;
30} // namespace llvm
31
32namespace clang {
33
34struct PrintingPolicy;
35
36/// Defines how we descend a level in the AST when we pass
37/// through expressions.
38enum TraversalKind {
39 /// Will traverse all child nodes.
40 TK_AsIs,
41
42 /// Ignore AST nodes not written in the source
43 TK_IgnoreUnlessSpelledInSource
44};
45
46/// Kind identifier.
47///
48/// It can be constructed from any node kind and allows for runtime type
49/// hierarchy checks.
50/// Use getFromNodeKind<T>() to construct them.
51class ASTNodeKind {
52public:
53 /// Empty identifier. It matches nothing.
54 ASTNodeKind() : KindId(NKI_None) {}
55
56 /// Construct an identifier for T.
57 template <class T>
58 static ASTNodeKind getFromNodeKind() {
59 return ASTNodeKind(KindToKindId<T>::Id);
60 }
61
62 /// \{
63 /// Construct an identifier for the dynamic type of the node
64 static ASTNodeKind getFromNode(const Decl &D);
65 static ASTNodeKind getFromNode(const Stmt &S);
66 static ASTNodeKind getFromNode(const Type &T);
67 static ASTNodeKind getFromNode(const TypeLoc &T);
68 static ASTNodeKind getFromNode(const LambdaCapture &L);
69 static ASTNodeKind getFromNode(const OMPClause &C);
70 static ASTNodeKind getFromNode(const Attr &A);
71 /// \}
72
73 /// Returns \c true if \c this and \c Other represent the same kind.
74 bool isSame(ASTNodeKind Other) const {
75 return KindId != NKI_None && KindId == Other.KindId;
76 }
77
78 /// Returns \c true only for the default \c ASTNodeKind()
79 bool isNone() const { return KindId == NKI_None; }
80
81 /// Returns \c true if \c this is a base kind of (or same as) \c Other.
82 /// \param Distance If non-null, used to return the distance between \c this
83 /// and \c Other in the class hierarchy.
84 bool isBaseOf(ASTNodeKind Other, unsigned *Distance = nullptr) const;
85
86 /// String representation of the kind.
87 StringRef asStringRef() const;
88
89 /// Strict weak ordering for ASTNodeKind.
90 bool operator<(const ASTNodeKind &Other) const {
91 return KindId < Other.KindId;
92 }
93
94 /// Return the most derived type between \p Kind1 and \p Kind2.
95 ///
96 /// Return ASTNodeKind() if they are not related.
97 static ASTNodeKind getMostDerivedType(ASTNodeKind Kind1, ASTNodeKind Kind2);
98
99 /// Return the most derived common ancestor between Kind1 and Kind2.
100 ///
101 /// Return ASTNodeKind() if they are not related.
102 static ASTNodeKind getMostDerivedCommonAncestor(ASTNodeKind Kind1,
103 ASTNodeKind Kind2);
104
105 ASTNodeKind getCladeKind() const;
106
107 /// Hooks for using ASTNodeKind as a key in a DenseMap.
108 struct DenseMapInfo {
109 // ASTNodeKind() is a good empty key because it is represented as a 0.
110 static inline ASTNodeKind getEmptyKey() { return ASTNodeKind(); }
111 // NKI_NumberOfKinds is not a valid value, so it is good for a
112 // tombstone key.
113 static inline ASTNodeKind getTombstoneKey() {
114 return ASTNodeKind(NKI_NumberOfKinds);
115 }
116 static unsigned getHashValue(const ASTNodeKind &Val) { return Val.KindId; }
117 static bool isEqual(const ASTNodeKind &LHS, const ASTNodeKind &RHS) {
118 return LHS.KindId == RHS.KindId;
119 }
120 };
121
122 /// Check if the given ASTNodeKind identifies a type that offers pointer
123 /// identity. This is useful for the fast path in DynTypedNode.
124 bool hasPointerIdentity() const {
125 return KindId > NKI_LastKindWithoutPointerIdentity;
126 }
127
128private:
129 /// Kind ids.
130 ///
131 /// Includes all possible base and derived kinds.
132 enum NodeKindId {
133 NKI_None,
134 NKI_TemplateArgument,
135 NKI_TemplateArgumentLoc,
136 NKI_LambdaCapture,
137 NKI_TemplateName,
138 NKI_NestedNameSpecifierLoc,
139 NKI_QualType,
140#define TYPELOC(CLASS, PARENT) NKI_##CLASS##TypeLoc,
141#include "clang/AST/TypeLocNodes.def"
142 NKI_TypeLoc,
143 NKI_LastKindWithoutPointerIdentity = NKI_TypeLoc,
144 NKI_CXXBaseSpecifier,
145 NKI_CXXCtorInitializer,
146 NKI_NestedNameSpecifier,
147 NKI_Decl,
148#define DECL(DERIVED, BASE) NKI_##DERIVED##Decl,
149#include "clang/AST/DeclNodes.inc"
150 NKI_Stmt,
151#define STMT(DERIVED, BASE) NKI_##DERIVED,
152#include "clang/AST/StmtNodes.inc"
153 NKI_Type,
154#define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
155#include "clang/AST/TypeNodes.inc"
156 NKI_OMPClause,
157#define GEN_CLANG_CLAUSE_CLASS
158#define CLAUSE_CLASS(Enum, Str, Class) NKI_##Class,
159#include "llvm/Frontend/OpenMP/OMP.inc"
160 NKI_Attr,
161#define ATTR(A) NKI_##A##Attr,
162#include "clang/Basic/AttrList.inc"
163 NKI_ObjCProtocolLoc,
164 NKI_NumberOfKinds
165 };
166
167 /// Use getFromNodeKind<T>() to construct the kind.
168 ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
169
170 /// Returns \c true if \c Base is a base kind of (or same as) \c
171 /// Derived.
172 /// \param Distance If non-null, used to return the distance between \c Base
173 /// and \c Derived in the class hierarchy.
174 static bool isBaseOf(NodeKindId Base, NodeKindId Derived, unsigned *Distance);
175
176 /// Helper meta-function to convert a kind T to its enum value.
177 ///
178 /// This struct is specialized below for all known kinds.
179 template <class T> struct KindToKindId {
180 static const NodeKindId Id = NKI_None;
181 };
182 template <class T>
183 struct KindToKindId<const T> : KindToKindId<T> {};
184
185 /// Per kind info.
186 struct KindInfo {
187 /// The id of the parent kind, or None if it has no parent.
188 NodeKindId ParentId;
189 /// Name of the kind.
190 const char *Name;
191 };
192 static const KindInfo AllKindInfo[NKI_NumberOfKinds];
193
194 NodeKindId KindId;
195};
196
197#define KIND_TO_KIND_ID(Class) \
198 template <> struct ASTNodeKind::KindToKindId<Class> { \
199 static const NodeKindId Id = NKI_##Class; \
200 };
201KIND_TO_KIND_ID(CXXCtorInitializer)
202KIND_TO_KIND_ID(TemplateArgument)
203KIND_TO_KIND_ID(TemplateArgumentLoc)
204KIND_TO_KIND_ID(LambdaCapture)
205KIND_TO_KIND_ID(TemplateName)
206KIND_TO_KIND_ID(NestedNameSpecifier)
207KIND_TO_KIND_ID(NestedNameSpecifierLoc)
208KIND_TO_KIND_ID(QualType)
209#define TYPELOC(CLASS, PARENT) KIND_TO_KIND_ID(CLASS##TypeLoc)
210#include "clang/AST/TypeLocNodes.def"
211KIND_TO_KIND_ID(TypeLoc)
212KIND_TO_KIND_ID(Decl)
213KIND_TO_KIND_ID(Stmt)
214KIND_TO_KIND_ID(Type)
215KIND_TO_KIND_ID(OMPClause)
216KIND_TO_KIND_ID(Attr)
217KIND_TO_KIND_ID(ObjCProtocolLoc)
218KIND_TO_KIND_ID(CXXBaseSpecifier)
219#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
220#include "clang/AST/DeclNodes.inc"
221#define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
222#include "clang/AST/StmtNodes.inc"
223#define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
224#include "clang/AST/TypeNodes.inc"
225#define GEN_CLANG_CLAUSE_CLASS
226#define CLAUSE_CLASS(Enum, Str, Class) KIND_TO_KIND_ID(Class)
227#include "llvm/Frontend/OpenMP/OMP.inc"
228#define ATTR(A) KIND_TO_KIND_ID(A##Attr)
229#include "clang/Basic/AttrList.inc"
230#undef KIND_TO_KIND_ID
231
232inline raw_ostream &operator<<(raw_ostream &OS, ASTNodeKind K) {
233 OS << K.asStringRef();
234 return OS;
235}
236
237/// A dynamically typed AST node container.
238///
239/// Stores an AST node in a type safe way. This allows writing code that
240/// works with different kinds of AST nodes, despite the fact that they don't
241/// have a common base class.
242///
243/// Use \c create(Node) to create a \c DynTypedNode from an AST node,
244/// and \c get<T>() to retrieve the node as type T if the types match.
245///
246/// See \c ASTNodeKind for which node base types are currently supported;
247/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
248/// the supported base types.
249class DynTypedNode {
250public:
251 /// Creates a \c DynTypedNode from \c Node.
252 template <typename T>
253 static DynTypedNode create(const T &Node) {
254 return BaseConverter<T>::create(Node);
255 }
256
257 /// Retrieve the stored node as type \c T.
258 ///
259 /// Returns NULL if the stored node does not have a type that is
260 /// convertible to \c T.
261 ///
262 /// For types that have identity via their pointer in the AST
263 /// (like \c Stmt, \c Decl, \c Type and \c NestedNameSpecifier) the returned
264 /// pointer points to the referenced AST node.
265 /// For other types (like \c QualType) the value is stored directly
266 /// in the \c DynTypedNode, and the returned pointer points at
267 /// the storage inside DynTypedNode. For those nodes, do not
268 /// use the pointer outside the scope of the DynTypedNode.
269 template <typename T> const T *get() const {
270 return BaseConverter<T>::get(NodeKind, &Storage);
5
Calling 'DynCastPtrConverter::get'
9
Returning from 'DynCastPtrConverter::get'
10
Returning null pointer, which participates in a condition later
271 }
272
273 /// Retrieve the stored node as type \c T.
274 ///
275 /// Similar to \c get(), but asserts that the type is what we are expecting.
276 template <typename T>
277 const T &getUnchecked() const {
278 return BaseConverter<T>::getUnchecked(NodeKind, &Storage);
279 }
280
281 ASTNodeKind getNodeKind() const { return NodeKind; }
282
283 /// Returns a pointer that identifies the stored AST node.
284 ///
285 /// Note that this is not supported by all AST nodes. For AST nodes
286 /// that don't have a pointer-defined identity inside the AST, this
287 /// method returns NULL.
288 const void *getMemoizationData() const {
289 return NodeKind.hasPointerIdentity()
290 ? *reinterpret_cast<void *const *>(&Storage)
291 : nullptr;
292 }
293
294 /// Prints the node to the given output stream.
295 void print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const;
296
297 /// Dumps the node to the given output stream.
298 void dump(llvm::raw_ostream &OS, const ASTContext &Context) const;
299
300 /// For nodes which represent textual entities in the source code,
301 /// return their SourceRange. For all other nodes, return SourceRange().
302 SourceRange getSourceRange() const;
303
304 /// @{
305 /// Imposes an order on \c DynTypedNode.
306 ///
307 /// Supports comparison of nodes that support memoization.
308 /// FIXME: Implement comparison for other node types (currently
309 /// only Stmt, Decl, Type and NestedNameSpecifier return memoization data).
310 bool operator<(const DynTypedNode &Other) const {
311 if (!NodeKind.isSame(Other.NodeKind))
312 return NodeKind < Other.NodeKind;
313
314 if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind))
315 return getUnchecked<QualType>().getAsOpaquePtr() <
316 Other.getUnchecked<QualType>().getAsOpaquePtr();
317
318 if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(NodeKind)) {
319 auto TLA = getUnchecked<TypeLoc>();
320 auto TLB = Other.getUnchecked<TypeLoc>();
321 return std::make_pair(TLA.getType().getAsOpaquePtr(),
322 TLA.getOpaqueData()) <
323 std::make_pair(TLB.getType().getAsOpaquePtr(),
324 TLB.getOpaqueData());
325 }
326
327 if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(
328 NodeKind)) {
329 auto NNSLA = getUnchecked<NestedNameSpecifierLoc>();
330 auto NNSLB = Other.getUnchecked<NestedNameSpecifierLoc>();
331 return std::make_pair(NNSLA.getNestedNameSpecifier(),
332 NNSLA.getOpaqueData()) <
333 std::make_pair(NNSLB.getNestedNameSpecifier(),
334 NNSLB.getOpaqueData());
335 }
336
337 assert(getMemoizationData() && Other.getMemoizationData())(static_cast <bool> (getMemoizationData() && Other
.getMemoizationData()) ? void (0) : __assert_fail ("getMemoizationData() && Other.getMemoizationData()"
, "clang/include/clang/AST/ASTTypeTraits.h", 337, __extension__
__PRETTY_FUNCTION__))
;
338 return getMemoizationData() < Other.getMemoizationData();
339 }
340 bool operator==(const DynTypedNode &Other) const {
341 // DynTypedNode::create() stores the exact kind of the node in NodeKind.
342 // If they contain the same node, their NodeKind must be the same.
343 if (!NodeKind.isSame(Other.NodeKind))
344 return false;
345
346 // FIXME: Implement for other types.
347 if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind))
348 return getUnchecked<QualType>() == Other.getUnchecked<QualType>();
349
350 if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(NodeKind))
351 return getUnchecked<TypeLoc>() == Other.getUnchecked<TypeLoc>();
352
353 if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(NodeKind))
354 return getUnchecked<NestedNameSpecifierLoc>() ==
355 Other.getUnchecked<NestedNameSpecifierLoc>();
356
357 assert(getMemoizationData() && Other.getMemoizationData())(static_cast <bool> (getMemoizationData() && Other
.getMemoizationData()) ? void (0) : __assert_fail ("getMemoizationData() && Other.getMemoizationData()"
, "clang/include/clang/AST/ASTTypeTraits.h", 357, __extension__
__PRETTY_FUNCTION__))
;
358 return getMemoizationData() == Other.getMemoizationData();
359 }
360 bool operator!=(const DynTypedNode &Other) const {
361 return !operator==(Other);
362 }
363 /// @}
364
365 /// Hooks for using DynTypedNode as a key in a DenseMap.
366 struct DenseMapInfo {
367 static inline DynTypedNode getEmptyKey() {
368 DynTypedNode Node;
369 Node.NodeKind = ASTNodeKind::DenseMapInfo::getEmptyKey();
370 return Node;
371 }
372 static inline DynTypedNode getTombstoneKey() {
373 DynTypedNode Node;
374 Node.NodeKind = ASTNodeKind::DenseMapInfo::getTombstoneKey();
375 return Node;
376 }
377 static unsigned getHashValue(const DynTypedNode &Val) {
378 // FIXME: Add hashing support for the remaining types.
379 if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(Val.NodeKind)) {
380 auto TL = Val.getUnchecked<TypeLoc>();
381 return llvm::hash_combine(TL.getType().getAsOpaquePtr(),
382 TL.getOpaqueData());
383 }
384
385 if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(
386 Val.NodeKind)) {
387 auto NNSL = Val.getUnchecked<NestedNameSpecifierLoc>();
388 return llvm::hash_combine(NNSL.getNestedNameSpecifier(),
389 NNSL.getOpaqueData());
390 }
391
392 assert(Val.getMemoizationData())(static_cast <bool> (Val.getMemoizationData()) ? void (
0) : __assert_fail ("Val.getMemoizationData()", "clang/include/clang/AST/ASTTypeTraits.h"
, 392, __extension__ __PRETTY_FUNCTION__))
;
393 return llvm::hash_value(Val.getMemoizationData());
394 }
395 static bool isEqual(const DynTypedNode &LHS, const DynTypedNode &RHS) {
396 auto Empty = ASTNodeKind::DenseMapInfo::getEmptyKey();
397 auto TombStone = ASTNodeKind::DenseMapInfo::getTombstoneKey();
398 return (ASTNodeKind::DenseMapInfo::isEqual(LHS.NodeKind, Empty) &&
399 ASTNodeKind::DenseMapInfo::isEqual(RHS.NodeKind, Empty)) ||
400 (ASTNodeKind::DenseMapInfo::isEqual(LHS.NodeKind, TombStone) &&
401 ASTNodeKind::DenseMapInfo::isEqual(RHS.NodeKind, TombStone)) ||
402 LHS == RHS;
403 }
404 };
405
406private:
407 /// Takes care of converting from and to \c T.
408 template <typename T, typename EnablerT = void> struct BaseConverter;
409
410 /// Converter that uses dyn_cast<T> from a stored BaseT*.
411 template <typename T, typename BaseT> struct DynCastPtrConverter {
412 static const T *get(ASTNodeKind NodeKind, const void *Storage) {
413 if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind))
6
Assuming the condition is false
7
Taking false branch
414 return &getUnchecked(NodeKind, Storage);
415 return nullptr;
8
Returning null pointer, which participates in a condition later
416 }
417 static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) {
418 assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind))(static_cast <bool> (ASTNodeKind::getFromNodeKind<T>
().isBaseOf(NodeKind)) ? void (0) : __assert_fail ("ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)"
, "clang/include/clang/AST/ASTTypeTraits.h", 418, __extension__
__PRETTY_FUNCTION__))
;
419 return *cast<T>(static_cast<const BaseT *>(
420 *reinterpret_cast<const void *const *>(Storage)));
421 }
422 static DynTypedNode create(const BaseT &Node) {
423 DynTypedNode Result;
424 Result.NodeKind = ASTNodeKind::getFromNode(Node);
425 new (&Result.Storage) const void *(&Node);
426 return Result;
427 }
428 };
429
430 /// Converter that stores T* (by pointer).
431 template <typename T> struct PtrConverter {
432 static const T *get(ASTNodeKind NodeKind, const void *Storage) {
433 if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
434 return &getUnchecked(NodeKind, Storage);
435 return nullptr;
436 }
437 static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) {
438 assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))(static_cast <bool> (ASTNodeKind::getFromNodeKind<T>
().isSame(NodeKind)) ? void (0) : __assert_fail ("ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)"
, "clang/include/clang/AST/ASTTypeTraits.h", 438, __extension__
__PRETTY_FUNCTION__))
;
439 return *static_cast<const T *>(
440 *reinterpret_cast<const void *const *>(Storage));
441 }
442 static DynTypedNode create(const T &Node) {
443 DynTypedNode Result;
444 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
445 new (&Result.Storage) const void *(&Node);
446 return Result;
447 }
448 };
449
450 /// Converter that stores T (by value).
451 template <typename T> struct ValueConverter {
452 static const T *get(ASTNodeKind NodeKind, const void *Storage) {
453 if (ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))
454 return reinterpret_cast<const T *>(Storage);
455 return nullptr;
456 }
457 static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) {
458 assert(ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind))(static_cast <bool> (ASTNodeKind::getFromNodeKind<T>
().isSame(NodeKind)) ? void (0) : __assert_fail ("ASTNodeKind::getFromNodeKind<T>().isSame(NodeKind)"
, "clang/include/clang/AST/ASTTypeTraits.h", 458, __extension__
__PRETTY_FUNCTION__))
;
459 return *reinterpret_cast<const T *>(Storage);
460 }
461 static DynTypedNode create(const T &Node) {
462 DynTypedNode Result;
463 Result.NodeKind = ASTNodeKind::getFromNodeKind<T>();
464 new (&Result.Storage) T(Node);
465 return Result;
466 }
467 };
468
469 /// Converter that stores nodes by value. It must be possible to dynamically
470 /// cast the stored node within a type hierarchy without breaking (especially
471 /// through slicing).
472 template <typename T, typename BaseT,
473 typename = std::enable_if_t<(sizeof(T) == sizeof(BaseT))>>
474 struct DynCastValueConverter {
475 static const T *get(ASTNodeKind NodeKind, const void *Storage) {
476 if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind))
477 return &getUnchecked(NodeKind, Storage);
478 return nullptr;
479 }
480 static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) {
481 assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind))(static_cast <bool> (ASTNodeKind::getFromNodeKind<T>
().isBaseOf(NodeKind)) ? void (0) : __assert_fail ("ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind)"
, "clang/include/clang/AST/ASTTypeTraits.h", 481, __extension__
__PRETTY_FUNCTION__))
;
482 return *static_cast<const T *>(reinterpret_cast<const BaseT *>(Storage));
483 }
484 static DynTypedNode create(const T &Node) {
485 DynTypedNode Result;
486 Result.NodeKind = ASTNodeKind::getFromNode(Node);
487 new (&Result.Storage) T(Node);
488 return Result;
489 }
490 };
491
492 ASTNodeKind NodeKind;
493
494 /// Stores the data of the node.
495 ///
496 /// Note that we can store \c Decls, \c Stmts, \c Types,
497 /// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are
498 /// guaranteed to be unique pointers pointing to dedicated storage in the AST.
499 /// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs,
500 /// \c TemplateArguments and \c TemplateArgumentLocs on the other hand do not
501 /// have storage or unique pointers and thus need to be stored by value.
502 llvm::AlignedCharArrayUnion<const void *, TemplateArgument,
503 TemplateArgumentLoc, NestedNameSpecifierLoc,
504 QualType, TypeLoc, ObjCProtocolLoc>
505 Storage;
506};
507
508template <typename T>
509struct DynTypedNode::BaseConverter<
510 T, std::enable_if_t<std::is_base_of<Decl, T>::value>>
511 : public DynCastPtrConverter<T, Decl> {};
512
513template <typename T>
514struct DynTypedNode::BaseConverter<
515 T, std::enable_if_t<std::is_base_of<Stmt, T>::value>>
516 : public DynCastPtrConverter<T, Stmt> {};
517
518template <typename T>
519struct DynTypedNode::BaseConverter<
520 T, std::enable_if_t<std::is_base_of<Type, T>::value>>
521 : public DynCastPtrConverter<T, Type> {};
522
523template <typename T>
524struct DynTypedNode::BaseConverter<
525 T, std::enable_if_t<std::is_base_of<OMPClause, T>::value>>
526 : public DynCastPtrConverter<T, OMPClause> {};
527
528template <typename T>
529struct DynTypedNode::BaseConverter<
530 T, std::enable_if_t<std::is_base_of<Attr, T>::value>>
531 : public DynCastPtrConverter<T, Attr> {};
532
533template <>
534struct DynTypedNode::BaseConverter<
535 NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
536
537template <>
538struct DynTypedNode::BaseConverter<
539 CXXCtorInitializer, void> : public PtrConverter<CXXCtorInitializer> {};
540
541template <>
542struct DynTypedNode::BaseConverter<
543 TemplateArgument, void> : public ValueConverter<TemplateArgument> {};
544
545template <>
546struct DynTypedNode::BaseConverter<TemplateArgumentLoc, void>
547 : public ValueConverter<TemplateArgumentLoc> {};
548
549template <>
550struct DynTypedNode::BaseConverter<LambdaCapture, void>
551 : public ValueConverter<LambdaCapture> {};
552
553template <>
554struct DynTypedNode::BaseConverter<
555 TemplateName, void> : public ValueConverter<TemplateName> {};
556
557template <>
558struct DynTypedNode::BaseConverter<
559 NestedNameSpecifierLoc,
560 void> : public ValueConverter<NestedNameSpecifierLoc> {};
561
562template <>
563struct DynTypedNode::BaseConverter<QualType,
564 void> : public ValueConverter<QualType> {};
565
566template <typename T>
567struct DynTypedNode::BaseConverter<
568 T, std::enable_if_t<std::is_base_of<TypeLoc, T>::value>>
569 : public DynCastValueConverter<T, TypeLoc> {};
570
571template <>
572struct DynTypedNode::BaseConverter<CXXBaseSpecifier, void>
573 : public PtrConverter<CXXBaseSpecifier> {};
574
575template <>
576struct DynTypedNode::BaseConverter<ObjCProtocolLoc, void>
577 : public ValueConverter<ObjCProtocolLoc> {};
578
579// The only operation we allow on unsupported types is \c get.
580// This allows to conveniently use \c DynTypedNode when having an arbitrary
581// AST node that is not supported, but prevents misuse - a user cannot create
582// a DynTypedNode from arbitrary types.
583template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
584 static const T *get(ASTNodeKind NodeKind, const char Storage[]) {
585 return NULL__null;
586 }
587};
588
589} // end namespace clang
590
591namespace llvm {
592
593template <>
594struct DenseMapInfo<clang::ASTNodeKind> : clang::ASTNodeKind::DenseMapInfo {};
595
596template <>
597struct DenseMapInfo<clang::DynTypedNode> : clang::DynTypedNode::DenseMapInfo {};
598
599} // end namespace llvm
600
601#endif