]> granicus.if.org Git - clang/commitdiff
Make the construction of the code-completion string for a function
authorDouglas Gregor <dgregor@apple.com>
Fri, 18 Sep 2009 23:21:38 +0000 (23:21 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 18 Sep 2009 23:21:38 +0000 (23:21 +0000)
template smarter, by taking into account which function template
parameters are deducible from the call arguments. For example,

  template<typename RandomAccessIterator>
  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<class X, class Y>
  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
lib/Sema/Sema.h
lib/Sema/SemaTemplateDeduction.cpp
test/CodeCompletion/function-templates.cpp [new file with mode: 0644]

index 2c682ebbfc41609fdfbc56ebf5b95f938239e35b..8c8d6a18318e23eb3d15156bb311f726441d5c1a 100644 (file)
@@ -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<TemplateTypeParmDecl>(*P)) {
@@ -850,13 +852,51 @@ CodeCompleteConsumer::CreateCodeCompletionString(Result R) {
   }
   
   if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(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<bool, 16> 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<TemplateTypeParmDecl>(Param))
+          HasDefaultArg = TTP->hasDefaultArgument();
+        else if (NonTypeTemplateParmDecl *NTTP 
+                   = dyn_cast<NonTypeTemplateParmDecl>(Param))
+          HasDefaultArg = NTTP->hasDefaultArgument();
+        else {
+          assert(isa<TemplateTemplateParmDecl>(Param));
+          HasDefaultArg 
+            = cast<TemplateTemplateParmDecl>(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(")");
index abbf1c3bff6059783c8852b845819428860d4883..a95fac9dcd54ad2e3736410975f2477250a62e17 100644 (file)
@@ -2750,8 +2750,10 @@ public:
   
   void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
                                   bool OnlyDeduced,
-                                  llvm::SmallVectorImpl<bool> &Deduced);
-
+                                  llvm::SmallVectorImpl<bool> &Used);
+  void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
+                                     llvm::SmallVectorImpl<bool> &Deduced);
+  
   //===--------------------------------------------------------------------===//
   // C++ Template Instantiation
   //
index 24246e57348ec319ebadc2a6ca818ccaf5e7d252..5a5d63edc2966a0b2fc3782f15eeaebc6fa6a5d6 100644 (file)
@@ -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<bool> &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 (file)
index 0000000..c9a893e
--- /dev/null
@@ -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<typename RandomAccessIterator>
+  void sort(RandomAccessIterator first, RandomAccessIterator last);
+  
+  template<class X, class Y>
+  X* dyn_cast(Y *Val);
+}
+
+void f() {
+  // CHECK-CC1: dyn_cast<<#class X#>>(<#Y *Val#>)
+  // CHECK-CC1: sort(<#RandomAccessIterator first#>, <#RandomAccessIterator last#>)
+  std::
+