From: Douglas Gregor Date: Sun, 10 Jan 2010 23:08:15 +0000 (+0000) Subject: Improve code completion by introducing patterns for the various C and X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=01dfea02d1da297e8b53db8eea3d3cc652acda8d;p=clang Improve code completion by introducing patterns for the various C and C++ grammatical constructs that show up in top-level (namespace-level) declarations, member declarations, template declarations, statements, expressions, conditions, etc. For example, we now provide a pattern for static_cast(expr) when we can have an expression, or using namespace identifier; when we can have a using directive. Also, improves the results of code completion at the beginning of a top-level declaration. Previously, we would see value names (function names, global variables, etc.); now we see types, namespace names, etc., but no values. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93134 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 1c8da3077c..96c1b2f087 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -581,7 +581,28 @@ enum CXCompletionChunkKind { * the text buffer. Rather, it is meant to illustrate the type that an * expression using the given completion string would have. */ - CXCompletionChunk_ResultType + CXCompletionChunk_ResultType, + /** + * \brief A colon (':'). + */ + CXCompletionChunk_Colon, + /** + * \brief A semicolon (';'). + */ + CXCompletionChunk_SemiColon, + /** + * \brief An '=' sign. + */ + CXCompletionChunk_Equal, + /** + * Horizontal space (' '). + */ + CXCompletionChunk_HorizontalSpace, + /** + * Vertical space ('\n'), after which it is generally a good idea to + * perform indentation. + */ + CXCompletionChunk_VerticalSpace }; /** diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 1bf999094b..be46851fe1 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -2340,11 +2340,40 @@ public: /// \todo Code completion for attributes. //@{ + /// \brief Describes the context in which code completion occurs. + enum CodeCompletionContext { + /// \brief Code completion occurs at top-level or namespace context. + CCC_Namespace, + /// \brief Code completion occurs within a class, struct, or union. + CCC_Class, + /// \brief Code completion occurs following one or more template + /// headers. + CCC_Template, + /// \brief Code completion occurs following one or more template + /// headers within a class. + CCC_MemberTemplate, + /// \brief Code completion occurs within an expression. + CCC_Expression, + /// \brief Code completion occurs within a statement, which may + /// also be an expression or a declaration. + CCC_Statement, + /// \brief Code completion occurs at the beginning of the + /// initialization statement (or expression) in a for loop. + CCC_ForInit, + /// \brief Code completion ocurs within the condition of an if, + /// while, switch, or for statement. + CCC_Condition + }; + /// \brief Code completion for an ordinary name that occurs within the given /// scope. /// /// \param S the scope in which the name occurs. - virtual void CodeCompleteOrdinaryName(Scope *S) { } + /// + /// \param CompletionContext the context in which code completion + /// occurs. + virtual void CodeCompleteOrdinaryName(Scope *S, + CodeCompletionContext CompletionContext) { } /// \brief Code completion for a member access expression. /// diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h index aec10f32fe..82f9bd8ccf 100644 --- a/include/clang/Sema/CodeCompleteConsumer.h +++ b/include/clang/Sema/CodeCompleteConsumer.h @@ -85,7 +85,18 @@ public: /// \brief A right angle bracket ('>'). CK_RightAngle, /// \brief A comma separator (','). - CK_Comma + CK_Comma, + /// \brief A colon (':'). + CK_Colon, + /// \brief A semicolon (';'). + CK_SemiColon, + /// \brief An '=' sign. + CK_Equal, + /// \brief Horizontal whitespace (' '). + CK_HorizontalSpace, + /// \brief Verticle whitespace ('\n' or '\r\n', depending on the + /// platform). + CK_VerticalSpace }; /// \brief One piece of the code completion string. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index f429ac991d..bc6dda8ed7 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -814,7 +814,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, AccessSpecifier AS, DeclSpecContext DSContext) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(CurScope); + Action::CodeCompletionContext CCC = Action::CCC_Namespace; + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) + CCC = DSContext == DSC_class? Action::CCC_MemberTemplate + : Action::CCC_Template; + else if (DSContext == DSC_class) + CCC = Action::CCC_Class; + + Actions.CodeCompleteOrdinaryName(CurScope, CCC); ConsumeToken(); } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 4d6988d5f2..669575c4f0 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -200,11 +200,6 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// expression ',' assignment-expression /// Parser::OwningExprResult Parser::ParseExpression() { - if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(CurScope); - ConsumeToken(); - } - OwningExprResult LHS(ParseAssignmentExpression()); if (LHS.isInvalid()) return move(LHS); @@ -248,6 +243,11 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { /// ParseAssignmentExpression - Parse an expr that doesn't include commas. /// Parser::OwningExprResult Parser::ParseAssignmentExpression() { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression); + ConsumeToken(); + } + if (Tok.is(tok::kw_throw)) return ParseThrowExpression(); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index abd26d7d49..3efa6f0180 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -585,6 +585,11 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { /// \returns true if there was a parsing, false otherwise. bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, DeclPtrTy &DeclResult) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Condition); + ConsumeToken(); + } + if (!isCXXConditionDeclaration()) { ExprResult = ParseExpression(); // expression DeclResult = DeclPtrTy(); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 277cc91d37..21e960aa81 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -95,7 +95,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } case tok::code_completion: - Actions.CodeCompleteOrdinaryName(CurScope); + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Statement); ConsumeToken(); return ParseStatementOrDeclaration(OnlyStatement); @@ -955,7 +955,9 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { DeclPtrTy SecondVar; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(CurScope); + Actions.CodeCompleteOrdinaryName(CurScope, + C99orCXXorObjC? Action::CCC_ForInit + : Action::CCC_Expression); ConsumeToken(); } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 52c0153bfa..bf0c7b286a 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -455,7 +455,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) SingleDecl = ParseObjCMethodDefinition(); break; case tok::code_completion: - Actions.CodeCompleteOrdinaryName(CurScope); + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Namespace); ConsumeToken(); return ParseExternalDeclaration(Attr); case tok::kw_using: diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index b9b85dfb80..0a00b4226d 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -85,6 +85,26 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) case CK_Comma: this->Text = ", "; break; + + case CK_Colon: + this->Text = ": "; + break; + + case CK_SemiColon: + this->Text = ";"; + break; + + case CK_Equal: + this->Text = " = "; + break; + + case CK_HorizontalSpace: + this->Text = " "; + break; + + case CK_VerticalSpace: + this->Text = "\n"; + break; } } @@ -140,6 +160,11 @@ CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const { case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: return Chunk(Kind, Text); case CK_Optional: { @@ -177,6 +202,11 @@ CodeCompletionString::Chunk::Destroy() { case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: break; } } @@ -271,6 +301,11 @@ void CodeCompletionString::Serialize(llvm::raw_ostream &OS) const { case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: break; } } @@ -326,6 +361,11 @@ CodeCompletionString *CodeCompletionString::Deserialize(const char *&Str, case CK_LeftAngle: case CK_RightAngle: case CK_Comma: + case CK_Colon: + case CK_SemiColon: + case CK_Equal: + case CK_HorizontalSpace: + case CK_VerticalSpace: Result->AddChunk(Chunk(Kind)); break; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index f487fbeb5b..ec08658b5c 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3806,7 +3806,8 @@ public: /// \name Code completion //@{ - virtual void CodeCompleteOrdinaryName(Scope *S); + virtual void CodeCompleteOrdinaryName(Scope *S, + CodeCompletionContext CompletionContext); virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, SourceLocation OpLoc, bool IsArrow); diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index ef82a941b5..582b36901c 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -158,6 +158,7 @@ namespace { /// //@{ bool IsOrdinaryName(NamedDecl *ND) const; + bool IsOrdinaryNonValueName(NamedDecl *ND) const; bool IsNestedNameSpecifier(NamedDecl *ND) const; bool IsEnum(NamedDecl *ND) const; bool IsClassOrStruct(NamedDecl *ND) const; @@ -517,6 +518,17 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { return ND->getIdentifierNamespace() & IDNS; } +/// \brief Determines whether this given declaration will be found by +/// ordinary name lookup. +bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const { + unsigned IDNS = Decl::IDNS_Ordinary; + if (SemaRef.getLangOptions().CPlusPlus) + IDNS |= Decl::IDNS_Tag; + + return (ND->getIdentifierNamespace() & IDNS) && + !isa(ND) && !isa(ND); +} + /// \brief Determines whether the given declaration is suitable as the /// start of a C++ nested-name-specifier, e.g., a class or namespace. bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const { @@ -797,22 +809,32 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, Results.MaybeAddResult(Result("enum", Rank)); Results.MaybeAddResult(Result("struct", Rank)); Results.MaybeAddResult(Result("union", Rank)); - + Results.MaybeAddResult(Result("const", Rank)); + Results.MaybeAddResult(Result("volatile", Rank)); + if (LangOpts.C99) { // C99-specific Results.MaybeAddResult(Result("_Complex", Rank)); Results.MaybeAddResult(Result("_Imaginary", Rank)); Results.MaybeAddResult(Result("_Bool", Rank)); + Results.MaybeAddResult(Result("restrict", Rank)); } if (LangOpts.CPlusPlus) { // C++-specific Results.MaybeAddResult(Result("bool", Rank)); Results.MaybeAddResult(Result("class", Rank)); - Results.MaybeAddResult(Result("typename", Rank)); Results.MaybeAddResult(Result("wchar_t", Rank)); + // typename qualified-id + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typename"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("qualified-id"); + Results.MaybeAddResult(Result(Pattern, Rank)); + if (LangOpts.CPlusPlus0x) { + Results.MaybeAddResult(Result("auto", Rank)); Results.MaybeAddResult(Result("char16_t", Rank)); Results.MaybeAddResult(Result("char32_t", Rank)); Results.MaybeAddResult(Result("decltype", Rank)); @@ -825,10 +847,487 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, unsigned Rank, // Results.MaybeAddResult(Result("_Decimal32", Rank)); // Results.MaybeAddResult(Result("_Decimal64", Rank)); // Results.MaybeAddResult(Result("_Decimal128", Rank)); - Results.MaybeAddResult(Result("typeof", Rank)); + + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typeof"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); } } +static void AddStorageSpecifiers(Action::CodeCompletionContext CCC, + const LangOptions &LangOpts, + unsigned Rank, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + // Note: we don't suggest either "auto" or "register", because both + // are pointless as storage specifiers. Elsewhere, we suggest "auto" + // in C++0x as a type specifier. + Results.MaybeAddResult(Result("extern", Rank)); + Results.MaybeAddResult(Result("static", Rank)); +} + +static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC, + const LangOptions &LangOpts, + unsigned Rank, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + switch (CCC) { + case Action::CCC_Class: + case Action::CCC_MemberTemplate: + if (LangOpts.CPlusPlus) { + Results.MaybeAddResult(Result("explicit", Rank)); + Results.MaybeAddResult(Result("friend", Rank)); + Results.MaybeAddResult(Result("mutable", Rank)); + Results.MaybeAddResult(Result("virtual", Rank)); + } + // Fall through + + case Action::CCC_Namespace: + case Action::CCC_Template: + if (LangOpts.CPlusPlus || LangOpts.C99) + Results.MaybeAddResult(Result("inline", Rank)); + break; + + case Action::CCC_Expression: + case Action::CCC_Statement: + case Action::CCC_ForInit: + case Action::CCC_Condition: + break; + } +} + +/// \brief Add language constructs that show up for "ordinary" names. +static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, + Scope *S, + Sema &SemaRef, + unsigned Rank, + ResultBuilder &Results) { + typedef CodeCompleteConsumer::Result Result; + switch (CCC) { + case Action::CCC_Namespace: + if (SemaRef.getLangOptions().CPlusPlus) { + // namespace { } + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("declarations"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // namespace identifier = identifier ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_Equal); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // Using directives + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // asm(string-literal) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("asm"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("string-literal"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // Explicit template instantiation + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("template"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("declaration"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + } + // Fall through + + case Action::CCC_Class: + Results.MaybeAddResult(Result("typedef", Rank)); + if (SemaRef.getLangOptions().CPlusPlus) { + // Using declaration + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("qualified-id"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // using typename qualified-id; (only in a dependent context) + if (SemaRef.CurContext->isDependentContext()) { + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("typename"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("qualified-id"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + } + + if (CCC == Action::CCC_Class) { + // public: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("public"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // protected: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("protected"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // private: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("private"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.MaybeAddResult(Result(Pattern, Rank)); + } + } + // Fall through + + case Action::CCC_Template: + case Action::CCC_MemberTemplate: + if (SemaRef.getLangOptions().CPlusPlus) { + // template < parameters > + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("template"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("parameters"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Results.MaybeAddResult(Result(Pattern, Rank)); + } + + AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Rank, Results); + AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Rank, Results); + break; + + case Action::CCC_Statement: { + Results.MaybeAddResult(Result("typedef", Rank)); + + CodeCompletionString *Pattern = 0; + if (SemaRef.getLangOptions().CPlusPlus) { + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("try"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("catch"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("declaration"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, Rank)); + } + + // if (condition) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("if"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // switch (condition) { } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("switch"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // Switch-specific statements. + if (!SemaRef.getSwitchStack().empty()) { + // case expression: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("case"); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // default: + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("default"); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + Results.MaybeAddResult(Result(Pattern, Rank)); + } + + /// while (condition) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("while"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus) + Pattern->AddPlaceholderChunk("condition"); + else + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // do { statements } while ( expression ); + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("do"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Pattern->AddTextChunk("while"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // for ( for-init-statement ; condition ; expression ) { statements } + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("for"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + if (SemaRef.getLangOptions().CPlusPlus || SemaRef.getLangOptions().C99) + Pattern->AddPlaceholderChunk("init-statement"); + else + Pattern->AddPlaceholderChunk("init-expression"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Pattern->AddPlaceholderChunk("condition"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Pattern->AddPlaceholderChunk("inc-expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddPlaceholderChunk("statements"); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + Results.MaybeAddResult(Result(Pattern, Rank)); + + if (S->getContinueParent()) { + // continue ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("continue"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + } + + if (S->getBreakParent()) { + // break ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("break"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + } + + // "return expression ;" or "return ;", depending on whether we + // know the function is void or not. + bool isVoid = false; + if (FunctionDecl *Function = dyn_cast(SemaRef.CurContext)) + isVoid = Function->getResultType()->isVoidType(); + else if (ObjCMethodDecl *Method + = dyn_cast(SemaRef.CurContext)) + isVoid = Method->getResultType()->isVoidType(); + else if (SemaRef.CurBlock && !SemaRef.CurBlock->ReturnType.isNull()) + isVoid = SemaRef.CurBlock->ReturnType->isVoidType(); + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("return"); + if (!isVoid) + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // goto identifier ; + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("goto"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // Using directives + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("using"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("namespace"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("identifier"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + Results.MaybeAddResult(Result(Pattern, Rank)); + } + + // Fall through (for statement expressions). + case Action::CCC_ForInit: + case Action::CCC_Condition: + AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Rank, Results); + // Fall through: conditions and statements can have expressions. + + case Action::CCC_Expression: { + CodeCompletionString *Pattern = 0; + if (SemaRef.getLangOptions().CPlusPlus) { + // 'this', if we're in a non-static member function. + if (CXXMethodDecl *Method = dyn_cast(SemaRef.CurContext)) + if (!Method->isStatic()) + Results.MaybeAddResult(Result("this", Rank)); + + // true, false + Results.MaybeAddResult(Result("true", Rank)); + Results.MaybeAddResult(Result("false", Rank)); + + // dynamic_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("dynamic_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // static_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("static_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // reinterpret_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("reinterpret_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // const_cast < type-id > ( expression ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("const_cast"); + Pattern->AddChunk(CodeCompletionString::CK_LeftAngle); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_RightAngle); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // typeid ( expression-or-type ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("typeid"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // new T ( ... ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("new"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expressions"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // new T [ ] ( ... ) + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("new"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("type-id"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); + Pattern->AddPlaceholderChunk("size"); + Pattern->AddChunk(CodeCompletionString::CK_RightBracket); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expressions"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // delete expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("delete"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // delete [] expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("delete"); + Pattern->AddChunk(CodeCompletionString::CK_LeftBracket); + Pattern->AddChunk(CodeCompletionString::CK_RightBracket); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.MaybeAddResult(Result(Pattern, Rank)); + + // throw expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("throw"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Results.MaybeAddResult(Result(Pattern, Rank)); + } + + if (SemaRef.getLangOptions().ObjC1) { + // Add "super", if we're in an Objective-C class with a superclass. + if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) + if (Method->getClassInterface()->getSuperClass()) + Results.MaybeAddResult(Result("super", Rank)); + } + + // sizeof expression + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("sizeof"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("expression-or-type"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.MaybeAddResult(Result(Pattern, Rank)); + break; + } + } + + AddTypeSpecifierResults(SemaRef.getLangOptions(), Rank, Results); + + if (SemaRef.getLangOptions().CPlusPlus) + Results.MaybeAddResult(Result("operator", Rank)); +} + /// \brief If the given declaration has an associated type, add it as a result /// type chunk. static void AddResultTypeChunk(ASTContext &Context, @@ -1422,22 +1921,35 @@ static void HandleCodeCompleteResults(Sema *S, Results[I].Destroy(); } -void Sema::CodeCompleteOrdinaryName(Scope *S) { +void Sema::CodeCompleteOrdinaryName(Scope *S, + CodeCompletionContext CompletionContext) { typedef CodeCompleteConsumer::Result Result; - ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); + ResultBuilder Results(*this); + + // Determine how to filter results, e.g., so that the names of + // values (functions, enumerators, function templates, etc.) are + // only allowed where we can have an expression. + switch (CompletionContext) { + case CCC_Namespace: + case CCC_Class: + case CCC_Template: + case CCC_MemberTemplate: + Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName); + break; + + case CCC_Expression: + case CCC_Statement: + case CCC_ForInit: + case CCC_Condition: + Results.setFilter(&ResultBuilder::IsOrdinaryName); + break; + } + unsigned NextRank = CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, Results); Results.EnterNewScope(); - AddTypeSpecifierResults(getLangOptions(), NextRank, Results); - - if (getLangOptions().ObjC1) { - // Add the "super" keyword, if appropriate. - if (ObjCMethodDecl *Method = dyn_cast(CurContext)) - if (Method->getClassInterface()->getSuperClass()) - Results.MaybeAddResult(Result("super", NextRank)); - } - + AddOrdinaryNameResults(CompletionContext, S, *this, NextRank, Results); Results.ExitScope(); if (CodeCompleter->includeMacros()) @@ -1561,9 +2073,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, E = ObjCPtr->qual_end(); I != E; ++I) AddObjCProperties(*I, true, CurContext, Results); - - // FIXME: We could (should?) also look for "implicit" properties, identified - // only by the presence of nullary and unary selectors. } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCInterfaceType())) { // Objective-C instance variable access. @@ -1746,7 +2255,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // Ignore type-dependent call expressions entirely. if (Fn->isTypeDependent() || Expr::hasAnyTypeDependentArguments(Args, NumArgs)) { - CodeCompleteOrdinaryName(S); + CodeCompleteOrdinaryName(S, CCC_Expression); return; } @@ -1784,7 +2293,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, } if (Results.empty()) - CodeCompleteOrdinaryName(S); + CodeCompleteOrdinaryName(S, CCC_Expression); else CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(), Results.size()); @@ -1968,7 +2477,7 @@ void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, // Since we have an interface or protocol, we can end it. Results.MaybeAddResult(Result("end", 0)); - if (LangOpts.ObjC2) { + if (getLangOptions().ObjC2) { // @property Results.MaybeAddResult(Result("property", 0)); } diff --git a/test/CodeCompletion/ordinary-name.cpp b/test/CodeCompletion/ordinary-name.cpp new file mode 100644 index 0000000000..99573e8507 --- /dev/null +++ b/test/CodeCompletion/ordinary-name.cpp @@ -0,0 +1,170 @@ +struct X { int x; }; +void z(int); +typedef struct t TYPEDEF; + +void foo() { + int y = 17; + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:6:14 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s + // CHECK-CC1: COMPLETION: y : 0 : [#int#]y + // CHECK-CC1-NEXT: COMPLETION: foo : 2 : [#void#]foo() + // CHECK-CC1-NEXT: COMPLETION: t : 2 : t + // CHECK-CC1-NEXT: COMPLETION: TYPEDEF : 2 : TYPEDEF + // CHECK-CC1-NEXT: COMPLETION: X : 2 : X + // CHECK-CC1-NOT: x + // CHECK-CC1-NEXT: COMPLETION: z : 2 : [#void#]z(<#int#>) + // CHECK-CC1-NEXT: COMPLETION: bool : 3 + // CHECK-CC1-NEXT: COMPLETION: char : 3 + // CHECK-CC1-NEXT: COMPLETION: class : 3 + // CHECK-CC1-NEXT: COMPLETION: const : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : const_cast<<#type-id#>>(<#expression#>) + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : delete <#expression#> + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : delete[] <#expression#> + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : do{<#statements#> + // CHECK-CC1: COMPLETION: double : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : dynamic_cast<<#type-id#>>(<#expression#>) + // CHECK-CC1-NEXT: COMPLETION: enum : 3 + // CHECK-CC1-NEXT: COMPLETION: extern : 3 + // CHECK-CC1-NEXT: COMPLETION: false : 3 + // CHECK-CC1-NEXT: COMPLETION: float : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : for(<#init-statement#>;<#condition#>;<#inc-expression#>){<#statements#> + // CHECK-CC1: COMPLETION: Pattern : 3 : goto <#identifier#>; + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : if(<#condition#>){<#statements#> + // CHECK-CC1: COMPLETION: int : 3 + // CHECK-CC1-NEXT: COMPLETION: long : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : new <#type-id#>(<#expressions#>) + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : new <#type-id#>[<#size#>](<#expressions#>) + // CHECK-CC1-NEXT: COMPLETION: operator : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : reinterpret_cast<<#type-id#>>(<#expression#>) + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : return; + // CHECK-CC1-NEXT: COMPLETION: short : 3 + // CHECK-CC1-NEXT: COMPLETION: signed : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : sizeof(<#expression-or-type#>) + // CHECK-CC1-NEXT: COMPLETION: static : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : static_cast<<#type-id#>>(<#expression#>) + // CHECK-CC1-NEXT: COMPLETION: struct : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : switch(<#condition#>){ + // CHECK-CC1: COMPLETION: Pattern : 3 : throw <#expression#> + // CHECK-CC1-NEXT: COMPLETION: true : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : try{<#statements#> + // CHECK-CC1: COMPLETION: typedef : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : typeid(<#expression-or-type#>) + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : typename <#qualified-id#> + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : typeof(<#expression-or-type#>) + // CHECK-CC1-NEXT: COMPLETION: union : 3 + // CHECK-CC1-NEXT: COMPLETION: unsigned : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : using namespace <#identifier#>; + // CHECK-CC1-NEXT: COMPLETION: void : 3 + // CHECK-CC1-NEXT: COMPLETION: volatile : 3 + // CHECK-CC1-NEXT: COMPLETION: wchar_t : 3 + // CHECK-CC1-NEXT: COMPLETION: Pattern : 3 : while(<#condition#>){<#statements#> + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:4:1 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s + // CHECK-CC2: COMPLETION: t : 1 : t + // CHECK-CC2-NEXT: COMPLETION: TYPEDEF : 1 : TYPEDEF + // CHECK-CC2-NEXT: COMPLETION: X : 1 : X + // CHECK-CC2-NOT: COMPLETION: z + // CHECK-CC2-NEXT: COMPLETION: Pattern : 2 : asm(<#string-literal#>); + // CHECK-CC2-NEXT: COMPLETION: bool : 2 + // CHECK-CC2-NEXT: COMPLETION: char : 2 + // CHECK-CC2-NEXT: COMPLETION: class : 2 + // CHECK-CC2-NEXT: COMPLETION: const : 2 + // CHECK-CC2-NEXT: COMPLETION: double : 2 + // CHECK-CC2-NEXT: COMPLETION: enum : 2 + // CHECK-CC2-NEXT: COMPLETION: extern : 2 + // CHECK-CC2-NEXT: COMPLETION: float : 2 + // CHECK-CC2-NEXT: COMPLETION: inline : 2 + // CHECK-CC2-NEXT: COMPLETION: int : 2 + // CHECK-CC2-NEXT: COMPLETION: long : 2 + // CHECK-CC2-NEXT: COMPLETION: Pattern : 2 : namespace <#identifier#>{<#declarations#> + // CHECK-CC2: COMPLETION: Pattern : 2 : namespace <#identifier#> = <#identifier#>; + // CHECK-CC2-NEXT: COMPLETION: operator : 2 + // CHECK-CC2-NEXT: COMPLETION: short : 2 + // CHECK-CC2-NEXT: COMPLETION: signed : 2 + // CHECK-CC2-NEXT: COMPLETION: static : 2 + // CHECK-CC2-NEXT: COMPLETION: struct : 2 + // CHECK-CC2-NEXT: COMPLETION: Pattern : 2 : template <#declaration#>; + // CHECK-CC2-NEXT: COMPLETION: Pattern : 2 : template<<#parameters#>> + // CHECK-CC2-NEXT: COMPLETION: typedef : 2 + // CHECK-CC2-NEXT: COMPLETION: Pattern : 2 : typename <#qualified-id#> + // CHECK-CC2-NEXT: COMPLETION: Pattern : 2 : typeof(<#expression-or-type#>) + // CHECK-CC2-NEXT: COMPLETION: union : 2 + // CHECK-CC2-NEXT: COMPLETION: unsigned : 2 + // CHECK-CC2-NEXT: COMPLETION: Pattern : 2 : using namespace <#identifier#>; + // CHECK-CC2-NEXT: COMPLETION: Pattern : 2 : using <#qualified-id#>; + // CHECK-CC2-NEXT: COMPLETION: void : 2 + // CHECK-CC2-NEXT: COMPLETION: volatile : 2 + // CHECK-CC2-NEXT: COMPLETION: wchar_t : 2 + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:1:19 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s + // CHECK-CC3: COMPLETION: X : 1 : X + // CHECK-CC3-NEXT: COMPLETION: bool : 4 + // CHECK-CC3-NEXT: COMPLETION: char : 4 + // CHECK-CC3-NEXT: COMPLETION: class : 4 + // CHECK-CC3-NEXT: COMPLETION: const : 4 + // CHECK-CC3-NEXT: COMPLETION: double : 4 + // CHECK-CC3-NEXT: COMPLETION: enum : 4 + // CHECK-CC3-NEXT: COMPLETION: explicit : 4 + // CHECK-CC3-NEXT: COMPLETION: extern : 4 + // CHECK-CC3-NEXT: COMPLETION: float : 4 + // CHECK-CC3-NEXT: COMPLETION: friend : 4 + // CHECK-CC3-NEXT: COMPLETION: inline : 4 + // CHECK-CC3-NEXT: COMPLETION: int : 4 + // CHECK-CC3-NEXT: COMPLETION: long : 4 + // CHECK-CC3-NEXT: COMPLETION: mutable : 4 + // CHECK-CC3-NEXT: COMPLETION: operator : 4 + // CHECK-CC3-NEXT: COMPLETION: Pattern : 4 : private: + // CHECK-CC3-NEXT: COMPLETION: Pattern : 4 : protected: + // CHECK-CC3-NEXT: COMPLETION: Pattern : 4 : public: + // CHECK-CC3-NEXT: COMPLETION: short : 4 + // CHECK-CC3-NEXT: COMPLETION: signed : 4 + // CHECK-CC3-NEXT: COMPLETION: static : 4 + // CHECK-CC3-NEXT: COMPLETION: struct : 4 + // CHECK-CC3-NEXT: COMPLETION: Pattern : 4 : template<<#parameters#>> + // CHECK-CC3-NEXT: COMPLETION: typedef : 4 + // CHECK-CC3-NEXT: COMPLETION: Pattern : 4 : typename <#qualified-id#> + // CHECK-CC3-NEXT: COMPLETION: Pattern : 4 : typeof(<#expression-or-type#>) + // CHECK-CC3-NEXT: COMPLETION: union : 4 + // CHECK-CC3-NEXT: COMPLETION: unsigned : 4 + // CHECK-CC3-NEXT: COMPLETION: Pattern : 4 : using <#qualified-id#>; + // CHECK-CC3-NEXT: COMPLETION: virtual : 4 + // CHECK-CC3-NEXT: COMPLETION: void : 4 + // CHECK-CC3-NEXT: COMPLETION: volatile : 4 + // CHECK-CC3-NEXT: COMPLETION: wchar_t : 4 + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:6:11 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s + // CHECK-CC4: COMPLETION: y : 0 : [#int#]y + // CHECK-CC4-NEXT: COMPLETION: foo : 2 : [#void#]foo() + // CHECK-CC4-NEXT: COMPLETION: t : 2 : t + // CHECK-CC4-NEXT: COMPLETION: TYPEDEF : 2 : TYPEDEF + // CHECK-CC4-NEXT: COMPLETION: X : 2 : X + // CHECK-CC4-NEXT: COMPLETION: z : 2 : [#void#]z(<#int#>) + // CHECK-CC4-NEXT: COMPLETION: bool : 3 + // CHECK-CC4-NEXT: COMPLETION: char : 3 + // CHECK-CC4-NEXT: COMPLETION: class : 3 + // CHECK-CC4-NEXT: COMPLETION: const : 3 + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : const_cast<<#type-id#>>(<#expression#>) + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : delete <#expression#> + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : delete[] <#expression#> + // CHECK-CC4-NEXT: COMPLETION: double : 3 + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : dynamic_cast<<#type-id#>>(<#expression#>) + // CHECK-CC4-NEXT: COMPLETION: enum : 3 + // CHECK-CC4-NEXT: COMPLETION: false : 3 + // CHECK-CC4-NEXT: COMPLETION: float : 3 + // CHECK-CC4-NEXT: COMPLETION: int : 3 + // CHECK-CC4-NEXT: COMPLETION: long : 3 + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : new <#type-id#>(<#expressions#>) + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : new <#type-id#>[<#size#>](<#expressions#>) + // CHECK-CC4-NEXT: COMPLETION: operator : 3 + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : reinterpret_cast<<#type-id#>>(<#expression#>) + // CHECK-CC4-NEXT: COMPLETION: short : 3 + // CHECK-CC4-NEXT: COMPLETION: signed : 3 + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : sizeof(<#expression-or-type#>) + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : static_cast<<#type-id#>>(<#expression#>) + // CHECK-CC4-NEXT: COMPLETION: struct : 3 + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : throw <#expression#> + // CHECK-CC4-NEXT: COMPLETION: true : 3 + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : typeid(<#expression-or-type#>) + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : typename <#qualified-id#> + // CHECK-CC4-NEXT: COMPLETION: Pattern : 3 : typeof(<#expression-or-type#>) + // CHECK-CC4-NEXT: COMPLETION: union : 3 + // CHECK-CC4-NEXT: COMPLETION: unsigned : 3 + // CHECK-CC4-NEXT: COMPLETION: void : 3 + // CHECK-CC4-NEXT: COMPLETION: volatile : 3 + // CHECK-CC4-NEXT: COMPLETION: wchar_t : 3 diff --git a/tools/CIndex/CIndexCodeCompletion.cpp b/tools/CIndex/CIndexCodeCompletion.cpp index f4ed6cafb0..f70479b5e8 100644 --- a/tools/CIndex/CIndexCodeCompletion.cpp +++ b/tools/CIndex/CIndexCodeCompletion.cpp @@ -62,6 +62,16 @@ clang_getCompletionChunkKind(CXCompletionString completion_string, return CXCompletionChunk_RightAngle; case CodeCompletionString::CK_Comma: return CXCompletionChunk_Comma; + case CodeCompletionString::CK_Colon: + return CXCompletionChunk_Colon; + case CodeCompletionString::CK_SemiColon: + return CXCompletionChunk_SemiColon; + case CodeCompletionString::CK_Equal: + return CXCompletionChunk_Equal; + case CodeCompletionString::CK_HorizontalSpace: + return CXCompletionChunk_HorizontalSpace; + case CodeCompletionString::CK_VerticalSpace: + return CXCompletionChunk_VerticalSpace; } // Should be unreachable, but let's be careful. @@ -90,6 +100,11 @@ const char *clang_getCompletionChunkText(CXCompletionString completion_string, case CodeCompletionString::CK_RightAngle: case CodeCompletionString::CK_Comma: case CodeCompletionString::CK_ResultType: + case CodeCompletionString::CK_Colon: + case CodeCompletionString::CK_SemiColon: + case CodeCompletionString::CK_Equal: + case CodeCompletionString::CK_HorizontalSpace: + case CodeCompletionString::CK_VerticalSpace: return (*CCStr)[chunk_number].Text; case CodeCompletionString::CK_Optional: @@ -124,6 +139,11 @@ clang_getCompletionChunkCompletionString(CXCompletionString completion_string, case CodeCompletionString::CK_RightAngle: case CodeCompletionString::CK_Comma: case CodeCompletionString::CK_ResultType: + case CodeCompletionString::CK_Colon: + case CodeCompletionString::CK_SemiColon: + case CodeCompletionString::CK_Equal: + case CodeCompletionString::CK_HorizontalSpace: + case CodeCompletionString::CK_VerticalSpace: return 0; case CodeCompletionString::CK_Optional: diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 8e84554e0b..0e532ffa0e 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -378,6 +378,11 @@ clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) { case CXCompletionChunk_RightAngle: return "RightAngle"; case CXCompletionChunk_Comma: return "Comma"; case CXCompletionChunk_ResultType: return "ResultType"; + case CXCompletionChunk_Colon: return "Colon"; + case CXCompletionChunk_SemiColon: return "SemiColon"; + case CXCompletionChunk_Equal: return "Equal"; + case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace"; + case CXCompletionChunk_VerticalSpace: return "VerticalSpace"; } return "Unknown";