<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package runtime

import (
	"fmt"
	"io"
	"path"
	"reflect"
	"sort"
	"strings"

	"k8s.io/kubernetes/pkg/conversion"
	"k8s.io/kubernetes/pkg/util"
)

type ConversionGenerator interface {
	GenerateConversionsForType(version string, reflection reflect.Type) error
	WriteConversionFunctions(w io.Writer) error
	RegisterConversionFunctions(w io.Writer, pkg string) error
	AddImport(pkg string) string
	RepackImports(exclude util.StringSet)
	WriteImports(w io.Writer) error
	OverwritePackage(pkg, overwrite string)
	AssumePrivateConversions()
}

func NewConversionGenerator(scheme *conversion.Scheme, targetPkg string) ConversionGenerator {
	g := &conversionGenerator{
		scheme:        scheme,
		targetPkg:     targetPkg,
		convertibles:  make(map[reflect.Type]reflect.Type),
		pkgOverwrites: make(map[string]string),
		imports:       make(map[string]string),
		shortImports:  make(map[string]string),
	}
	g.targetPackage(targetPkg)
	g.AddImport("reflect")
	g.AddImport("k8s.io/kubernetes/pkg/conversion")
	return g
}

var complexTypes []reflect.Kind = []reflect.Kind{reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct}

type conversionGenerator struct {
	scheme       *conversion.Scheme
	targetPkg    string
	convertibles map[reflect.Type]reflect.Type
	// If pkgOverwrites is set for a given package name, that package name
	// will be replaced while writing conversion function. If empty, package
	// name will be omitted.
	pkgOverwrites map[string]string
	// map of package names to shortname
	imports map[string]string
	// map of short names to package names
	shortImports map[string]string

	// A buffer that is used for storing lines that needs to be written.
	linesToPrint []string

	// if true, we assume conversions on the scheme are not available to us in the current package
	assumePrivateConversions bool
}

func (g *conversionGenerator) AssumePrivateConversions() {
	g.assumePrivateConversions = true
}

func (g *conversionGenerator) AddImport(pkg string) string {
	return g.addImportByPath(pkg)
}

func (g *conversionGenerator) GenerateConversionsForType(version string, reflection reflect.Type) error {
	kind := reflection.Name()
	internalObj, err := g.scheme.NewObject(g.scheme.InternalVersion, kind)
	if err != nil {
		return fmt.Errorf("cannot create an object of type %v in internal version", kind)
	}
	internalObjType := reflect.TypeOf(internalObj)
	if internalObjType.Kind() != reflect.Ptr {
		return fmt.Errorf("created object should be of type Ptr: ", internalObjType.Kind())
	}
	inErr := g.generateConversionsBetween(reflection, internalObjType.Elem())
	outErr := g.generateConversionsBetween(internalObjType.Elem(), reflection)
	if inErr != nil || outErr != nil {
		return fmt.Errorf("errors: %v, %v", inErr, outErr)
	}
	return nil
}

func (g *conversionGenerator) generateConversionsBetween(inType, outType reflect.Type) error {
	existingConversion := g.scheme.Converter().HasConversionFunc(inType, outType) && g.scheme.Converter().HasConversionFunc(outType, inType)

	// Avoid processing the same type multiple times.
	if value, found := g.convertibles[inType]; found {
		if value != outType {
			return fmt.Errorf("multiple possible convertibles for %v", inType)
		}
		return nil
	}
	if inType == outType {
		// Don't generate conversion methods for the same type.
		return nil
	}

	if inType.Kind() != outType.Kind() {
		if existingConversion {
			return nil
		}
		return fmt.Errorf("cannot convert types of different kinds: %v %v", inType, outType)
	}

	g.addImportByPath(inType.PkgPath())
	g.addImportByPath(outType.PkgPath())

	// We should be able to generate conversions both sides.
	switch inType.Kind() {
	case reflect.Map:
		inErr := g.generateConversionsForMap(inType, outType)
		outErr := g.generateConversionsForMap(outType, inType)
		if !existingConversion && (inErr != nil || outErr != nil) {
			return inErr
		}
		// We don't add it to g.convertibles - maps should be handled correctly
		// inside appropriate conversion functions.
		return nil
	case reflect.Ptr:
		inErr := g.generateConversionsBetween(inType.Elem(), outType.Elem())
		outErr := g.generateConversionsBetween(outType.Elem(), inType.Elem())
		if !existingConversion && (inErr != nil || outErr != nil) {
			return inErr
		}
		// We don't add it to g.convertibles - maps should be handled correctly
		// inside appropriate conversion functions.
		return nil
	case reflect.Slice:
		inErr := g.generateConversionsForSlice(inType, outType)
		outErr := g.generateConversionsForSlice(outType, inType)
		if !existingConversion && (inErr != nil || outErr != nil) {
			return inErr
		}
		// We don't add it to g.convertibles - slices should be handled correctly
		// inside appropriate conversion functions.
		return nil
	case reflect.Interface:
		// TODO(wojtek-t): Currently we don't support converting interfaces.
		return fmt.Errorf("interfaces are not supported")
	case reflect.Struct:
		inErr := g.generateConversionsForStruct(inType, outType)
		outErr := g.generateConversionsForStruct(outType, inType)
		if !existingConversion && (inErr != nil || outErr != nil) {
			return inErr
		}
		if !existingConversion {
			g.convertibles[inType] = outType
		}
		return nil
	default:
		// All simple types should be handled correctly with default conversion.
		return nil
	}
	panic("This should never happen")
}

