swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.49k stars 10.35k forks source link

Index data is missing references when Swift uses an Objective-C property added through category adding a protocol conformance #67446

Open dylansturg opened 1 year ago

dylansturg commented 1 year ago

Description When a Swift file references a property on an Objective-C type where:

Then the SourceKit index and indexstore data contain no reference to that property in the Swift file. It appears like the property's use doesn't exist in the Swift file.

As an example of the coding pattern, consider these files:

Objc Class:

@interface SomeClass: NSObject
@end

Objc Protocol & Category

@protocol Properties <NSObject>
@property NSInteger foo;
@end

@interface SomeClass (additions) <Properties>
@end

When some Swift code uses -[SomeClass foo], there's no corresponding reference in the index data.

let obj = SomeClass()
obj.foo  // MISSING from index!

Steps to reproduce

Create an Objective-C module for use from Swift, containing these two files:

Class header:

#import <Foundation/Foundation.h>
@interface BaseClass : NSObject
@end

Protocol header:

#import <Foundation/Foundation.h>

#import "BaseClass.h"

@protocol Additions <NSObject>
@property(nonatomic, readonly) id propertyInProtocol;
@end

@interface BaseClass(Category) <Additions>
@property(nonatomic, readonly) id propertyInCategory;
@end

And a module map (for compilation):

module "Objc_Base" {
    export *
    header "BaseClass.h"
    header "Protocol.h"
    use "Foundation"
}

Create a Swift file to use the Objective-C class:

import Objc_Base

func test() {
    let b = BaseClass()
    _ = b.propertyInProtocol
    _ = b.propertyInCategory
}

Run sourcekitd-test to index the Swift file and observe the entities output:

$ sourcekitd-test -req index User.swift --  \
  -sdk /var/db/xcode_select_link//Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk  \
  -target x86_64-apple-ios15.0-simulator \
  -Xcc -fmodule-map-file=[path to your module map] \
  User.swift
key.entities: [
    {
      key.kind: source.lang.swift.ref.module,
      key.name: "Objc_Base",
      key.usr: "c:@M@Objc_Base",
      key.line: 1,
      key.column: 8
    },
    {
      key.kind: source.lang.swift.decl.function.free,
      key.name: "test()",
      key.usr: "s:4User4testyyF",
      key.line: 3,
      key.column: 6,
      key.entities: [
        {
          key.kind: source.lang.swift.ref.class,
          key.name: "BaseClass",
          key.usr: "c:objc(cs)BaseClass",
          key.line: 4,
          key.column: 10
        },
        {
          key.kind: source.lang.swift.ref.function.constructor,
          key.name: "init()",
          key.usr: "c:objc(cs)NSObject(im)init",
          key.line: 4,
          key.column: 10
        },
        {
          key.kind: source.lang.swift.ref.var.instance,
          key.name: "propertyInCategory",
          key.usr: "c:objc(cs)BaseClass(py)propertyInCategory",
          key.line: 6,
          key.column: 8,
          key.receiver_usr: "c:objc(cs)BaseClass",
          key.is_dynamic: 1,
          key.entities: [
            {
              key.kind: source.lang.swift.ref.function.accessor.getter,
              key.usr: "c:@CM@Objc_Base@@objc(cs)BaseClass(im)propertyInCategory",
              key.line: 6,
              key.column: 8,
              key.receiver_usr: "c:objc(cs)BaseClass",
              key.is_dynamic: 1,
              key.is_implicit: 1
            }
          ]
        }
      ],
      key.effective_access: source.decl.effective_access.internal
    }
  ]

The entities does not contain any references to propertyInProtocol.

Expected behavior

I expect to see a reference to the property propertyInProtocol because it was used in the Swift code.

Environment

dylansturg commented 12 months ago

The semantic data for the reference exists when requesting cursor-info instead of the index for the whole instead.

$ sourcekitd-test -req cursor -offset 60 User.swift --  \
  -sdk /var/db/xcode_select_link//Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk  \
  -target x86_64-apple-ios15.0-simulator \
  -Xcc -fmodule-map-file=[path to your module map] \
  User.swift
{
  key.kind: source.lang.swift.ref.var.instance,
  key.name: "propertyInProtocol",
  key.usr: "c:objc(pl)Additions(py)propertyInProtocol",
  key.line: 6,
  key.column: 35,
  key.receivers: [
    {
      key.usr: "c:objc(cs)BaseClass"
    }
  ],
  key.is_dynamic: 1,
  key.offset: 123,
  key.length: 18,
  key.typename: "Any?",
  key.typeusr: "$sypSgD",
  key.containertypeusr: "$sSo9BaseClassCD",
  key.modulename: "Objc_Base",
  key.reusingastcontext: 0,
  key.decl_lang: source.lang.objc,
  key.is_synthesized: 1
}

It looks like the semantic data for this also exists, and just isn't getting into the response from index or the output of building with indexing.