mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-16 20:53:57 +08:00
a329df883a
The declared-member receiver inference #2171 gave C#, Java and Kotlin now reads Swift too: `var cache: ImageCache!`, `let storage: DiskStorage.Backend<Data>`, `self.x` as well as `x`, a function's own `let` shadowing the property. The dotted-call path types the receiver from it, and a chained bare call keeps only members of that type or its supertypes / protocols. Kingfisher: `cache.imageCachedType(forKey:)` -> ImageCache's (was a test subclass's override), `storage.store/value/isCached` -> DiskStorage.Backend, `manager.retrieveImage` -> KingfisherManager (was a test double), DispatchQueue `ioQueue.async` no longer a project method. realm-swift: `List::append`, `RealmCollection::sum/index` (were Objective-C RLMArray selectors); vapor: `self.storage.write` -> NIOHTTPBodyWriterStorage. Kingfisher -100 +179, realm-swift -108 +203, Alamofire -16 +54, vapor -15 +10, IceCubesApp -6 +5; Newtonsoft.Json, okhttp unchanged. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
2.0 KiB
TypeScript
61 lines
2.0 KiB
TypeScript
/**
|
||
* A Swift call on a property the enclosing type declares with a type —
|
||
* Kingfisher's `var cache: ImageCache!` — is a member of that type (or of
|
||
* what it inherits): `cache.imageCachedType(forKey:)` is ImageCache's, not a
|
||
* test subclass's override (`EvictingPrefetchCache`) that shared its name.
|
||
*/
|
||
import { describe, it, expect, afterAll, beforeAll } from 'vitest';
|
||
import * as fs from 'fs';
|
||
import * as os from 'os';
|
||
import * as path from 'path';
|
||
import { CodeGraph } from '../src';
|
||
|
||
let root = '';
|
||
let cg: CodeGraph;
|
||
|
||
beforeAll(async () => {
|
||
root = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-swift-member-'));
|
||
const files: Record<string, string> = {
|
||
'Sources/Cache/ImageCache.swift': `open class ImageCache {
|
||
open func imageCachedType(forKey key: String) -> Int {
|
||
return 0
|
||
}
|
||
}
|
||
`,
|
||
'Tests/KingfisherTests/ImagePrefetcherTests.swift': `class EvictingPrefetchCache: ImageCache {
|
||
override func imageCachedType(forKey key: String) -> Int {
|
||
return 1
|
||
}
|
||
}
|
||
`,
|
||
'Tests/KingfisherTests/ImageCacheTests.swift': `class ImageCacheTests {
|
||
var cache: ImageCache!
|
||
|
||
func testCachedType() {
|
||
_ = cache.imageCachedType(forKey: "a")
|
||
_ = self.cache.imageCachedType(forKey: "b")
|
||
}
|
||
}
|
||
`,
|
||
};
|
||
for (const [rel, content] of Object.entries(files)) {
|
||
fs.mkdirSync(path.dirname(path.join(root, rel)), { recursive: true });
|
||
fs.writeFileSync(path.join(root, rel), content);
|
||
}
|
||
cg = await CodeGraph.init(root, { index: true });
|
||
});
|
||
|
||
afterAll(() => {
|
||
cg?.close();
|
||
if (root) fs.rmSync(root, { recursive: true, force: true });
|
||
});
|
||
|
||
describe('Swift calls on a typed property', () => {
|
||
it('reach the declared type’s method, not a subclass override elsewhere', () => {
|
||
const ids = cg.getNodesInFile('Tests/KingfisherTests/ImageCacheTests.swift').map((n) => n.id);
|
||
const targets = [...new Set(cg.getOutgoingEdgesFrom(ids).filter((e) => e.kind === 'calls')
|
||
.map((e) => cg.getNode(e.target)!.qualifiedName))];
|
||
expect(targets).toEqual(['ImageCache::imageCachedType']);
|
||
});
|
||
});
|