diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index fb7f641f3107..d86b8ee1c84d 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -2192,9 +2192,19 @@ public: /// found at a point in the grammar where the Action implementation is /// likely to be able to provide a list of possible completions, e.g., /// after the "." or "->" of a member access expression. - /// + /// + /// \todo Code completion for designated field initializers + /// \todo Code completion for call arguments after a function template-id + /// \todo Code completion within a call expression, object construction, etc. + /// \todo Code completion within a template argument list. //@{ + /// \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) { } + /// \brief Code completion for a member access expression. /// /// This code completion action is invoked when the code-completion token diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 2eccbd04dad9..4ca5b48e8b67 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -710,6 +710,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSContext) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope); + ConsumeToken(); + } + DS.SetRangeStart(Tok.getLocation()); while (1) { bool isInvalid = false; diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index db507c2d3adb..156c84804fd0 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -200,6 +200,11 @@ 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); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 4fdcf2a077f3..907ca802b4ae 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -90,6 +90,11 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { return ParseObjCAtStatement(AtLoc); } + case tok::code_completion: + Actions.CodeCompleteOrdinaryName(CurScope); + ConsumeToken(); + return ParseStatementOrDeclaration(OnlyStatement); + case tok::identifier: if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement @@ -918,6 +923,11 @@ Parser::OwningStmtResult Parser::ParseForStatement() { OwningStmtResult FirstPart(Actions); OwningExprResult SecondPart(Actions), ThirdPart(Actions); + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteOrdinaryName(CurScope); + ConsumeToken(); + } + // Parse the first part of the for specifier. if (Tok.is(tok::semi)) { // for (; // no first part, eat the ';'. diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 177290b4381d..2f500a484da3 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -442,6 +442,10 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration() { } SingleDecl = ParseObjCMethodDefinition(); break; + case tok::code_completion: + Actions.CodeCompleteOrdinaryName(CurScope); + ConsumeToken(); + return ParseExternalDeclaration(); case tok::kw_using: case tok::kw_namespace: case tok::kw_typedef: diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index aa35a60ee65e..7fa546258e43 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -3629,6 +3629,7 @@ public: /// \name Code completion //@{ void setCodeCompleteConsumer(CodeCompleteConsumer *CCC); + virtual void CodeCompleteOrdinaryName(Scope *S); virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, SourceLocation OpLoc, bool IsArrow); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 79904c9c5329..52e7d0e00504 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -104,6 +104,7 @@ namespace { /// results of name lookup. All of the predicates have the same type, so that /// //@{ + bool IsOrdinaryName(NamedDecl *ND) const; bool IsNestedNameSpecifier(NamedDecl *ND) const; bool IsEnum(NamedDecl *ND) const; bool IsClassOrStruct(NamedDecl *ND) const; @@ -316,6 +317,16 @@ void ResultBuilder::ExitScope() { ShadowMaps.pop_back(); } +/// \brief Determines whether this given declaration will be found by +/// ordinary name lookup. +bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { + unsigned IDNS = Decl::IDNS_Ordinary; + if (SemaRef.getLangOptions().CPlusPlus) + IDNS |= Decl::IDNS_Tag; + + return ND->getIdentifierNamespace() & IDNS; +} + /// \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 { @@ -874,6 +885,13 @@ static void HandleCodeCompleteResults(CodeCompleteConsumer *CodeCompleter, CodeCompleter->ProcessCodeCompleteResults(Results, NumResults); } +void Sema::CodeCompleteOrdinaryName(Scope *S) { + ResultBuilder Results(*this, &ResultBuilder::IsOrdinaryName); + CollectLookupResults(S, Context.getTranslationUnitDecl(), 0, CurContext, + Results); + HandleCodeCompleteResults(CodeCompleter, Results.data(), Results.size()); +} + void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, SourceLocation OpLoc, bool IsArrow) { diff --git a/clang/test/CodeCompletion/ordinary-name.c b/clang/test/CodeCompletion/ordinary-name.c new file mode 100644 index 000000000000..a532409d606c --- /dev/null +++ b/clang/test/CodeCompletion/ordinary-name.c @@ -0,0 +1,12 @@ +// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s && +// RUN: true + +struct X { int x; }; + +typedef struct X TYPEDEF; + +void foo() { + int y; + // CHECK-CC1: y : 0 + // CHECK-NEXT-CC1: TYPEDEF : 2 + // CHECK-NEXT-CC1: foo : 2