diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -5150,7 +5150,7 @@ CodeCompleter->getCodeCompletionTUInfo(), CCContext, &ResultBuilder::IsMember); - auto DoCompletion = [&](Expr *Base, bool IsArrow, + auto DoCompletion = [&](Expr *Base, bool IsArrow, bool IncludeObjC, Optional AccessOpFixIt) -> bool { if (!Base) return false; @@ -5196,6 +5196,9 @@ } } else if (!IsArrow && BaseType->isObjCObjectPointerType()) { // Objective-C property reference. + if (!IncludeObjC) { + return false; + } AddedPropertiesSet AddedProperties; if (const ObjCObjectPointerType *ObjCPtr = @@ -5216,6 +5219,9 @@ } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCObjectType())) { // Objective-C instance variable access. + if (!IncludeObjC) { + return false; + } ObjCInterfaceDecl *Class = nullptr; if (const ObjCObjectPointerType *ObjCPtr = BaseType->getAs()) @@ -5239,12 +5245,18 @@ Results.EnterNewScope(); - bool CompletionSucceded = DoCompletion(Base, IsArrow, None); + bool CompletionSucceded = + DoCompletion(Base, IsArrow, /*IncludeObjC=*/true, None); + + // Fixits are only included for C++. We avoid this for Objective-C properties + // and ivars since most properties are backed by an ivar; otherwise we would + // recommend an ivar fixit when code-completing a property. Another possible + // solution would be to de-duplicate the ivar/property mixing. if (CodeCompleter->includeFixIts()) { const CharSourceRange OpRange = CharSourceRange::getTokenRange(OpLoc, OpLoc); CompletionSucceded |= DoCompletion( - OtherOpBase, !IsArrow, + OtherOpBase, !IsArrow, /*IncludeObjC=*/false, FixItHint::CreateReplacement(OpRange, IsArrow ? "." : "->")); } diff --git a/clang/test/CodeCompletion/objc-member-access.m b/clang/test/CodeCompletion/objc-member-access.m new file mode 100644 --- /dev/null +++ b/clang/test/CodeCompletion/objc-member-access.m @@ -0,0 +1,22 @@ +// Note: the run lines follow their respective tests, since line/column +// matter in this test. + +@interface TypeWithPropertiesBackedByIvars { + int _bar; + int _foo; +} +@property(nonatomic) int foo; +@property(nonatomic) int bar; +@end + +int getFoo(id object) { + TypeWithPropertiesBackedByIvars *model = (TypeWithPropertiesBackedByIvars *)object; + int foo = model.; + return foo; +} + +// RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:16:19 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s +// CHECK-CC1-NOT: [#int#]_bar +// CHECK-CC1-NOT: [#int#]_foo +// CHECK-CC1: [#int#]bar +// CHECK-CC1: [#int#]foo