aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-05-04 23:50:46 +0000
committerDouglas Gregor <dgregor@apple.com>2011-05-04 23:50:46 +0000
commite74c25c5c0375004bd84945bda53c3a96f443da8 (patch)
treef468c9cb46cbd90449271588c071933054b726be
parentebcbe1d3dc7d4f0c1f540a632fa0684dd0a857d5 (diff)
When adding KVC code completions, keep track of all of the selectors
that we've previously seen, both in declared methods and from previous KVC completions, to eliminate duplicates. Fixes <rdar://problem/9162207>. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130890 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/SemaCodeComplete.cpp53
-rw-r--r--test/Index/complete-kvc.m16
2 files changed, 46 insertions, 23 deletions
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index cc8726de9d..3673139acc 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -5549,7 +5549,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
bool IsInstanceMethod,
QualType ReturnType,
ASTContext &Context,
- const KnownMethodsMap &KnownMethods,
+ VisitedSelectorSet &KnownSelectors,
ResultBuilder &Results) {
IdentifierInfo *PropName = Property->getIdentifier();
if (!PropName || PropName->getLength() == 0)
@@ -5595,7 +5595,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// Add the normal accessor -(type)key.
if (IsInstanceMethod &&
- !KnownMethods.count(Selectors.getNullarySelector(PropName)) &&
+ KnownSelectors.insert(Selectors.getNullarySelector(PropName)) &&
ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) {
if (ReturnType.isNull())
AddObjCPassingTypeChunk(Property->getType(), Context, Builder);
@@ -5615,7 +5615,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
Property->getType()->isBooleanType())))) {
std::string SelectorName = (llvm::Twine("is") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("BOOL");
@@ -5634,7 +5634,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
!Property->getSetterMethodDecl()) {
std::string SelectorName = (llvm::Twine("set") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5685,7 +5685,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
(ReturnType.isNull() || ReturnType->isIntegerType())) {
std::string SelectorName = (llvm::Twine("countOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSUInteger");
@@ -5708,7 +5708,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("objectIn") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("id");
@@ -5735,7 +5735,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine(Property->getName()) + "AtIndexes").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSArray *");
@@ -5760,7 +5760,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("range")
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5794,7 +5794,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get(SelectorName)
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5826,7 +5826,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("atIndexes")
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5854,7 +5854,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("removeObjectFrom") + UpperKey + "AtIndex").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5876,7 +5876,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("remove") + UpperKey + "AtIndexes").str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5902,7 +5902,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get("withObject")
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5935,7 +5935,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
&Context.Idents.get(SelectorName2)
};
- if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+ if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -5968,7 +5968,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
->getName() == "NSEnumerator"))) {
std::string SelectorName = (llvm::Twine("enumeratorOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSEnumerator *");
@@ -5986,7 +5986,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
(ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) {
std::string SelectorName = (llvm::Twine("memberOf") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddPlaceholderChunk("object-type");
@@ -6016,7 +6016,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("add") + UpperKey + llvm::Twine("Object")).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6038,7 +6038,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (llvm::Twine("add") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6060,7 +6060,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("remove") + UpperKey + llvm::Twine("Object")).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6082,7 +6082,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (llvm::Twine("remove") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6103,7 +6103,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
if (IsInstanceMethod && ReturnTypeMatchesVoid) {
std::string SelectorName = (llvm::Twine("intersect") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("void");
@@ -6131,7 +6131,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
std::string SelectorName
= (llvm::Twine("keyPathsForValuesAffecting") + UpperKey).str();
IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName);
- if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+ if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId))) {
if (ReturnType.isNull()) {
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
Builder.AddTextChunk("NSSet *");
@@ -6271,6 +6271,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
llvm::SmallVector<ObjCContainerDecl *, 4> Containers;
Containers.push_back(SearchDecl);
+ VisitedSelectorSet KnownSelectors;
+ for (KnownMethodsMap::iterator M = KnownMethods.begin(),
+ MEnd = KnownMethods.end();
+ M != MEnd; ++M)
+ KnownSelectors.insert(M->first);
+
+
ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(SearchDecl);
if (!IFace)
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(SearchDecl))
@@ -6287,7 +6294,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
PEnd = Containers[I]->prop_end();
P != PEnd; ++P) {
AddObjCKeyValueCompletions(*P, IsInstanceMethod, ReturnType, Context,
- KnownMethods, Results);
+ KnownSelectors, Results);
}
}
}
diff --git a/test/Index/complete-kvc.m b/test/Index/complete-kvc.m
index 43a874b553..5ff36487e1 100644
--- a/test/Index/complete-kvc.m
+++ b/test/Index/complete-kvc.m
@@ -41,6 +41,17 @@ typedef signed char BOOL;
+ (NSSet *)keyPathsForValuesAffectingIntProperty { return 0; }
@end
+@interface MySubClass : MyClass
+@end
+
+@interface MySubClass ()
+@property int intProperty;
+@end
+
+@implementation MySubClass
+- (int)intProperty { return 0; }
+@end
+
// RUN: c-index-test -code-completion-at=%s:39:3 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText addMutableArrayPropertyObject:}{LeftParen (}{Placeholder object-type}{Text *}{RightParen )}{Text object} (55)
// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText addMutableSetProperty:}{LeftParen (}{Text NSSet *}{RightParen )}{Text objects} (40)
@@ -85,3 +96,8 @@ typedef signed char BOOL;
// RUN: c-index-test -code-completion-at=%s:41:3 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: ObjCInstanceMethodDecl:{LeftParen (}{Text NSSet *}{RightParen )}{TypedText keyPathsForValuesAffectingMutableArrayProperty} (40)
+
+// RUN: c-index-test -code-completion-at=%s:52:8 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// CHECK-CC3: ObjCInstanceMethodDecl:{TypedText countOfIntProperty} (55)
+// CHECK-CC3-NEXT: ObjCInstanceMethodDecl:{TypedText intProperty} (40)
+// CHECK-CC3-NEXT: ObjCInstanceMethodDecl:{TypedText isIntProperty} (40)