[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