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

Code before:
}

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)
	referencedProviders := make(map[addrs.UniqueKey]struct{})

	// Loop through the vertices trying to find provider references
	// If no references are found, we will create a stub provider
	// so the provider can call functions without Configuring it
	for _, v := range g.Vertices() {
		// Check if a provider is referenced
		var addr addrs.AbsProviderConfig
		var ok bool
		switch v := v.(type) {
		case NodeValidatableResource:
			addr, ok = v.ProvidedBy().ProviderConfig.(addrs.AbsProviderConfig)
			if !ok {
				continue
			}
		case GraphNodeProviderConsumer:
			addr, ok = v.ProvidedBy().ProviderConfig.(addrs.AbsProviderConfig)
			if !ok {
				continue
			}
		case *graphNodeProxyProvider:
			addr = v.Target().ProviderAddr()
		default:
			// Since it can't be referenced, skip it
			continue
		}

		referencedProviders[addr.UniqueKey()] = struct{}{}
	}

	for _, p := range providerVerts {
		// If there are no resources on this provider, we change it
		// to a stub provider
		testProvider := p
		if proxied, ok := p.(*graphNodeProxyProvider); ok {
			testProvider = proxied.Target()

Review comment (suggestion):
1. I think this should be `*NodeValidatableResource`
2. I think NodeValidatableResource actually implements GraphNodeProviderConsumer already, so i dont actually think this case is needed unless the intent is to be super explicit. 

Code after:
			&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()

					if outside, isOutside := v.(GraphNodeReferenceOutside); isOutside {
						_, refPath = outside.ReferenceOutside()
					}

					key := ProviderFunctionReference{
						ModulePath:    refPath.String(),
						ProviderName:  pf.ProviderName,
						ProviderAlias: pf.ProviderAlias,
					}

					// We already know about this provider and can link directly
					if provider, ok := providerReferences[key]; ok {
						// Is it worth skipping if we have already connected this provider?
						g.Connect(dag.BasicEdge(v, provider))