Repository: opentofu/opentofu
File: internal/tofu/transform_provider.go (Go)

Code before:
		return nil
	}

	// Locate all providerVerts in the graph
	providerVerts := providerVertexMap(g)
	// Iterate through the providers to identify their dependencies (edges). If a provider
	// lacks both references and configuration, use a NodeEvalableProvider.
providerVertsLoop:
	for _, p := range providerVerts {
		applyableProvider, ok := p.(*NodeApplyableProvider)
		// If it's not an NodeApplyableProvider or there's existing configuration, we can skip it.
		if !ok || applyableProvider.Config != nil {
			continue
		}

		edges := append(g.EdgesFrom(p), g.EdgesTo(p)...)
		for _, edge := range edges {
			// We just need to check `Source` since we're getting all edges both from
			// `EdgesFrom` and `EdgesTo`.
			if _, ok := edge.Source().(GraphNodeProviderConsumer); ok {
				continue providerVertsLoop
			}
		}

		pAddr := applyableProvider.ProviderAddr()
		log.Printf("[TRACE] ProviderFunctionTransformer: creating unconfigured node for %s", pAddr)
		unconfiguredProvider := &NodeEvalableProvider{
			&NodeAbstractProvider{
				Addr: pAddr,
			},
		}

		providerVerts[pAddr.String()] = unconfiguredProvider
		g.Replace(applyableProvider, unconfiguredProvider)
	}
	return nil
}

// ProviderFunctionTransformer is a GraphTransformer that maps nodes which reference functions to providers
// within the graph. This will error if there are any provider functions that don't map to known providers.
type ProviderFunctionTransformer struct {
	Config                  *configs.Config
	ProviderFunctionTracker ProviderFunctionMapping
}

func (t *ProviderFunctionTransformer) Transform(_ context.Context, g *Graph) error {
	var diags tfdiags.Diagnostics

	if t.Config == nil {
		// This is probably a test case, inherited from ProviderTransformer
		log.Printf("[WARN] Skipping provider function transformer due to missing config")

Review comment (suggestion):
```suggestion
		log.Printf("[TRACE] ProviderFunctionTransformer: replacing NodeApplyableProvider with NodeEvalableProvider for %s since it's missing configuration and there are no consumers of it", pAddr)
```

Code after:
		applyableProvider, ok := p.(*NodeApplyableProvider)
		// There are three conditions to skip the conversion
		// from NodeApplyableProvider to NodeEvalableProvider:
		//   1. The node is not an NodeApplyableProvider
		//   2. The provider has existing configuration
		//   3. The provider node is referenced by another node
		edges := append(g.EdgesFrom(applyableProvider), g.EdgesTo(applyableProvider)...)
		if !ok || applyableProvider.Config != nil || len(edges) > 0 {
			continue
		}

		pAddr := applyableProvider.ProviderAddr()
		log.Printf("[TRACE] ProviderFunctionTransformer: replacing NodeApplyableProvider with NodeEvalableProvider for %s since it's missing configuration and there are no consumers of it", pAddr)
		unconfiguredProvider := &NodeEvalableProvider{
			&NodeAbstractProvider{
				Addr: pAddr,
			},
		}
		g.Replace(applyableProvider, unconfiguredProvider)
	}
	return nil
}

// ProviderFunctionTransformer is a GraphTransformer that maps nodes which reference functions to providers
// within the graph. This will error if there are any provider functions that don't map to known providers.
type ProviderFunctionTransformer struct {
	Config                  *configs.Config
	ProviderFunctionTracker ProviderFunctionMapping
}

func (t *ProviderFunctionTransformer) Transform(_ context.Context, g *Graph) error {
	var diags tfdiags.Diagnostics

	if t.Config == nil {
		// This is probably a test case, inherited from ProviderTransformer
		log.Printf("[WARN] Skipping provider function transformer due to missing config")
		return nil
	}

	// Locate all providerVerts in the graph
	providerVerts := providerVertexMap(g)
	// LuT of provider reference -> provider vertex
	providerReferences := make(map[ProviderFunctionReference]dag.Vertex)

	for _, v := range g.Vertices() {
		// Provider function references
		if nr, ok := v.(GraphNodeReferencer); ok && t.Config != nil {
			for _, ref := range nr.References() {
				if pf, ok := ref.Subject.(addrs.ProviderFunction); ok {
					refPath := nr.ModulePath()