bool ClassTemplateToClass::isValidClassTemplateDecl(ClassTemplateDecl *TmplD) { TemplateParameterList *TPList = TmplD->getTemplateParameters(); if (TPList->size() != 1) return false; CXXRecordDecl *CXXRD = TmplD->getTemplatedDecl(); CXXRecordDecl *Def = CXXRD->getDefinition(); if (!Def) return true; NamedDecl *ND = TPList->getParam(0); if (dyn_cast<NonTypeTemplateParmDecl>(ND)) return true; if (isUsedNamedDecl(ND, Def)) return false; SmallVector<ClassTemplatePartialSpecializationDecl *, 10> PartialDecls; TmplD->getPartialSpecializations(PartialDecls); for (SmallVector<ClassTemplatePartialSpecializationDecl *, 10>::iterator I = PartialDecls.begin(), E = PartialDecls.end(); I != E; ++I) { if (hasUsedNameDecl(*I)) return false; } return true; }
ValuePrinterInfo::ValuePrinterInfo(Expr* E, ASTContext* Ctx) : m_Expr(E), m_Context(Ctx), m_Flags(0) { assert(E && "Expression cannot be null!"); assert(Ctx && "ASTContext cannot be null!"); // 1. Get the flags const QualType QT = m_Expr->getType(); if (E->isRValue() || QT.isLocalConstQualified() || QT.isConstant(*Ctx)){ m_Flags |= VPI_Const; } if (QT->isPointerType()) { // treat arrary-to-pointer decay as array: QualType PQT = QT->getPointeeType(); const Type* PTT = PQT.getTypePtr(); if (!PTT || !PTT->isArrayType()) { m_Flags |= VPI_Ptr; if (const RecordType* RT = dyn_cast<RecordType>(QT.getTypePtr())) if (RecordDecl* RD = RT->getDecl()) { CXXRecordDecl* CRD = dyn_cast<CXXRecordDecl>(RD); if (CRD && CRD->isPolymorphic()) m_Flags |= VPI_Polymorphic; } } } }
/// Warns on methods overridden in DerivedDecl with respect to BaseDecl. /// FIXME: this warns on all overrides outside of the sliced path in case of /// multiple inheritance. void SlicingCheck::DiagnoseSlicedOverriddenMethods( const Expr &Call, const CXXRecordDecl &DerivedDecl, const CXXRecordDecl &BaseDecl) { if (DerivedDecl.getCanonicalDecl() == BaseDecl.getCanonicalDecl()) return; for (const auto &Method : DerivedDecl.methods()) { // Virtual destructors are OK. We're ignoring constructors since they are // tagged as overrides. if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) continue; if (Method->size_overridden_methods() > 0) { diag(Call.getExprLoc(), "slicing object from type %0 to %1 discards override %2") << &DerivedDecl << &BaseDecl << Method; } } // Recursively process bases. for (const auto &Base : DerivedDecl.bases()) { if (const auto *BaseRecordType = Base.getType()->getAs<RecordType>()) { if (const auto *BaseRecord = cast_or_null<CXXRecordDecl>( BaseRecordType->getDecl()->getDefinition())) DiagnoseSlicedOverriddenMethods(Call, *BaseRecord, BaseDecl); } } }
void ValuePrinterInfo::Init(clang::QualType Ty) { assert(!Ty.isNull() && "Type must be valid!"); assert(m_Context && "ASTContext cannot be null!"); assert(sizeof(m_Type) >= sizeof(clang::QualType) && "m_Type too small!"); m_Type = *reinterpret_cast<void**>(&Ty); // 1. Get the flags if (Ty.isLocalConstQualified() || Ty.isConstant(*m_Context)){ m_Flags |= VPI_Const; } if (Ty->isPointerType()) { // treat arrary-to-pointer decay as array: QualType PQT = Ty->getPointeeType(); const Type* PTT = PQT.getTypePtr(); if (!PTT || !PTT->isArrayType()) { m_Flags |= VPI_Ptr; if (const RecordType* RT = dyn_cast<RecordType>(Ty.getTypePtr())) if (RecordDecl* RD = RT->getDecl()) { CXXRecordDecl* CRD = dyn_cast<CXXRecordDecl>(RD); if (CRD && CRD->isPolymorphic()) m_Flags |= VPI_Polymorphic; } } } }
/// \brief Whether this nested name specifier refers to a dependent /// type or not. bool NestedNameSpecifier::isDependent() const { switch (getKind()) { case Identifier: // Identifier specifiers always represent dependent types return true; case Namespace: case NamespaceAlias: case Global: return false; case Super: { CXXRecordDecl *RD = static_cast<CXXRecordDecl *>(Specifier); for (const auto &Base : RD->bases()) if (Base.getType()->isDependentType()) return true; return false; } case TypeSpec: case TypeSpecWithTemplate: return getAsType()->isDependentType(); } llvm_unreachable("Invalid NNS Kind!"); }
bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc, SourceLocation ColonColonLoc, CXXScopeSpec &SS) { CXXRecordDecl *RD = nullptr; for (Scope *S = getCurScope(); S; S = S->getParent()) { if (S->isFunctionScope()) { if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(S->getEntity())) RD = MD->getParent(); break; } if (S->isClassScope()) { RD = cast<CXXRecordDecl>(S->getEntity()); break; } } if (!RD) { Diag(SuperLoc, diag::err_invalid_super_scope); return true; } else if (RD->isLambda()) { Diag(SuperLoc, diag::err_super_in_lambda_unsupported); return true; } else if (RD->getNumBases() == 0) { Diag(SuperLoc, diag::err_no_base_classes) << RD->getName(); return true; } SS.MakeSuper(Context, RD, SuperLoc, ColonColonLoc); return false; }
void RecordInfo::walkBases() { // This traversal is akin to CXXRecordDecl::forallBases()'s, // but without stepping over dependent bases -- these might also // have a "GC base name", so are to be included and considered. SmallVector<const CXXRecordDecl*, 8> queue; const CXXRecordDecl *base_record = record(); while (true) { for (const auto& it : base_record->bases()) { const RecordType *type = it.getType()->getAs<RecordType>(); CXXRecordDecl* base; if (!type) base = GetDependentTemplatedDecl(*it.getType()); else { base = cast_or_null<CXXRecordDecl>(type->getDecl()->getDefinition()); if (base) queue.push_back(base); } if (!base) continue; const std::string& name = base->getName(); if (Config::IsGCBase(name)) { gc_base_names_.push_back(name); is_gc_derived_ = true; } } if (queue.empty()) break; base_record = queue.pop_back_val(); // not actually a queue. } }
/** * Return the concrete type in the same extensible class string as me, or * NULL if it can't be found. * * This query only really makes sense for an extensible class. */ CXXRecordDecl* getAssociatedConcreteType(CXXRecordDecl* decl) { // a concrete type is always part of its own extensible class string. if (isOMRConcreteType(decl)) return decl; // Only extensible decls have a meaningful concrete class string. if (isExtensible(decl)) { int loopCount = 0; CXXRecordDecl* concrete = mostDerivedType(decl); trace("==isExtensible: " << decl->getQualifiedNameAsString() << " concrete: " << (concrete ? concrete->getQualifiedNameAsString() : "no concrete found")); while (concrete) { if (loopCount++ > 50) { std::string diagnostic("Found more than 50 layers of classes, likely bug."); DiagnosticsEngine &diagEngine = Context->getDiagnostics(); unsigned diagID = diagEngine.getCustomDiagID(DiagnosticsEngine::Error, "%0"); diagEngine.Report(decl->getLocation(), diagID) << diagnostic; exit(EXIT_FAILURE); } if (inSameClassString(decl, concrete)) { trace("=== in same string"); return concrete; //Found the concrete class in the same string. } concrete = mostDerivedType(concrete); if (concrete) trace("==== new concrete " << concrete->getQualifiedNameAsString() << " for " << decl->getQualifiedNameAsString()); } trace("Didn't find a concrete class for " << decl->getQualifiedNameAsString() << " ... issue diagnostic?") } return NULL; }
void ReduceClassTemplateParameter::removeParameterFromMethods() { CXXRecordDecl *CXXRD = TheClassTemplateDecl->getTemplatedDecl(); for (auto I = CXXRD->method_begin(), E = CXXRD->method_end(); I != E; ++I) { ClassTemplateMethodVisitor V(this, TheParameterIndex); V.TraverseDecl(*I); } }
void ASTConsumerHTML::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) { CXXRecordDecl *decl = RD; if (decl) { log << "\n" << static_cast<Decl *> (decl) << " HandleVTable" << "\n"; decl->print(log); log << "\n"; } }
void QGetEnv::VisitStmt(clang::Stmt *stmt) { // Lets check only in function calls. Otherwise there are too many false positives, it's common // to implicit cast to bool when checking pointers for validity, like if (ptr) CXXMemberCallExpr *memberCall = dyn_cast<CXXMemberCallExpr>(stmt); if (!memberCall) return; CXXMethodDecl *method = memberCall->getMethodDecl(); if (!method) return; CXXRecordDecl *record = method->getParent(); if (!record || record->getNameAsString() != "QByteArray") { return; } std::vector<CallExpr *> calls = Utils::callListForChain(memberCall); if (calls.size() != 2) return; CallExpr *qgetEnvCall = calls.back(); FunctionDecl *func = qgetEnvCall->getDirectCallee(); if (!func || func->getNameAsString() != "qgetenv") return; string methodname = method->getNameAsString(); string errorMsg; std::string replacement; if (methodname == "isEmpty") { errorMsg = "qgetenv().isEmpty() allocates."; replacement = "qEnvironmentVariableIsEmpty"; } else if (methodname == "isNull") { errorMsg = "qgetenv().isNull() allocates."; replacement = "qEnvironmentVariableIsSet"; } else if (methodname == "toInt") { errorMsg = "qgetenv().toInt() is slow."; replacement = "qEnvironmentVariableIntValue"; } if (!errorMsg.empty()) { std::vector<FixItHint> fixits; if (isFixitEnabled(FixitAll)) { const bool success = FixItUtils::transformTwoCallsIntoOne(m_ci, qgetEnvCall, memberCall, replacement, fixits); if (!success) { queueManualFixitWarning(memberCall->getLocStart(), FixitAll); } } errorMsg += " Use " + replacement + "() instead"; emitWarning(memberCall->getLocStart(), errorMsg.c_str(), fixits); } }
bool UnnecessaryIncludeFinder::VisitTemplateSpecializationTypeLoc ( TemplateSpecializationTypeLoc typeLoc) { CXXRecordDecl* pCXXRecordDecl = typeLoc.getTypePtr()->getAsCXXRecordDecl(); if (pCXXRecordDecl) { markUsed(pCXXRecordDecl->getLocation(), typeLoc.getTemplateNameLoc()); } return true; }
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths, bool LookupInDependent) const { // If we didn't find anything, report that. if (!Paths.lookupInBases(getASTContext(), this, BaseMatches, LookupInDependent)) return false; // If we're not recording paths or we won't ever find ambiguities, // we're done. if (!Paths.isRecordingPaths() || !Paths.isFindingAmbiguities()) return true; // C++ [class.member.lookup]p6: // When virtual base classes are used, a hidden declaration can be // reached along a path through the sub-object lattice that does // not pass through the hiding declaration. This is not an // ambiguity. The identical use with nonvirtual base classes is an // ambiguity; in that case there is no unique instance of the name // that hides all the others. // // FIXME: This is an O(N^2) algorithm, but DPG doesn't see an easy // way to make it any faster. Paths.Paths.remove_if([&Paths](const CXXBasePath &Path) { for (const CXXBasePathElement &PE : Path) { if (!PE.Base->isVirtual()) continue; CXXRecordDecl *VBase = nullptr; if (const RecordType *Record = PE.Base->getType()->getAs<RecordType>()) VBase = cast<CXXRecordDecl>(Record->getDecl()); if (!VBase) break; // The declaration(s) we found along this path were found in a // subobject of a virtual base. Check whether this virtual // base is a subobject of any other path; if so, then the // declaration in this path are hidden by that patch. for (const CXXBasePath &HidingP : Paths) { CXXRecordDecl *HidingClass = nullptr; if (const RecordType *Record = HidingP.back().Base->getType()->getAs<RecordType>()) HidingClass = cast<CXXRecordDecl>(Record->getDecl()); if (!HidingClass) break; if (HidingClass->isVirtuallyDerivedFrom(VBase)) return true; } } return false; }); return true; }
static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, llvm::Constant *DeclPtr) { assert(D.hasGlobalStorage() && "VarDecl must have global storage!"); assert(!D.getType()->isReferenceType() && "Should not call EmitDeclInit on a reference!"); CodeGenModule &CGM = CGF.CGM; ASTContext &Context = CGF.getContext(); const Expr *Init = D.getInit(); QualType T = D.getType(); bool isVolatile = Context.getCanonicalType(T).isVolatileQualified(); if (!CGF.hasAggregateLLVMType(T)) { llvm::Value *V = CGF.EmitScalarExpr(Init); CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, T); } else if (T->isAnyComplexType()) { CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); } else { CGF.EmitAggExpr(Init, DeclPtr, isVolatile); // Avoid generating destructor(s) for initialized objects. if (!isa<CXXConstructExpr>(Init)) return; const ConstantArrayType *Array = Context.getAsConstantArrayType(T); if (Array) T = Context.getBaseElementType(Array); const RecordType *RT = T->getAs<RecordType>(); if (!RT) return; CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); if (RD->hasTrivialDestructor()) return; CXXDestructorDecl *Dtor = RD->getDestructor(Context); llvm::Constant *DtorFn; if (Array) { DtorFn = CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor, Array, DeclPtr); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); DeclPtr = llvm::Constant::getNullValue(Int8PtrTy); } else DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); } }
static bool isParentOf(const CXXRecordDecl &Parent, const CXXRecordDecl &ThisClass) { if (Parent.getCanonicalDecl() == ThisClass.getCanonicalDecl()) return true; const CXXRecordDecl *ParentCanonicalDecl = Parent.getCanonicalDecl(); return ThisClass.bases_end() != llvm::find_if(ThisClass.bases(), [=](const CXXBaseSpecifier &Base) { auto *BaseDecl = Base.getType()->getAsCXXRecordDecl(); assert(BaseDecl); return ParentCanonicalDecl == BaseDecl->getCanonicalDecl(); }); }
/** * Once the recursive visitor has completed, this routine analyzes the * MostDerivedTypeMap to find errors in the structure of the OMR classes */ void VerifyTypeStructure() { trace("Starting Structure Verification"); for (std::map<CXXRecordDecl*, bool>::iterator I = Types.begin(), E=Types.end(); I != E; ++I) { CXXRecordDecl * Type = I->first; bool extensible = I->second; trace(Type << " " << extensible << " " << getAssociatedConcreteType(Type)); if (extensible && !getAssociatedConcreteType(Type)) { trace("xxxx Issue diagnostic because there's no associated concrete type"); continue; } if (extensible) { //Extnsible type . trace("xxxx Verifying " << Type->getQualifiedNameAsString() << " has no non-extensible base classes." ); for (CXXRecordDecl::base_class_iterator BI = Type->bases_begin(), BE = Type->bases_end(); BI != BE; ++BI) { CXXRecordDecl * base_class = BI->getType()->getAsCXXRecordDecl(); if (base_class && !isExtensible(base_class) // Ensure extensible parent. && !isOMRRootType(Type)) { // OMR Root type can have non-extensible parents. //Base is not extensible, but an extensible type reaches it, with no concrete class in the middle. //Issue diagnostic. std::string diagnostic("OMR_EXTENSIBLE Type "); diagnostic += Type->getQualifiedNameAsString(); diagnostic += " derives from "; diagnostic += base_class->getQualifiedNameAsString(); diagnostic += " that is not marked as OMR_EXTENSIBLE.\n"; DiagnosticsEngine &diagEngine = Context->getDiagnostics(); unsigned diagID = diagEngine.getCustomDiagID(DiagnosticsEngine::Error, "%0"); diagEngine.Report(base_class->getLocation(), diagID) << diagnostic; } } } else { trace("xxxx Verifying " << Type->getQualifiedNameAsString() << " has no non-extensible base classes." ); for (CXXRecordDecl::base_class_iterator BI = Type->bases_begin(), BE = Type->bases_end(); BI != BE; ++BI) { CXXRecordDecl * base_class = BI->getType()->getAsCXXRecordDecl(); if (base_class && isExtensible(base_class) && !isOMRConcreteType(base_class)) { //Base is not extensible, but an extensible type reaches it, with no concrete class in the middle. //Issue diagnostic. std::string diagnostic("Type "); diagnostic += Type->getQualifiedNameAsString(); diagnostic += " derives from "; diagnostic += base_class->getQualifiedNameAsString(); diagnostic += " that is marked as OMR_EXTENSIBLE.\n"; DiagnosticsEngine &diagEngine = Context->getDiagnostics(); unsigned diagID = diagEngine.getCustomDiagID(DiagnosticsEngine::Error, "%0"); diagEngine.Report(Type->getLocation(), diagID) << diagnostic; } } } } //each most derived type }
// A GC mixin is a class that inherits from a GC mixin base and has // has not yet been "mixed in" with another GC base class. bool RecordInfo::IsGCMixin() { if (!IsGCDerived() || base_paths_->begin() == base_paths_->end()) return false; // Get the last element of the first path. CXXBasePaths::paths_iterator it = base_paths_->begin(); const CXXBasePathElement& elem = (*it)[it->size() - 1]; CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl(); // If it is not a mixin base we are done. if (!Config::IsGCMixinBase(base->getName())) return false; // This is a mixin if there are no other paths to GC bases. return ++it == base_paths_->end(); }
bool RecordInfo::IsGCFinalized() { if (!IsGCDerived()) return false; for (CXXBasePaths::paths_iterator it = base_paths_->begin(); it != base_paths_->end(); ++it) { const CXXBasePathElement& elem = (*it)[it->size() - 1]; CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl(); if (Config::IsGCFinalizedBase(base->getName())) return true; } return false; }
static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { DeclContext *DC = D->getDeclContext(); // This can only happen at top: enum decls only "publish" their // immediate members. if (isa<EnumDecl>(DC)) DC = cast<EnumDecl>(DC)->getDeclContext(); CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); while (DeclaringClass->isAnonymousStructOrUnion()) DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); return DeclaringClass; }
void RuleOfTwoSoft::VisitStmt(Stmt *s) { CXXOperatorCallExpr *op = dyn_cast<CXXOperatorCallExpr>(s); if (op) { FunctionDecl *func = op->getDirectCallee(); if (func && func->getNameAsString() == "operator=") { CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(func); if (method && method->getParent()) { CXXRecordDecl *record = method->getParent(); const bool hasCopyCtor = record->hasNonTrivialCopyConstructor(); const bool hasCopyAssignOp = record->hasNonTrivialCopyAssignment(); if (hasCopyCtor && !hasCopyAssignOp && !isBlacklisted(record)) { string msg = "Using assign operator but class " + record->getQualifiedNameAsString() + " has copy-ctor but no assign operator"; emitWarning(s->getLocStart(), msg); } } } } else if (CXXConstructExpr *ctorExpr = dyn_cast<CXXConstructExpr>(s)) { CXXConstructorDecl *ctorDecl = ctorExpr->getConstructor(); CXXRecordDecl *record = ctorDecl->getParent(); if (ctorDecl->isCopyConstructor() && record) { const bool hasCopyCtor = record->hasNonTrivialCopyConstructor(); const bool hasCopyAssignOp = record->hasNonTrivialCopyAssignment(); if (!hasCopyCtor && hasCopyAssignOp && !isBlacklisted(record)) { string msg = "Using copy-ctor but class " + record->getQualifiedNameAsString() + " has a trivial copy-ctor but non trivial assign operator"; emitWarning(s->getLocStart(), msg); } } } }
/// Determines whether the given friend class template matches /// anything in the effective context. static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC, ClassTemplateDecl *Friend) { AccessResult OnFailure = AR_inaccessible; // Check whether the friend is the template of a class in the // context chain. for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { CXXRecordDecl *Record = *I; // Figure out whether the current class has a template: ClassTemplateDecl *CTD; // A specialization of the template... if (isa<ClassTemplateSpecializationDecl>(Record)) { CTD = cast<ClassTemplateSpecializationDecl>(Record) ->getSpecializedTemplate(); // ... or the template pattern itself. } else { CTD = Record->getDescribedClassTemplate(); if (!CTD) continue; } // It's a match. if (Friend == CTD->getCanonicalDecl()) return AR_accessible; // If the context isn't dependent, it can't be a dependent match. if (!EC.isDependent()) continue; // If the template names don't match, it can't be a dependent // match. This isn't true in C++0x because of template aliases. if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName()) continue; // If the class's context can't instantiate to the friend's // context, it can't be a dependent match. if (!MightInstantiateTo(S, CTD->getDeclContext(), Friend->getDeclContext())) continue; // Otherwise, it's a dependent match. OnFailure = AR_dependent; } return OnFailure; }
TEST_F(StructuralEquivalenceTest, WrongOrderOfFieldsInClass) { auto Code = "class X { int a; int b; };"; auto Decls = makeNamedDecls(Code, Code, Lang_CXX, "X"); CXXRecordDecl *RD = FirstDeclMatcher<CXXRecordDecl>().match( get<1>(Decls), cxxRecordDecl(hasName("X"))); FieldDecl *FD = FirstDeclMatcher<FieldDecl>().match(get<1>(Decls), fieldDecl(hasName("a"))); // Reorder the FieldDecls RD->removeDecl(FD); RD->addDeclInternal(FD); EXPECT_FALSE(testStructuralMatch(Decls)); }
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()); } } }
void VarCheckVisitor::checkClass(clang::Decl* d) { auto loc = getDeclLocation(d); CXXRecordDecl* c = (CXXRecordDecl*)d; string name = c->getName(); boost::regex r{CLASS_NAME}; if(!boost::regex_match(name, r)){ lineIssues_.push_back(Issue(loc.first, loc.second, "Incorrect Class/Struct name", "Classes and Structures should be named in upper camel case.", WARNING)); } }
bool RecordInfo::IsTreeShared() { if (Config::IsTreeSharedBase(name_)) return true; if (!IsGCDerived()) return false; for (CXXBasePaths::paths_iterator it = base_paths_->begin(); it != base_paths_->end(); ++it) { // TreeShared is an immediate base of GCFinalized. if (it->size() < 2) continue; const CXXBasePathElement& elem = (*it)[it->size() - 2]; CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl(); if (Config::IsTreeSharedBase(base->getName())) return true; } return false; }
void MustOverrideChecker::check(const MatchFinder::MatchResult &Result) { auto D = Result.Nodes.getNodeAs<CXXRecordDecl>("class"); // Look through all of our immediate bases to find methods that need to be // overridden typedef std::vector<CXXMethodDecl *> OverridesVector; OverridesVector MustOverrides; for (const auto &Base : D->bases()) { // The base is either a class (CXXRecordDecl) or it's a templated class... CXXRecordDecl *Parent = Base.getType() .getDesugaredType(D->getASTContext()) ->getAsCXXRecordDecl(); // The parent might not be resolved to a type yet. In this case, we can't // do any checking here. For complete correctness, we should visit // template instantiations, but this case is likely to be rare, so we will // ignore it until it becomes important. if (!Parent) { continue; } Parent = Parent->getDefinition(); for (const auto &M : Parent->methods()) { if (hasCustomAnnotation(M, "moz_must_override")) MustOverrides.push_back(M); } } for (auto &O : MustOverrides) { bool Overridden = false; for (const auto &M : D->methods()) { // The way that Clang checks if a method M overrides its parent method // is if the method has the same name but would not overload. if (getNameChecked(M) == getNameChecked(O) && !CI->getSema().IsOverload(M, O, false)) { Overridden = true; break; } } if (!Overridden) { diag(D->getLocation(), "%0 must override %1", DiagnosticIDs::Error) << D->getDeclName() << O->getDeclName(); diag(O->getLocation(), "function to override is here", DiagnosticIDs::Note); } } }
/// Find the current instantiation that associated with the given type. static CXXRecordDecl *getCurrentInstantiationOf(QualType T, DeclContext *CurContext) { if (T.isNull()) return nullptr; const Type *Ty = T->getCanonicalTypeInternal().getTypePtr(); if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl()); if (!Record->isDependentContext() || Record->isCurrentInstantiation(CurContext)) return Record; return nullptr; } else if (isa<InjectedClassNameType>(Ty)) return cast<InjectedClassNameType>(Ty)->getDecl(); else return nullptr; }
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; }
void CopyablePolymorphic::VisitDecl(clang::Decl *decl) { CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(decl); if (!record || !record->hasDefinition() || record->getDefinition() != record || !record->isPolymorphic()) return; CXXConstructorDecl *copyCtor = Utils::copyCtor(record); CXXMethodDecl *copyAssign = Utils::copyAssign(record); const bool hasCallableCopyCtor = copyCtor && !copyCtor->isDeleted() && copyCtor->getAccess() != clang::AS_private; const bool hasCallableCopyAssign = copyAssign && !copyAssign->isDeleted() && copyAssign->getAccess() != clang::AS_private; if (!hasCallableCopyCtor && !hasCallableCopyAssign) return; emitWarning(record->getLocStart(), "Polymorphic class is copyable. Potential slicing."); }