diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -137,14 +137,42 @@ } bool shouldSkipFunctionBody(Decl *D) override { - // Generally we skip function bodies in preambles for speed. - // We can make exceptions for functions that are cheap to parse and - // instantiate, widely used, and valuable (e.g. commonly produce errors). - if (const auto *FT = llvm::dyn_cast(D)) { - if (const auto *II = FT->getDeclName().getAsIdentifierInfo()) - // std::make_unique is trivial, and we diagnose bad constructor calls. - if (II->isStr("make_unique") && FT->isInStdNamespace()) - return false; + // Find functions with variadic template arguments: + // Any templated function... + if (auto *FT = llvm::dyn_cast(D)) { + // ... with a template parameter pack... + if (FT->getTemplateParameters()->hasParameterPack()) { + auto PackIt = std::find_if( + FT->getInjectedTemplateArgs().begin(), + FT->getInjectedTemplateArgs().end(), [](const auto &Arg) { + return Arg.getKind() == TemplateArgument::Pack; + }); + assert(PackIt != FT->getInjectedTemplateArgs().end() && + "Can't find parameter pack in argument list!"); + const auto &Pack = PackIt->getPackAsArray(); + + // ... that is a type parameter pack... + if (Pack.size() == 1 && Pack[0].getKind() == TemplateArgument::Type) { + const auto *PackType = + Pack[0].getAsType().getNonPackExpansionType().getTypePtr(); + const auto *FD = FT->getAsFunction(); + const auto NumParams = FD->getNumParams(); + if (NumParams > 0) { + const auto *LastParam = FD->getParamDecl(NumParams - 1); + // ... with its type matching the last parameter (pack) of the + // function (minus references)... + if (LastParam->isParameterPack()) { + if (LastParam->getType() + .getNonPackExpansionType() + .getNonReferenceType() + .getTypePtr() == PackType) { + // ... we need to parse the body + return false; + } + } + } + } + } } return true; }