From: Douglas Gregor Date: Sun, 29 Aug 2010 19:27:27 +0000 (+0000) Subject: Improve code completion for initializer lists in constructors. Instead X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0c431c8c001e4c1f7488663d98700a8ce1e89e2a;p=clang Improve code completion for initializer lists in constructors. Instead of prioritizing just by initialization order, we bump the priority of just the *next* initializer in the list, and leave everything else at the normal priority. That way, if one intentionally skips the initialization of a base or member (to get default initialization), we'll still get ordered completion for the rest. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112454 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index edc6331af0..c8799372ab 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -30,6 +30,9 @@ namespace clang { /// \brief Default priority values for code-completion results based /// on their kind. enum { + /// \brief Priority for the next initialization in a constructor initializer + /// list. + CCP_NextInitializer = 7, /// \brief Priority for a send-to-super completion. CCP_SuperCompletion = 8, /// \brief Priority for a declaration that is in the local scope. diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index d1851813e1..a7ac0f1170 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -3290,13 +3290,19 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, } // Add completions for base classes. - unsigned Priority = 1; + bool SawLastInitializer = (NumInitializers == 0); CXXRecordDecl *ClassDecl = Constructor->getParent(); for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), BaseEnd = ClassDecl->bases_end(); Base != BaseEnd; ++Base) { - if (!InitializedBases.insert(Context.getCanonicalType(Base->getType()))) + if (!InitializedBases.insert(Context.getCanonicalType(Base->getType()))) { + SawLastInitializer + = NumInitializers > 0 && + Initializers[NumInitializers - 1]->isBaseInitializer() && + Context.hasSameUnqualifiedType(Base->getType(), + QualType(Initializers[NumInitializers - 1]->getBaseClass(), 0)); continue; + } CodeCompletionString *Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk( @@ -3304,15 +3310,24 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("args"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(CodeCompletionResult(Pattern, Priority++)); + Results.AddResult(CodeCompletionResult(Pattern, + SawLastInitializer? CCP_NextInitializer + : CCP_MemberDeclaration)); + SawLastInitializer = false; } // Add completions for virtual base classes. for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); Base != BaseEnd; ++Base) { - if (!InitializedBases.insert(Context.getCanonicalType(Base->getType()))) + if (!InitializedBases.insert(Context.getCanonicalType(Base->getType()))) { + SawLastInitializer + = NumInitializers > 0 && + Initializers[NumInitializers - 1]->isBaseInitializer() && + Context.hasSameUnqualifiedType(Base->getType(), + QualType(Initializers[NumInitializers - 1]->getBaseClass(), 0)); continue; + } CodeCompletionString *Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk( @@ -3320,15 +3335,23 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("args"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(CodeCompletionResult(Pattern, Priority++)); + Results.AddResult(CodeCompletionResult(Pattern, + SawLastInitializer? CCP_NextInitializer + : CCP_MemberDeclaration)); + SawLastInitializer = false; } // Add completions for members. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { - if (!InitializedFields.insert(cast(Field->getCanonicalDecl()))) + if (!InitializedFields.insert(cast(Field->getCanonicalDecl()))) { + SawLastInitializer + = NumInitializers > 0 && + Initializers[NumInitializers - 1]->isMemberInitializer() && + Initializers[NumInitializers - 1]->getMember() == *Field; continue; + } if (!Field->getDeclName()) continue; @@ -3338,7 +3361,10 @@ void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("args"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(CodeCompletionResult(Pattern, Priority++)); + Results.AddResult(CodeCompletionResult(Pattern, + SawLastInitializer? CCP_NextInitializer + : CCP_MemberDeclaration)); + SawLastInitializer = false; } Results.ExitScope(); diff --git a/test/Index/complete-ctor-inits.cpp b/test/Index/complete-ctor-inits.cpp index d1c517daf9..f9cc7022ea 100644 --- a/test/Index/complete-ctor-inits.cpp +++ b/test/Index/complete-ctor-inits.cpp @@ -15,19 +15,26 @@ struct Z : public X, public Y { int a, b, c; }; -Z::Z() : ::X(0), Virt(), a() { } +Z::Z() : ::X(0), Virt(), b(), c() { } // RUN: c-index-test -code-completion-at=%s:18:10 %s | FileCheck -check-prefix=CHECK-CC1 %s -// CHECK-CC1: NotImplemented:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (4) -// CHECK-CC1: NotImplemented:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} (5) -// CHECK-CC1: NotImplemented:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (6) -// CHECK-CC1: NotImplemented:{TypedText Virt}{LeftParen (}{Placeholder args}{RightParen )} (3) -// CHECK-CC1: NotImplemented:{TypedText X}{LeftParen (}{Placeholder args}{RightParen )} (1) -// CHECK-CC1: NotImplemented:{TypedText Y}{LeftParen (}{Placeholder args}{RightParen )} (2) +// CHECK-CC1: NotImplemented:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC1: NotImplemented:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC1: NotImplemented:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC1: NotImplemented:{TypedText Virt}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC1: NotImplemented:{TypedText X}{LeftParen (}{Placeholder args}{RightParen )} (7) +// CHECK-CC1: NotImplemented:{TypedText Y}{LeftParen (}{Placeholder args}{RightParen )} (20) // RUN: c-index-test -code-completion-at=%s:18:23 %s | FileCheck -check-prefix=CHECK-CC2 %s -// CHECK-CC2: NotImplemented:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (3) -// CHECK-CC2: NotImplemented:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} (4) -// CHECK-CC2: NotImplemented:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (5) -// CHECK-CC2: NotImplemented:{TypedText Virt}{LeftParen (}{Placeholder args}{RightParen )} (2) -// CHECK-CC2: NotImplemented:{TypedText Y}{LeftParen (}{Placeholder args}{RightParen )} (1) +// CHECK-CC2: NotImplemented:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC2: NotImplemented:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC2: NotImplemented:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC2: NotImplemented:{TypedText Virt}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC2: NotImplemented:{TypedText Y}{LeftParen (}{Placeholder args}{RightParen )} (7) + +// RUN: c-index-test -code-completion-at=%s:18:36 %s | FileCheck -check-prefix=CHECK-CC3 %s +// CHECK-CC3: NotImplemented:{TypedText a}{LeftParen (}{Placeholder args}{RightParen )} (20) +// CHECK-CC3-NOT: NotImplemented:{TypedText b}{LeftParen (}{Placeholder args}{RightParen )} +// CHECK-CC3: NotImplemented:{TypedText c}{LeftParen (}{Placeholder args}{RightParen )} (7) +// CHECK-CC3-NOT: NotImplemented:{TypedText Virt}{LeftParen (}{Placeholder args}{RightParen )} +// CHECK-CC3: NotImplemented:{TypedText Y}{LeftParen (}{Placeholder args}{RightParen )} (20)