5555@ Rule (key = "S1854" )
5656public class DeadStoreCheck extends PythonSubscriptionCheck {
5757
58+ public static final String QUICK_FIX_MESSAGE = "Remove the unused assignment" ;
5859 private static final String MESSAGE_TEMPLATE = "Remove this assignment to local variable '%s'; the value is never used." ;
59-
6060 private static final String SECONDARY_MESSAGE_TEMPLATE = "'%s' is reassigned here." ;
61- public static final String QUICK_FIX_MESSAGE = "Remove the unused assignment" ;
62-
6361 private boolean isTemplateVariablesAccessEnabled = false ;
6462
65- @ Override
66- public void initialize (Context context ) {
67- context .registerSyntaxNodeConsumer (Tree .Kind .FILE_INPUT , this ::checkTemplateVariablesAccessEnabled );
68- context .registerSyntaxNodeConsumer (Tree .Kind .FUNCDEF , ctx -> {
69- FunctionDef functionDef = (FunctionDef ) ctx .syntaxNode ();
70- if (TreeUtils .hasDescendant (functionDef , tree -> tree .is (Tree .Kind .TRY_STMT ))) {
71- return ;
72- }
73- ControlFlowGraph cfg = ctx .cfg (functionDef );
74- if (cfg == null ) {
75- return ;
76- }
77- LiveVariablesAnalysis lva = LiveVariablesAnalysis .analyze (cfg );
78- cfg .blocks ().forEach (block -> verifyBlock (ctx , block , lva .getLiveVariables (block ), lva .getReadSymbols (), functionDef ));
79- });
80- }
81-
82- private void checkTemplateVariablesAccessEnabled (SubscriptionContext ctx ) {
83- var importedNamesCollector = new ImportedNamesCollector ();
84- importedNamesCollector .collect (ctx .syntaxNode ());
85- isTemplateVariablesAccessEnabled = importedNamesCollector .anyMatches ("pandas" ::equals );
86- }
87-
88- /**
89- * Bottom-up approach, keeping track of which variables will be read by successor elements.
90- */
91- private void verifyBlock (SubscriptionContext ctx , CfgBlock block , LiveVariablesAnalysis .LiveVariables blockLiveVariables ,
92- Set <Symbol > readSymbols , FunctionDef functionDef ) {
93-
94- var stringLiteralValuesCollector = new StringLiteralValuesCollector ();
95- if (isTemplateVariablesAccessEnabled ) {
96- stringLiteralValuesCollector .collect (functionDef );
97- }
98- DeadStoreUtils .findUnnecessaryAssignments (block , blockLiveVariables , functionDef )
99- .stream ()
100- // symbols should have at least one read usage (otherwise will be reported by S1481)
101- .filter (unnecessaryAssignment -> readSymbols .contains (unnecessaryAssignment .symbol ))
102- .filter ((unnecessaryAssignment -> !isException (unnecessaryAssignment .symbol , unnecessaryAssignment .element , functionDef ,
103- stringLiteralValuesCollector )))
104- .forEach (unnecessaryAssignment -> raiseIssue (ctx , unnecessaryAssignment ));
105- }
106-
10763 private static void raiseIssue (SubscriptionContext ctx , DeadStoreUtils .UnnecessaryAssignment unnecessaryAssignment ) {
10864 Tree element ;
10965 if (unnecessaryAssignment .element instanceof ClassDef classDefElement ) {
@@ -247,7 +203,6 @@ private static boolean isFunctionDeclarationSymbol(Symbol symbol) {
247203 return symbol .usages ().stream ().anyMatch (u -> u .kind () == Usage .Kind .FUNC_DECLARATION );
248204 }
249205
250-
251206 private static boolean isExceptionForQuickFix (Statement tree ) {
252207 switch (tree .getKind ()) {
253208 // foo:str = bar
@@ -265,6 +220,51 @@ private static boolean isExceptionForQuickFix(Statement tree) {
265220 }
266221 }
267222
223+ @ Override
224+ public void initialize (Context context ) {
225+ context .registerSyntaxNodeConsumer (Tree .Kind .FILE_INPUT , this ::checkTemplateVariablesAccessEnabled );
226+ context .registerSyntaxNodeConsumer (Tree .Kind .FUNCDEF , ctx -> {
227+ FunctionDef functionDef = (FunctionDef ) ctx .syntaxNode ();
228+ if (TreeUtils .hasDescendant (functionDef , tree -> tree .is (Tree .Kind .TRY_STMT ))) {
229+ return ;
230+ }
231+ ControlFlowGraph cfg = ctx .cfg (functionDef );
232+ if (cfg == null ) {
233+ return ;
234+ }
235+ LiveVariablesAnalysis lva = ctx .lva (functionDef );
236+ if (lva == null ) {
237+ return ;
238+ }
239+ cfg .blocks ().forEach (block -> verifyBlock (ctx , block , lva .getLiveVariables (block ), lva .getReadSymbols (), functionDef ));
240+ });
241+ }
242+
243+ private void checkTemplateVariablesAccessEnabled (SubscriptionContext ctx ) {
244+ var importedNamesCollector = new ImportedNamesCollector ();
245+ importedNamesCollector .collect (ctx .syntaxNode ());
246+ isTemplateVariablesAccessEnabled = importedNamesCollector .anyMatches ("pandas" ::equals );
247+ }
248+
249+ /**
250+ * Bottom-up approach, keeping track of which variables will be read by successor elements.
251+ */
252+ private void verifyBlock (SubscriptionContext ctx , CfgBlock block , LiveVariablesAnalysis .LiveVariables blockLiveVariables ,
253+ Set <Symbol > readSymbols , FunctionDef functionDef ) {
254+
255+ var stringLiteralValuesCollector = new StringLiteralValuesCollector ();
256+ if (isTemplateVariablesAccessEnabled ) {
257+ stringLiteralValuesCollector .collect (functionDef );
258+ }
259+ DeadStoreUtils .findUnnecessaryAssignments (block , blockLiveVariables , functionDef )
260+ .stream ()
261+ // symbols should have at least one read usage (otherwise will be reported by S1481)
262+ .filter (unnecessaryAssignment -> readSymbols .contains (unnecessaryAssignment .symbol ))
263+ .filter ((unnecessaryAssignment -> !isException (unnecessaryAssignment .symbol , unnecessaryAssignment .element , functionDef ,
264+ stringLiteralValuesCollector )))
265+ .forEach (unnecessaryAssignment -> raiseIssue (ctx , unnecessaryAssignment ));
266+ }
267+
268268 private static class SideEffectDetector extends BaseTreeVisitor {
269269
270270 private boolean sideEffect = false ;
0 commit comments