clang  14.0.0git
SymbolManager.cpp
Go to the documentation of this file.
1 //===- SymbolManager.h - Management of Symbolic Values --------------------===//
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 // This file defines SymbolManager, a class that manages symbolic values
10 // created for use by ExprEngine and related classes.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/Expr.h"
17 #include "clang/AST/StmtObjC.h"
20 #include "clang/Basic/LLVM.h"
25 #include "llvm/ADT/FoldingSet.h"
26 #include "llvm/ADT/STLExtras.h"
27 #include "llvm/Support/Casting.h"
28 #include "llvm/Support/Compiler.h"
29 #include "llvm/Support/ErrorHandling.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include <cassert>
32 
33 using namespace clang;
34 using namespace ento;
35 
36 void SymExpr::anchor() {}
37 
38 StringRef SymbolConjured::getKindStr() const { return "conj_$"; }
39 StringRef SymbolDerived::getKindStr() const { return "derived_$"; }
40 StringRef SymbolExtent::getKindStr() const { return "extent_$"; }
41 StringRef SymbolMetadata::getKindStr() const { return "meta_$"; }
42 StringRef SymbolRegionValue::getKindStr() const { return "reg_$"; }
43 
44 LLVM_DUMP_METHOD void SymExpr::dump() const { dumpToStream(llvm::errs()); }
45 
46 void BinarySymExpr::dumpToStreamImpl(raw_ostream &OS, const SymExpr *Sym) {
47  OS << '(';
48  Sym->dumpToStream(OS);
49  OS << ')';
50 }
51 
52 void BinarySymExpr::dumpToStreamImpl(raw_ostream &OS,
53  const llvm::APSInt &Value) {
54  if (Value.isUnsigned())
55  OS << Value.getZExtValue();
56  else
57  OS << Value.getSExtValue();
58  if (Value.isUnsigned())
59  OS << 'U';
60 }
61 
62 void BinarySymExpr::dumpToStreamImpl(raw_ostream &OS,
64  OS << ' ' << BinaryOperator::getOpcodeStr(Op) << ' ';
65 }
66 
67 void SymbolCast::dumpToStream(raw_ostream &os) const {
68  os << '(' << ToTy.getAsString() << ") (";
69  Operand->dumpToStream(os);
70  os << ')';
71 }
72 
73 void SymbolConjured::dumpToStream(raw_ostream &os) const {
74  os << getKindStr() << getSymbolID() << '{' << T.getAsString() << ", LC"
75  << LCtx->getID();
76  if (S)
77  os << ", S" << S->getID(LCtx->getDecl()->getASTContext());
78  else
79  os << ", no stmt";
80  os << ", #" << Count << '}';
81 }
82 
83 void SymbolDerived::dumpToStream(raw_ostream &os) const {
84  os << getKindStr() << getSymbolID() << '{' << getParentSymbol() << ','
85  << getRegion() << '}';
86 }
87 
88 void SymbolExtent::dumpToStream(raw_ostream &os) const {
89  os << getKindStr() << getSymbolID() << '{' << getRegion() << '}';
90 }
91 
92 void SymbolMetadata::dumpToStream(raw_ostream &os) const {
93  os << getKindStr() << getSymbolID() << '{' << getRegion() << ','
94  << T.getAsString() << '}';
95 }
96 
97 void SymbolData::anchor() {}
98 
99 void SymbolRegionValue::dumpToStream(raw_ostream &os) const {
100  os << getKindStr() << getSymbolID() << '<' << getType().getAsString() << ' '
101  << R << '>';
102 }
103 
104 bool SymExpr::symbol_iterator::operator==(const symbol_iterator &X) const {
105  return itr == X.itr;
106 }
107 
108 bool SymExpr::symbol_iterator::operator!=(const symbol_iterator &X) const {
109  return itr != X.itr;
110 }
111 
112 SymExpr::symbol_iterator::symbol_iterator(const SymExpr *SE) {
113  itr.push_back(SE);
114 }
115 
116 SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() {
117  assert(!itr.empty() && "attempting to iterate on an 'end' iterator");
118  expand();
119  return *this;
120 }
121 
122 SymbolRef SymExpr::symbol_iterator::operator*() {
123  assert(!itr.empty() && "attempting to dereference an 'end' iterator");
124  return itr.back();
125 }
126 
127 void SymExpr::symbol_iterator::expand() {
128  const SymExpr *SE = itr.pop_back_val();
129 
130  switch (SE->getKind()) {
131  case SymExpr::SymbolRegionValueKind:
132  case SymExpr::SymbolConjuredKind:
133  case SymExpr::SymbolDerivedKind:
134  case SymExpr::SymbolExtentKind:
135  case SymExpr::SymbolMetadataKind:
136  return;
137  case SymExpr::SymbolCastKind:
138  itr.push_back(cast<SymbolCast>(SE)->getOperand());
139  return;
140  case SymExpr::SymIntExprKind:
141  itr.push_back(cast<SymIntExpr>(SE)->getLHS());
142  return;
143  case SymExpr::IntSymExprKind:
144  itr.push_back(cast<IntSymExpr>(SE)->getRHS());
145  return;
146  case SymExpr::SymSymExprKind: {
147  const auto *x = cast<SymSymExpr>(SE);
148  itr.push_back(x->getLHS());
149  itr.push_back(x->getRHS());
150  return;
151  }
152  }
153  llvm_unreachable("unhandled expansion case");
154 }
155 
156 const SymbolRegionValue*
157 SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) {
158  llvm::FoldingSetNodeID profile;
159  SymbolRegionValue::Profile(profile, R);
160  void *InsertPos;
161  SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
162  if (!SD) {
163  SD = (SymExpr*) BPAlloc.Allocate<SymbolRegionValue>();
164  new (SD) SymbolRegionValue(SymbolCounter, R);
165  DataSet.InsertNode(SD, InsertPos);
166  ++SymbolCounter;
167  }
168 
169  return cast<SymbolRegionValue>(SD);
170 }
171 
172 const SymbolConjured* SymbolManager::conjureSymbol(const Stmt *E,
173  const LocationContext *LCtx,
174  QualType T,
175  unsigned Count,
176  const void *SymbolTag) {
177  llvm::FoldingSetNodeID profile;
178  SymbolConjured::Profile(profile, E, T, Count, LCtx, SymbolTag);
179  void *InsertPos;
180  SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
181  if (!SD) {
182  SD = (SymExpr*) BPAlloc.Allocate<SymbolConjured>();
183  new (SD) SymbolConjured(SymbolCounter, E, LCtx, T, Count, SymbolTag);
184  DataSet.InsertNode(SD, InsertPos);
185  ++SymbolCounter;
186  }
187 
188  return cast<SymbolConjured>(SD);
189 }
190 
191 const SymbolDerived*
192 SymbolManager::getDerivedSymbol(SymbolRef parentSymbol,
193  const TypedValueRegion *R) {
194  llvm::FoldingSetNodeID profile;
195  SymbolDerived::Profile(profile, parentSymbol, R);
196  void *InsertPos;
197  SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
198  if (!SD) {
199  SD = (SymExpr*) BPAlloc.Allocate<SymbolDerived>();
200  new (SD) SymbolDerived(SymbolCounter, parentSymbol, R);
201  DataSet.InsertNode(SD, InsertPos);
202  ++SymbolCounter;
203  }
204 
205  return cast<SymbolDerived>(SD);
206 }
207 
208 const SymbolExtent*
209 SymbolManager::getExtentSymbol(const SubRegion *R) {
210  llvm::FoldingSetNodeID profile;
211  SymbolExtent::Profile(profile, R);
212  void *InsertPos;
213  SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
214  if (!SD) {
215  SD = (SymExpr*) BPAlloc.Allocate<SymbolExtent>();
216  new (SD) SymbolExtent(SymbolCounter, R);
217  DataSet.InsertNode(SD, InsertPos);
218  ++SymbolCounter;
219  }
220 
221  return cast<SymbolExtent>(SD);
222 }
223 
224 const SymbolMetadata *
225 SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T,
226  const LocationContext *LCtx,
227  unsigned Count, const void *SymbolTag) {
228  llvm::FoldingSetNodeID profile;
229  SymbolMetadata::Profile(profile, R, S, T, LCtx, Count, SymbolTag);
230  void *InsertPos;
231  SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos);
232  if (!SD) {
233  SD = (SymExpr*) BPAlloc.Allocate<SymbolMetadata>();
234  new (SD) SymbolMetadata(SymbolCounter, R, S, T, LCtx, Count, SymbolTag);
235  DataSet.InsertNode(SD, InsertPos);
236  ++SymbolCounter;
237  }
238 
239  return cast<SymbolMetadata>(SD);
240 }
241 
242 const SymbolCast*
243 SymbolManager::getCastSymbol(const SymExpr *Op,
244  QualType From, QualType To) {
245  llvm::FoldingSetNodeID ID;
246  SymbolCast::Profile(ID, Op, From, To);
247  void *InsertPos;
248  SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
249  if (!data) {
250  data = (SymbolCast*) BPAlloc.Allocate<SymbolCast>();
251  new (data) SymbolCast(Op, From, To);
252  DataSet.InsertNode(data, InsertPos);
253  }
254 
255  return cast<SymbolCast>(data);
256 }
257 
258 const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
259  BinaryOperator::Opcode op,
260  const llvm::APSInt& v,
261  QualType t) {
262  llvm::FoldingSetNodeID ID;
263  SymIntExpr::Profile(ID, lhs, op, v, t);
264  void *InsertPos;
265  SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
266 
267  if (!data) {
268  data = (SymIntExpr*) BPAlloc.Allocate<SymIntExpr>();
269  new (data) SymIntExpr(lhs, op, v, t);
270  DataSet.InsertNode(data, InsertPos);
271  }
272 
273  return cast<SymIntExpr>(data);
274 }
275 
276 const IntSymExpr *SymbolManager::getIntSymExpr(const llvm::APSInt& lhs,
277  BinaryOperator::Opcode op,
278  const SymExpr *rhs,
279  QualType t) {
280  llvm::FoldingSetNodeID ID;
281  IntSymExpr::Profile(ID, lhs, op, rhs, t);
282  void *InsertPos;
283  SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
284 
285  if (!data) {
286  data = (IntSymExpr*) BPAlloc.Allocate<IntSymExpr>();
287  new (data) IntSymExpr(lhs, op, rhs, t);
288  DataSet.InsertNode(data, InsertPos);
289  }
290 
291  return cast<IntSymExpr>(data);
292 }
293 
294 const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs,
295  BinaryOperator::Opcode op,
296  const SymExpr *rhs,
297  QualType t) {
298  llvm::FoldingSetNodeID ID;
299  SymSymExpr::Profile(ID, lhs, op, rhs, t);
300  void *InsertPos;
301  SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
302 
303  if (!data) {
304  data = (SymSymExpr*) BPAlloc.Allocate<SymSymExpr>();
305  new (data) SymSymExpr(lhs, op, rhs, t);
306  DataSet.InsertNode(data, InsertPos);
307  }
308 
309  return cast<SymSymExpr>(data);
310 }
311 
312 QualType SymbolConjured::getType() const {
313  return T;
314 }
315 
316 QualType SymbolDerived::getType() const {
317  return R->getValueType();
318 }
319 
320 QualType SymbolExtent::getType() const {
321  ASTContext &Ctx = R->getMemRegionManager().getContext();
322  return Ctx.getSizeType();
323 }
324 
325 QualType SymbolMetadata::getType() const {
326  return T;
327 }
328 
329 QualType SymbolRegionValue::getType() const {
330  return R->getValueType();
331 }
332 
333 bool SymbolManager::canSymbolicate(QualType T) {
334  T = T.getCanonicalType();
335 
336  if (Loc::isLocType(T))
337  return true;
338 
339  if (T->isIntegralOrEnumerationType())
340  return true;
341 
342  if (T->isRecordType() && !T->isUnionType())
343  return true;
344 
345  return false;
346 }
347 
348 void SymbolManager::addSymbolDependency(const SymbolRef Primary,
349  const SymbolRef Dependent) {
350  auto &dependencies = SymbolDependencies[Primary];
351  if (!dependencies) {
352  dependencies = std::make_unique<SymbolRefSmallVectorTy>();
353  }
354  dependencies->push_back(Dependent);
355 }
356 
357 const SymbolRefSmallVectorTy *SymbolManager::getDependentSymbols(
358  const SymbolRef Primary) {
359  SymbolDependTy::const_iterator I = SymbolDependencies.find(Primary);
360  if (I == SymbolDependencies.end())
361  return nullptr;
362  return I->second.get();
363 }
364 
365 void SymbolReaper::markDependentsLive(SymbolRef sym) {
366  // Do not mark dependents more then once.
367  SymbolMapTy::iterator LI = TheLiving.find(sym);
368  assert(LI != TheLiving.end() && "The primary symbol is not live.");
369  if (LI->second == HaveMarkedDependents)
370  return;
371  LI->second = HaveMarkedDependents;
372 
373  if (const SymbolRefSmallVectorTy *Deps = SymMgr.getDependentSymbols(sym)) {
374  for (const auto I : *Deps) {
375  if (TheLiving.find(I) != TheLiving.end())
376  continue;
377  markLive(I);
378  }
379  }
380 }
381 
382 void SymbolReaper::markLive(SymbolRef sym) {
383  TheLiving[sym] = NotProcessed;
384  markDependentsLive(sym);
385 }
386 
387 void SymbolReaper::markLive(const MemRegion *region) {
388  RegionRoots.insert(region->getBaseRegion());
389  markElementIndicesLive(region);
390 }
391 
392 void SymbolReaper::markElementIndicesLive(const MemRegion *region) {
393  for (auto SR = dyn_cast<SubRegion>(region); SR;
394  SR = dyn_cast<SubRegion>(SR->getSuperRegion())) {
395  if (const auto ER = dyn_cast<ElementRegion>(SR)) {
396  SVal Idx = ER->getIndex();
397  for (auto SI = Idx.symbol_begin(), SE = Idx.symbol_end(); SI != SE; ++SI)
398  markLive(*SI);
399  }
400  }
401 }
402 
403 void SymbolReaper::markInUse(SymbolRef sym) {
404  if (isa<SymbolMetadata>(sym))
405  MetadataInUse.insert(sym);
406 }
407 
408 bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
409  // TODO: For now, liveness of a memory region is equivalent to liveness of its
410  // base region. In fact we can do a bit better: say, if a particular FieldDecl
411  // is not used later in the path, we can diagnose a leak of a value within
412  // that field earlier than, say, the variable that contains the field dies.
413  MR = MR->getBaseRegion();
414 
415  if (RegionRoots.count(MR))
416  return true;
417 
418  if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
419  return isLive(SR->getSymbol());
420 
421  if (const auto *VR = dyn_cast<VarRegion>(MR))
422  return isLive(VR, true);
423 
424  // FIXME: This is a gross over-approximation. What we really need is a way to
425  // tell if anything still refers to this region. Unlike SymbolicRegions,
426  // AllocaRegions don't have associated symbols, though, so we don't actually
427  // have a way to track their liveness.
428  if (isa<AllocaRegion>(MR))
429  return true;
430 
431  if (isa<CXXThisRegion>(MR))
432  return true;
433 
434  if (isa<MemSpaceRegion>(MR))
435  return true;
436 
437  if (isa<CodeTextRegion>(MR))
438  return true;
439 
440  return false;
441 }
442 
443 bool SymbolReaper::isLive(SymbolRef sym) {
444  if (TheLiving.count(sym)) {
445  markDependentsLive(sym);
446  return true;
447  }
448 
449  bool KnownLive;
450 
451  switch (sym->getKind()) {
452  case SymExpr::SymbolRegionValueKind:
453  KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion());
454  break;
455  case SymExpr::SymbolConjuredKind:
456  KnownLive = false;
457  break;
458  case SymExpr::SymbolDerivedKind:
459  KnownLive = isLive(cast<SymbolDerived>(sym)->getParentSymbol());
460  break;
461  case SymExpr::SymbolExtentKind:
462  KnownLive = isLiveRegion(cast<SymbolExtent>(sym)->getRegion());
463  break;
464  case SymExpr::SymbolMetadataKind:
465  KnownLive = MetadataInUse.count(sym) &&
466  isLiveRegion(cast<SymbolMetadata>(sym)->getRegion());
467  if (KnownLive)
468  MetadataInUse.erase(sym);
469  break;
470  case SymExpr::SymIntExprKind:
471  KnownLive = isLive(cast<SymIntExpr>(sym)->getLHS());
472  break;
473  case SymExpr::IntSymExprKind:
474  KnownLive = isLive(cast<IntSymExpr>(sym)->getRHS());
475  break;
476  case SymExpr::SymSymExprKind:
477  KnownLive = isLive(cast<SymSymExpr>(sym)->getLHS()) &&
478  isLive(cast<SymSymExpr>(sym)->getRHS());
479  break;
480  case SymExpr::SymbolCastKind:
481  KnownLive = isLive(cast<SymbolCast>(sym)->getOperand());
482  break;
483  }
484 
485  if (KnownLive)
486  markLive(sym);
487 
488  return KnownLive;
489 }
490 
491 bool
492 SymbolReaper::isLive(const Expr *ExprVal, const LocationContext *ELCtx) const {
493  if (LCtx == nullptr)
494  return false;
495 
496  if (LCtx != ELCtx) {
497  // If the reaper's location context is a parent of the expression's
498  // location context, then the expression value is now "out of scope".
499  if (LCtx->isParentOf(ELCtx))
500  return false;
501  return true;
502  }
503 
504  // If no statement is provided, everything in this and parent contexts is
505  // live.
506  if (!Loc)
507  return true;
508 
509  return LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, ExprVal);
510 }
511 
512 bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
513  const StackFrameContext *VarContext = VR->getStackFrame();
514 
515  if (!VarContext)
516  return true;
517 
518  if (!LCtx)
519  return false;
520  const StackFrameContext *CurrentContext = LCtx->getStackFrame();
521 
522  if (VarContext == CurrentContext) {
523  // If no statement is provided, everything is live.
524  if (!Loc)
525  return true;
526 
527  // Anonymous parameters of an inheriting constructor are live for the entire
528  // duration of the constructor.
529  if (isa<CXXInheritedCtorInitExpr>(Loc))
530  return true;
531 
532  if (LCtx->getAnalysis<RelaxedLiveVariables>()->isLive(Loc, VR->getDecl()))
533  return true;
534 
535  if (!includeStoreBindings)
536  return false;
537 
538  unsigned &cachedQuery =
539  const_cast<SymbolReaper *>(this)->includedRegionCache[VR];
540 
541  if (cachedQuery) {
542  return cachedQuery == 1;
543  }
544 
545  // Query the store to see if the region occurs in any live bindings.
546  if (Store store = reapedStore.getStore()) {
547  bool hasRegion =
548  reapedStore.getStoreManager().includedInBindings(store, VR);
549  cachedQuery = hasRegion ? 1 : 2;
550  return hasRegion;
551  }
552 
553  return false;
554  }
555 
556  return VarContext->isParentOf(CurrentContext);
557 }
clang::Decl::getASTContext
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:414
clang::ento::SymbolCast::dumpToStream
void dumpToStream(raw_ostream &os) const override
Definition: SymbolManager.cpp:67
SVals.h
AnalysisDeclContext.h
clang::ento::BinarySymExpr::dumpToStreamImpl
static void dumpToStreamImpl(raw_ostream &os, const SymExpr *Value)
clang::ento::SymbolMetadata::getRegion
const MemRegion * getRegion() const
Definition: SymbolManager.h:229
clang::ento::SymbolDerived::getKindStr
StringRef getKindStr() const override
Get a string representation of the kind of the region.
Definition: SymbolManager.cpp:39
clang::BinaryOperator::getOpcodeStr
StringRef getOpcodeStr() const
Definition: Expr.h:3868
SymbolManager.h
clang::ento::SymbolDerived::dumpToStream
void dumpToStream(raw_ostream &os) const override
Definition: SymbolManager.cpp:83
clang::QualType::getAsString
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
Definition: Type.h:1015
clang::ento::SymbolMetadata::dumpToStream
void dumpToStream(raw_ostream &os) const override
Definition: SymbolManager.cpp:92
clang::ento::SymbolDerived::getRegion
const TypedValueRegion * getRegion() const
Definition: SymbolManager.h:144
clang::ento::SymbolExtent::getRegion
const SubRegion * getRegion() const
Definition: SymbolManager.h:182
APSInt
llvm::APSInt APSInt
Definition: ByteCodeEmitter.cpp:19
SymExpr.h
LiveVariables.h
clang::ento::SymbolMetadata::getKindStr
StringRef getKindStr() const override
Get a string representation of the kind of the region.
Definition: SymbolManager.cpp:41
clang::ento::SymExpr
Symbolic value.
Definition: SymExpr.h:29
Store.h
clang::ento::SymbolDerived::getParentSymbol
SymbolRef getParentSymbol() const
Definition: SymbolManager.h:143
clang::ento::SymbolConjured::dumpToStream
void dumpToStream(raw_ostream &os) const override
Definition: SymbolManager.cpp:73
Expr.h
ASTContext.h
StmtObjC.h
clang::ento::SymbolExtent::dumpToStream
void dumpToStream(raw_ostream &os) const override
Definition: SymbolManager.cpp:88
clang::Stmt::getID
int64_t getID(const ASTContext &Context) const
Definition: Stmt.cpp:360
clang::ento::SymbolExtent::getKindStr
StringRef getKindStr() const override
Get a string representation of the kind of the region.
Definition: SymbolManager.cpp:40
clang::ento::SymbolRegionValue::getType
QualType getType() const override
Definition: SymbolManager.cpp:329
clang::ento::SymExpr::dump
virtual void dump() const
Definition: SymbolManager.cpp:44
clang::transformer::expression
Stencil expression(llvm::StringRef Id)
Generates the source of the expression bound to Id, wrapping it in parentheses if it may parse differ...
Definition: Stencil.cpp:493
Value
Value
Definition: UninitializedValues.cpp:102
clang::ento::SymbolConjured::getKindStr
StringRef getKindStr() const override
Get a string representation of the kind of the region.
Definition: SymbolManager.cpp:38
LLVM.h
clang::BinaryOperatorKind
BinaryOperatorKind
Definition: OperationKinds.h:25
clang::ento::SymbolData::getSymbolID
SymbolID getSymbolID() const
Definition: SymExpr.h:132
clang::LocationContext::getID
int64_t getID() const
Definition: AnalysisDeclContext.h:239
clang
Definition: CalledOnceCheck.h:17
clang::ento::SymExpr::dumpToStream
virtual void dumpToStream(raw_ostream &os) const
Definition: SymExpr.h:60
clang::ento::SymbolRegionValue::dumpToStream
void dumpToStream(raw_ostream &os) const override
Definition: SymbolManager.cpp:99
MemRegion.h
s
__device__ __2f16 float bool s
Definition: __clang_hip_libdevice_declares.h:315
clang::ento::SymbolRegionValue::getKindStr
StringRef getKindStr() const override
Get a string representation of the kind of the region.
Definition: SymbolManager.cpp:42
clang::LocationContext::getDecl
const Decl * getDecl() const
Definition: AnalysisDeclContext.h:247
clang::ento::ObjKind::OS
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...