void UseNodiscardCheck::registerMatchers(MatchFinder *Finder) { // If we use ``[[nodiscard]]`` attribute, we require at least C++17. Use a // macro or ``__attribute__`` with pre c++17 compilers by using // ReplacementString option. if ((NoDiscardMacro == "[[nodiscard]]" && !getLangOpts().CPlusPlus17) || !getLangOpts().CPlusPlus) return; auto FunctionObj = cxxRecordDecl(hasAnyName("::std::function", "::boost::function")); // Find all non-void const methods which have not already been marked to // warn on unused result. Finder->addMatcher( cxxMethodDecl( allOf(isConst(), isDefinitionOrInline(), unless(anyOf( returns(voidType()), isNoReturn(), isOverloadedOperator(), isVariadic(), hasTemplateReturnType(), hasClassMutableFields(), isConversionOperator(), hasAttr(clang::attr::WarnUnusedResult), hasType(isInstantiationDependentType()), hasAnyParameter(anyOf( parmVarDecl(anyOf(hasType(FunctionObj), hasType(references(FunctionObj)))), hasType(isNonConstReferenceOrPointer()), hasParameterPack())))))) .bind("no_discard"), this); }
void VirtualNearMissCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; Finder->addMatcher( cxxMethodDecl( unless(anyOf(isOverride(), isImplicit(), cxxConstructorDecl(), cxxDestructorDecl(), cxxConversionDecl(), isStatic(), isOverloadedOperator()))) .bind("method"), this); }
bool DeclReferencer::Reference(const clang::NamedDecl *D) { if (D->isInvalidDecl()) return true; for (const clang::Decl *DI = D; !isa<clang::TranslationUnitDecl>(DI); DI = cast<clang::Decl>(DI->getDeclContext())) if (auto RD = dyn_cast<clang::CXXRecordDecl>(DI)) if (RD->isLocalClass()) return true; // are local records emitted when emitting a function? if no this is a FIXME if (auto VD = dyn_cast<clang::VarDecl>(D)) if (!VD->isFileVarDecl()) return true; if (auto FD = dyn_cast<clang::FunctionDecl>(D)) { if (!isMapped(D)) return true; if (FD->getBuiltinID() || (FD->isOverloadedOperator() && FD->isImplicit())) return true; if (FD->isExternC()) return true; // FIXME: Clang 3.6 doesn't always map decls to the right source file, // so the path generated by typeQualifiedFor although correct will result in a failed lookup. // This may get fixed by 3.7. } if (Referenced.count(D->getCanonicalDecl())) return true; Referenced.insert(D->getCanonicalDecl()); // Although we try to add all the needed imports during importAll(), sometimes we miss a module so ensure it gets loaded auto im = mapper.AddImplicitImportForDecl(loc, D, true); im->isstatic = true; auto dst = Package::resolve(im->packages, NULL, &im->pkg); if (!dst->lookup(im->id)) { im->semantic(sc); im->semantic2(sc); } ReferenceTemplateArguments(D); auto Func = dyn_cast<clang::FunctionDecl>(D); if (Func && Func->getPrimaryTemplate()) D = cast<clang::NamedDecl>(getCanonicalDecl(getSpecializedDeclOrExplicit(Func))); // HACK FIXME if (Func && Func->isOutOfLine() && Func->getFriendObjectKind() != clang::Decl::FOK_None) { auto Pattern = Func; if (auto MemberFunc = Func->getInstantiatedFromMemberFunction()) Pattern = MemberFunc; if (Pattern->isDependentContext()) return true; } auto e = expmap.fromExpressionDeclRef(loc, const_cast<clang::NamedDecl*>(D), nullptr, TQ_OverOpSkipSpecArg); e = e->semantic(sc); if (Func && Func->getPrimaryTemplate()) { assert(e->op == TOKvar || e->op == TOKtemplate || e->op == TOKimport); Dsymbol *s; if (e->op == TOKvar) s = static_cast<SymbolExp*>(e)->var; else if (e->op == TOKtemplate) s = static_cast<TemplateExp*>(e)->td; else s = static_cast<ScopeExp*>(e)->sds; // if it's a non-template function there's nothing to do, it will be semantic'd along with its declcontext // if it's a template spec we must instantiate the right overload struct DEquals { const clang::Decl* D; Dsymbol *s = nullptr; // return value static int fp(void *param, Dsymbol *s) { if (!isCPP(s)) return 0; auto fd = s->isFuncDeclaration(); auto td = static_cast<cpp::TemplateDeclaration*>( s->isTemplateDeclaration()); DEquals *p = (DEquals *)param; decltype(D) s_D = fd ? getFD(fd) : td->TempOrSpec; if (p->D == getCanonicalDecl(s_D)) { p->s = s; return 1; } return 0; } }; DEquals p; p.D = D; overloadApply(s, &p, &DEquals::fp); assert(p.s && p.s->isTemplateDeclaration()); auto td = static_cast<cpp::TemplateDeclaration*>(p.s->isTemplateDeclaration()); if (td->semanticRun == PASSinit) { assert(td->scope); td->semantic(td->scope); // this must be done here because havetempdecl being set to true it won't be done by findTempDecl() assert(td->semanticRun > PASSinit); } auto tiargs = mapper.fromTemplateArguments(loc, Func->getTemplateSpecializationArgs()); assert(tiargs); SpecValue spec(mapper); getIdentifier(Func, &spec, true); if (spec) tiargs->shift(spec.toTemplateArg(loc)); auto tempinst = new cpp::TemplateInstance(loc, td, tiargs); tempinst->Inst = const_cast<clang::FunctionDecl*>(Func); tempinst->semantictiargsdone = false; // NOTE: the "havetempdecl" ctor of Templateinstance set semantictiargsdone to true... // Time was lost finding this out for the second or third time. td->makeForeignInstance(tempinst); tempinst->semantic(sc); } // Memory usage can skyrocket when using a large library if (im->packages) delete im->packages; delete im; delete e; return true; }