CXType clang_getPointeeType(CXType CT) { QualType T = GetQualType(CT); const Type *TP = T.getTypePtrOrNull(); if (!TP) return MakeCXType(QualType(), GetTU(CT)); switch (TP->getTypeClass()) { case Type::Pointer: T = cast<PointerType>(TP)->getPointeeType(); break; case Type::BlockPointer: T = cast<BlockPointerType>(TP)->getPointeeType(); break; case Type::LValueReference: case Type::RValueReference: T = cast<ReferenceType>(TP)->getPointeeType(); break; case Type::ObjCObjectPointer: T = cast<ObjCObjectPointerType>(TP)->getPointeeType(); break; default: T = QualType(); break; } return MakeCXType(T, GetTU(CT)); }
bool ReserveCandidates::expressionIsComplex(clang::Expr *expr) const { if (!expr) return false; vector<CallExpr*> callExprs; HierarchyUtils::getChilds<CallExpr>(expr, callExprs); for (CallExpr *callExpr : callExprs) { if (QtUtils::isJavaIterator(dyn_cast<CXXMemberCallExpr>(callExpr))) continue; QualType qt = callExpr->getType(); const Type *t = qt.getTypePtrOrNull(); if (t && (!t->isIntegerType() || t->isBooleanType())) return true; } vector<ArraySubscriptExpr*> subscriptExprs; HierarchyUtils::getChilds<ArraySubscriptExpr>(expr, subscriptExprs); if (!subscriptExprs.empty()) return true; BinaryOperator* binary = dyn_cast<BinaryOperator>(expr); if (binary && binary->isAssignmentOp()) { // Filter things like for ( ...; ...; next = node->next) Expr *rhs = binary->getRHS(); if (isa<MemberExpr>(rhs) || (isa<ImplicitCastExpr>(rhs) && dyn_cast_or_null<MemberExpr>(HierarchyUtils::getFirstChildAtDepth(rhs, 1)))) return true; } // llvm::errs() << expr->getStmtClassName() << "\n"; return false; }
static CXTypeKind GetTypeKind(QualType T) { const Type *TP = T.getTypePtrOrNull(); if (!TP) return CXType_Invalid; #define TKCASE(K) case Type::K: return CXType_##K switch (TP->getTypeClass()) { case Type::Builtin: return GetBuiltinTypeKind(cast<BuiltinType>(TP)); TKCASE(Complex); TKCASE(Pointer); TKCASE(BlockPointer); TKCASE(LValueReference); TKCASE(RValueReference); TKCASE(Record); TKCASE(Enum); TKCASE(Typedef); TKCASE(ObjCInterface); TKCASE(ObjCObjectPointer); TKCASE(FunctionNoProto); TKCASE(FunctionProto); TKCASE(ConstantArray); TKCASE(Vector); default: return CXType_Unexposed; } #undef TKCASE }
CXCursor clang_getTypeDeclaration(CXType CT) { if (CT.kind == CXType_Invalid) return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); QualType T = GetQualType(CT); const Type *TP = T.getTypePtrOrNull(); if (!TP) return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); Decl *D = nullptr; try_again: switch (TP->getTypeClass()) { case Type::Typedef: D = cast<TypedefType>(TP)->getDecl(); break; case Type::ObjCObject: D = cast<ObjCObjectType>(TP)->getInterface(); break; case Type::ObjCInterface: D = cast<ObjCInterfaceType>(TP)->getDecl(); break; case Type::Record: case Type::Enum: D = cast<TagType>(TP)->getDecl(); break; case Type::TemplateSpecialization: if (const RecordType *Record = TP->getAs<RecordType>()) D = Record->getDecl(); else D = cast<TemplateSpecializationType>(TP)->getTemplateName() .getAsTemplateDecl(); break; case Type::Auto: TP = cast<AutoType>(TP)->getDeducedType().getTypePtrOrNull(); if (TP) goto try_again; break; case Type::InjectedClassName: D = cast<InjectedClassNameType>(TP)->getDecl(); break; // FIXME: Template type parameters! case Type::Elaborated: TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull(); goto try_again; default: break; } if (!D) return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); return cxcursor::MakeCXCursor(D, GetTU(CT)); }
CXType clang_getArrayElementType(CXType CT) { QualType ET = QualType(); QualType T = GetQualType(CT); const Type *TP = T.getTypePtrOrNull(); if (TP) { switch (TP->getTypeClass()) { case Type::ConstantArray: ET = cast<ConstantArrayType> (TP)->getElementType(); break; case Type::IncompleteArray: ET = cast<IncompleteArrayType> (TP)->getElementType(); break; case Type::VariableArray: ET = cast<VariableArrayType> (TP)->getElementType(); break; case Type::DependentSizedArray: ET = cast<DependentSizedArrayType> (TP)->getElementType(); break; default: break; } } return MakeCXType(ET, GetTU(CT)); }
unsigned clang_Type_isTransparentTagTypedef(CXType TT){ QualType T = GetQualType(TT); if (auto *TT = dyn_cast_or_null<TypedefType>(T.getTypePtrOrNull())) { if (auto *D = TT->getDecl()) return D->isTransparentTag(); } return false; }
CXXRecordDecl * Utils::namedCastOuterDecl(CXXNamedCastExpr *staticOrDynamicCast) { QualType qt = staticOrDynamicCast->getTypeAsWritten(); const Type *t = qt.getTypePtrOrNull(); QualType qt2 = t->getPointeeType(); const Type *t2 = qt2.getTypePtrOrNull(); if (!t2) return nullptr; return t2->getAsCXXRecordDecl(); }
CXType clang_Type_getNamedType(CXType CT){ QualType T = GetQualType(CT); const Type *TP = T.getTypePtrOrNull(); if (TP && TP->getTypeClass() == Type::Elaborated) return MakeCXType(cast<ElaboratedType>(TP)->getNamedType(), GetTU(CT)); return MakeCXType(QualType(), GetTU(CT)); }
unsigned clang_isPODType(CXType X) { QualType T = GetQualType(X); if (!T.getTypePtrOrNull()) return 0; CXTranslationUnit TU = GetTU(X); ASTUnit *AU = static_cast<ASTUnit*>(TU->TUData); return T.isPODType(AU->getASTContext()) ? 1 : 0; }
CXType clang_Type_getClassType(CXType CT) { QualType ET = QualType(); QualType T = GetQualType(CT); const Type *TP = T.getTypePtrOrNull(); if (TP && TP->getTypeClass() == Type::MemberPointer) { ET = QualType(cast<MemberPointerType> (TP)->getClass(), 0); } return MakeCXType(ET, GetTU(CT)); }
CXType clang_getResultType(CXType X) { QualType T = GetQualType(X); if (!T.getTypePtrOrNull()) return MakeCXType(QualType(), GetTU(X)); if (const FunctionType *FD = T->getAs<FunctionType>()) return MakeCXType(FD->getResultType(), GetTU(X)); return MakeCXType(QualType(), GetTU(X)); }
CXXRecordDecl * Utils::namedCastInnerDecl(CXXNamedCastExpr *staticOrDynamicCast) { Expr *e = staticOrDynamicCast->getSubExpr(); if (!e) return nullptr; QualType qt = e->getType(); const Type *t = qt.getTypePtrOrNull(); if (!t) return nullptr; QualType qt2 = t->getPointeeType(); const Type *t2 = qt2.getTypePtrOrNull(); if (!t2) return nullptr; return t2->getAsCXXRecordDecl(); }
CXXRecordDecl *Utils::recordFromVarDecl(Decl *decl) { auto varDecl = dyn_cast<VarDecl>(decl); if (!varDecl) return nullptr; QualType qt = varDecl->getType(); const Type *t = qt.getTypePtrOrNull(); if (!t) return nullptr; return t->getAsCXXRecordDecl(); }
ClassTemplateSpecializationDecl *TemplateUtils::templateDecl(Decl *decl) { if (isa<ClassTemplateSpecializationDecl>(decl)) return dyn_cast<ClassTemplateSpecializationDecl>(decl); VarDecl *varDecl = dyn_cast<VarDecl>(decl); if (!varDecl) return nullptr; QualType qt = varDecl->getType(); const Type *t = qt.getTypePtrOrNull(); if (!t) return nullptr; CXXRecordDecl *classDecl = t->getAsCXXRecordDecl(); if (!classDecl) return nullptr; return dyn_cast<ClassTemplateSpecializationDecl>(classDecl); }
void ImplicitCasts::VisitStmt(clang::Stmt *stmt) { auto implicitCast = dyn_cast<ImplicitCastExpr>(stmt); if (implicitCast == nullptr) return; if (implicitCast->getCastKind() == clang::CK_LValueToRValue) return; if (implicitCast->getType().getTypePtrOrNull()->isBooleanType()) return; Expr *expr = implicitCast->getSubExpr(); QualType qt = expr->getType(); if (!qt.getTypePtrOrNull()->isBooleanType()) // Filter out some bool to const bool return; Stmt *p = Utils::parent(m_parentMap, stmt); if (p && isa<BinaryOperator>(p)) return; if (p && (isa<CStyleCastExpr>(p) || isa<CXXFunctionalCastExpr>(p))) return; if (Utils::isInsideOperatorCall(m_parentMap, stmt, {"QTextStream", "QAtomicInt", "QBasicAtomicInt"})) return; if (Utils::insideCTORCall(m_parentMap, stmt, {"QAtomicInt", "QBasicAtomicInt"})) return; if (Utils::parent(m_parentMap, implicitCast) == nullptr) return; StringUtils::printLocation(stmt->getLocStart()); EnumConstantDecl *enumerator = m_lastDecl ? dyn_cast<EnumConstantDecl>(m_lastDecl) : nullptr; if (enumerator) { // False positive in Qt headers which generates a lot of noise return; } auto macro = Lexer::getImmediateMacroName(stmt->getLocStart(), m_ci.getSourceManager(), m_ci.getLangOpts()); if (macro == "Q_UNLIKELY" || macro == "Q_LIKELY") { return; } emitWarning(stmt->getLocStart(), "Implicit cast from bool"); }
void FunctionArgsByRef::VisitDecl(Decl *decl) { FunctionDecl *functionDecl = dyn_cast<FunctionDecl>(decl); if (functionDecl == nullptr || !functionDecl->hasBody() || shouldIgnoreFunction(functionDecl->getNameAsString()) || !functionDecl->isThisDeclarationADefinition()) return; Stmt *body = functionDecl->getBody(); for (auto it = functionDecl->param_begin(), end = functionDecl->param_end(); it != end; ++it) { const ParmVarDecl *param = *it; QualType paramQt = param->getType(); const Type *paramType = paramQt.getTypePtrOrNull(); if (paramType == nullptr || paramType->isDependentType()) continue; const int size_of_T = m_ci.getASTContext().getTypeSize(paramQt) / 8; const bool isSmall = size_of_T <= 16; // TODO: What about arm ? CXXRecordDecl *recordDecl = paramType->getAsCXXRecordDecl(); const bool isUserNonTrivial = recordDecl && (recordDecl->hasUserDeclaredCopyConstructor() || recordDecl->hasUserDeclaredDestructor()); const bool isReference = paramType->isLValueReferenceType(); const bool isConst = paramQt.isConstQualified(); if (recordDecl && shouldIgnoreClass(recordDecl->getQualifiedNameAsString())) continue; std::string error; if (isConst && !isReference) { if (!isSmall) { error += warningMsgForSmallType(size_of_T, paramQt.getAsString()); } else if (isUserNonTrivial) { error += "Missing reference on non-trivial type " + recordDecl->getQualifiedNameAsString(); } } else if (isConst && isReference && !isUserNonTrivial && isSmall) { //error += "Don't use by-ref on small trivial type"; } else if (!isConst && !isReference && (!isSmall || isUserNonTrivial)) { if (Utils::containsNonConstMemberCall(body, param) || Utils::containsCallByRef(body, param)) continue; if (!isSmall) { error += warningMsgForSmallType(size_of_T, paramQt.getAsString()); } else if (isUserNonTrivial) { error += "Missing reference on non-trivial type " + recordDecl->getQualifiedNameAsString(); } } if (!error.empty()) { emitWarning(param->getLocStart(), error.c_str()); } } }
void MissingTypeinfo::registerQTypeInfo(ClassTemplateSpecializationDecl *decl) { if (decl->getName() == "QTypeInfo") { auto &args = decl->getTemplateArgs(); if (args.size() != 1) return; QualType qt = args[0].getAsType(); const Type *t = qt.getTypePtrOrNull(); CXXRecordDecl *recordDecl = t ? t->getAsCXXRecordDecl() : nullptr; // llvm::errs() << qt.getAsString() << " foo\n"; if (recordDecl != nullptr) { m_typeInfos.insert(recordDecl->getQualifiedNameAsString()); } } }
long long clang_getArraySize(CXType CT) { long long result = -1; QualType T = GetQualType(CT); const Type *TP = T.getTypePtrOrNull(); if (TP) { switch (TP->getTypeClass()) { case Type::ConstantArray: result = cast<ConstantArrayType> (TP)->getSize().getSExtValue(); break; default: break; } } return result; }
bool Utils::hasMember(CXXRecordDecl *record, const string &memberTypeName) { if (!record) return false; for (auto field : record->fields()) { field->getParent()->getNameAsString(); QualType qt = field->getType(); const Type *t = qt.getTypePtrOrNull(); if (t && t->getAsCXXRecordDecl()) { CXXRecordDecl *rec = t->getAsCXXRecordDecl(); if (rec->getNameAsString() == memberTypeName) return true; } } return false; }
bool HostProgramTuning::VisitCallExpr(CallExpr *E) { if (E != NULL){ QualType q = E->getType(); const Type *t = q.getTypePtrOrNull(); if(t != NULL) { FunctionDecl *func = E->getDirectCallee(); if (!func) return false; ProcessFuncCall(func->getNameInfo().getName().getAsString(), E); } } return true; }
static bool isArgOfFunc(T expr, FunctionDecl *fDecl, const VarDecl *varDecl, bool byRefOrPtrOnly) { unsigned int param = -1; for (auto arg : expr->arguments()) { ++param; DeclRefExpr *refExpr = dyn_cast<DeclRefExpr>(arg); if (!refExpr) { if (clazy_std::hasChildren(arg)) { Stmt* firstChild = *(arg->child_begin()); // Can be null (bug #362236) refExpr = firstChild ? dyn_cast<DeclRefExpr>(firstChild) : nullptr; if (!refExpr) continue; } else { continue; } } if (refExpr->getDecl() != varDecl) // It's our variable ? continue; if (!byRefOrPtrOnly) { // We found it return true; } // It is, lets see if the callee takes our variable by const-ref if (param >= fDecl->param_size()) continue; ParmVarDecl *paramDecl = fDecl->getParamDecl(param); if (!paramDecl) continue; QualType qt = paramDecl->getType(); const Type *t = qt.getTypePtrOrNull(); if (!t) continue; if ((t->isReferenceType() || t->isPointerType()) && !t->getPointeeType().isConstQualified()) return true; // function receives non-const ref, so our foreach variable cant be const-ref } return false; }
bool VisitVarDecl(const VarDecl *D) { // Bail out early if this location should not be checked. if (doIgnore(D->getLocation())) { return true; } const QualType qualType = D->getType(); // Bail out if this type is either an enum or does not look like a real // value. if (qualType->isEnumeralType() || qualType->isBooleanType() || qualType->isArithmeticType() == false) { return true; } const Type *t = qualType.getTypePtrOrNull(); assert(t && "Type of arithmetic types has to be available."); const std::string typeName = qualType.getAsString(); // If it is of the same type as "size_t" and does have "size_t" somewhere in // its name we can go with it. // Please note: This also allows a typedef for "unsigned long" to be named // e.g. "size_type" without any size indicator - which may or may not be a // good thing. if (context->hasSameUnqualifiedType(qualType, context->getSizeType()) && typeName.find("size_t") != std::string::npos) { return true; } // char_t and wchar_t are not subject to this rule. const std::string needle = "char_t"; if (std::equal(needle.rbegin(), needle.rend(), typeName.rbegin())) { return true; } const uint64_t typeSize = context->getTypeSize(t); const std::string sizeStr = llvm::utostr(typeSize); // For all remaining types, the number of occupied bits must be embedded in // the typename. if (typeName.rfind(sizeStr) == std::string::npos) { reportError(D->getLocation()); } return true; }
string TemplateUtils::getTemplateArgumentTypeStr(ClassTemplateSpecializationDecl *specialization, unsigned int index, const LangOptions &lo, bool recordOnly) { if (!specialization) return {}; auto &args = specialization->getTemplateArgs(); if (args.size() <= index) return {}; QualType qt = args[index].getAsType(); if (recordOnly) { const Type *t = qt.getTypePtrOrNull(); if (!t || !t->getAsCXXRecordDecl()) return {}; } return StringUtils::simpleTypeName(args[index].getAsType(), lo); }
bool TypeUtils::classifyQualType(const CompilerInstance &ci, const VarDecl *varDecl, QualTypeClassification &classif, clang::Stmt *body) { if (!varDecl) return false; QualType qualType = TypeUtils::unrefQualType(varDecl->getType()); const Type *paramType = qualType.getTypePtrOrNull(); if (!paramType || paramType->isIncompleteType()) return false; if (isUndeducibleAuto(paramType)) return false; classif.size_of_T = ci.getASTContext().getTypeSize(qualType) / 8; classif.isBig = classif.size_of_T > 16; CXXRecordDecl *recordDecl = paramType->getAsCXXRecordDecl(); classif.isNonTriviallyCopyable = recordDecl && (recordDecl->hasNonTrivialCopyConstructor() || recordDecl->hasNonTrivialDestructor()); classif.isReference = varDecl->getType()->isLValueReferenceType(); classif.isConst = qualType.isConstQualified(); if (varDecl->getType()->isRValueReferenceType()) // && ref, nothing to do here return true; if (classif.isConst && !classif.isReference) { classif.passNonTriviallyCopyableByConstRef = classif.isNonTriviallyCopyable; if (classif.isBig) { classif.passBigTypeByConstRef = true; } } else if (classif.isConst && classif.isReference && !classif.isNonTriviallyCopyable && !classif.isBig) { classif.passSmallTrivialByValue = true; } else if (!classif.isConst && !classif.isReference && (classif.isBig || classif.isNonTriviallyCopyable)) { if (body && (Utils::containsNonConstMemberCall(body, varDecl) || Utils::isPassedToFunction(StmtBodyRange(body), varDecl, /*byrefonly=*/ true))) return true; classif.passNonTriviallyCopyableByConstRef = classif.isNonTriviallyCopyable; if (classif.isBig) { classif.passBigTypeByConstRef = true; } } return true; }
static bool iterateCallExpr2(T* callExpr, CheckBase *check, ParentMap *parentMap) { if (!callExpr) return false; bool result = false; int i = 0; for (auto arg : callExpr->arguments()) { ++i; auto implicitCast = dyn_cast<ImplicitCastExpr>(arg); if (!implicitCast || implicitCast->getCastKind() != clang::CK_IntegralCast) continue; if (implicitCast->getType().getTypePtrOrNull()->isBooleanType()) continue; Expr *expr = implicitCast->getSubExpr(); QualType qt = expr->getType(); if (!qt.getTypePtrOrNull()->isBooleanType()) // Filter out some bool to const bool continue; if (HierarchyUtils::getFirstChildOfType<CXXFunctionalCastExpr>(implicitCast)) continue; if (HierarchyUtils::getFirstChildOfType<CStyleCastExpr>(implicitCast)) continue; if (Utils::isInsideOperatorCall(parentMap, implicitCast, {"QTextStream", "QAtomicInt", "QBasicAtomicInt"})) continue; if (Utils::insideCTORCall(parentMap, implicitCast, {"QAtomicInt", "QBasicAtomicInt"})) continue; check->emitWarning(implicitCast->getLocStart(), "Implicit bool to int cast (argument " + std::to_string(i) + ')'); result = true; } return result; }
bool is_of_class_for_MemberExpr(MemberExpr const * const e, std::string const & class_name) { ValueDecl const * decl = e->getMemberDecl(); QualType qt = decl->getType(); Type const * t = qt.getTypePtrOrNull(); if( t ) { RecordType const * rec = t->getAs<RecordType>(); if( rec ) { TagDecl const * tagdecl = rec->getDecl(); IdentifierInfo * idinfo = tagdecl->getIdentifier(); if( idinfo->getName() == class_name ) { return true; } } } return false; }
CXType clang_getElementType(CXType CT) { QualType ET = QualType(); QualType T = GetQualType(CT); const Type *TP = T.getTypePtrOrNull(); if (TP) { switch (TP->getTypeClass()) { case Type::ConstantArray: ET = cast<ConstantArrayType> (TP)->getElementType(); break; case Type::Vector: ET = cast<VectorType> (TP)->getElementType(); break; case Type::Complex: ET = cast<ComplexType> (TP)->getElementType(); break; default: break; } } return MakeCXType(ET, GetTU(CT)); }
void MutableContainerKey::VisitDecl(clang::Decl *decl) { auto tsdecl = Utils::templateSpecializationFromVarDecl(decl); if (!tsdecl || !isInterestingContainer(tsdecl->getName())) return; const TemplateArgumentList &templateArguments = tsdecl->getTemplateArgs(); if (templateArguments.size() != 2) return; QualType qt = templateArguments[0].getAsType(); const Type *t = qt.getTypePtrOrNull(); if (!t) return; auto record = t->isRecordType() ? t->getAsCXXRecordDecl() : nullptr; if (!StringUtils::classIsOneOf(record, {"QPointer", "QWeakPointer", "QPersistentModelIndex", "weak_ptr"})) return; emitWarning(decl->getLocStart(), "Associative container key might be modified externally"); }
CXType clang_getPointeeType(CXType CT) { QualType T = GetQualType(CT); const Type *TP = T.getTypePtrOrNull(); if (!TP) return MakeCXType(QualType(), GetTU(CT)); try_again: switch (TP->getTypeClass()) { case Type::Pointer: T = cast<PointerType>(TP)->getPointeeType(); break; case Type::BlockPointer: T = cast<BlockPointerType>(TP)->getPointeeType(); break; case Type::LValueReference: case Type::RValueReference: T = cast<ReferenceType>(TP)->getPointeeType(); break; case Type::ObjCObjectPointer: T = cast<ObjCObjectPointerType>(TP)->getPointeeType(); break; case Type::MemberPointer: T = cast<MemberPointerType>(TP)->getPointeeType(); break; case Type::Auto: case Type::DeducedTemplateSpecialization: TP = cast<DeducedType>(TP)->getDeducedType().getTypePtrOrNull(); if (TP) goto try_again; break; default: T = QualType(); break; } return MakeCXType(T, GetTU(CT)); }
const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, const LocationContext *LC) { const MemRegion *sReg = 0; if (D->hasGlobalStorage() && !D->isStaticLocal()) { // First handle the globals defined in system headers. if (C.getSourceManager().isInSystemHeader(D->getLocation())) { // Whitelist the system globals which often DO GET modified, assume the // rest are immutable. if (D->getName().find("errno") != StringRef::npos) sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); else sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); // Treat other globals as GlobalInternal unless they are constants. } else { QualType GQT = D->getType(); const Type *GT = GQT.getTypePtrOrNull(); // TODO: We could walk the complex types here and see if everything is // constified. if (GT && GQT.isConstQualified() && GT->isArithmeticType()) sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); else sReg = getGlobalsRegion(); } // Finally handle static locals. } else { // FIXME: Once we implement scope handling, we will need to properly lookup // 'D' to the proper LocationContext. const DeclContext *DC = D->getDeclContext(); llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V = getStackOrCaptureRegionForDeclContext(LC, DC, D); if (V.is<const VarRegion*>()) return V.get<const VarRegion*>(); const StackFrameContext *STC = V.get<const StackFrameContext*>(); if (!STC) sReg = getUnknownRegion(); else { if (D->hasLocalStorage()) { sReg = isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D) ? static_cast<const MemRegion*>(getStackArgumentsRegion(STC)) : static_cast<const MemRegion*>(getStackLocalsRegion(STC)); } else { assert(D->isStaticLocal()); const Decl *STCD = STC->getDecl(); if (isa<FunctionDecl>(STCD) || isa<ObjCMethodDecl>(STCD)) sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, getFunctionTextRegion(cast<NamedDecl>(STCD))); else if (const BlockDecl *BD = dyn_cast<BlockDecl>(STCD)) { const BlockTextRegion *BTR = getBlockTextRegion(BD, C.getCanonicalType(BD->getSignatureAsWritten()->getType()), STC->getAnalysisDeclContext()); sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, BTR); } else { sReg = getGlobalsRegion(); } } } } return getSubRegion<VarRegion>(D, sReg); }