From 63f07c55d58951574afe9bbb9f7cb3f92eecdd9b Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 18 Sep 2009 23:21:38 +0000 Subject: [PATCH] Make the construction of the code-completion string for a function template smarter, by taking into account which function template parameters are deducible from the call arguments. For example, template void sort(RandomAccessIterator first, RandomAccessIterator last); will have a code-completion string like sort({RandomAccessIterator first}, {RandomAccessIterator last}) since the template argument for its template parameter is deducible. On the other hand, template X* dyn_cast(Y *Val); will have a code-completion string like dyn_cast<{class X}>({Y *Val}) since the template type parameter X is not deducible from the function call. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82306 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/CodeCompleteConsumer.cpp | 56 ++++++++++++++++++---- lib/Sema/Sema.h | 6 ++- lib/Sema/SemaTemplateDeduction.cpp | 15 ++++++ test/CodeCompletion/function-templates.cpp | 16 +++++++ 4 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 test/CodeCompletion/function-templates.cpp diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 2c682ebbfc..8c8d6a1831 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -765,14 +765,16 @@ static void AddFunctionParameterChunks(ASTContext &Context, /// \brief Add template parameter chunks to the given code completion string. static void AddTemplateParameterChunks(ASTContext &Context, TemplateDecl *Template, - CodeCompletionString *Result) { + CodeCompletionString *Result, + unsigned MaxParameters = 0) { CodeCompletionString *CCStr = Result; bool FirstParameter = true; TemplateParameterList *Params = Template->getTemplateParameters(); - for (TemplateParameterList::iterator P = Params->begin(), - PEnd = Params->end(); - P != PEnd; ++P) { + TemplateParameterList::iterator PEnd = Params->end(); + if (MaxParameters) + PEnd = Params->begin() + MaxParameters; + for (TemplateParameterList::iterator P = Params->begin(); P != PEnd; ++P) { bool HasDefaultArg = false; std::string PlaceholderStr; if (TemplateTypeParmDecl *TTP = dyn_cast(*P)) { @@ -850,13 +852,51 @@ CodeCompleteConsumer::CreateCodeCompletionString(Result R) { } if (FunctionTemplateDecl *FunTmpl = dyn_cast(ND)) { - // FIXME: We treat these like functions for now, but it would be far - // better if we computed the template parameters that are non-deduced from - // a call, then printed only those template parameters in "<...>" before - // printing the function call arguments. CodeCompletionString *Result = new CodeCompletionString; FunctionDecl *Function = FunTmpl->getTemplatedDecl(); Result->AddTextChunk(Function->getNameAsString().c_str()); + + // Figure out which template parameters are deduced (or have default + // arguments). + llvm::SmallVector Deduced; + getSema().MarkDeducedTemplateParameters(FunTmpl, Deduced); + unsigned LastDeducibleArgument; + for (LastDeducibleArgument = Deduced.size(); LastDeducibleArgument > 0; + --LastDeducibleArgument) { + if (!Deduced[LastDeducibleArgument - 1]) { + // C++0x: Figure out if the template argument has a default. If so, + // the user doesn't need to type this argument. + // FIXME: We need to abstract template parameters better! + bool HasDefaultArg = false; + NamedDecl *Param = FunTmpl->getTemplateParameters()->getParam( + LastDeducibleArgument - 1); + if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) + HasDefaultArg = TTP->hasDefaultArgument(); + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast(Param)) + HasDefaultArg = NTTP->hasDefaultArgument(); + else { + assert(isa(Param)); + HasDefaultArg + = cast(Param)->hasDefaultArgument(); + } + + if (!HasDefaultArg) + break; + } + } + + if (LastDeducibleArgument) { + // Some of the function template arguments cannot be deduced from a + // function call, so we introduce an explicit template argument list + // containing all of the arguments up to the first deducible argument. + Result->AddTextChunk("<"); + AddTemplateParameterChunks(getSema().Context, FunTmpl, Result, + LastDeducibleArgument); + Result->AddTextChunk(">"); + } + + // Add the function parameters Result->AddTextChunk("("); AddFunctionParameterChunks(getSema().Context, Function, Result); Result->AddTextChunk(")"); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index abbf1c3bff..a95fac9dcd 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2750,8 +2750,10 @@ public: void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, - llvm::SmallVectorImpl &Deduced); - + llvm::SmallVectorImpl &Used); + void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, + llvm::SmallVectorImpl &Deduced); + //===--------------------------------------------------------------------===// // C++ Template Instantiation // diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 24246e5734..5a5d63edc2 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2199,3 +2199,18 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Used); } + +/// \brief Marks all of the template parameters that will be deduced by a +/// call to the given function template. +void Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, + llvm::SmallVectorImpl &Deduced) { + TemplateParameterList *TemplateParams + = FunctionTemplate->getTemplateParameters(); + Deduced.clear(); + Deduced.resize(TemplateParams->size()); + + FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); + for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) + ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(), + true, Deduced); +} diff --git a/test/CodeCompletion/function-templates.cpp b/test/CodeCompletion/function-templates.cpp new file mode 100644 index 0000000000..c9a893ec9c --- /dev/null +++ b/test/CodeCompletion/function-templates.cpp @@ -0,0 +1,16 @@ +// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s && +// RUN: true + +namespace std { + template + void sort(RandomAccessIterator first, RandomAccessIterator last); + + template + X* dyn_cast(Y *Val); +} + +void f() { + // CHECK-CC1: dyn_cast<<#class X#>>(<#Y *Val#>) + // CHECK-CC1: sort(<#RandomAccessIterator first#>, <#RandomAccessIterator last#>) + std:: + -- 2.40.0