func isComplexType(reflection reflect.Type) bool {
	for _, complexType := range complexTypes {
		if complexType == reflection.Kind() {
			return true
		}
	}
	return false
}

func (g *conversionGenerator) generateConversionsForMap(inType, outType reflect.Type) error {
	inKey := inType.Key()
	outKey := outType.Key()
	g.addImportByPath(inKey.PkgPath())
	g.addImportByPath(outKey.PkgPath())
	if err := g.generateConversionsBetween(inKey, outKey); err != nil {
		return err
	}
	inValue := inType.Elem()
	outValue := outType.Elem()
	g.addImportByPath(inKey.PkgPath())
	g.addImportByPath(outKey.PkgPath())
	if err := g.generateConversionsBetween(inValue, outValue); err != nil {
		return err
	}
	return nil
}

func (g *conversionGenerator) generateConversionsForSlice(inType, outType reflect.Type) error {
	inElem := inType.Elem()
	outElem := outType.Elem()
	if err := g.generateConversionsBetween(inElem, outElem); err != nil {
		return err
	}
	return nil
}

func (g *conversionGenerator) generateConversionsForStruct(inType, outType reflect.Type) error {
	for i := 0; i < inType.NumField(); i++ {
		inField := inType.Field(i)
		outField, found := outType.FieldByName(inField.Name)
		if !found {
			return fmt.Errorf("couldn't find a corresponding field %v in %v", inField.Name, outType)
		}
		if isComplexType(inField.Type) {
			if err := g.generateConversionsBetween(inField.Type, outField.Type); err != nil {<commit_msg>use package from out value<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package runtime

import (
	"fmt"
	"io"
	"path"
	"reflect"
	"sort"
	"strings"

	"k8s.io/kubernetes/pkg/conversion"
	"k8s.io/kubernetes/pkg/util"
)

type ConversionGenerator interface {
	GenerateConversionsForType(version string, reflection reflect.Type) error
	WriteConversionFunctions(w io.Writer) error
	RegisterConversionFunctions(w io.Writer, pkg string) error
	AddImport(pkg string) string
	RepackImports(exclude util.StringSet)
	WriteImports(w io.Writer) error
	OverwritePackage(pkg, overwrite string)
	AssumePrivateConversions()
}

func NewConversionGenerator(scheme *conversion.Scheme, targetPkg string) ConversionGenerator {
	g := &conversionGenerator{
		scheme:        scheme,
		targetPkg:     targetPkg,
		convertibles:  make(map[reflect.Type]reflect.Type),
		pkgOverwrites: make(map[string]string),
		imports:       make(map[string]string),
		shortImports:  make(map[string]string),
	}
	g.targetPackage(targetPkg)
	g.AddImport("reflect")
	g.AddImport("k8s.io/kubernetes/pkg/conversion")
	return g
}

var complexTypes []reflect.Kind = []reflect.Kind{reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface, reflect.Struct}

type conversionGenerator struct {
	scheme       *conversion.Scheme
	targetPkg    string
	convertibles map[reflect.Type]reflect.Type
	// If pkgOverwrites is set for a given package name, that package name
	// will be replaced while writing conversion function. If empty, package
	// name will be omitted.
	pkgOverwrites map[string]string
	// map of package names to shortname
	imports map[string]string
	// map of short names to package names
	shortImports map[string]string

	// A buffer that is used for storing lines that needs to be written.
	linesToPrint []string

	// if true, we assume conversions on the scheme are not available to us in the current package
	assumePrivateConversions bool
}

func (g *conversionGenerator) AssumePrivateConversions() {
	g.assumePrivateConversions = true
}

func (g *conversionGenerator) AddImport(pkg string) string {
	return g.addImportByPath(pkg)
}

func (g *conversionGenerator) GenerateConversionsForType(version string, reflection reflect.Type) error {
	kind := reflection.Name()
	internalObj, err := g.scheme.NewObject(g.scheme.InternalVersion, kind)
	if err != nil {
		return fmt.Errorf("cannot create an object of type %v in internal version", kind)
	}
	internalObjType := reflect.TypeOf(internalObj)
	if internalObjType.Kind() != reflect.Ptr {
		return fmt.Errorf("created object should be of type Ptr: ", internalObjType.Kind())
	}
	inErr := g.generateConversionsBetween(reflection, internalObjType.Elem())
	outErr := g.generateConversionsBetween(internalObjType.Elem(), reflection)
	if inErr != nil || outErr != nil {
		return fmt.Errorf("errors: %v, %v", inErr, outErr)
	}
	return nil
}

func (g *conversionGenerator) generateConversionsBetween(inType, outType reflect.Type) error {
	existingConversion := g.scheme.Converter().HasConversionFunc(inType, outType) && g.scheme.Converter().HasConversionFunc(outType, inType)

	// Avoid processing the same type multiple times.
	if value, found := g.convertibles[inType]; found {
		if value != outType {
			return fmt.Errorf("multiple possible convertibles for %v", inType)
		}
		return nil
	}
	if inType == outType {
		// Don't generate conversion methods for the same type.
		return nil
	}

	if inType.Kind() != outType.Kind() {
		if existingConversion {
			return nil
		}
		return fmt.Errorf("cannot convert types of different kinds: %v %v", inType, outType)
	}

	g.addImportByPath(inType.PkgPath())
	g.addImportByPath(outType.PkgPath())

	// We should be able to generate conversions both sides.
	switch inType.Kind() {
	case reflect.Map:
		inErr := g.generateConversionsForMap(inType, outType)
		outErr := g.generateConversionsForMap(outType, inType)
		if !existingConversion && (inErr != nil || outErr != nil) {
			return inErr
		}
		// We don't add it to g.convertibles - maps should be handled correctly
		// inside appropriate conversion functions.
		return nil
	case reflect.Ptr:
		inErr := g.generateConversionsBetween(inType.Elem(), outType.Elem())
		outErr := g.generateConversionsBetween(outType.Elem(), inType.Elem())
		if !existingConversion && (inErr != nil || outErr != nil) {
			return inErr
		}
		// We don't add it to g.convertibles - maps should be handled correctly
		// inside appropriate conversion functions.
		return nil
	case reflect.Slice:
		inErr := g.generateConversionsForSlice(inType, outType)
		outErr := g.generateConversionsForSlice(outType, inType)
		if !existingConversion && (inErr != nil || outErr != nil) {
			return inErr
		}
		// We don't add it to g.convertibles - slices should be handled correctly
		// inside appropriate conversion functions.
		return nil
	case reflect.Interface:
		// TODO(wojtek-t): Currently we don't support converting interfaces.
		return fmt.Errorf("interfaces are not supported")
	case reflect.Struct:
		inErr := g.generateConversionsForStruct(inType, outType)
		outErr := g.generateConversionsForStruct(outType, inType)
		if !existingConversion && (inErr != nil || outErr != nil) {
			return inErr
		}
		if !existingConversion {
			g.convertibles[inType] = outType
		}
		return nil
	default:
		// All simple types should be handled correctly with default conversion.
		return nil
	}
	panic("This should never happen")
}

func isComplexType(reflection reflect.Type) bool {
	for _, complexType := range complexTypes {
		if complexType == reflection.Kind() {
			return true
		}
	}
	return false
}

func (g *conversionGenerator) generateConversionsForMap(inType, outType reflect.Type) error {
	inKey := inType.Key()
	outKey := outType.Key()
	g.addImportByPath(inKey.PkgPath())
	g.addImportByPath(outKey.PkgPath())
	if err := g.generateConversionsBetween(inKey, outKey); err != nil {
		return err
	}
	inValue := inType.Elem()
	outValue := outType.Elem()
	g.addImportByPath(inValue.PkgPath())
	g.addImportByPath(outValue.PkgPath())
	if err := g.generateConversionsBetween(inValue, outValue); err != nil {
		return err
	}
	return nil
}

func (g *conversionGenerator) generateConversionsForSlice(inType, outType reflect.Type) error {
	inElem := inType.Elem()
	outElem := outType.Elem()
	if err := g.generateConversionsBetween(inElem, outElem); err != nil {
		return err
	}
	return nil
}

func (g *conversionGenerator) generateConversionsForStruct(inType, outType reflect.Type) error {
	for i := 0; i < inType.NumField(); i++ {
		inField := inType.Field(i)
		outField, found := outType.FieldByName(inField.Name)
		if !found {
			return fmt.Errorf("couldn't find a corresponding field %v in %v", inField.Name, outType)
		}
		if isComplexType(inField.Type) {
			if err := g.generateConversionsBetween(inField.Type, outField.Type); err != nil {
{'fraction_non_alphanumeric': 0.10462667300767715, 'fraction_numerical': 0.0016305455533663971, 'mean_word_length': 4.620465826651394, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1540003', 'n_tokens_mistral': 4733, 'n_tokens_neox': 4450, 'n_words': 1338}