namespace tidy {
namespace misc {
+namespace {
+// FIXME: Move ASTMatcher library.
+AST_POLYMORPHIC_MATCHER_P(
+ forEachTemplateArgument,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
+ TemplateSpecializationType, FunctionDecl),
+ clang::ast_matchers::internal::Matcher<TemplateArgument>, InnerMatcher) {
+ ArrayRef<TemplateArgument> TemplateArgs =
+ clang::ast_matchers::internal::getTemplateSpecializationArgs(Node);
+ clang::ast_matchers::internal::BoundNodesTreeBuilder Result;
+ bool Matched = false;
+ for (const auto &Arg : TemplateArgs) {
+ clang::ast_matchers::internal::BoundNodesTreeBuilder ArgBuilder(*Builder);
+ if (InnerMatcher.matches(Arg, Finder, &ArgBuilder)) {
+ Matched = true;
+ Result.addMatch(ArgBuilder);
+ }
+ }
+ *Builder = std::move(Result);
+ return Matched;
+}
+} // namespace
+
// A function that helps to tell whether a TargetDecl in a UsingDecl will be
// checked. Only variable, function, function template, class template, class,
// enum declaration and enum constant declaration are considered.
Finder->addMatcher(callExpr(callee(unresolvedLookupExpr().bind("used"))),
this);
Finder->addMatcher(
- callExpr(hasDeclaration(functionDecl(hasAnyTemplateArgument(
- anyOf(refersToTemplate(templateName().bind("used")),
- refersToDeclaration(functionDecl().bind("used"))))))),
+ callExpr(hasDeclaration(functionDecl(
+ forEachTemplateArgument(templateArgument().bind("used"))))),
this);
- Finder->addMatcher(loc(templateSpecializationType(hasAnyTemplateArgument(
+ Finder->addMatcher(loc(templateSpecializationType(forEachTemplateArgument(
templateArgument().bind("used")))),
this);
}
Contexts.push_back(Context);
return;
}
- // Mark using declarations as used by setting FoundDecls' value to zero. As
- // the AST is walked in order, usages are only marked after a the
- // corresponding using declaration has been found.
- // FIXME: This currently doesn't look at whether the type reference is
- // actually found with the help of the using declaration.
- if (const auto *Used = Result.Nodes.getNodeAs<NamedDecl>("used")) {
+
+ // Mark a corresponding using declaration as used.
+ auto RemoveNamedDecl = [&](const NamedDecl *Used) {
+ removeFromFoundDecls(Used);
+ // Also remove variants of Used.
if (const auto *FD = dyn_cast<FunctionDecl>(Used)) {
removeFromFoundDecls(FD->getPrimaryTemplate());
} else if (const auto *Specialization =
dyn_cast<ClassTemplateSpecializationDecl>(Used)) {
- Used = Specialization->getSpecializedTemplate();
+ removeFromFoundDecls(Specialization->getSpecializedTemplate());
+ } else if (const auto *FD = dyn_cast<FunctionDecl>(Used)) {
+ if (const auto *FDT = FD->getPrimaryTemplate())
+ removeFromFoundDecls(FDT);
+ } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(Used)) {
+ if (const auto *ET = ECD->getType()->getAs<EnumType>())
+ removeFromFoundDecls(ET->getDecl());
}
- removeFromFoundDecls(Used);
+ };
+ // We rely on the fact that the clang AST is walked in order, usages are only
+ // marked after a corresponding using decl has been found.
+ if (const auto *Used = Result.Nodes.getNodeAs<NamedDecl>("used")) {
+ RemoveNamedDecl(Used);
return;
}
if (const auto *Used = Result.Nodes.getNodeAs<TemplateArgument>("used")) {
- // FIXME: Support non-type template parameters.
if (Used->getKind() == TemplateArgument::Template) {
if (const auto *TD = Used->getAsTemplate().getAsTemplateDecl())
removeFromFoundDecls(TD);
} else if (Used->getKind() == TemplateArgument::Type) {
if (auto *RD = Used->getAsType()->getAsCXXRecordDecl())
removeFromFoundDecls(RD);
+ } else if (Used->getKind() == TemplateArgument::Declaration) {
+ RemoveNamedDecl(Used->getAsDecl());
}
return;
}
- if (const auto *Used = Result.Nodes.getNodeAs<TemplateName>("used")) {
- removeFromFoundDecls(Used->getAsTemplateDecl());
- return;
- }
-
if (const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>("used")) {
- if (const auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
- if (const auto *FDT = FD->getPrimaryTemplate())
- removeFromFoundDecls(FDT);
- else
- removeFromFoundDecls(FD);
- } else if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- removeFromFoundDecls(VD);
- } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
- removeFromFoundDecls(ECD);
- if (const auto *ET = ECD->getType()->getAs<EnumType>())
- removeFromFoundDecls(ET->getDecl());
- }
+ RemoveNamedDecl(DRE->getDecl());
+ return;
}
// Check the uninstantiated template function usage.
if (const auto *ULE = Result.Nodes.getNodeAs<UnresolvedLookupExpr>("used")) {