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; }
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); } } }
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."); }
bool ReduceClassTemplateParameterASTVisitor::VisitClassTemplateDecl( ClassTemplateDecl *D) { if (ConsumerInstance->isInIncludedFile(D)) return true; ClassTemplateDecl *CanonicalD = D->getCanonicalDecl(); if (ConsumerInstance->VisitedDecls.count(CanonicalD)) return true; ConsumerInstance->VisitedDecls.insert(CanonicalD); if (!ConsumerInstance->isValidClassTemplateDecl(D)) return true; TemplateParameterSet ParamsSet; TemplateParameterVisitor ParameterVisitor(ParamsSet); CXXRecordDecl *CXXRD = D->getTemplatedDecl(); CXXRecordDecl *Def = CXXRD->getDefinition(); if (Def) ParameterVisitor.TraverseDecl(Def); // ISSUE: we should also check the parameter usage for partial template // specializations. For example: // template<typename T1, typename T2> struct S{}; // template<typename T1, typename T2> struct<T1 *, T2 *> S{...}; // T1 or T2 could be used in "..." // Also, we could have another bad transformation, for example, // template<bool, typename T> struct S{}; // template<typename T> struct<true, T> S{}; // if we remove bool and true, we will have two definitions for S TemplateParameterList *TPList; if (Def) { // make sure we use the params as in ParameterVisitor const ClassTemplateDecl *CT = Def->getDescribedClassTemplate(); TransAssert(CT && "NULL DescribedClassTemplate!"); TPList = CT->getTemplateParameters(); } else { TPList = CanonicalD->getTemplateParameters(); } unsigned Index = 0; for (TemplateParameterList::const_iterator I = TPList->begin(), E = TPList->end(); I != E; ++I) { const NamedDecl *ND = (*I); if (ParamsSet.count(ND)) { Index++; continue; } ConsumerInstance->ValidInstanceNum++; if (ConsumerInstance->ValidInstanceNum == ConsumerInstance->TransformationCounter) { ConsumerInstance->TheClassTemplateDecl = CanonicalD; ConsumerInstance->TheParameterIndex = Index; ConsumerInstance->TheTemplateName = new TemplateName(CanonicalD); ConsumerInstance->setDefaultArgFlag(ND); } Index++; } return true; }