Esempio n. 1
0
// checkStaticDependencyCycle checks the given variable/field node for a initialization dependency
// cycle.
func (sb *scopeBuilder) checkStaticDependencyCycle(varNode compilergraph.GraphNode, currentDep *proto.ScopeReference, encountered *ordered_map.OrderedMap, path []typegraph.TGMember) bool {
	// If we've already examined this dependency, nothing else to do.
	if _, found := encountered.Get(currentDep.GetReferencedNode()); found {
		return true
	}

	encountered.Set(currentDep.GetReferencedNode(), true)

	// Lookup the dependency (which is a type or module member) in the type graph.
	memberNodeId := compilergraph.GraphNodeId(currentDep.GetReferencedNode())
	member := sb.sg.tdg.GetTypeOrMember(memberNodeId)

	// Find the associated source node.
	sourceNodeId, hasSourceNode := member.SourceNodeId()
	if !hasSourceNode {
		return true
	}

	updatedPath := append([]typegraph.TGMember(nil), path...)
	updatedPath = append(updatedPath, member.(typegraph.TGMember))

	// If we've found the variable itself, then we have a dependency cycle.
	if sourceNodeId == varNode.GetNodeId() {
		// Found a cycle.
		var chain bytes.Buffer
		chain.WriteString(member.Title())
		chain.WriteRune(' ')
		chain.WriteString(member.Name())

		for _, cMember := range updatedPath {
			chain.WriteString(" -> ")
			chain.WriteString(cMember.Title())
			chain.WriteRune(' ')
			chain.WriteString(cMember.Name())
		}

		sb.decorateWithError(varNode, "Initialization cycle found on %v %v: %s", member.Title(), member.Name(), chain.String())
		sb.Status = false
		return false
	}

	// Lookup the dependency in the SRG, so we can recursively check *its* dependencies.
	srgNode, hasSRGNode := sb.sg.srg.TryGetNode(sourceNodeId)
	if !hasSRGNode {
		return true
	}

	// Recursively lookup the static deps for the node and check them.
	nodeScope := sb.getScopeForRootNode(srgNode)
	for _, staticDep := range nodeScope.GetStaticDependencies() {
		if !sb.checkStaticDependencyCycle(varNode, staticDep, encountered, updatedPath) {
			return false
		}
	}

	return true
}