Pular para o conteúdo principal

victorstein.dev

72/100 Dias de Golang - Criando um linter básico com golang - Buscando ifs dentro de ifs

Table of Contents

# Criando um linter básico com golang - Buscando ifs dentro de ifs

Pensei em criar um função que analisa o código em busca de ifs aninhados. Vamos usar a mesma base do projeto e só adicionar mais duas funções no arquivo de regras.

Vamos fazer o mesmo esquema com o ast.Inspect e avaliar node por node. Aqui vou fazer um switch no statement, para no caso de adicionar mais algumas verificações, mas poderia ser um if para validar se o statement é um if.

func EstruturasAninhadas(fset *token.FileSet, node *ast.File) {
	ast.Inspect(node, func(n ast.Node) bool {
		switch stmt := n.(type) {

		case *ast.IfStmt:
			count := contaIfs(stmt.Body)
			if count > 0 {
				pos := fset.Position(stmt.Pos())
				fmt.Printf("Encontrado %d if(s) aninhado(s) em %s:%d\n", count, pos.Filename, pos.Line)
			}
		}

		return true
	})
}

Quando encontramos um if, passamos o stmt.Body para uma função contaIfs. Esse stmt.Body é o bloco de código que está dentro da estrutura. Veja esse exemplo:

if x > 0 {
    fmt.Println("positivo")
    if x > 10 {
        fmt.Println("maior que 10")
    }
}

O stmt.Body desse primeiro if é:

{
    fmt.Println("positivo")
    if x > 10 {
        fmt.Println("maior que 10")
    }
}

E a função contaIfs é uma função recursiva que verifica a existência de outros ifs no bloco.

func contaIfs(block *ast.BlockStmt) int {
	nested := 0
	for _, stmt := range block.List {
		switch s := stmt.(type) {
		case *ast.IfStmt:
			nested += 1 + contaIfs(s.Body)
		case *ast.BlockStmt:
			nested += contaIfs(s)
		}
	}
	return nested
}

Agora podemos analisar nosso arquivo.go

func exemplo() {
	x := 20
	y := 30
	if x > 0 {
		if y > 0 {
			fmt.Println("Aninhado")
		}
	}
}
Encontrado 1 if(s) aninhado(s) em arquivo.go:13

Como o contaIfs é recursivo, ele vai analisar todos os ifs, não importando a profundidade ou a quantidade de níveis aninhados de ifs.