diff --git a/pkg/expr/pruneident_walker.go b/pkg/expr/pruneident_walker.go index 2c3073f3a7d2f359eb86152fa148114380eec61a..47afc9026a4e616a04ca05c7e0e66fed3adef682 100644 --- a/pkg/expr/pruneident_walker.go +++ b/pkg/expr/pruneident_walker.go @@ -10,8 +10,13 @@ import ( ) type PruneidentWalker struct { + // idents содержит идентификаторы для удаления в виде map для оптимизации idents map[string]struct{} + + // pruned отслеживает местоположения обрезанных узлов для их идентификации pruned map[file.Location]struct{} + + // scopes хранит стек областей видимости объявленных переменных scopes []scope } @@ -25,18 +30,23 @@ func NewPruneidentWalker(idents []string) *PruneidentWalker { return w } +// scope представляет область видимости для одной переменной type scope struct { variable string } func (w *PruneidentWalker) Walk(node *ast.Node) { + // очищаем состояние для случая повторного использования w.scopes = []scope{} w.pruned = make(map[file.Location]struct{}) w.walk(node) } -//nolint:cyclop,funlen,gocyclo // Вынесение логики в функции ещё больше усложнит восприятие кода +// walk рекурсивно обходит узлы, управляя областями видимости для переменных. +// Реализация аналогична ast.Walk с добавлением обработки областей видимости. +// +//nolint:cyclop,funlen,gocyclo func (w *PruneidentWalker) walk(node *ast.Node) { if node == nil || *node == nil { return @@ -111,7 +121,10 @@ func (w *PruneidentWalker) walk(node *ast.Node) { w.visit(node) } -//nolint:cyclop,funlen,gocyclo,gocognit // Вынесение логики в функции ещё больше усложнит восприятие кода +// visit проверяет и модифицирует узлы, удаляя указанные идентификаторы +// и оптимизируя логические выражения после удаления. +// +//nolint:cyclop,funlen,gocyclo,gocognit func (w *PruneidentWalker) visit(node *ast.Node) { switch n := (*node).(type) { case *ast.IdentifierNode: @@ -137,6 +150,8 @@ func (w *PruneidentWalker) visit(node *ast.Node) { leftPruned := w.prunedNode(n.Left) rightPruned := w.prunedNode(n.Right) + // Для булевых операторов сохраняем оставшуюся ветку, + // для остальных - удаляем весь узел при любом удаленном операнде if operator.IsBoolean(n.Operator) { switch { case leftPruned && rightPruned: @@ -210,11 +225,14 @@ func (w *PruneidentWalker) visit(node *ast.Node) { } } +// mustPruned возвращает true, если идентификатор должен быть удален +// и не находится в текущей области видимости. func (w *PruneidentWalker) mustPruned(ident string) bool { _, exists := w.idents[ident] return exists && !w.scoped(ident) } +// pruneNode заменяет указанный узел на ast.NilNode и сохраняет его позицию. func (w *PruneidentWalker) pruneNode(node *ast.Node) { if node == nil || *node == nil { return @@ -225,6 +243,7 @@ func (w *PruneidentWalker) pruneNode(node *ast.Node) { w.pruned[prune.Location()] = struct{}{} } +// prunedNode проверяет, был ли узел помечен как удаленный. func (w *PruneidentWalker) prunedNode(node ast.Node) bool { if node == nil { return false @@ -236,14 +255,17 @@ func (w *PruneidentWalker) prunedNode(node ast.Node) bool { return false } +// beginScope добавляет новую область видимости для переменной. func (w *PruneidentWalker) beginScope(variable string) { w.scopes = append(w.scopes, scope{variable: variable}) } +// endScope удаляет последнюю добавленную область видимости. func (w *PruneidentWalker) endScope() { w.scopes = w.scopes[:len(w.scopes)-1] } +// scoped проверяет, существует ли переменная в текущей области видимости. func (w *PruneidentWalker) scoped(variable string) bool { for i := len(w.scopes) - 1; i >= 0; i-- { if w.scopes[i].variable == variable {