diff --git a/clang/include/clang/Sema/Action.h b/clang/include/clang/Sema/Action.h index cc2b71adbb4905b3351054fb34128e194e5bf240..611d2f42f26190eb3347b32295e49d7cf85fd212 100644 --- a/clang/include/clang/Sema/Action.h +++ b/clang/include/clang/Sema/Action.h @@ -3052,6 +3052,15 @@ public: IdentifierInfo **SelIdents, unsigned NumSelIdents) { } + /// \brief Code completion for the collection argument of an Objective-C + /// for-each statement. + /// + /// \param S The Scope in which the completion occurs. + /// + /// \param IterationBar The iteration variable declaration. + virtual void CodeCompleteObjCForCollection(Scope *S, + DeclGroupPtrTy IterationVar) { } + /// \brief Code completion for a list of protocol references in Objective-C, /// such as P1 and P2 in \c id. /// diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a8a3562a5390949e4136b443b61e72899ebbe877..41abdb4bfaea88562814eb2f2915e524d6475cb2 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4643,8 +4643,10 @@ public: virtual void CodeCompleteDeclarator(Scope *S, bool AllowNonIdentifiers, bool AllowNestedNameSpecifiers); - virtual void CodeCompleteExpression(Scope *S, QualType T, - bool IntegralConstantExpression = false); + + struct CodeCompleteExpressionData; + virtual void CodeCompleteExpression(Scope *S, + const CodeCompleteExpressionData &Data); virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, SourceLocation OpLoc, bool IsArrow); @@ -4686,6 +4688,8 @@ public: virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, IdentifierInfo **SelIdents, unsigned NumSelIdents); + virtual void CodeCompleteObjCForCollection(Scope *S, + DeclGroupPtrTy IterationVar); virtual void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, unsigned NumProtocols); virtual void CodeCompleteObjCProtocolDecl(Scope *S); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index de39a924b5110164f5f48aa7a258a013cd93b84a..de81c7797a0777ec2e8979a15bd6306117c22f76 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1023,6 +1023,11 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { Actions.ActOnForEachDeclStmt(DG); // ObjC: for (id x in expr) ConsumeToken(); // consume 'in' + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCForCollection(getCurScope(), DG); + ConsumeCodeCompletionToken(); + } Collection = ParseExpression(); } else { Diag(Tok, diag::err_expected_semi_for); @@ -1039,6 +1044,11 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { ConsumeToken(); } else if ((ForEach = isTokIdentifier_in())) { ConsumeToken(); // consume 'in' + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCForCollection(getCurScope(), DeclGroupPtrTy()); + ConsumeCodeCompletionToken(); + } Collection = ParseExpression(); } else { if (!Value.isInvalid()) Diag(Tok, diag::err_expected_semi_for); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 61c17c89bd09c3223d2635b1f64fdddb3c5a1770..1d91c3fa812a4e22d49eb0b94dd672e6b6f6205a 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -239,6 +239,7 @@ namespace { bool IsMember(NamedDecl *ND) const; bool IsObjCIvar(NamedDecl *ND) const; bool IsObjCMessageReceiver(NamedDecl *ND) const; + bool IsObjCCollection(NamedDecl *ND) const; //@} }; } @@ -366,8 +367,12 @@ getRequiredQualification(ASTContext &Context, DeclContext *Parent = TargetParents.back(); TargetParents.pop_back(); - if (NamespaceDecl *Namespace = dyn_cast(Parent)) + if (NamespaceDecl *Namespace = dyn_cast(Parent)) { + if (!Namespace->getIdentifier()) + continue; + Result = NestedNameSpecifier::Create(Context, Result, Namespace); + } else if (TagDecl *TD = dyn_cast(Parent)) Result = NestedNameSpecifier::Create(Context, Result, false, @@ -946,6 +951,20 @@ bool ResultBuilder::IsObjCMessageReceiver(NamedDecl *ND) const { return isObjCReceiverType(SemaRef.Context, T); } +bool ResultBuilder::IsObjCCollection(NamedDecl *ND) const { + if ((SemaRef.getLangOptions().CPlusPlus && !IsOrdinaryName(ND)) || + (!SemaRef.getLangOptions().CPlusPlus && !IsOrdinaryNonTypeName(ND))) + return false; + + QualType T = getDeclUsageType(SemaRef.Context, ND); + if (T.isNull()) + return false; + + T = SemaRef.Context.getBaseElementType(T); + return T->isObjCObjectType() || T->isObjCObjectPointerType() || + T->isObjCIdType() || + (SemaRef.getLangOptions().CPlusPlus && T->isRecordType()); +} /// \rief Determines whether the given declaration is an Objective-C /// instance variable. @@ -2303,23 +2322,42 @@ void Sema::CodeCompleteDeclarator(Scope *S, Results.data(), Results.size()); } +struct Sema::CodeCompleteExpressionData { + CodeCompleteExpressionData(QualType PreferredType = QualType()) + : PreferredType(PreferredType), IntegralConstantExpression(false), + ObjCCollection(false) { } + + QualType PreferredType; + bool IntegralConstantExpression; + bool ObjCCollection; + llvm::SmallVector IgnoreDecls; +}; + /// \brief Perform code-completion in an expression context when we know what /// type we're looking for. /// /// \param IntegralConstantExpression Only permit integral constant /// expressions. -void Sema::CodeCompleteExpression(Scope *S, QualType T, - bool IntegralConstantExpression) { +void Sema::CodeCompleteExpression(Scope *S, + const CodeCompleteExpressionData &Data) { typedef CodeCompleteConsumer::Result Result; ResultBuilder Results(*this); - if (IntegralConstantExpression) + if (Data.ObjCCollection) + Results.setFilter(&ResultBuilder::IsObjCCollection); + else if (Data.IntegralConstantExpression) Results.setFilter(&ResultBuilder::IsIntegralConstantValue); else if (WantTypesInContext(PCC_Expression, getLangOptions())) Results.setFilter(&ResultBuilder::IsOrdinaryName); else Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName); - Results.setPreferredType(T.getNonReferenceType()); + + if (!Data.PreferredType.isNull()) + Results.setPreferredType(Data.PreferredType.getNonReferenceType()); + + // Ignore any declarations that we were told that we don't care about. + for (unsigned I = 0, N = Data.IgnoreDecls.size(); I != N; ++I) + Results.Ignore(Data.IgnoreDecls[I]); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer, @@ -2330,14 +2368,16 @@ void Sema::CodeCompleteExpression(Scope *S, QualType T, Results.ExitScope(); bool PreferredTypeIsPointer = false; - if (!T.isNull()) - PreferredTypeIsPointer = T->isAnyPointerType() || - T->isMemberPointerType() || T->isBlockPointerType(); + if (!Data.PreferredType.isNull()) + PreferredTypeIsPointer = Data.PreferredType->isAnyPointerType() + || Data.PreferredType->isMemberPointerType() + || Data.PreferredType->isBlockPointerType(); if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, PreferredTypeIsPointer); HandleCodeCompleteResults(this, CodeCompleter, - CodeCompletionContext(CodeCompletionContext::CCC_Expression, T), + CodeCompletionContext(CodeCompletionContext::CCC_Expression, + Data.PreferredType), Results.data(),Results.size()); } @@ -2534,7 +2574,9 @@ void Sema::CodeCompleteCase(Scope *S) { SwitchStmt *Switch = getSwitchStack().back(); if (!Switch->getCond()->getType()->isEnumeralType()) { - CodeCompleteExpression(S, Switch->getCond()->getType(), true); + CodeCompleteExpressionData Data(Switch->getCond()->getType()); + Data.IntegralConstantExpression = true; + CodeCompleteExpression(S, Data); return; } @@ -3752,6 +3794,22 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, Results.data(),Results.size()); } +void Sema::CodeCompleteObjCForCollection(Scope *S, + DeclGroupPtrTy IterationVar) { + CodeCompleteExpressionData Data; + Data.ObjCCollection = true; + + if (IterationVar.getAsOpaquePtr()) { + DeclGroupRef DG = IterationVar.getAsVal(); + for (DeclGroupRef::iterator I = DG.begin(), End = DG.end(); I != End; ++I) { + if (*I) + Data.IgnoreDecls.push_back(*I); + } + } + + CodeCompleteExpression(S, Data); +} + /// \brief Add all of the protocol declarations that we find in the given /// (translation unit) context. static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, diff --git a/clang/test/Index/complete-declarators.m b/clang/test/Index/complete-declarators.m index d2c3f61cd8a06e7aba0232162ca0caa57b34f9ee..3a69282df437e332be37375771fdc1a8f9554855 100644 --- a/clang/test/Index/complete-declarators.m +++ b/clang/test/Index/complete-declarators.m @@ -11,7 +11,12 @@ @implementation A - (int)method:(id)param1 { - for(id x in param1) { + int q2; + for(id q in param1) { + int y; + } + id q; + for(q in param1) { int y; } } @@ -21,9 +26,20 @@ // CHECK-CC1-NOT: NotImplemented:{TypedText extern} (30) // CHECK-CC1: NotImplemented:{TypedText param1} (30) // RUN: c-index-test -code-completion-at=%s:9:15 %s | FileCheck -check-prefix=CHECK-CC2 %s -// RUN: c-index-test -code-completion-at=%s:14:10 %s | FileCheck -check-prefix=CHECK-CC2 %s -// RUN: c-index-test -code-completion-at=%s:15:9 %s | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: c-index-test -code-completion-at=%s:15:10 %s | FileCheck -check-prefix=CHECK-CC2 %s +// RUN: c-index-test -code-completion-at=%s:16:9 %s | FileCheck -check-prefix=CHECK-CC2 %s // CHECK-CC2: NotImplemented:{TypedText const} (30) // CHECK-CC2-NOT: int // CHECK-CC2: NotImplemented:{TypedText restrict} (30) // CHECK-CC2: NotImplemented:{TypedText volatile} (30) +// RUN: c-index-test -code-completion-at=%s:15:15 %s | FileCheck -check-prefix=CHECK-CC3 %s +// CHECK-CC3: ParmDecl:{ResultType id}{TypedText param1} (8) +// CHECK-CC3-NOT: VarDecl:{ResultType int}{TypedText q2} (8) +// CHECK-CC3-NOT: VarDecl:{ResultType id}{TypedText q} (8) +// CHECK-CC3: NotImplemented:{ResultType A *}{TypedText self} (8) +// CHECK-CC3: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30) +// RUN: c-index-test -code-completion-at=%s:15:15 %s | FileCheck -check-prefix=CHECK-CC4 %s +// CHECK-CC4: ParmDecl:{ResultType id}{TypedText param1} (8) +// CHECK-CC4-NOT: VarDecl:{ResultType int}{TypedText q2} (8) +// CHECK-CC4: NotImplemented:{ResultType A *}{TypedText self} (8) +// CHECK-CC4: NotImplemented:{TypedText sizeof}{LeftParen (}{Placeholder expression-or-type}{RightParen )} (30)