cilium/cilium · info

expected function to be a method

Error message

expected function to be a method

What it means

filterRelevantMethods requires the receiver of a "With*" call to itself be a selector expression (a method call on some object, e.g. a.WithX() where a is itself a selector). If fn.X is not a *ast.SelectorExpr — for example a plain identifier like m.WithX() or a function literal — this error is returned. It encodes the tool's assumption that it only analyzes method chains.

Source

Thrown at tools/metricslint/pkg/analyzer/analyzer.go:160

		return "", "", 0, fmt.Errorf("ignoring noisy constructor name")
	}

	return object, constructor, argCount, nil
}

func filterRelevantMethods(call *ast.CallExpr) (object, method string, err error) {
	fn, ok := call.Fun.(*ast.SelectorExpr)
	if !ok {
		return "", "", fmt.Errorf("expected SelectorExpr")
	}

	if !strings.HasPrefix(fn.Sel.Name, "With") {
		return "", "", fmt.Errorf("ignoring noisy method name")
	}

	obj, ok := fn.X.(*ast.SelectorExpr)
	if !ok {
		return "", "", fmt.Errorf("expected function to be a method")
	}

	return obj.Sel.Name, fn.Sel.Name, nil
}

func run(pass *analysis.Pass) (any, error) {
	insp := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)

	// Collect objects that are initialized with a variable length slice
	// parameter as the last argument to a constructor. Map object name to
	// parameter count, and store the constructor name for later reference.
	objs := make(map[string]int)
	constructors := make(map[string]string)
	insp.Preorder([]ast.Node{
		(*ast.KeyValueExpr)(nil),
	}, func(node ast.Node) {
		obj, constructor, args, err := filterRelevantConstructors(node)
		if err != nil {

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Verify the call site: the receiver must be a method/field access chain (obj.Method.WithX(...)).
  2. Ignore if the call is a direct method call on a local variable that the tool intentionally does not analyze.
  3. Extend the analyzer to also accept *ast.Ident receivers if that pattern should be covered.
Defensive patterns

Strategy: type-guard

Validate before calling

sel, ok := call.Fun.(*ast.SelectorExpr); if ok { _, okRecv := sel.X.(*ast.SelectorExpr); if !okRecv { /* will be skipped */ } }

Type guard

func isMethodChain(call *ast.CallExpr) bool {
	sel, ok := call.Fun.(*ast.SelectorExpr)
	if !ok {
		return false
	}
	_, ok = sel.X.(*ast.SelectorExpr)
	return ok
}

Prevention

When it happens

Trigger: A call like pkgVar.WithFoo() where pkgVar is a simple identifier (not a selector), or fn.X is any non-selector expression such as a parenthesized expression or index expression.

Common situations: Calling With-style builders on local struct variables or package-level identifiers that the analyzer's chain-heuristic does not recognize.

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/a89fac8df673f39f. Report an issue: GitHub.