Merge changes I4bb1a17f,I05ffdf6d,I5dc201f4,If16ee798,I2e42c0d6, ... into main

* changes:
  Store mutator in mutatorContext instead of name
  Explicitly delete old logicModule entries from Context.moduleInfo
  Keep logicModule for obsolete variants
  Add Provider to transition contexts
  Cache outgoing transitions
  Use maps and slices packages
This commit is contained in:
Colin Cross 2024-04-02 17:24:37 +00:00 committed by Gerrit Code Review
commit a6074ea049
9 changed files with 153 additions and 114 deletions

View file

@ -20,6 +20,7 @@ import (
"go/doc"
"html/template"
"reflect"
"slices"
"strconv"
"strings"
"unicode"
@ -34,7 +35,7 @@ import (
func (ps *PropertyStruct) Clone() *PropertyStruct {
ret := *ps
ret.Properties = append([]Property(nil), ret.Properties...)
ret.Properties = slices.Clone(ret.Properties)
for i, prop := range ret.Properties {
ret.Properties[i] = prop.Clone()
}
@ -44,7 +45,7 @@ func (ps *PropertyStruct) Clone() *PropertyStruct {
func (p *Property) Clone() Property {
ret := *p
ret.Properties = append([]Property(nil), ret.Properties...)
ret.Properties = slices.Clone(ret.Properties)
for i, prop := range ret.Properties {
ret.Properties[i] = prop.Clone()
}

View file

@ -24,6 +24,7 @@ import (
"hash/fnv"
"io"
"io/ioutil"
"maps"
"os"
"path/filepath"
"reflect"
@ -344,12 +345,17 @@ type moduleInfo struct {
// set during each runMutator
splitModules modulesOrAliases
obsoletedByNewVariants bool
// Used by TransitionMutator implementations
transitionVariations []string
currentTransitionMutator string
requiredVariationsLock sync.Mutex
// outgoingTransitionCache stores the final variation for each dependency, indexed by the source variation
// index in transitionVariations and then by the index of the dependency in directDeps
outgoingTransitionCache [][]string
// set during PrepareBuildActions
actionDefs localBuildActions
@ -418,15 +424,7 @@ type Variation struct {
type variationMap map[string]string
func (vm variationMap) clone() variationMap {
if vm == nil {
return nil
}
newVm := make(variationMap)
for k, v := range vm {
newVm[k] = v
}
return newVm
return maps.Clone(vm)
}
// Compare this variationMap to another one. Returns true if the every entry in this map
@ -441,10 +439,7 @@ func (vm variationMap) subsetOf(other variationMap) bool {
}
func (vm variationMap) equal(other variationMap) bool {
if len(vm) != len(other) {
return false
}
return vm.subsetOf(other)
return maps.Equal(vm, other)
}
type singletonInfo struct {
@ -694,6 +689,14 @@ type IncomingTransitionContext interface {
// Config returns the config object that was passed to
// Context.PrepareBuildActions.
Config() interface{}
// Provider returns the value for a provider for the target of the dependency edge for which the
// transition is being computed. If the value is not set it returns nil and false. It panics if
// called before the appropriate mutator or GenerateBuildActions pass for the provider. The value
// returned may be a deep copy of the value originally passed to SetProvider.
//
// This method shouldn't be used directly, prefer the type-safe android.ModuleProvider instead.
Provider(provider AnyProviderKey) (any, bool)
}
type OutgoingTransitionContext interface {
@ -708,6 +711,14 @@ type OutgoingTransitionContext interface {
// Config returns the config object that was passed to
// Context.PrepareBuildActions.
Config() interface{}
// Provider returns the value for a provider for the source of the dependency edge for which the
// transition is being computed. If the value is not set it returns nil and false. It panics if
// called before the appropriate mutator or GenerateBuildActions pass for the provider. The value
// returned may be a deep copy of the value originally passed to SetProvider.
//
// This method shouldn't be used directly, prefer the type-safe android.ModuleProvider instead.
Provider(provider AnyProviderKey) (any, bool)
}
// TransitionMutator implements a top-down mechanism where a module tells its
@ -800,16 +811,11 @@ type transitionMutatorImpl struct {
// Adds each argument in items to l if it's not already there.
func addToStringListIfNotPresent(l []string, items ...string) []string {
OUTER:
for _, i := range items {
for _, existing := range l {
if existing == i {
continue OUTER
}
}
if !slices.Contains(l, i) {
l = append(l, i)
}
}
return l
}
@ -843,17 +849,23 @@ func (t *transitionMutatorImpl) topDownMutator(mctx TopDownMutatorContext) {
module.transitionVariations = addToStringListIfNotPresent(module.transitionVariations, mutatorSplits...)
sort.Strings(module.transitionVariations)
for _, srcVariation := range module.transitionVariations {
for _, dep := range module.directDeps {
finalVariation := t.transition(mctx)(mctx.Module(), srcVariation, dep.module.logicModule, dep.tag)
outgoingTransitionCache := make([][]string, len(module.transitionVariations))
for srcVariationIndex, srcVariation := range module.transitionVariations {
srcVariationTransitionCache := make([]string, len(module.directDeps))
for depIndex, dep := range module.directDeps {
finalVariation := t.transition(mctx)(mctx.moduleInfo(), srcVariation, dep.module, dep.tag)
srcVariationTransitionCache[depIndex] = finalVariation
t.addRequiredVariation(dep.module, finalVariation)
}
outgoingTransitionCache[srcVariationIndex] = srcVariationTransitionCache
}
module.outgoingTransitionCache = outgoingTransitionCache
}
type transitionContextImpl struct {
source Module
dep Module
context *Context
source *moduleInfo
dep *moduleInfo
depTag DependencyTag
config interface{}
}
@ -871,7 +883,11 @@ type outgoingTransitionContextImpl struct {
}
func (c *outgoingTransitionContextImpl) Module() Module {
return c.source
return c.source.logicModule
}
func (c *outgoingTransitionContextImpl) Provider(provider AnyProviderKey) (any, bool) {
return c.context.provider(c.source, provider.provider())
}
type incomingTransitionContextImpl struct {
@ -879,13 +895,26 @@ type incomingTransitionContextImpl struct {
}
func (c *incomingTransitionContextImpl) Module() Module {
return c.dep
return c.dep.logicModule
}
func (t *transitionMutatorImpl) transition(mctx BaseMutatorContext) Transition {
return func(source Module, sourceVariation string, dep Module, depTag DependencyTag) string {
tc := transitionContextImpl{source: source, dep: dep, depTag: depTag, config: mctx.Config()}
func (c *incomingTransitionContextImpl) Provider(provider AnyProviderKey) (any, bool) {
return c.context.provider(c.dep, provider.provider())
}
func (t *transitionMutatorImpl) transition(mctx BaseModuleContext) Transition {
return func(source *moduleInfo, sourceVariation string, dep *moduleInfo, depTag DependencyTag) string {
tc := transitionContextImpl{
context: mctx.base().context,
source: source,
dep: dep,
depTag: depTag,
config: mctx.Config(),
}
outgoingVariation := t.mutator.OutgoingTransition(&outgoingTransitionContextImpl{tc}, sourceVariation)
if mctx.Failed() {
return outgoingVariation
}
finalVariation := t.mutator.IncomingTransition(&incomingTransitionContextImpl{tc}, outgoingVariation)
return finalVariation
}
@ -897,7 +926,9 @@ func (t *transitionMutatorImpl) bottomUpMutator(mctx BottomUpMutatorContext) {
// only time interaction between multiple modules is required is during the
// computation of the variations required by a given module.
variations := mc.module.transitionVariations
outgoingTransitionCache := mc.module.outgoingTransitionCache
mc.module.transitionVariations = nil
mc.module.outgoingTransitionCache = nil
mc.module.currentTransitionMutator = ""
if len(variations) < 1 {
@ -907,9 +938,10 @@ func (t *transitionMutatorImpl) bottomUpMutator(mctx BottomUpMutatorContext) {
if len(variations) == 1 && variations[0] == "" {
// Module is not split, just apply the transition
mc.applyTransition(t.transition(mctx))
mc.context.convertDepsToVariation(mc.module, 0,
chooseDepByIndexes(mc.mutator.name, outgoingTransitionCache))
} else {
mc.createVariationsWithTransition(t.transition(mctx), variations...)
mc.createVariationsWithTransition(variations, outgoingTransitionCache)
}
}
@ -1719,12 +1751,12 @@ func newVariant(module *moduleInfo, mutatorName string, variationName string,
return variant{newVariantName, newVariations, newDependencyVariations}
}
func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
func (c *Context) createVariations(origModule *moduleInfo, mutator *mutatorInfo,
depChooser depChooser, variationNames []string, local bool) (modulesOrAliases, []error) {
if len(variationNames) == 0 {
panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
mutatorName, origModule.Name()))
mutator.name, origModule.Name()))
}
var newModules modulesOrAliases
@ -1746,18 +1778,18 @@ func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
m := *origModule
newModule := &m
newModule.directDeps = append([]depInfo(nil), origModule.directDeps...)
newModule.directDeps = slices.Clone(origModule.directDeps)
newModule.reverseDeps = nil
newModule.forwardDeps = nil
newModule.logicModule = newLogicModule
newModule.variant = newVariant(origModule, mutatorName, variationName, local)
newModule.variant = newVariant(origModule, mutator.name, variationName, local)
newModule.properties = newProperties
newModule.providers = append([]interface{}(nil), origModule.providers...)
newModule.providerInitialValueHashes = append([]uint64(nil), origModule.providerInitialValueHashes...)
newModule.providers = slices.Clone(origModule.providers)
newModule.providerInitialValueHashes = slices.Clone(origModule.providerInitialValueHashes)
newModules = append(newModules, newModule)
newErrs := c.convertDepsToVariation(newModule, depChooser)
newErrs := c.convertDepsToVariation(newModule, i, depChooser)
if len(newErrs) > 0 {
errs = append(errs, newErrs...)
}
@ -1765,7 +1797,7 @@ func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
// Mark original variant as invalid. Modules that depend on this module will still
// depend on origModule, but we'll fix it when the mutator is called on them.
origModule.logicModule = nil
origModule.obsoletedByNewVariants = true
origModule.splitModules = newModules
atomic.AddUint32(&c.depsModified, 1)
@ -1773,37 +1805,12 @@ func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
return newModules, errs
}
type depChooser func(source *moduleInfo, dep depInfo) (*moduleInfo, string)
type depChooser func(source *moduleInfo, variationIndex, depIndex int, dep depInfo) (*moduleInfo, string)
// This function is called for every dependency edge to determine which
// variation of the dependency is needed. Its inputs are the depending module,
// its variation, the dependency and the dependency tag.
type Transition func(source Module, sourceVariation string, dep Module, depTag DependencyTag) string
func chooseDepByTransition(mutatorName string, transition Transition) depChooser {
return func(source *moduleInfo, dep depInfo) (*moduleInfo, string) {
sourceVariation := source.variant.variations[mutatorName]
depLogicModule := dep.module.logicModule
if depLogicModule == nil {
// This is really a lie because the original dependency before the split
// went away when it was split. We choose an arbitrary split module
// instead and hope that whatever information the transition wants from it
// is the same as in the original one
// TODO(lberki): this can be fixed by calling transition() once and saving
// its results somewhere
depLogicModule = dep.module.splitModules[0].moduleOrAliasTarget().logicModule
}
desiredVariation := transition(source.logicModule, sourceVariation, depLogicModule, dep.tag)
for _, m := range dep.module.splitModules {
if m.moduleOrAliasVariant().variations[mutatorName] == desiredVariation {
return m.moduleOrAliasTarget(), ""
}
}
return nil, desiredVariation
}
}
type Transition func(source *moduleInfo, sourceVariation string, dep *moduleInfo, depTag DependencyTag) string
func chooseDep(candidates modulesOrAliases, mutatorName, variationName string, defaultVariationName *string) (*moduleInfo, string) {
for _, m := range candidates {
@ -1824,24 +1831,31 @@ func chooseDep(candidates modulesOrAliases, mutatorName, variationName string, d
return nil, variationName
}
func chooseDepByIndexes(mutatorName string, variations [][]string) depChooser {
return func(source *moduleInfo, variationIndex, depIndex int, dep depInfo) (*moduleInfo, string) {
desiredVariation := variations[variationIndex][depIndex]
return chooseDep(dep.module.splitModules, mutatorName, desiredVariation, nil)
}
}
func chooseDepExplicit(mutatorName string,
variationName string, defaultVariationName *string) depChooser {
return func(source *moduleInfo, dep depInfo) (*moduleInfo, string) {
return func(source *moduleInfo, variationIndex, depIndex int, dep depInfo) (*moduleInfo, string) {
return chooseDep(dep.module.splitModules, mutatorName, variationName, defaultVariationName)
}
}
func chooseDepInherit(mutatorName string, defaultVariationName *string) depChooser {
return func(source *moduleInfo, dep depInfo) (*moduleInfo, string) {
return func(source *moduleInfo, variationIndex, depIndex int, dep depInfo) (*moduleInfo, string) {
sourceVariation := source.variant.variations[mutatorName]
return chooseDep(dep.module.splitModules, mutatorName, sourceVariation, defaultVariationName)
}
}
func (c *Context) convertDepsToVariation(module *moduleInfo, depChooser depChooser) (errs []error) {
func (c *Context) convertDepsToVariation(module *moduleInfo, variationIndex int, depChooser depChooser) (errs []error) {
for i, dep := range module.directDeps {
if dep.module.logicModule == nil {
newDep, missingVariation := depChooser(module, dep)
if dep.module.obsoletedByNewVariants {
newDep, missingVariation := depChooser(module, variationIndex, i, dep)
if newDep == nil {
errs = append(errs, &BlueprintError{
Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
@ -3072,6 +3086,11 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
deps []string
}
type newVariationPair struct {
newVariations modulesOrAliases
origLogicModule Module
}
reverseDeps := make(map[*moduleInfo][]depInfo)
var rename []rename
var replace []replace
@ -3079,7 +3098,7 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
errsCh := make(chan []error)
globalStateCh := make(chan globalStateChange)
newVariationsCh := make(chan modulesOrAliases)
newVariationsCh := make(chan newVariationPair)
done := make(chan bool)
c.depsModified = 0
@ -3095,10 +3114,12 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
config: config,
module: module,
},
name: mutator.name,
mutator: mutator,
pauseCh: pause,
}
origLogicModule := module.logicModule
module.startedMutator = mutator
func() {
@ -3124,7 +3145,7 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
}
if len(mctx.newVariations) > 0 {
newVariationsCh <- mctx.newVariations
newVariationsCh <- newVariationPair{mctx.newVariations, origLogicModule}
}
if len(mctx.reverseDeps) > 0 || len(mctx.replace) > 0 || len(mctx.rename) > 0 || len(mctx.newModules) > 0 || len(mctx.ninjaFileDeps) > 0 {
@ -3140,6 +3161,8 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
return false
}
var obsoleteLogicModules []Module
// Process errs and reverseDeps in a single goroutine
go func() {
for {
@ -3155,7 +3178,10 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
newModules = append(newModules, globalStateChange.newModules...)
deps = append(deps, globalStateChange.deps...)
case newVariations := <-newVariationsCh:
for _, moduleOrAlias := range newVariations {
if newVariations.origLogicModule != newVariations.newVariations[0].module().logicModule {
obsoleteLogicModules = append(obsoleteLogicModules, newVariations.origLogicModule)
}
for _, moduleOrAlias := range newVariations.newVariations {
if m := moduleOrAlias.module(); m != nil {
newModuleInfo[m.logicModule] = m
}
@ -3187,6 +3213,10 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
return nil, errs
}
for _, obsoleteLogicModule := range obsoleteLogicModules {
delete(newModuleInfo, obsoleteLogicModule)
}
c.moduleInfo = newModuleInfo
for _, group := range c.moduleGroups {
@ -3205,12 +3235,12 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
// Fix up any remaining dependencies on modules that were split into variants
// by replacing them with the first variant
for j, dep := range module.directDeps {
if dep.module.logicModule == nil {
if dep.module.obsoletedByNewVariants {
module.directDeps[j].module = dep.module.splitModules.firstModule()
}
}
if module.createdBy != nil && module.createdBy.logicModule == nil {
if module.createdBy != nil && module.createdBy.obsoletedByNewVariants {
module.createdBy = module.createdBy.splitModules.firstModule()
}
@ -3235,7 +3265,7 @@ func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
// change inside the loop
for i := 0; i < len(group.modules); i++ {
if alias := group.modules[i].alias(); alias != nil {
if alias.target.logicModule == nil {
if alias.target.obsoletedByNewVariants {
newTarget := findAliasTarget(alias.target.variant)
if newTarget != nil {
alias.target = newTarget

View file

@ -16,6 +16,7 @@ package blueprint
import (
"fmt"
"slices"
"sort"
"strings"
@ -40,7 +41,7 @@ func verifyGlob(key globKey, pattern string, excludes []string, g pathtools.Glob
func (c *Context) glob(pattern string, excludes []string) ([]string, error) {
// Sort excludes so that two globs with the same excludes in a different order reuse the same
// key. Make a copy first to avoid modifying the caller's version.
excludes = append([]string(nil), excludes...)
excludes = slices.Clone(excludes)
sort.Strings(excludes)
key := globToKey(pattern, excludes)
@ -54,7 +55,7 @@ func (c *Context) glob(pattern string, excludes []string) ([]string, error) {
// Glob has already been done, double check it is identical
verifyGlob(key, pattern, excludes, g)
// Return a copy so that modifications don't affect the cached value.
return append([]string(nil), g.Matches...), nil
return slices.Clone(g.Matches), nil
}
// Get a globbed file list
@ -74,11 +75,11 @@ func (c *Context) glob(pattern string, excludes []string) ([]string, error) {
// Getting the list raced with another goroutine, throw away the results and use theirs
verifyGlob(key, pattern, excludes, g)
// Return a copy so that modifications don't affect the cached value.
return append([]string(nil), g.Matches...), nil
return slices.Clone(g.Matches), nil
}
// Return a copy so that modifications don't affect the cached value.
return append([]string(nil), result.Matches...), nil
return slices.Clone(result.Matches), nil
}
func (c *Context) Globs() pathtools.MultipleGlobResults {

View file

@ -360,6 +360,8 @@ type BaseModuleContext interface {
SetProvider(provider AnyProviderKey, value any)
EarlyGetMissingDependencies() []string
base() *baseModuleContext
}
type DynamicDependerModuleContext BottomUpMutatorContext
@ -751,6 +753,10 @@ func (m *baseModuleContext) ModuleFactories() map[string]ModuleFactory {
return ret
}
func (m *baseModuleContext) base() *baseModuleContext {
return m
}
func (m *moduleContext) ModuleSubDir() string {
return m.module.variant.name
}
@ -807,7 +813,7 @@ func (m *baseModuleContext) EarlyGetMissingDependencies() []string {
type mutatorContext struct {
baseModuleContext
name string
mutator *mutatorInfo
reverseDeps []reverseDep
rename []rename
replace []replace
@ -984,20 +990,20 @@ func (BaseDependencyTag) dependencyTag(DependencyTag) {
var _ DependencyTag = BaseDependencyTag{}
func (mctx *mutatorContext) MutatorName() string {
return mctx.name
return mctx.mutator.name
}
func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module {
depChooser := chooseDepInherit(mctx.name, mctx.defaultVariation)
depChooser := chooseDepInherit(mctx.mutator.name, mctx.defaultVariation)
return mctx.createVariations(variationNames, depChooser, false)
}
func (mctx *mutatorContext) createVariationsWithTransition(transition Transition, variationNames ...string) []Module {
return mctx.createVariations(variationNames, chooseDepByTransition(mctx.name, transition), false)
func (mctx *mutatorContext) createVariationsWithTransition(variationNames []string, outgoingTransitions [][]string) []Module {
return mctx.createVariations(variationNames, chooseDepByIndexes(mctx.mutator.name, outgoingTransitions), false)
}
func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module {
depChooser := chooseDepInherit(mctx.name, mctx.defaultVariation)
depChooser := chooseDepInherit(mctx.mutator.name, mctx.defaultVariation)
return mctx.createVariations(variationNames, depChooser, true)
}
@ -1013,7 +1019,7 @@ func (mctx *mutatorContext) SetVariationProvider(module Module, provider AnyProv
func (mctx *mutatorContext) createVariations(variationNames []string, depChooser depChooser, local bool) []Module {
var ret []Module
modules, errs := mctx.context.createVariations(mctx.module, mctx.name, depChooser, variationNames, local)
modules, errs := mctx.context.createVariations(mctx.module, mctx.mutator, depChooser, variationNames, local)
if len(errs) > 0 {
mctx.errs = append(mctx.errs, errs...)
}
@ -1044,7 +1050,7 @@ func (mctx *mutatorContext) AliasVariation(variationName string) {
}
for _, variant := range mctx.newVariations {
if variant.moduleOrAliasVariant().variations[mctx.name] == variationName {
if variant.moduleOrAliasVariant().variations[mctx.mutator.name] == variationName {
alias := &moduleAlias{
variant: mctx.module.variant,
target: variant.moduleOrAliasTarget(),
@ -1058,13 +1064,13 @@ func (mctx *mutatorContext) AliasVariation(variationName string) {
var foundVariations []string
for _, variant := range mctx.newVariations {
foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.name])
foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.mutator.name])
}
panic(fmt.Errorf("no %q variation in module variations %q", variationName, foundVariations))
}
func (mctx *mutatorContext) CreateAliasVariation(aliasVariationName, targetVariationName string) {
newVariant := newVariant(mctx.module, mctx.name, aliasVariationName, false)
newVariant := newVariant(mctx.module, mctx.mutator.name, aliasVariationName, false)
for _, moduleOrAlias := range mctx.module.splitModules {
if moduleOrAlias.moduleOrAliasVariant().variations.equal(newVariant.variations) {
@ -1077,7 +1083,7 @@ func (mctx *mutatorContext) CreateAliasVariation(aliasVariationName, targetVaria
}
for _, variant := range mctx.newVariations {
if variant.moduleOrAliasVariant().variations[mctx.name] == targetVariationName {
if variant.moduleOrAliasVariant().variations[mctx.mutator.name] == targetVariationName {
// Append the alias here so that it comes after any aliases created by AliasVariation.
mctx.module.splitModules = append(mctx.module.splitModules, &moduleAlias{
variant: newVariant,
@ -1089,18 +1095,14 @@ func (mctx *mutatorContext) CreateAliasVariation(aliasVariationName, targetVaria
var foundVariations []string
for _, variant := range mctx.newVariations {
foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.name])
foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.mutator.name])
}
panic(fmt.Errorf("no %q variation in module variations %q", targetVariationName, foundVariations))
}
func (mctx *mutatorContext) applyTransition(transition Transition) {
mctx.context.convertDepsToVariation(mctx.module, chooseDepByTransition(mctx.name, transition))
}
func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
mctx.context.convertDepsToVariation(mctx.module, chooseDepExplicit(
mctx.name, variationName, nil))
mctx.context.convertDepsToVariation(mctx.module, 0, chooseDepExplicit(
mctx.mutator.name, variationName, nil))
}
func (mctx *mutatorContext) SetDefaultDependencyVariation(variationName *string) {

View file

@ -16,6 +16,7 @@ package blueprint
import (
"reflect"
"slices"
"strconv"
"strings"
"testing"
@ -271,7 +272,7 @@ func Test_parseNinjaOrSimpleStrings(t *testing.T) {
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
inCopy := append([]string(nil), tt.in...)
inCopy := slices.Clone(tt.in)
scope := newLocalScope(nil, "")
scope.AddLocalVariable("abc", "abc")

View file

@ -18,6 +18,7 @@ import (
"os"
"path/filepath"
"reflect"
"slices"
"syscall"
"testing"
)
@ -233,7 +234,7 @@ func TestFs_ListDirsRecursiveFollowSymlinks(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
got, err := fs.ListDirsRecursive(filepath.Join(dir, test.name), FollowSymlinks)
checkErr(t, test.err, err)
want := append([]string(nil), test.dirs...)
want := slices.Clone(test.dirs)
for i := range want {
want[i] = filepath.Join(dir, want[i])
}
@ -279,7 +280,7 @@ func TestFs_ListDirsRecursiveDontFollowSymlinks(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
got, err := fs.ListDirsRecursive(filepath.Join(dir, test.name), DontFollowSymlinks)
checkErr(t, test.err, err)
want := append([]string(nil), test.dirs...)
want := slices.Clone(test.dirs)
for i := range want {
want[i] = filepath.Join(dir, want[i])
}

View file

@ -15,6 +15,7 @@
package proptools
import (
"slices"
"strings"
"unsafe"
)
@ -33,7 +34,7 @@ func NinjaEscapeList(slice []string) []string {
if !sliceCopied {
// If this was the first string that was modified by escaping then make a copy of the
// input slice to use as the output slice.
slice = append([]string(nil), slice...)
slice = slices.Clone(slice)
sliceCopied = true
}
slice[i] = escaped
@ -66,7 +67,7 @@ func ShellEscapeList(slice []string) []string {
if !sliceCopied {
// If this was the first string that was modified by escaping then make a copy of the
// input slice to use as the output slice.
slice = append([]string(nil), slice...)
slice = slices.Clone(slice)
sliceCopied = true
}
slice[i] = escaped
@ -83,7 +84,7 @@ func ShellEscapeListIncludingSpaces(slice []string) []string {
if !sliceCopied {
// If this was the first string that was modified by escaping then make a copy of the
// input slice to use as the output slice.
slice = append([]string(nil), slice...)
slice = slices.Clone(slice)
sliceCopied = true
}
slice[i] = escaped

View file

@ -18,6 +18,7 @@ import (
"bytes"
"os/exec"
"reflect"
"slices"
"testing"
"unsafe"
)
@ -235,7 +236,7 @@ func TestNinjaEscapeList(t *testing.T) {
t.Run(tf.name, func(t *testing.T) {
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
inCopy := append([]string(nil), tt.in...)
inCopy := slices.Clone(tt.in)
got := tf.f(tt.in)

View file

@ -17,6 +17,7 @@ package proptools
import (
"fmt"
"reflect"
"slices"
"strings"
)
@ -317,7 +318,7 @@ func extendPropertiesRecursive(dstValues []reflect.Value, srcValue reflect.Value
// of destinations to consider. Make a copy of dstValues if necessary
// to avoid modifying the backing array of an input parameter.
if !dstValuesCopied {
dstValues = append([]reflect.Value(nil), dstValues...)
dstValues = slices.Clone(dstValues)
dstValuesCopied = true
}
dstValues = append(dstValues, embeddedDstValue)