From: Douglas Gregor Date: Sat, 28 Aug 2010 00:00:50 +0000 (+0000) Subject: Basic code completion support for the base and member initializers in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0133f525a23e18dd444880f7554f25fbcbd834e5;p=clang Basic code completion support for the base and member initializers in a constructor. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112330 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 907472955e..5558eae4da 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4348,7 +4348,10 @@ public: virtual void CodeCompleteNamespaceDecl(Scope *S); virtual void CodeCompleteNamespaceAliasDecl(Scope *S); virtual void CodeCompleteOperatorName(Scope *S); - + virtual void CodeCompleteConstructorInitializer(Decl *Constructor, + CXXBaseOrMemberInitializer** Initializers, + unsigned NumInitializers); + virtual void CodeCompleteObjCAtDirective(Scope *S, Decl *ObjCImpDecl, bool InInterface); virtual void CodeCompleteObjCAtVisibility(Scope *S); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index a62e37bc43..26d460c6ff 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1714,12 +1714,19 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { bool AnyErrors = false; do { - MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); - if (!MemInit.isInvalid()) - MemInitializers.push_back(MemInit.get()); - else - AnyErrors = true; - + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteConstructorInitializer(ConstructorDecl, + MemInitializers.data(), + MemInitializers.size()); + ConsumeCodeCompletionToken(); + } else { + MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); + if (!MemInit.isInvalid()) + MemInitializers.push_back(MemInit.get()); + else + AnyErrors = true; + } + if (Tok.is(tok::comma)) ConsumeToken(); else if (Tok.is(tok::l_brace)) diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 9a2cfe75c1..d1851813e1 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -3267,6 +3267,86 @@ void Sema::CodeCompleteOperatorName(Scope *S) { Results.data(),Results.size()); } +void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, + CXXBaseOrMemberInitializer** Initializers, + unsigned NumInitializers) { + CXXConstructorDecl *Constructor + = static_cast(ConstructorD); + if (!Constructor) + return; + + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Fill in any already-initialized fields or base classes. + llvm::SmallPtrSet InitializedFields; + llvm::SmallPtrSet InitializedBases; + for (unsigned I = 0; I != NumInitializers; ++I) { + if (Initializers[I]->isBaseInitializer()) + InitializedBases.insert( + Context.getCanonicalType(QualType(Initializers[I]->getBaseClass(), 0))); + else + InitializedFields.insert(cast(Initializers[I]->getMember())); + } + + // Add completions for base classes. + unsigned Priority = 1; + 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()))) + continue; + + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk( + Base->getType().getAsString(Context.PrintingPolicy)); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("args"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(CodeCompletionResult(Pattern, Priority++)); + } + + // 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()))) + continue; + + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk( + Base->getType().getAsString(Context.PrintingPolicy)); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("args"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(CodeCompletionResult(Pattern, Priority++)); + } + + // 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()))) + continue; + + if (!Field->getDeclName()) + continue; + + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(Field->getIdentifier()->getName()); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("args"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(CodeCompletionResult(Pattern, Priority++)); + } + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Name, + Results.data(), Results.size()); +} + // Macro that expands to @Keyword or Keyword, depending on whether NeedAt is // true or false. #define OBJC_AT_KEYWORD_NAME(NeedAt,Keyword) NeedAt? "@" #Keyword : #Keyword