[cfe-commits] r82467 - in /cfe/trunk: include/clang/Parse/Action.h lib/Parse/ParseStmt.cpp lib/Sema/Sema.h lib/Sema/SemaCodeComplete.cpp test/CodeCompletion/enum-switch-case.c

Douglas Gregor dgregor at apple.com
Mon Sep 21 11:10:24 PDT 2009


Author: dgregor
Date: Mon Sep 21 13:10:23 2009
New Revision: 82467

URL: http://llvm.org/viewvc/llvm-project?rev=82467&view=rev
Log:
Code completion for "case" statements within a switch on an expression
of enumeration type, providing the various unused enumerators as options.

Added:
    cfe/trunk/test/CodeCompletion/enum-switch-case.c
Modified:
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=82467&r1=82466&r2=82467&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Mon Sep 21 13:10:23 2009
@@ -2217,12 +2217,17 @@
   /// This code completion action is invoked when the code-completion
   /// token is found after a tag keyword (struct, union, enum, or class).
   ///
-  /// \para, S the scope in which the tag reference occurs.
+  /// \param S the scope in which the tag reference occurs.
   ///
   /// \param TagSpec an instance of DeclSpec::TST, indicating what kind of tag
   /// this is (struct/union/enum/class).
   virtual void CodeCompleteTag(Scope *S, unsigned TagSpec) { }
   
+  /// \brief Code completion for a case statement.
+  ///
+  /// \brief S the scope in which the case statement occurs.
+  virtual void CodeCompleteCase(Scope *S) { }
+  
   /// \brief Code completion for a C++ nested-name-specifier that precedes a
   /// qualified-id of some form.
   ///

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=82467&r1=82466&r2=82467&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Mon Sep 21 13:10:23 2009
@@ -261,6 +261,11 @@
   do {
     SourceLocation CaseLoc = ConsumeToken();  // eat the 'case'.
 
+    if (Tok.is(tok::code_completion)) {
+      Actions.CodeCompleteCase(CurScope);
+      ConsumeToken();
+    }
+    
     OwningExprResult LHS(ParseConstantExpression());
     if (LHS.isInvalid()) {
       SkipUntil(tok::colon);

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=82467&r1=82466&r2=82467&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Sep 21 13:10:23 2009
@@ -3633,6 +3633,7 @@
                                                SourceLocation OpLoc,
                                                bool IsArrow);
   virtual void CodeCompleteTag(Scope *S, unsigned TagSpec);
+  virtual void CodeCompleteCase(Scope *S);
   virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
                                        bool EnteringContext);
   virtual void CodeCompleteUsing(Scope *S);

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=82467&r1=82466&r2=82467&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Mon Sep 21 13:10:23 2009
@@ -883,6 +883,79 @@
   HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());
 }
 
+void Sema::CodeCompleteCase(Scope *S) {
+  if (getSwitchStack().empty() || !CodeCompleter)
+    return;
+  
+  SwitchStmt *Switch = getSwitchStack().back();
+  if (!Switch->getCond()->getType()->isEnumeralType())
+    return;
+  
+  // Code-complete the cases of a switch statement over an enumeration type
+  // by providing the list of 
+  EnumDecl *Enum = Switch->getCond()->getType()->getAs<EnumType>()->getDecl();
+  
+  // Determine which enumerators we have already seen in the switch statement.
+  // FIXME: Ideally, we would also be able to look *past* the code-completion
+  // token, in case we are code-completing in the middle of the switch and not
+  // at the end. However, we aren't able to do so at the moment.
+  llvm::SmallPtrSet<EnumConstantDecl *, 8> EnumeratorsSeen;
+  for (SwitchCase *SC = Switch->getSwitchCaseList(); SC; 
+       SC = SC->getNextSwitchCase()) {
+    CaseStmt *Case = dyn_cast<CaseStmt>(SC);
+    if (!Case)
+      continue;
+
+    Expr *CaseVal = Case->getLHS()->IgnoreParenCasts();
+    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CaseVal))
+      if (EnumConstantDecl *Enumerator 
+            = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
+        // We look into the AST of the case statement to determine which 
+        // enumerator was named. Alternatively, we could compute the value of 
+        // the integral constant expression, then compare it against the
+        // values of each enumerator. However, value-based approach would not 
+        // work as well with C++ templates where enumerators declared within a 
+        // template are type- and value-dependent.
+        EnumeratorsSeen.insert(Enumerator);
+        
+        // FIXME: If this is a qualified-id, should we keep track of the 
+        // nested-name-specifier so we can reproduce it as part of code
+        // completion? e.g.,
+        //
+        //   switch (TagD.getKind()) {
+        //     case TagDecl::TK_enum:
+        //       break;
+        //     case XXX
+        //
+        // At the XXX, we would like our completions to be TagDecl::TK_union,
+        // TagDecl::TK_struct, and TagDecl::TK_class, rather than TK_union,
+        // TK_struct, and TK_class.
+      }
+  }
+  
+  // Add any enumerators that have not yet been mentioned.
+  ResultBuilder Results(*this);
+  Results.EnterNewScope();
+  for (EnumDecl::enumerator_iterator E = Enum->enumerator_begin(),
+                                  EEnd = Enum->enumerator_end();
+       E != EEnd; ++E) {
+    if (EnumeratorsSeen.count(*E))
+      continue;
+    
+    Results.MaybeAddResult(CodeCompleteConsumer::Result(*E, 0));
+  }
+  Results.ExitScope();
+  
+  // In C++, add nested-name-specifiers.
+  if (getLangOptions().CPlusPlus) {
+    Results.setFilter(&ResultBuilder::IsNestedNameSpecifier);
+    CollectLookupResults(S, Context.getTranslationUnitDecl(), 1, 
+                         Results);
+  }
+  
+  HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size());  
+}
+
 void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS,
                                    bool EnteringContext) {
   if (!SS.getScopeRep() || !CodeCompleter)

Added: cfe/trunk/test/CodeCompletion/enum-switch-case.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeCompletion/enum-switch-case.c?rev=82467&view=auto

==============================================================================
--- cfe/trunk/test/CodeCompletion/enum-switch-case.c (added)
+++ cfe/trunk/test/CodeCompletion/enum-switch-case.c Mon Sep 21 13:10:23 2009
@@ -0,0 +1,27 @@
+// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
+// RUN: true
+
+enum Color {
+  Red,
+  Orange,
+  Yellow,
+  Green,
+  Blue,
+  Indigo,
+  Violet
+};
+
+void test(enum Color color) {
+  switch (color) {
+    case Red:
+      break;
+      
+    case Yellow:
+      break;
+
+    // CHECK-CC1: Blue : 0
+    // CHECK-NEXT-CC1: Green : 0
+    // CHECK-NEXT-CC1: Indigo : 0
+    // CHECK-NEXT-CC1: Orange : 0
+    // CHECK-NEXT-CC1: Violet : 0
+    case 





More information about the cfe-commits mailing list