cg-code-graph 0.23.7__tar.gz → 0.23.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cg_code_graph-0.23.7/cg_code_graph.egg-info → cg_code_graph-0.23.9}/PKG-INFO +1 -1
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/__init__.py +1 -1
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/cli.py +6 -3
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/parity.py +77 -9
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/parity_structure.py +119 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/platforms.py +35 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/kotlin/plugin.py +169 -5
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/plugin.py +200 -14
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9/cg_code_graph.egg-info}/PKG-INFO +1 -1
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph.egg-info/SOURCES.txt +3 -0
- cg_code_graph-0.23.9/tests/test_dispatch_part3.py +122 -0
- cg_code_graph-0.23.9/tests/test_parity_fields.py +125 -0
- cg_code_graph-0.23.9/tests/test_swift_platform_files.py +103 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/LICENSE +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/MANIFEST.in +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/README.md +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/__main__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/affected.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/agent_rules.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/agents.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/aitools.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/android_ipc.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/apple_ipc.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/apps.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/blindspots.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/bridges.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/brokers.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/cmake_sources.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/concepts.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/config.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/cache.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/detect.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/env.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/extractors.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/fsutil.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/generated.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/model.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/paths.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/redact.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/store.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/core/syntax_errors.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/coverage.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/dart_isolates.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/doctor.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/explore.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/external.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/graphql.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/guard_facts.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/hooks.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/indexer.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/insecure_transport.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/install_rules.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/jobs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/link.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/lint_async.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/local_ipc.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/local_sockets.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/mcp_graphs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/mcp_install.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/mcp_server.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/payload.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plans.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/platform_scan.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/astro/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/astro/content.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/astro/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/cfamily/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/cfamily/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/cfamily/syntax.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/bridges.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/extractor/bin/extract.dart +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/extractor/pubspec.lock +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/extractor/pubspec.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/http.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/models.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/dart/program.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/extras.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/models.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/schemas.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/shapes.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/django/urls.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/express/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/express/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/flutter/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/flutter/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/java/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/java/exact.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/java/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/jvm/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/jvm/interop.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/jvm/spring.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/kotlin/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/kotlin/exact.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/kotlin/reparse.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/broadcast.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/massassign.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/tests.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/laravel/values.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/native/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/native/gates.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/native/runner.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/native/scipread.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/native/ts.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nest/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nest/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nextjs/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nextjs/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nuxt/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/nuxt/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/external.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/extractor/composer.json +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/extractor/composer.lock +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/extractor/extract.php +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/gating.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/http_client.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/inline_guards.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/php/strings.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/aitools.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/external.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/fields.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/refs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/roots.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/socketio.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/subproc.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/tests.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/python/values.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/pyweb/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/pyweb/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/pyweb/values.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/rust/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/rust/cargo.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/rust/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/rust/syntax.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/scip/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/scip/importer.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/scip/scip.proto +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/scip/scip_pb2.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/stubs/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/stubs/plugins.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/baseurl.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/exact.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/indexstore.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/swift/packages.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/baseurl.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/extractor/extract.mjs +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/extractor/fw.mjs +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/extractor/package-lock.json +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/extractor/package.json +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/extractor/rr.mjs +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/nav.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/plugin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/ts/react_router.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/tsweb/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/tsweb/common.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/plugins/tsweb/data.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/c_cpp.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/common.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/dart.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/django-ninja.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/django.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/djangorestframework.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/express.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/java.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/kotlin.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/laravel.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/nest.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/nextjs.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/nuxt.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/php.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/python.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/react-router.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/rust.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/spring.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/swift.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/presets/typescript.yaml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/process_runs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/protocols/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/protocols/builtin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/protocols/matchers.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/protocols/view.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/query.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/realtime.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/realtime_events.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/realtime_native.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/realtime_ws.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/roundtrip.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/routes.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/rpc.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/sdk_systems.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/sockets.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/ssrf_input.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/starters.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/surface.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/tests_index.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/udp_apps.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/update_check.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/__init__.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/graph.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/server.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/app.css +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/app.js +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/index.html +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/layered.js +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/vendor/VERSIONS.txt +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/vendor/cose-base.js +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/vendor/cytoscape-fcose.js +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/vendor/cytoscape.min.js +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/static/vendor/layout-base.js +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/tools/package-lock.json +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/tools/package.json +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/viz/tools/shoot.mjs +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/watch.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/webhook_subs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/webhooks.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph/xcode.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph.egg-info/dependency_links.txt +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph.egg-info/entry_points.txt +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph.egg-info/requires.txt +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/cg_code_graph.egg-info/top_level.txt +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/pyproject.toml +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/setup.cfg +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_affected.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_agents_install.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_agents_md.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ai_tools.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_android_ipc.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_apple_ipc.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_astro.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_astro_content.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_astro_server.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_bridges.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_bridges_pigeon_monorepo.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_brokers.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_cache_clean.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_cache_invalidation.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_cache_migration.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_channels_tests.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_cli_output.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_cmake_sources.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_completeness.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_config_extras.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_coverage.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_coverage_ts_hint.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_dart_isolates.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_db_connections.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_dead_wrappers.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_dispatch_interfaces.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_django_flutter.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_docs_languages.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_docs_links.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_echo_ref.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_echo_wrapper.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_elysia.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_enum_constants.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_env.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_explore.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_external.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_fp_batch.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_gating.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_generated.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_graphql.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_hooks.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_impact_overrides.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_index_isolation.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_inherited_overrides.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_inline_guards.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_install_rules.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_192.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_201.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_202.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_203.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_204.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_205.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_206.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_207.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_208.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_209.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_210.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_211.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_211_used_at.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_212.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_212_langs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_218.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_219.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_issue_222.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_java.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_java_exact.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_jobs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_js_refs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_js_runtime.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_binding.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_exact.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_fields.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_mixed.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_nav_consts.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_kotlin_props.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_laravel_determinism.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_laravel_receiver_narrowing.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_laravel_resources.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_laravel_route_paths.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_link_origin.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_lint_async.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_listing_files.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_local_ipc.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_local_sockets.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mass_assignment.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mcp.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mcp_index.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mcp_install.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mcp_instructions.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_mcp_multi_graph.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_native_cfamily.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_native_concurrency.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_native_rust.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_nuxt_i18n.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_nuxt_import_dirs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_nuxt_nitro.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_nuxt_rootsrc.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_nuxt_side_dirs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_packaging.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_parity.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_parity_structure.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_php_http.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_php_props.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_plain_js.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_plans.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_platform_gaps.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_platform_type_variants.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_platforms.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_platforms_apple.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_presets_config.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_process_ipc.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_process_runs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_protocols.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_app_tests_module.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_collection_chains.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_compat.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_entry_refs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_fields.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_infer_cycles.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_roots.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_subprocess_tests.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_tests.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_web_hosts.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_web_routes.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_python_web_routes_more.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_react_router.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_readers_writers_specs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_realtime.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_realtime_native.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_redact_salt.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_request_keys.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_roundtrip.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_route_specs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_route_tables.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_routes_search_explain.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_rpc.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_scip_health.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_sdk_external.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_sdk_external_infra.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_sdk_external_mail.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_snippet.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_sockets.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_spring.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ssrf.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_starters_budget.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_surface.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_surface_transport.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_binding.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_exact.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_facts.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_fields.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_modules.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_more.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_nav_values.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_parse_errors.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_props.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_sdk.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_testing.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_swift_values.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_tauri_events.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_tests_scope.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_fields.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_fields_js_vue.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_file_specs.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_frameworks.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_node_http.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_nuxt.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_ts_src_tsconfig.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_unguarded.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_update_check.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_values.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_viz.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_vue_nav.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_watch.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_webhooks.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_webhooks_152.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_webhooks_152b.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_websockets.py +0 -0
- {cg_code_graph-0.23.7 → cg_code_graph-0.23.9}/tests/test_workspace_link.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""code-graph: deterministic code knowledge graph (beta)."""
|
|
2
|
-
__version__ = "0.23.
|
|
2
|
+
__version__ = "0.23.9"
|
|
@@ -301,9 +301,12 @@ def main(argv=None):
|
|
|
301
301
|
p.add_argument("--strip-prefix", action="append", default=[], help="a name prefix one side adds (`Vault` in "
|
|
302
302
|
"VaultAddEditState for AddEditState), ignored when matching (repeatable)")
|
|
303
303
|
p.add_argument("--structure", action="store_true", help="also pair symbols whose names differ by what they use: "
|
|
304
|
-
"shared strings, localization keys, endpoints and already-paired callees,
|
|
305
|
-
"from the pairs found (#93); matches carry their
|
|
304
|
+
"shared strings, localization keys, resources, endpoints and already-paired callees, then types by "
|
|
305
|
+
"their declared fields, plus rename rules learned from the pairs found (#93); matches carry their "
|
|
306
|
+
"evidence")
|
|
306
307
|
p.add_argument("--no-learn", action="store_true", help="with --structure: no learned rename rules")
|
|
308
|
+
p.add_argument("--both-sides", action="store_true", help="also list the matched pairs and what only --against "
|
|
309
|
+
"has (target symbols no source symbol matched)")
|
|
307
310
|
p.add_argument("--write-map", help="with --structure: write the inferred pairs as a --map JSON file to review")
|
|
308
311
|
p.add_argument("--json", action="store_true"); p.add_argument("--max-items", type=int, default=200)
|
|
309
312
|
p = sub.add_parser("lint", help="heuristic lints (#88): `lint async-state` flags stale async results, state with "
|
|
@@ -574,7 +577,7 @@ def main(argv=None):
|
|
|
574
577
|
from . import parity as PA
|
|
575
578
|
mapping = json.loads(open(a.map, encoding="utf-8").read()) if a.map else None
|
|
576
579
|
res = PA.parity(a.db, a.against, mapping=mapping, fuzzy=not a.no_fuzzy, strip_prefixes=a.strip_prefix,
|
|
577
|
-
structure=a.structure, learn=not a.no_learn)
|
|
580
|
+
structure=a.structure, learn=not a.no_learn, both_sides=a.both_sides)
|
|
578
581
|
if a.write_map:
|
|
579
582
|
with open(a.write_map, "w", encoding="utf-8") as fh:
|
|
580
583
|
json.dump(PA.rename_map(res), fh, indent=1, sort_keys=True)
|
|
@@ -220,21 +220,27 @@ def _cat(sym: dict, is_type: bool) -> str:
|
|
|
220
220
|
return "type" if is_type else "const" if sym["kind"] in ("constant", "enum_case") else "func"
|
|
221
221
|
|
|
222
222
|
|
|
223
|
+
INFERRED = ("structure", "fields", "learned")
|
|
224
|
+
PREVIEW_NAME = re.compile(r"Preview")
|
|
225
|
+
|
|
226
|
+
|
|
223
227
|
def parity(source_db: str, target_db: str, mapping: dict | None = None, fuzzy: bool = True,
|
|
224
|
-
strip_prefixes: list[str] | None = None, structure: bool = False, learn: bool = True
|
|
228
|
+
strip_prefixes: list[str] | None = None, structure: bool = False, learn: bool = True,
|
|
229
|
+
both_sides: bool = False) -> dict:
|
|
225
230
|
"""See the module docstring. `strip_prefixes`: name prefixes one side adds (`Vault` in `VaultAddEditState`
|
|
226
231
|
for `AddEditState`), dropped before normalized matching on both sides. `structure` (#93): after the name rules,
|
|
227
232
|
pair the rest by shared strings, localization keys, endpoints and paired callees, and (`learn`) apply rename
|
|
228
|
-
rules learned from the pairs found (cg_code_graph/parity_structure.py); off, the output is the name matching alone.
|
|
233
|
+
rules learned from the pairs found (cg_code_graph/parity_structure.py); off, the output is the name matching alone.
|
|
234
|
+
`both_sides`: also list what only the target has (`target_only`)."""
|
|
229
235
|
_PREFIXES[:] = [p.lower() for p in strip_prefixes or ()]
|
|
230
236
|
try:
|
|
231
|
-
return _parity(source_db, target_db, mapping, fuzzy, structure, learn)
|
|
237
|
+
return _parity(source_db, target_db, mapping, fuzzy, structure, learn, both_sides)
|
|
232
238
|
finally:
|
|
233
239
|
_PREFIXES.clear()
|
|
234
240
|
|
|
235
241
|
|
|
236
242
|
def _parity(source_db: str, target_db: str, mapping: dict | None, fuzzy: bool, structure: bool = False,
|
|
237
|
-
learn: bool = True) -> dict:
|
|
243
|
+
learn: bool = True, both_sides: bool = False) -> dict:
|
|
238
244
|
S, T = load(source_db), load(target_db)
|
|
239
245
|
mapping = mapping or {}
|
|
240
246
|
exact_ix, norm_ix, comp_ix, all_short = defaultdict(list), defaultdict(list), defaultdict(list), defaultdict(list)
|
|
@@ -357,7 +363,7 @@ def _parity(source_db: str, target_db: str, mapping: dict | None, fuzzy: bool, s
|
|
|
357
363
|
tm.setdefault(_short(nt), T["types"][nt])
|
|
358
364
|
tm_norm = {norm_member(k): k for k in tm}
|
|
359
365
|
for nm, sym in sorted(S["members"].get(sfq, {}).items()):
|
|
360
|
-
if nm in
|
|
366
|
+
if nm in BOILERPLATE or sym["override"]:
|
|
361
367
|
out["skipped"] += 1 # lifecycle / platform overrides (viewDidLoad, onCreate) and boilerplate
|
|
362
368
|
continue
|
|
363
369
|
if nm in tm:
|
|
@@ -375,7 +381,7 @@ def _parity(source_db: str, target_db: str, mapping: dict | None, fuzzy: bool, s
|
|
|
375
381
|
match_members(tmap)
|
|
376
382
|
if structure:
|
|
377
383
|
_structure(S, T, out, tmap, learn)
|
|
378
|
-
inferred = {r["symbol"]: r["target"] for r in out["matched"] if r.get("confidence") in
|
|
384
|
+
inferred = {r["symbol"]: r["target"] for r in out["matched"] if r.get("confidence") in INFERRED
|
|
379
385
|
and r["symbol"] in S["types"] and r["target"] in T["types"]}
|
|
380
386
|
match_members(inferred)
|
|
381
387
|
counts = defaultdict(int)
|
|
@@ -387,10 +393,44 @@ def _parity(source_db: str, target_db: str, mapping: dict | None, fuzzy: bool, s
|
|
|
387
393
|
"missing": len(out["missing"]), "unknown": len(out["unknown"]),
|
|
388
394
|
"platform_only": len(out["platform_only"])}
|
|
389
395
|
if structure:
|
|
390
|
-
out["summary"]["inferred"] = sum(1 for r in out["matched"] if r["confidence"] in
|
|
396
|
+
out["summary"]["inferred"] = sum(1 for r in out["matched"] if r["confidence"] in INFERRED)
|
|
397
|
+
if both_sides:
|
|
398
|
+
_target_only(T, out, t_nested)
|
|
399
|
+
out["summary"]["target_only"] = len(out["target_only"])
|
|
391
400
|
return out
|
|
392
401
|
|
|
393
402
|
|
|
403
|
+
BOILERPLATE = ("body", "init", "deinit", "hash", "description", "encode", "hashValue")
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
def _target_only(T, out, t_nested):
|
|
407
|
+
"""`--both-sides`: target types and top-level symbols no source symbol matched, and the unmatched members of
|
|
408
|
+
target types that were matched. Members of an unmatched type are counted under it, not listed."""
|
|
409
|
+
used = {r["target"] for r in out["matched"]}
|
|
410
|
+
rows, hidden = [], 0
|
|
411
|
+
for coll in (T["types"], T["top"]):
|
|
412
|
+
for fq, sym in sorted(coll.items()):
|
|
413
|
+
if fq in used:
|
|
414
|
+
continue
|
|
415
|
+
owner = fq.rsplit(".", 1)[0] if "." in fq else None
|
|
416
|
+
if owner in T["types"] and owner not in used:
|
|
417
|
+
continue # a nested type of an unmatched type: the type is listed
|
|
418
|
+
if PREVIEW_NAME.search(_short(fq)) or sym["file"] in T["err_files"]:
|
|
419
|
+
hidden += 1
|
|
420
|
+
continue
|
|
421
|
+
rows.append(_row(sym, None, None))
|
|
422
|
+
for o in sorted(o for o in T["members"] if o in used):
|
|
423
|
+
for nm, sym in sorted(T["members"][o].items()):
|
|
424
|
+
if f"{o}.{nm}" in used:
|
|
425
|
+
continue
|
|
426
|
+
if nm in BOILERPLATE or sym["override"] or sym["file"] in T["err_files"]:
|
|
427
|
+
hidden += 1
|
|
428
|
+
continue
|
|
429
|
+
rows.append(_row(sym, None, None))
|
|
430
|
+
out["target_only"] = rows
|
|
431
|
+
out["target_only_hidden"] = hidden
|
|
432
|
+
|
|
433
|
+
|
|
394
434
|
def _structure(S, T, out, tmap, learn):
|
|
395
435
|
from . import parity_structure as PS
|
|
396
436
|
sym_of, cat_of, t_syms, t_cat = {}, {}, {}, {}
|
|
@@ -409,7 +449,7 @@ def _structure(S, T, out, tmap, learn):
|
|
|
409
449
|
|
|
410
450
|
def rename_map(res: dict) -> dict:
|
|
411
451
|
"""The structure / learned matches as a `--map` file ({source: target}) to review and commit."""
|
|
412
|
-
return {r["symbol"]: r["target"] for r in res["matched"] if r.get("confidence") in
|
|
452
|
+
return {r["symbol"]: r["target"] for r in res["matched"] if r.get("confidence") in INFERRED}
|
|
413
453
|
|
|
414
454
|
|
|
415
455
|
def _row(sym, target, how, owner_match=None) -> dict:
|
|
@@ -435,6 +475,25 @@ def _group(file: str) -> str:
|
|
|
435
475
|
return "/".join(parts[:2]) if len(parts) > 2 else (parts[0] if parts else "")
|
|
436
476
|
|
|
437
477
|
|
|
478
|
+
def _grouped(lines, title, rows, total, max_items):
|
|
479
|
+
by = defaultdict(list)
|
|
480
|
+
for r in rows:
|
|
481
|
+
by[r["module"]].append(r)
|
|
482
|
+
if not by:
|
|
483
|
+
return
|
|
484
|
+
lines += ["", f"== {title}: {total}"]
|
|
485
|
+
shown = 0
|
|
486
|
+
for mod in sorted(by, key=lambda k: -len(by[k])):
|
|
487
|
+
lines.append(f" {mod or '.'} ({len(by[mod])})")
|
|
488
|
+
for r in by[mod]:
|
|
489
|
+
if shown >= max_items:
|
|
490
|
+
break
|
|
491
|
+
shown += 1
|
|
492
|
+
lines.append(f" {r['symbol']} [{r['kind']}] {r['file']}:{r['line']}")
|
|
493
|
+
if shown < total:
|
|
494
|
+
lines.append(f" ... {total - shown} more (--json for all)")
|
|
495
|
+
|
|
496
|
+
|
|
438
497
|
def render(res: dict, max_items: int = 200) -> str:
|
|
439
498
|
s = res["summary"]
|
|
440
499
|
m = s["matched"]
|
|
@@ -457,7 +516,14 @@ def render(res: dict, max_items: int = 200) -> str:
|
|
|
457
516
|
lines.append(f" {r['symbol']} [{r['kind']}] {r['file']}:{r['line']}")
|
|
458
517
|
if shown < s["missing"]:
|
|
459
518
|
lines.append(f" ... {s['missing'] - shown} more (--json for all)")
|
|
460
|
-
|
|
519
|
+
if "target_only" in res:
|
|
520
|
+
lines[1] += f"; {s['target_only']} only in the target"
|
|
521
|
+
lines += ["", f"== MATCHED pairs: {sum(m.values())}"]
|
|
522
|
+
for r in sorted(res["matched"], key=lambda r: (r["confidence"] != "explicit", r["symbol"]))[:max_items]:
|
|
523
|
+
lines.append(f" {r['symbol']} -> {r['target']} [{r['confidence']}]")
|
|
524
|
+
if sum(m.values()) > max_items:
|
|
525
|
+
lines.append(f" ... {sum(m.values()) - max_items} more (--json for all)")
|
|
526
|
+
inferred = [r for r in res["matched"] if r.get("confidence") in INFERRED]
|
|
461
527
|
if inferred:
|
|
462
528
|
lines += ["", f"== INFERRED matches (not by name): {len(inferred)}"]
|
|
463
529
|
for r in inferred[:max_items]:
|
|
@@ -467,6 +533,8 @@ def render(res: dict, max_items: int = 200) -> str:
|
|
|
467
533
|
if rule is (res.get("learned_rules") or [None])[0]:
|
|
468
534
|
lines += ["", "== LEARNED rename rules"]
|
|
469
535
|
lines.append(f" {rule['at']}: {rule['from']!r} -> {rule['to']!r} (seen {rule['support']}x)")
|
|
536
|
+
if "target_only" in res:
|
|
537
|
+
_grouped(lines, "ONLY IN TARGET (no source counterpart)", res["target_only"], s["target_only"], max_items)
|
|
470
538
|
if res["unknown"]:
|
|
471
539
|
lines += ["", f"== UNKNOWN (file parsed with syntax errors): {s['unknown']}"]
|
|
472
540
|
lines += [f" {r['symbol']} {r['file']}:{r['line']}" for r in res["unknown"][:max_items]]
|
|
@@ -11,8 +11,21 @@ its outgoing edges:
|
|
|
11
11
|
sym:<target> symbols it calls / instantiates / navigates to that are already paired (the source side is
|
|
12
12
|
rewritten to the target's name, so a call to a paired API on both sides is a shared feature)
|
|
13
13
|
call:<name> the names of the members it calls (two words or more)
|
|
14
|
+
res:<name> image and raw resources it uses (`Image("ic_lock")`, `UIImage(named:)`, `Asset.Images.icLock`,
|
|
15
|
+
`Image(.icLock)`, `R.drawable.ic_lock`, `Res.drawable.x`), case and `_` folded; colors are design
|
|
16
|
+
tokens shared by every screen and are left out
|
|
14
17
|
w:<stem> the stemmed content words of its own name
|
|
15
18
|
|
|
19
|
+
A use is specific when it appears in at most SPECIFIC_FILES files on each side (files, not symbols, since a type's span
|
|
20
|
+
holds its members'); a pair whose shared uses are all generic needs two shared name words, so two screens that only
|
|
21
|
+
share `l10n:cancel` / `l10n:yes` and one word do not pair.
|
|
22
|
+
|
|
23
|
+
Types that are still missing after that are paired by their declared fields (`fields`): stored properties, each under
|
|
24
|
+
its wire name when one is declared (Swift `CodingKeys` raw values, Kotlin `@SerialName` / `@SerializedName` /
|
|
25
|
+
`@Json(name =)`), and enum cases, kept apart from properties; case and `_` folded. A pair needs MIN_FIELDS shared
|
|
26
|
+
fields, an IDF-weighted overlap of at least MIN_FIELD_SCORE, a shared name word or a higher overlap, mutual best and
|
|
27
|
+
the margin.
|
|
28
|
+
|
|
16
29
|
A pair is accepted when it shares a use (any feature but w:) and either two uses or two name words, its IDF-weighted
|
|
17
30
|
cosine is at least MIN_SCORE, both symbols are each other's best candidate, the runner-up scores below MARGIN times
|
|
18
31
|
the best, and category, UI-ness and architecture role agree (`compatible`). Learned rules come from the
|
|
@@ -21,6 +34,7 @@ MIN_SUPPORT times, two thirds of the time for that source tail, is applied to th
|
|
|
21
34
|
top-level symbols. Every match carries its evidence; name matches are left as they are."""
|
|
22
35
|
from __future__ import annotations
|
|
23
36
|
|
|
37
|
+
import json
|
|
24
38
|
import math
|
|
25
39
|
import re
|
|
26
40
|
import sqlite3
|
|
@@ -32,9 +46,16 @@ MIN_SHARED = 2
|
|
|
32
46
|
MARGIN = 0.8 # the runner-up must score below MARGIN * best
|
|
33
47
|
MIN_SUPPORT = 2
|
|
34
48
|
MAX_DF = 40
|
|
49
|
+
SPECIFIC_FILES = 3 # a shared use found in more files than this on either side is generic (`l10n:cancel`)
|
|
50
|
+
MIN_FIELDS = 3
|
|
51
|
+
MIN_FIELD_SCORE = 0.5
|
|
35
52
|
PREVIEW = re.compile(r"Preview") # Compose @Preview functions / PreviewParameterProviders, SwiftUI previews # features shared by more symbols than this do not propose candidates
|
|
36
53
|
L10N = re.compile(r"\b(?:Localizations|L10n|R\.string|BitwardenString|CommonStrings|[A-Z]\w*Strings)\.([A-Za-z_]\w*)")
|
|
37
54
|
STR = re.compile(r'"((?:[^"\\\n]|\\.){5,80})"')
|
|
55
|
+
RES = re.compile(r"""\b(?:UI|NS)?Image\(\s*(?:named:\s*)?"([^"\n]+)"|\bAsset\.(?:Images|Assets)\.(\w+)|"""
|
|
56
|
+
r"""\bImage\(\s*\.(\w+)\s*\)|\b(?:R|Res)\.(?:drawable|mipmap|raw)\.(\w+)""")
|
|
57
|
+
WIRE = re.compile(r'@(?:SerialName|SerializedName|JsonProperty|Json\(\s*name\s*=)\s*\(?\s*(?:value\s*=\s*)?"([^"\n]+)"')
|
|
58
|
+
RAW_CASE = re.compile(r'\bcase\s+`?(\w+)`?\s*=\s*"([^"\n]+)"')
|
|
38
59
|
EDGE_KINDS = ("CALLS", "INSTANTIATES", "NAVIGATES_TO", "HTTP_CALLS", "USES_VALUE", "REFERENCES_FN", "USES_TYPE")
|
|
39
60
|
|
|
40
61
|
|
|
@@ -123,8 +144,40 @@ class Side:
|
|
|
123
144
|
for r in c.execute(q, EDGE_KINDS):
|
|
124
145
|
self.out[r["src"]].append((r["dst"], r["kind"]))
|
|
125
146
|
self.http = {r["id"]: (r["name"] or r["id"]) for r in c.execute("SELECT id, name FROM nodes WHERE kind='http'")}
|
|
147
|
+
self.decl = defaultdict(list) # owner fqn -> [(name, kind, file, line)] of stored fields / enum cases
|
|
148
|
+
for r in c.execute("SELECT kind, fqn, file, line, attrs FROM nodes WHERE kind IN ('field', 'enum_case') "
|
|
149
|
+
"AND fqn IS NOT NULL AND file IS NOT NULL"):
|
|
150
|
+
if ".Companion." in r["fqn"] or "." not in r["fqn"]:
|
|
151
|
+
continue
|
|
152
|
+
if r["kind"] == "field" and (json.loads(r["attrs"] or "{}").get("property") or "stored") != "stored":
|
|
153
|
+
continue
|
|
154
|
+
o, nm = r["fqn"].rsplit(".", 1)
|
|
155
|
+
self.decl[o].append((nm, r["kind"], r["file"], r["line"]))
|
|
126
156
|
c.close()
|
|
127
157
|
|
|
158
|
+
def fields(self, fq: str) -> set:
|
|
159
|
+
"""`field:<wire name>` for each stored property declared directly on the type: the explicit wire name
|
|
160
|
+
(`@SerialName("item_title")`, a `CodingKeys` case `title = "item_title"`) or else the property name; `case:<name>`
|
|
161
|
+
for each enum case, so an enum of field names does not meet the type that has those fields."""
|
|
162
|
+
raw = {}
|
|
163
|
+
for nm, kind, file, line in self.decl.get(fq + ".CodingKeys", ()):
|
|
164
|
+
m = RAW_CASE.search(self.text(file, line, line))
|
|
165
|
+
if m:
|
|
166
|
+
raw[m.group(1)] = m.group(2)
|
|
167
|
+
out = set()
|
|
168
|
+
for nm, kind, file, line in self.decl.get(fq, ()):
|
|
169
|
+
wire = raw.get(nm)
|
|
170
|
+
if not wire and kind == "field":
|
|
171
|
+
m = WIRE.search(self.text(file, line, line))
|
|
172
|
+
if not m and line > 1: # an annotation on its own line above
|
|
173
|
+
prev = self.text(file, line - 1, line - 1)
|
|
174
|
+
m = None if re.search(r"\b(?:val|var|let)\s", prev) else WIRE.search(prev)
|
|
175
|
+
wire = m.group(1) if m else None
|
|
176
|
+
k = _fold(wire or nm)
|
|
177
|
+
if len(k) > 1:
|
|
178
|
+
out.add(("case:" if kind == "enum_case" else "field:") + k)
|
|
179
|
+
return out
|
|
180
|
+
|
|
128
181
|
def text(self, file: str, a: int, b: int) -> str:
|
|
129
182
|
if file not in self.lines:
|
|
130
183
|
try:
|
|
@@ -139,6 +192,9 @@ class Side:
|
|
|
139
192
|
if file and a:
|
|
140
193
|
src = self.text(file, a, b)
|
|
141
194
|
f |= {"l10n:" + _fold(m) for m in L10N.findall(src)}
|
|
195
|
+
for m in RES.finditer(src):
|
|
196
|
+
f.add("res:" + _fold(next(g for g in m.groups() if g)))
|
|
197
|
+
src = RES.sub(" ", src)
|
|
142
198
|
for m in STR.findall(src):
|
|
143
199
|
s = m.strip().lstrip("/")
|
|
144
200
|
if len(s) >= 5 and re.search(r"[A-Za-z]{3}", s) and not re.search(r"\\\(|\$\{|%[@sd]", s):
|
|
@@ -250,6 +306,60 @@ def _apply_rules(rules, out, sym_of, cat_of, t_syms, t_cat, used):
|
|
|
250
306
|
out["missing"] = keep
|
|
251
307
|
|
|
252
308
|
|
|
309
|
+
def _by_fields(sS, sT, out, sym_of, cat_of, t_syms, t_cat, used, S, T):
|
|
310
|
+
"""Types still missing, paired by the fields they declare (`ViewItemState` / `VaultItemState`, a Swift
|
|
311
|
+
`Codable` model and its Kotlin `@Serializable` port)."""
|
|
312
|
+
src = {r["symbol"]: sS.fields(r["symbol"]) for r in out["missing"] if cat_of.get(r["symbol"]) == "type"
|
|
313
|
+
and "owner_matched" not in r}
|
|
314
|
+
src = {k: v for k, v in src.items() if len(v) >= MIN_FIELDS and _short(k) != "CodingKeys"}
|
|
315
|
+
tgt = {fq: sT.fields(fq) for fq in t_syms if t_cat.get(fq) == "type" and fq not in used}
|
|
316
|
+
tgt = {k: v for k, v in tgt.items() if len(v) >= MIN_FIELDS and _short(k) != "CodingKeys"}
|
|
317
|
+
if not src or not tgt:
|
|
318
|
+
return
|
|
319
|
+
df = Counter()
|
|
320
|
+
for fs in list(src.values()) + list(tgt.values()):
|
|
321
|
+
df.update(fs)
|
|
322
|
+
n = len(src) + len(tgt)
|
|
323
|
+
w = {f: math.log(1 + n / c) for f, c in df.items()}
|
|
324
|
+
inv = defaultdict(list)
|
|
325
|
+
for fq, fs in tgt.items():
|
|
326
|
+
for f in fs:
|
|
327
|
+
inv[f].append(fq)
|
|
328
|
+
|
|
329
|
+
def score(fq, t):
|
|
330
|
+
a, b = src[fq], tgt[t]
|
|
331
|
+
sh = a & b
|
|
332
|
+
if len(sh) < MIN_FIELDS:
|
|
333
|
+
return 0.0, sh
|
|
334
|
+
sc = sum(w[f] for f in sh) / sum(w[f] for f in a | b)
|
|
335
|
+
words = name_words(fq) & name_words(t)
|
|
336
|
+
if sc < MIN_FIELD_SCORE or (not words and sc < 0.75):
|
|
337
|
+
return 0.0, sh
|
|
338
|
+
return sc, sh | words
|
|
339
|
+
|
|
340
|
+
best = {}
|
|
341
|
+
for fq, fs in src.items():
|
|
342
|
+
cands = {t for f in fs if df[f] <= MAX_DF for t in inv[f]
|
|
343
|
+
if compatible(fq, "type", t, "type", S["_ui"].get(fq), T["_ui"].get(t))}
|
|
344
|
+
scored = sorted(((score(fq, t), t) for t in cands), key=lambda x: -x[0][0])
|
|
345
|
+
if scored and scored[0][0][0] > 0 and (len(scored) == 1 or scored[1][0][0] < MARGIN * scored[0][0][0]):
|
|
346
|
+
best[fq] = (scored[0][1], scored[0][0][0], scored[0][0][1])
|
|
347
|
+
by_t = defaultdict(list)
|
|
348
|
+
for fq, (t, sc, sh) in best.items():
|
|
349
|
+
by_t[t].append((sc, fq))
|
|
350
|
+
keep = []
|
|
351
|
+
for row in out["missing"]:
|
|
352
|
+
got = best.get(row["symbol"])
|
|
353
|
+
if got and max(by_t[got[0]])[1] == row["symbol"] and got[0] not in used:
|
|
354
|
+
t, sc, sh = got
|
|
355
|
+
used.add(t)
|
|
356
|
+
ev = sorted(sh, key=lambda f: (f.startswith("w:"), -w.get(f, 0), f))[:6]
|
|
357
|
+
out["matched"].append(dict(row, target=t, confidence="fields", score=round(sc, 2), evidence=ev))
|
|
358
|
+
else:
|
|
359
|
+
keep.append(row)
|
|
360
|
+
out["missing"] = keep
|
|
361
|
+
|
|
362
|
+
|
|
253
363
|
def _structure(S, T, out, sym_of, cat_of, t_syms, t_cat, used):
|
|
254
364
|
sS, sT = Side(S), Side(T)
|
|
255
365
|
pairs = {r["symbol"]: r["target"] for r in out["matched"]}
|
|
@@ -264,6 +374,12 @@ def _structure(S, T, out, sym_of, cat_of, t_syms, t_cat, used):
|
|
|
264
374
|
df = Counter()
|
|
265
375
|
for fs in list(src_f.values()) + list(tgt_f.values()):
|
|
266
376
|
df.update(fs)
|
|
377
|
+
spread = [defaultdict(set), defaultdict(set)] # feature -> files having it, per side
|
|
378
|
+
for k, (fsets, syms) in enumerate(((src_f, sym_of), (tgt_f, t_syms))):
|
|
379
|
+
for fq, fs in fsets.items():
|
|
380
|
+
for f in fs:
|
|
381
|
+
spread[k][f].add(syms[fq]["file"])
|
|
382
|
+
specific = {f for f in df if len(spread[0][f]) <= SPECIFIC_FILES and len(spread[1][f]) <= SPECIFIC_FILES}
|
|
267
383
|
n = max(1, len(src_f) + len(tgt_f))
|
|
268
384
|
w = {f: math.log(1 + n / c) for f, c in df.items()}
|
|
269
385
|
inv = defaultdict(list)
|
|
@@ -278,6 +394,8 @@ def _structure(S, T, out, sym_of, cat_of, t_syms, t_cat, used):
|
|
|
278
394
|
# what they use must carry the match: two shared uses, or one use and two shared name words
|
|
279
395
|
if nw < 1 or (nw < MIN_SHARED and len(sh) - nw < 2):
|
|
280
396
|
return 0.0, sh
|
|
397
|
+
if len(sh) - nw < 2 and not any(f in specific for f in sh if not f.startswith("w:")):
|
|
398
|
+
return 0.0, sh # only generic uses (`l10n:cancel`, `l10n:yes`) and one name word
|
|
281
399
|
return sum(w[f] for f in sh) / math.sqrt(sum(w[f] for f in a) * sum(w[f] for f in b)), sh
|
|
282
400
|
|
|
283
401
|
best_s = {}
|
|
@@ -305,3 +423,4 @@ def _structure(S, T, out, sym_of, cat_of, t_syms, t_cat, used):
|
|
|
305
423
|
else:
|
|
306
424
|
keep.append(row)
|
|
307
425
|
out["missing"] = keep
|
|
426
|
+
_by_fields(sS, sT, out, sym_of, cat_of, t_syms, t_cat, used, S, T)
|
|
@@ -254,6 +254,29 @@ OTHER_OS_STEM = re.compile(r"(?:^|[_-])(aix|sunos|solaris|os390|zos|ibmi|freebsd
|
|
|
254
254
|
r"cygwin|hurd|illumos|pase)$", re.I)
|
|
255
255
|
|
|
256
256
|
|
|
257
|
+
# Swift platform files (#225): `Foo+iOS.swift`, `Foo.macOS.swift`, `Foo_watchOS.swift`, or a folder `macOS/` / `iOS/`
|
|
258
|
+
# of a multiplatform app. A guess: built for that platform, unknown on the other Apple platforms, absent elsewhere
|
|
259
|
+
SWIFT_PLAT = {"ios": "ios", "iphone": "ios", "ipados": "ios", "macos": "macos", "osx": "macos", "mac": "macos",
|
|
260
|
+
"appkit": "macos", "tvos": "tvos", "watchos": "watchos", "visionos": "visionos", "xros": "visionos"}
|
|
261
|
+
SWIFT_STEM = re.compile(r"[+._-](iOS|iPhone|iPadOS|macOS|OSX|Mac|AppKit|tvOS|watchOS|visionOS|xrOS)$")
|
|
262
|
+
SWIFT_DIR = re.compile(r"^(iOS|iPadOS|macOS|OSX|tvOS|watchOS|visionOS|xrOS)$")
|
|
263
|
+
APPLE = ("ios", "macos", "tvos", "watchos", "visionos")
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def swift_path_convention(rel: str) -> tuple[str, str] | None:
|
|
267
|
+
parts = rel.split("/")
|
|
268
|
+
stem = parts[-1][:-len(".swift")] if parts[-1].endswith(".swift") else None
|
|
269
|
+
if stem is None:
|
|
270
|
+
return None
|
|
271
|
+
m = SWIFT_STEM.search(stem)
|
|
272
|
+
if m:
|
|
273
|
+
return SWIFT_PLAT[m.group(1).lower()], f"file name {parts[-1]}"
|
|
274
|
+
for d in parts[:-1]:
|
|
275
|
+
if SWIFT_DIR.match(d):
|
|
276
|
+
return SWIFT_PLAT[d.lower()], f"directory {d}/"
|
|
277
|
+
return None
|
|
278
|
+
|
|
279
|
+
|
|
257
280
|
def _plat_atom(name: str):
|
|
258
281
|
if name == "other": # an OS outside the known targets
|
|
259
282
|
return ("atom", "platform", "__other__")
|
|
@@ -655,6 +678,18 @@ def apply(project, builder) -> dict:
|
|
|
655
678
|
tree = ("any", [_plat_atom(p) for p in ps]) if len(ps) > 1 else _plat_atom(ps[0])
|
|
656
679
|
names = ", ".join(m["targets"][:3]) + (" …" if len(m["targets"]) > 3 else "")
|
|
657
680
|
mark(builder, f, 1, BIG, Cond("tree", tree, f"Xcode target membership ({names})"), line=1)
|
|
681
|
+
if "swift" in langs and pc.get("path_conventions", True):
|
|
682
|
+
whole = {m["file"] for m in builder.platform_marks if m["start"] <= 1 and m.get("end") in (None, BIG)}
|
|
683
|
+
for f, ns in nodes_by_file.items():
|
|
684
|
+
if f in whole or ns[0].lang != "swift":
|
|
685
|
+
continue # Xcode membership (or .cg.yaml paths) already says where it is built
|
|
686
|
+
pcv = swift_path_convention(f)
|
|
687
|
+
if pcv:
|
|
688
|
+
n0 = len(builder.platform_marks)
|
|
689
|
+
tree = ("any", [_plat_atom(pcv[0])] + [("atom", "unknown_on", p) for p in APPLE if p != pcv[0]])
|
|
690
|
+
mark(builder, f, 1, BIG, Cond("tree", tree, f"{pcv[1]} (platform file name)"), line=1)
|
|
691
|
+
if len(builder.platform_marks) > n0:
|
|
692
|
+
builder.platform_marks[-1]["convention"] = True
|
|
658
693
|
marks = builder.platform_marks
|
|
659
694
|
if not marks:
|
|
660
695
|
return {}
|
|
@@ -296,6 +296,8 @@ class KotlinPlugin(LanguagePlugin):
|
|
|
296
296
|
if files is None:
|
|
297
297
|
files = source_files(project.root, project)
|
|
298
298
|
self.decls: dict[str, Decl] = {}
|
|
299
|
+
self.rets: dict[str, str] = {} # function / method id -> declared (or constructed) result type text (#109)
|
|
300
|
+
self._ksrc: dict[str, bytes] = {}
|
|
299
301
|
self.test_fw: dict[str, str | None] = {}
|
|
300
302
|
self._fd = None
|
|
301
303
|
self.by_name: dict[str, list[Decl]] = defaultdict(list)
|
|
@@ -361,7 +363,8 @@ class KotlinPlugin(LanguagePlugin):
|
|
|
361
363
|
tree = nt
|
|
362
364
|
self.st["files_reparsed_by_member"] += 1
|
|
363
365
|
self.st["members_dropped_by_reparse"] += len(dropped)
|
|
364
|
-
kf = KFile(rel, src, tree)
|
|
366
|
+
kf = KFile(rel, src, tree)
|
|
367
|
+
self._ksrc[rel] = src # names and text from the original bytes; offsets are unchanged
|
|
365
368
|
if tree.root_node.has_error or dropped:
|
|
366
369
|
self.st["files_with_syntax_errors"] += 1
|
|
367
370
|
errs[rel] = merge(tree_spans(tree.root_node) + [list(x) for x in dropped])
|
|
@@ -608,6 +611,9 @@ class KotlinPlugin(LanguagePlugin):
|
|
|
608
611
|
self._params(params) if params is not None else {}, kf.test, self._name_line(c),
|
|
609
612
|
slots=self._fn_slots(params))
|
|
610
613
|
self._local_types(c, dc.types)
|
|
614
|
+
rt = self._ret_text(c)
|
|
615
|
+
if rt is not None:
|
|
616
|
+
self.rets[dc.id] = rt if self.rets.get(dc.id, rt) == rt else ""
|
|
611
617
|
if any(dflt for _n, dflt, _f in fparams):
|
|
612
618
|
self.fn_params[dc.id] = fparams
|
|
613
619
|
self._add_decl(dc, kind)
|
|
@@ -1970,11 +1976,28 @@ class KotlinPlugin(LanguagePlugin):
|
|
|
1970
1976
|
**({"via": write} if isinstance(write, str) else {}))
|
|
1971
1977
|
self.st["stored_property_writes" if write else "stored_property_reads"] += 1
|
|
1972
1978
|
|
|
1973
|
-
def _local_type(self, decl: Decl, name: str, kf: KFile) -> str | None:
|
|
1974
|
-
"""`val d = Cart(...)` inside the function body: the constructed type of a local
|
|
1979
|
+
def _local_type(self, decl: Decl, name: str, kf: KFile, depth: int = 0) -> str | None:
|
|
1980
|
+
"""`val d = Cart(...)` inside the function body: the constructed type of a local; also `val g: Garage<E>`,
|
|
1981
|
+
`val g = Garage<E>(..)` and `val e = shop.engine()` through the call chain's declared result (#109)."""
|
|
1975
1982
|
src = "\n".join(kf.src.decode("utf-8", "replace").split("\n")[decl.line - 1:decl.end])
|
|
1976
|
-
m = re.search(r"\b(?:val|var)\s+" + re.escape(name) +
|
|
1977
|
-
|
|
1983
|
+
m = re.search(r"\b(?:val|var)\s+" + re.escape(name) +
|
|
1984
|
+
r"\s*(?::\s*([A-Z][\w.]*(?:<[^=\n]*?>)?))?\s*=\s*([A-Z][\w.]*(?:<[^=\n(){}]*?>)?)\s*\(", src)
|
|
1985
|
+
if m:
|
|
1986
|
+
return m.group(1) or m.group(2)
|
|
1987
|
+
m = re.search(r"\b(?:val|var)\s+" + re.escape(name) + r"\s*(?::\s*([A-Z][\w.]*(?:<[^=\n]*?>)?)\s*\??)?\s*="
|
|
1988
|
+
r"\s*([^\n;]*)", src)
|
|
1989
|
+
if not m:
|
|
1990
|
+
return None
|
|
1991
|
+
if m.group(1):
|
|
1992
|
+
return m.group(1)
|
|
1993
|
+
rhs = m.group(2).strip()
|
|
1994
|
+
if depth > 2 or not re.fullmatch(r"[a-z_][\w]*(?:\([^()]*\))?(?:\s*[?!]*\.\s*\w+(?:\([^()]*\))?)*", rhs) \
|
|
1995
|
+
or rhs.split(".")[0].split("(")[0] == name:
|
|
1996
|
+
return None
|
|
1997
|
+
if "(" not in rhs and "." not in rhs:
|
|
1998
|
+
return None
|
|
1999
|
+
c, args = self._expr_type(rhs, kf, decl, depth + 1)
|
|
2000
|
+
return (c.name + (f"<{', '.join(args)}>" if args else "")) if c is not None else None
|
|
1978
2001
|
|
|
1979
2002
|
def _prop_member(self, cls: Decl, name: str, depth: int = 0) -> list[Decl]:
|
|
1980
2003
|
hit = self.prop_members.get(cls.fqn, {}).get(name)
|
|
@@ -2056,6 +2079,140 @@ class KotlinPlugin(LanguagePlugin):
|
|
|
2056
2079
|
**({"binding": how} if how else {}))
|
|
2057
2080
|
self.st[{"read": "property_reads", "write": "property_writes"}.get(m, "property_read_writes")] += 1
|
|
2058
2081
|
|
|
2082
|
+
def _ret_text(self, c) -> str | None:
|
|
2083
|
+
"""`fun f(): Garage<Engine>?` -> 'Garage<Engine>'; `fun f() = Engine(..)` -> 'Engine' (#109)."""
|
|
2084
|
+
kids = c.children
|
|
2085
|
+
seen_params = False
|
|
2086
|
+
for i, x in enumerate(kids):
|
|
2087
|
+
if x.type == "function_value_parameters":
|
|
2088
|
+
seen_params = True
|
|
2089
|
+
elif seen_params and x.type == ":" and i + 1 < len(kids):
|
|
2090
|
+
return self.t(kids[i + 1]).rstrip("?! ").strip()
|
|
2091
|
+
elif seen_params and x.type == "function_body":
|
|
2092
|
+
m = re.match(r"=\s*([A-Z]\w*(?:<[^=\n(){}]*?>)?)\s*\(", self.t(x))
|
|
2093
|
+
return m.group(1) if m else None
|
|
2094
|
+
return None
|
|
2095
|
+
|
|
2096
|
+
@staticmethod
|
|
2097
|
+
def _split_type(txt: str | None) -> tuple[str | None, list]:
|
|
2098
|
+
"""'Garage<Engine, Map<A, B>>?' -> ('Garage', ['Engine', 'Map'])."""
|
|
2099
|
+
if not txt:
|
|
2100
|
+
return None, []
|
|
2101
|
+
m = re.match(r"\s*([A-Z][\w.]*)\s*(?:<(.*)>)?", txt, re.S)
|
|
2102
|
+
if not m:
|
|
2103
|
+
return None, []
|
|
2104
|
+
args, depth, cur = [], 0, ""
|
|
2105
|
+
for ch in (m.group(2) or "") + ("," if m.group(2) else ""):
|
|
2106
|
+
if ch in "<([":
|
|
2107
|
+
depth += 1
|
|
2108
|
+
elif ch in ">)]":
|
|
2109
|
+
depth -= 1
|
|
2110
|
+
if ch == "," and depth == 0:
|
|
2111
|
+
a = re.match(r"\s*(?:out\s+|in\s+)?([A-Z][\w.]*)", cur)
|
|
2112
|
+
args.append(a.group(1).split(".")[-1] if a else "")
|
|
2113
|
+
cur = ""
|
|
2114
|
+
else:
|
|
2115
|
+
cur += ch
|
|
2116
|
+
return m.group(1).split(".")[-1], args
|
|
2117
|
+
|
|
2118
|
+
def _gparams(self, cls: Decl) -> list[str]:
|
|
2119
|
+
cache = self.__dict__.setdefault("_gp_cache", {})
|
|
2120
|
+
if cls.id not in cache:
|
|
2121
|
+
src = self._ksrc.get(cls.file, b"").decode("utf-8", "replace").split("\n")[cls.line - 1:cls.line + 2]
|
|
2122
|
+
m = re.search(r"\b(?:class|interface)\s+" + re.escape(cls.name) + r"\s*<([^>{(]*)>", "\n".join(src))
|
|
2123
|
+
cache[cls.id] = [re.split(r"[:\s]", re.sub(r"^\s*(?:out|in|reified)\s+", "", x).strip())[0]
|
|
2124
|
+
for x in m.group(1).split(",")] if m else []
|
|
2125
|
+
return cache[cls.id]
|
|
2126
|
+
|
|
2127
|
+
def _full_type(self, where: Decl | None, name: str, ty: str | None) -> str | None:
|
|
2128
|
+
"""Parameter / property types are kept without their generic arguments; read them back from the declaring
|
|
2129
|
+
span (`val garage: Garage<Engine>`, `fun f(g: Garage<Engine>)`) when the stored type is generic there."""
|
|
2130
|
+
if where is None or not ty or "<" in ty:
|
|
2131
|
+
return ty
|
|
2132
|
+
src = "\n".join(self._ksrc.get(where.file, b"").decode("utf-8", "replace").split("\n")[where.line - 1:where.end])
|
|
2133
|
+
m = re.search(r"\b" + re.escape(name) + r"\s*:\s*((?:[\w]+\.)*" + re.escape(ty) + r"\s*<[^=\n(){}]*>)", src)
|
|
2134
|
+
return m.group(1) if m else ty
|
|
2135
|
+
|
|
2136
|
+
def _as_class(self, txt: str | None, owner: Decl | None, args: list, kf: KFile) -> tuple:
|
|
2137
|
+
"""A declared type text read on a receiver: a generic parameter of `owner` becomes the receiver's argument."""
|
|
2138
|
+
name, targs = self._split_type(txt)
|
|
2139
|
+
if name is None:
|
|
2140
|
+
return None, []
|
|
2141
|
+
if owner is not None:
|
|
2142
|
+
gp = self._gparams(owner)
|
|
2143
|
+
if name in gp:
|
|
2144
|
+
i = gp.index(name)
|
|
2145
|
+
name, targs = (args[i] if i < len(args) and args[i] else None), []
|
|
2146
|
+
if name is None:
|
|
2147
|
+
return None, []
|
|
2148
|
+
c = self._class_of(name, kf)
|
|
2149
|
+
return c, targs
|
|
2150
|
+
|
|
2151
|
+
def _expr_type(self, txt: str, kf: KFile, decl: Decl | None, depth: int = 0) -> tuple:
|
|
2152
|
+
"""The project class of a receiver expression (`shop.engine()`, `Garage<E>(e).get()`, `makeShop().engine()`,
|
|
2153
|
+
`repo.items.first()`), with its generic arguments; (None, []) when a step is not known (#109)."""
|
|
2154
|
+
if depth > 3 or not txt:
|
|
2155
|
+
return None, []
|
|
2156
|
+
segs, d, cut, q = [], 0, 0, False
|
|
2157
|
+
t = txt.strip()
|
|
2158
|
+
for i, ch in enumerate(t):
|
|
2159
|
+
if ch == '"':
|
|
2160
|
+
q = not q
|
|
2161
|
+
if q:
|
|
2162
|
+
continue
|
|
2163
|
+
if ch in "([{<" and not (ch == "<" and not t[cut:i].strip()[:1].isupper()):
|
|
2164
|
+
d += 1
|
|
2165
|
+
elif ch in ")]}>" and d > 0:
|
|
2166
|
+
d -= 1
|
|
2167
|
+
elif ch == "." and d == 0:
|
|
2168
|
+
segs.append(t[cut:i])
|
|
2169
|
+
cut = i + 1
|
|
2170
|
+
segs.append(t[cut:])
|
|
2171
|
+
segs = [x.strip().rstrip("?!").strip() for x in segs]
|
|
2172
|
+
cls = self.classes.get(decl.cls) if decl is not None and decl.cls else None
|
|
2173
|
+
cur, args = None, []
|
|
2174
|
+
for i, seg in enumerate(segs):
|
|
2175
|
+
m = re.match(r"^([A-Za-z_]\w*)\s*(<[^=\n(){}]*?>)?\s*(\(|\{)?", seg)
|
|
2176
|
+
if not m:
|
|
2177
|
+
return None, []
|
|
2178
|
+
ident, ga, called = m.group(1), m.group(2), m.group(3)
|
|
2179
|
+
if i == 0:
|
|
2180
|
+
if ident == "this":
|
|
2181
|
+
cur = cls
|
|
2182
|
+
elif ident[:1].isupper():
|
|
2183
|
+
cur = self._class_of(ident, kf)
|
|
2184
|
+
args = self._split_type(ident + (ga or ""))[1]
|
|
2185
|
+
elif called:
|
|
2186
|
+
ds = [x for x in self._member(cls, ident) if x.kind != "class"] if cls is not None else []
|
|
2187
|
+
if not ds:
|
|
2188
|
+
ds = [x for x in self.by_name.get(ident, []) if x.kind == "function"]
|
|
2189
|
+
rets = {self.rets.get(x.id) for x in ds}
|
|
2190
|
+
if len(rets) != 1 or not next(iter(rets)):
|
|
2191
|
+
return None, []
|
|
2192
|
+
cur, args = self._as_class(next(iter(rets)), None, [], kf)
|
|
2193
|
+
else:
|
|
2194
|
+
ty = (self._full_type(decl, ident, decl.types.get(ident)) if decl is not None else None) or \
|
|
2195
|
+
(self._full_type(cls, ident, self._field_type(cls, ident)) if cls is not None else None) or \
|
|
2196
|
+
(self._local_type(decl, ident, kf, depth + 1) if decl is not None and decl.kind != "class" else None)
|
|
2197
|
+
cur, args = self._as_class(ty, None, [], kf)
|
|
2198
|
+
if cur is None:
|
|
2199
|
+
return None, []
|
|
2200
|
+
continue
|
|
2201
|
+
owner = cur
|
|
2202
|
+
if called:
|
|
2203
|
+
ds = [x for x in self._member(cur, ident) if x.kind != "class"]
|
|
2204
|
+
rets = {self.rets.get(x.id) for x in ds}
|
|
2205
|
+
if len(rets) != 1 or not next(iter(rets)):
|
|
2206
|
+
return None, []
|
|
2207
|
+
dcls = self.classes.get(ds[0].cls) if ds[0].cls else cur
|
|
2208
|
+
cur, args = self._as_class(next(iter(rets)), dcls, args, kf)
|
|
2209
|
+
else:
|
|
2210
|
+
ty = self._full_type(cur, ident, self._field_type(cur, ident))
|
|
2211
|
+
cur, args = self._as_class(ty, owner, args, kf)
|
|
2212
|
+
if cur is None:
|
|
2213
|
+
return None, []
|
|
2214
|
+
return cur, args
|
|
2215
|
+
|
|
2059
2216
|
def _targets(self, name: str, recv: str | None, kf: KFile, decl: Decl | None) -> list[Decl]:
|
|
2060
2217
|
cls = self.classes.get(decl.cls) if decl is not None and decl.cls else None
|
|
2061
2218
|
if recv is None or recv == "this":
|
|
@@ -2098,6 +2255,13 @@ class KotlinPlugin(LanguagePlugin):
|
|
|
2098
2255
|
tyname = decl.types.get(rname)
|
|
2099
2256
|
if tyname is None and cls is not None:
|
|
2100
2257
|
tyname = self._field_type(cls, rname)
|
|
2258
|
+
if tyname is None and ("." in recv.strip("?!") or "(" in recv or rname[:1].islower()):
|
|
2259
|
+
tc, _args = self._expr_type(recv, kf, decl) # `shop.engine().run()`, a local from a call (#109)
|
|
2260
|
+
if tc is not None:
|
|
2261
|
+
r = self._member(tc, name)
|
|
2262
|
+
if r:
|
|
2263
|
+
self._recv = tc
|
|
2264
|
+
return self._same_set(r, kf)
|
|
2101
2265
|
if tyname is None and rname[:1].isupper():
|
|
2102
2266
|
tyname = re.sub(r"\s*[({].*$", "", rname, flags=re.S) # `WishController().add(x)`: a WishController
|
|
2103
2267
|
if tyname:
|