Skip to content

Commit

Permalink
add checker
Browse files Browse the repository at this point in the history
  • Loading branch information
Zekun Wang committed Jun 4, 2024
1 parent ef264da commit 7fa87eb
Showing 1 changed file with 78 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

//! Implements a pipeline that checks and gives warning on unused assignments.
//! Prerequisite: live variable annotation.
//! Side effect: the `LiveVarAnnotation` will be added to the function target annotations.
use crate::pipeline::livevar_analysis_processor::LiveVarAnnotation;
use codespan_reporting::diagnostic::Severity;
use move_binary_format::file_format::CodeOffset;
use move_model::{ast::TempIndex, model::FunctionEnv};
use move_stackless_bytecode::{
function_target::{FunctionData, FunctionTarget},
function_target_pipeline::{FunctionTargetProcessor, FunctionTargetsHolder},
stackless_bytecode::{AttrId, Bytecode},
};

pub struct UnusedAssignmentChecker {}

impl UnusedAssignmentChecker {
/// Check if the assignment to `dst` at offset after the position given by `offset` and `after`.
fn check_unused_assignment(target: &FunctionTarget, id: AttrId, offset: CodeOffset, dst: TempIndex, after: bool) {
let data = target.data;
// only check for user defined variables
if let Some(dst_name) = data.local_names.get(&dst) {
let live_var_info = target
.get_annotations()
.get::<LiveVarAnnotation>()
.expect("live variable annotation")
.get_info_at(offset as u16);
let live_var_info = if after {
&live_var_info.after
} else {
&live_var_info.before
};
let dst_name = dst_name.display(target.func_env.symbol_pool()).to_string();
if !dst_name.starts_with("_") && live_var_info.get(&dst).is_none() {
let loc = target.get_bytecode_loc(id);
target.global_env().diag(Severity::Warning, &loc, &format!("Unused assignment to {}. Consider removing or prefixing with an underscore: `_{}`", dst_name, dst_name));
}
}
}
}

impl FunctionTargetProcessor for UnusedAssignmentChecker {
fn process(
&self,
_targets: &mut FunctionTargetsHolder,
func_env: &FunctionEnv,
data: FunctionData,
_scc_opt: Option<&[FunctionEnv]>,
) -> FunctionData {
if func_env.is_native() {
return data;
}
let target = FunctionTarget::new(func_env, &data);
for (offset, bytecode) in data.code.iter().enumerate() {
let offset = offset as u16;
use Bytecode::*;
match bytecode {
Load(id, dst, _) | Assign(id, dst, _, _) => {
UnusedAssignmentChecker::check_unused_assignment(&target, *id, offset, *dst, true)
},
Call(id, dsts, _, _, _) => {
for dst in dsts {
UnusedAssignmentChecker::check_unused_assignment(&target, *id, offset, *dst, true)
}
}
_ => {},
}
}
data
}

fn name(&self) -> String {
"UnusedAssignmentChecker".to_string()
}
}

0 comments on commit 7fa87eb

Please sign in to comment.