diff options
-rw-r--r-- | include/clang/Basic/IdentifierTable.h | 11 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 58 | ||||
-rw-r--r-- | test/Index/complete-objc-message.m | 14 |
3 files changed, 67 insertions, 16 deletions
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index 24fe086a79..2cb68b39be 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -570,6 +570,17 @@ struct DenseMapInfo<clang::Selector> { template <> struct isPodLike<clang::Selector> { static const bool value = true; }; +template<> +class PointerLikeTypeTraits<clang::Selector> { +public: + static inline const void *getAsVoidPointer(clang::Selector P) { + return P.getAsOpaquePtr(); + } + static inline clang::Selector getFromVoidPointer(const void *P) { + return clang::Selector(reinterpret_cast<uintptr_t>(P)); + } + enum { NumLowBitsAvailable = 0 }; +}; // Provide PointerLikeTypeTraits for IdentifierInfo pointers, which // are not guaranteed to be 8-byte aligned. diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 615d126fb3..e305172e51 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -22,6 +22,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -3824,7 +3825,13 @@ static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, return isAcceptableObjCSelector(Method->getSelector(), WantKind, SelIdents, NumSelIdents); } - + +namespace { + /// \brief A set of selectors, which is used to avoid introducing multiple + /// completions with the same selector into the result set. + typedef llvm::SmallPtrSet<Selector, 16> VisitedSelectorSet; +} + /// \brief Add all of the Objective-C methods in the given Objective-C /// container to the set of results. /// @@ -3848,6 +3855,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container, IdentifierInfo **SelIdents, unsigned NumSelIdents, DeclContext *CurContext, + VisitedSelectorSet &Selectors, ResultBuilder &Results, bool InOriginalClass = true) { typedef CodeCompletionResult Result; @@ -3860,6 +3868,9 @@ static void AddObjCMethods(ObjCContainerDecl *Container, if (!isAcceptableObjCMethod(*M, WantKind, SelIdents, NumSelIdents)) continue; + if (!Selectors.insert((*M)->getSelector())) + continue; + Result R = Result(*M, 0); R.StartParameter = NumSelIdents; R.AllParametersAreInformative = (WantKind != MK_Any); @@ -3877,7 +3888,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container, E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, NumSelIdents, - CurContext, Results, false); + CurContext, Selectors, Results, false); } ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container); @@ -3890,13 +3901,14 @@ static void AddObjCMethods(ObjCContainerDecl *Container, E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, NumSelIdents, - CurContext, Results, false); + CurContext, Selectors, Results, false); // Add methods in categories. for (ObjCCategoryDecl *CatDecl = IFace->getCategoryList(); CatDecl; CatDecl = CatDecl->getNextClassCategory()) { AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results, InOriginalClass); + NumSelIdents, CurContext, Selectors, Results, + InOriginalClass); // Add a categories protocol methods. const ObjCList<ObjCProtocolDecl> &Protocols @@ -3905,23 +3917,26 @@ static void AddObjCMethods(ObjCContainerDecl *Container, E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results, false); + NumSelIdents, CurContext, Selectors, Results, false); // Add methods in category implementations. if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation()) AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results, InOriginalClass); + NumSelIdents, CurContext, Selectors, Results, + InOriginalClass); } // Add methods in superclass. if (IFace->getSuperClass()) AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind, - SelIdents, NumSelIdents, CurContext, Results, false); + SelIdents, NumSelIdents, CurContext, Selectors, Results, + false); // Add methods in our implementation, if any. if (ObjCImplementationDecl *Impl = IFace->getImplementation()) AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results, InOriginalClass); + NumSelIdents, CurContext, Selectors, Results, + InOriginalClass); } @@ -3958,7 +3973,9 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl, } } - AddObjCMethods(Class, true, MK_ZeroArgSelector, 0, 0, CurContext, Results); + VisitedSelectorSet Selectors; + AddObjCMethods(Class, true, MK_ZeroArgSelector, 0, 0, CurContext, Selectors, + Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Other, @@ -3999,7 +4016,9 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl, } } - AddObjCMethods(Class, true, MK_OneArgSelector, 0, 0, CurContext, Results); + VisitedSelectorSet Selectors; + AddObjCMethods(Class, true, MK_OneArgSelector, 0, 0, CurContext, + Selectors, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, @@ -4357,9 +4376,10 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, if (ObjCMethodDecl *CurMethod = SemaRef.getCurMethodDecl()) Results.setPreferredSelector(CurMethod->getSelector()); + VisitedSelectorSet Selectors; if (CDecl) AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, - SemaRef.CurContext, Results); + SemaRef.CurContext, Selectors, Results); else { // We're messaging "id" as a type; provide all class/factory methods. @@ -4450,6 +4470,9 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, ReceiverType = Context.getObjCObjectPointerType( Context.getObjCInterfaceType(IFace)); + // Keep track of the selectors we've already added. + VisitedSelectorSet Selectors; + // Handle messages to Class. This really isn't a message to an instance // method, so we treat it the same way we would treat a message send to a // class method. @@ -4458,7 +4481,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { if (ObjCInterfaceDecl *ClassDecl = CurMethod->getClassInterface()) AddObjCMethods(ClassDecl, false, MK_Any, SelIdents, NumSelIdents, - CurContext, Results); + CurContext, Selectors, Results); } } // Handle messages to a qualified ID ("id<foo>"). @@ -4469,21 +4492,21 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, E = QualID->qual_end(); I != E; ++I) AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext, - Results); + Selectors, Results); } // Handle messages to a pointer to interface type. else if (const ObjCObjectPointerType *IFacePtr = ReceiverType->getAsObjCInterfacePointerType()) { // Search the class, its superclasses, etc., for instance methods. AddObjCMethods(IFacePtr->getInterfaceDecl(), true, MK_Any, SelIdents, - NumSelIdents, CurContext, Results); + NumSelIdents, CurContext, Selectors, Results); // Search protocols for instance methods. for (ObjCObjectPointerType::qual_iterator I = IFacePtr->qual_begin(), E = IFacePtr->qual_end(); I != E; ++I) AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext, - Results); + Selectors, Results); } // Handle messages to "id". else if (ReceiverType->isObjCIdType()) { @@ -4512,7 +4535,10 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) continue; - + + if (!Selectors.insert(MethList->Method->getSelector())) + continue; + Result R(MethList->Method, 0); R.StartParameter = NumSelIdents; R.AllParametersAreInformative = false; diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m index 6a96b95223..03388f1dc6 100644 --- a/test/Index/complete-objc-message.m +++ b/test/Index/complete-objc-message.m @@ -141,6 +141,15 @@ void test_overload3(Overload *ovl) { (Overload2 Method:1 Arg1:1 OtherArg:ovl]); } +@interface C : B +- (void)method2; +- (void)method3; +@end + +void test_redundancy(C *c) { + [c method2]; +}; + // RUN: c-index-test -code-completion-at=%s:23:19 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: {TypedText categoryClassMethod} // CHECK-CC1: {TypedText classMethod1:}{Placeholder (id)}{HorizontalSpace }{Text withKeyword:}{Placeholder (int)} @@ -242,6 +251,11 @@ void test_overload3(Overload *ovl) { // CHECK-CCI: ObjCInstanceMethodDecl:{ResultType void}{TypedText method1} (22) // CHECK-CCI: ObjCInstanceMethodDecl:{ResultType void}{TypedText method2} (20) +// RUN: c-index-test -code-completion-at=%s:150:5 %s | FileCheck -check-prefix=CHECK-REDUNDANT %s +// CHECK-REDUNDANT: ObjCInstanceMethodDecl:{ResultType void}{TypedText method2} (20) +// CHECK-REDUNDANT-NOT: ObjCInstanceMethodDecl:{ResultType void}{TypedText method2} +// CHECK-REDUNDANT: ObjCInstanceMethodDecl:{ResultType void}{TypedText method3} (20) + // Test code completion with a missing opening bracket: // RUN: c-index-test -code-completion-at=%s:135:5 %s | FileCheck -check-prefix=CHECK-CCI %s // RUN: c-index-test -code-completion-at=%s:139:7 %s | FileCheck -check-prefix=CHECK-CC7 %s |