diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index de18b86da023..1ac0f3be5ea2 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -247,12 +247,12 @@ public: /// This does not work with all kinds of tokens: strings and specific other /// tokens must be consumed with custom methods below. This returns the /// location of the consumed token. - SourceLocation ConsumeToken() { + SourceLocation ConsumeToken(bool ConsumeCodeCompletionTok = false) { assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() && !isTokenBrace() && "Should consume special tokens with Consume*Token"); - if (Tok.is(tok::code_completion)) + if (!ConsumeCodeCompletionTok && Tok.is(tok::code_completion)) return handleUnexpectedCodeCompletionToken(); PrevTokLocation = Tok.getLocation(); @@ -291,7 +291,7 @@ private: /// ConsumeAnyToken - Dispatch to the right Consume* method based on the /// current token type. This should only be used in cases where the type of /// the token really isn't known, e.g. in error recovery. - SourceLocation ConsumeAnyToken() { + SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok = false) { if (isTokenParen()) return ConsumeParen(); else if (isTokenBracket()) @@ -301,7 +301,7 @@ private: else if (isTokenStringLiteral()) return ConsumeStringToken(); else - return ConsumeToken(); + return ConsumeToken(ConsumeCodeCompletionTok); } /// ConsumeParen - This consume method keeps the paren count up-to-date. diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index 30aee20b2674..bc634b57d9ce 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -407,7 +407,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && "Inline method not starting with '{', ':' or 'try'"); @@ -510,7 +510,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); SourceLocation EqualLoc; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 4d1147b5df92..7dfbf5ff86cd 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -931,7 +931,7 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, LA.Toks.push_back(Tok); PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) { // FIXME: Do not warn on C++11 attributes, once we start supporting diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index e4a880e89aba..fb0237ac05ea 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -2896,7 +2896,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); assert((Tok.is(tok::l_brace) || Tok.is(tok::kw_try) || Tok.is(tok::colon)) && diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 1327dd59e557..f14666922b95 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -1305,7 +1305,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { PP.EnterTokenStream(LMT.Toks.data(), LMT.Toks.size(), true, false); // Consume the previously pushed token. - ConsumeAnyToken(); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && "Inline method not starting with '{', ':' or 'try'"); diff --git a/clang/test/Index/complete-declarators.m b/clang/test/Index/complete-declarators.m index d42a3c7a6c4b..b3a60ded110a 100644 --- a/clang/test/Index/complete-declarators.m +++ b/clang/test/Index/complete-declarators.m @@ -22,6 +22,7 @@ static P *p = 0; } +- (boid)method2 {} @end // RUN: c-index-test -code-completion-at=%s:7:4 %s | FileCheck -check-prefix=CHECK-CC0 %s @@ -81,3 +82,8 @@ // CHECK-CC5: NotImplemented:{TypedText unsigned} (50) // CHECK-CC5: NotImplemented:{TypedText void} (50) // CHECK-CC5: NotImplemented:{TypedText volatile} (50) + +// Check that there are no duplicate entries if we code-complete after an @implementation +// RUN: c-index-test -code-completion-at=%s:27:1 %s | FileCheck -check-prefix=CHECK-CC6 %s +// CHECK-CC6: ObjCInterfaceDecl:{TypedText A} +// CHECK-CC6-NOT: ObjCInterfaceDecl:{TypedText A}