Skip to content

fix(pipeline): a Go import can resolve to a function or method — 89 false IMPORTS edges, including os/exec → a test helper method #1934

Description

@ilyabrykau-orca

fix(pipeline): a Go import can resolve to a function or method — the name-guess fallbacks are language-blind

Status: fix open — PR #1938 (both name-guess fallbacks — Strategy 3 symbol-name and Strategy 1b sibling-file — gated on the importing file's language via cbm_import_symbol_fallback_allowed, false for Go). Measured: Go IMPORTS targets Method 85 → 0, Function 4 → 0, Folder 2206 unchanged. Generalises #1926/#1931 (import "C" was the special case).

What happens

A Go import path names a package — never a function, method, field, or a Makefile target. Strategy 1 in cbm_pipeline_resolve_import_node() resolves every correct Go import (module path → package Folder). When it misses — the normal case for stdlib/third-party — the correct result is no edge, but two fallbacks fire instead:

  • Strategy 3 (pass_pkgmap.c): takes the last path segment, cbm_gbuf_find_by_names it project-wide, filters by the permissive import_targetable_label() (admits Function/Method/…, right for Python/Java where imports can name members), returns the lexicographically smallest survivor. import "os/exec" → any project symbol named exec.
  • Strategy 1b (sibling-file resolution) admits symbol labels through the same filter, re-creating the bug one directory closer (found by field census after gating Strategy 3 alone: one surviving os/exec → a same-package exec() method).

Damage measured (~1150-file Go repo)

Go IMPORTS resolved to count
Folder (correct) 2206
Method/Function (false) 89 (3.9%)

Breakdown: os/exec → a test harness's exec method (52); "C" → a test helper's C (27, = #1926); .../wait → a rate limiter's method (6); two imports → a Function extracted from a Makefile (4). Blast radius is confined to the IMPORTS relation (calls in those files resolve via LSP first; only 1 knock-on call edge) — but IMPORTS is what get_architecture and dependency views are built from, where a Go file "depends on" a test harness or a Makefile.

Minimal reproduction

// app/run.go
package app

import "os/exec"

func Run() error { return exec.Command("true").Run() }
// helper/harness.go
package helper

type harness struct{ n int }

func (h *harness) exec(cmd string) error { return nil }
  • go.mod. Expected: os/exec is external → no IMPORTS edge. Actual: edge to helper.harness.exec.

Detection recipe

SELECT t.label, count(*) FROM edges e
JOIN nodes s ON s.id = e.source_id JOIN nodes t ON t.id = e.target_id
WHERE e.type = 'IMPORTS' AND s.file_path LIKE '%.go'
GROUP BY 1 ORDER BY 2 DESC;

For Go, any row that is not Folder/Module/File is false.

Fix (as landed)

The issue's "cheaper first cut": skip both name-guess fallbacks when the importing file is Go — the measurement found no correct Go import that needed either. Member-importing languages (Python from m import f, Java, Kotlin, Rust use crate::ops::helper) keep Strategy 3; build/markup grammars (SCSS partials, Meson subdir, Pony use) keep Strategy 1b. Reproduce-first exact-count probe (ei_edge_count_is — a floor can't catch a fabricated extra edge) with cross-package and same-package decoys.

Related: #1926/#1931, #725, #787; tracked in #1932.

Metadata

Metadata

Assignees

No one assigned

    Labels

    parsing/qualityGraph extraction bugs, false positives, missing edges

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions