CodeQL queries 1.25
Skip to end of metadata
Go to start of metadata

Name: Useless assignment to local variable

Description: An assignment to a local variable that is not used later on, or whose value is always overwritten, has no effect.

ID: go/useless-assignment-to-local

Kind: problem

Severity: warning

Precision: very-high

Query: DeadStoreOfLocal.ql
/**
 * @name Useless assignment to local variable
 * @description An assignment to a local variable that is not used later on, or whose value is always
 *              overwritten, has no effect.
 * @kind problem
 * @problem.severity warning
 * @id go/useless-assignment-to-local
 * @tags maintainability
 *       external/cwe/cwe-563
 * @precision very-high
 */

import go

/** Holds if `nd` is an initializer that we do not want to flag for this query. */
predicate isSimple(IR::Instruction nd) {
  exists(Expr e |
    e.isConst() or
    e.(CompositeLit).getNumElement() = 0
  |
    nd = IR::evalExprInstruction(e)
  )
  or
  nd = IR::implicitInitInstruction(_)
  or
  // don't flag parameters
  nd instanceof IR::ReadArgumentInstruction
}

from IR::Instruction def, SsaSourceVariable target, IR::Instruction rhs
where
  def.writes(target, rhs) and
  not exists(SsaExplicitDefinition ssa | ssa.getInstruction() = def) and
  // exclude assignments in dead code
  def.getBasicBlock() instanceof ReachableBasicBlock and
  // exclude assignments with default values or simple expressions
  not isSimple(rhs) and
  // exclude variables that are not used at all
  exists(target.getAReference()) and
  // exclude variables with indirect references
  not target.mayHaveIndirectReferences()
select def, "This definition of " + target + " is never used."

A value is assigned to a variable, but either it is never read, or its value is always overwritten before being read. This means that the original assignment has no effect, and could indicate a logic error or incomplete code.

Recommendation

Remove assignments to variables that are immediately overwritten, or use the blank identifier _ as a placeholder for return values that are never used.

Example

In the following example, a value is assigned to a, but then immediately overwritten, a value is assigned to b and never used, and finally, the results of a call to fmt.Println are assigned to two temporary variables, which are then immediately overwritten by a call to function.

package main

import "fmt"

func main() {
	a := calculateValue()
	a = 2

	b := calculateValue()

	ignore, ignore1 := fmt.Println(a)

	ignore, ignore1, err := function()
	if err != nil {
		panic(err)
	}

	fmt.Println(a)
}

The result of calculateValue is never used, and if calculateValue is a side-effect free function, those assignments can be removed. To ignore all the return values of fmt.Println, you can simply not assign it to any variables. To ignore only certain return values, use _.

package main

import "fmt"

func main() {
	a := 2

	fmt.Println(a)

	_, _, err := function()
	if err != nil {
		panic(err)
	}

	fmt.Println(a)
}

References