ReachingDefinitionsAnalysis { public Set<Expression> valuesAtLocation(Name variable) { Symbol symbol = variable.symbol(); if (symbol == null) { return Collections.emptySet(); } Set<Expression> assignedExpressions = assignedExpressionByName.get(variable); if (assignedExpressions != null) { return assignedExpressions; } FunctionDef enclosingFunction = (FunctionDef) TreeUtils.firstAncestorOfKind(variable, FUNCDEF); if (enclosingFunction == null || TreeUtils.hasDescendant(enclosingFunction, t -> t.is(TRY_STMT))) { return Collections.emptySet(); } ControlFlowGraph cfg = ControlFlowGraph.build(enclosingFunction, pythonFile); if (cfg == null) { return Collections.emptySet(); } compute(cfg, enclosingFunction.localVariables()); return assignedExpressionByName.getOrDefault(variable, Collections.emptySet()); } ReachingDefinitionsAnalysis(PythonFile pythonFile); Set<Expression> valuesAtLocation(Name variable);  }
@Test public void valuesAtLocation_single_assignment() { Name x = (Name) lastExpressionInFunction("x = 42; x"); assertThat(analysis.valuesAtLocation(x)).extracting(ReachingDefinitionsAnalysisTest::getValueAsString).containsExactly("42"); }
@Test public void valuesAtLocation_multiple_assignments() { Name x = (Name) lastExpressionInFunction("x = 1; x = 2; x"); assertThat(analysis.valuesAtLocation(x)).extracting(ReachingDefinitionsAnalysisTest::getValueAsString).containsExactly("2"); }
@Test public void valuesAtLocation_branches() { Name x = (Name) lastExpressionInFunction( "if p:", " x = 1", "else:", " x = 2", "x" ); assertThat(analysis.valuesAtLocation(x)).extracting(ReachingDefinitionsAnalysisTest::getValueAsString).containsExactlyInAnyOrder("1", "2"); }
@Test public void valuesAtLocation_outside_function() { Name x = (Name) lastExpression("x = 42; x"); assertThat(analysis.valuesAtLocation(x)).isEmpty(); }
@Test public void valuesAtLocation_invalid_cfg() { Name x = (Name) lastExpressionInFunction("x = 42", "break", "x"); assertThat(analysis.valuesAtLocation(x)).isEmpty(); }
@Test public void valuesAtLocation_no_name_assignment() { Name x = (Name) lastExpressionInFunction("x.foo = 42", "x"); assertThat(analysis.valuesAtLocation(x)).isEmpty(); }
@Test public void valuesAtLocation_assignment_lhs() { Name x = (Name) lastExpressionInFunction("x = y = 42", "x"); assertThat(analysis.valuesAtLocation(x)).isEmpty(); }
@Test public void loop_with_conditions() { FileInput fileInput = parse( "def f():", " for i in range(3):", " if i > 1:", " x", " elif i==1:", " x = 2", " else:", " x = 1", " x" ); Name x = ((Name) ((ExpressionStatement) getFirstDescendant(fileInput, tree -> tree.is(EXPRESSION_STMT))).expressions().get(0)); assertThat(analysis.valuesAtLocation(x)).extracting(ReachingDefinitionsAnalysisTest::getValueAsString).containsExactlyInAnyOrder("1", "2"); x = ((Name) ((ExpressionStatement) getLastDescendant(fileInput, tree -> tree.is(EXPRESSION_STMT))).expressions().get(0)); assertThat(analysis.valuesAtLocation(x)).extracting(ReachingDefinitionsAnalysisTest::getValueAsString).containsExactlyInAnyOrder("1"); fileInput = parse( "def f():", " for i in range(3):", " x = 1", " if i > 1:", " x = 2", " x" ); x = ((Name) ((ExpressionStatement) getLastDescendant(fileInput, tree -> tree.is(EXPRESSION_STMT))).expressions().get(0)); assertThat(analysis.valuesAtLocation(x)).extracting(ReachingDefinitionsAnalysisTest::getValueAsString).containsExactlyInAnyOrder("1", "2"); }
@Test public void ignore_outer_scope() { FileInput fileInput = parse( "def f():", " x = 42", " def inner():", " x" ); Name x = ((Name) ((ExpressionStatement) getLastDescendant(fileInput, tree -> tree.is(EXPRESSION_STMT))).expressions().get(0)); assertThat(analysis.valuesAtLocation(x)).isEmpty(); }
@Test public void compound_assignments() { Name x = (Name) lastExpressionInFunction("x = 42; x += 1; x"); assertThat(analysis.valuesAtLocation(x)).isEmpty(); }
@Test public void try_stmt() { Name x = (Name) lastExpressionInFunction( "x = 1", "try:", " x = 2", "except:", " pass", "x" ); assertThat(analysis.valuesAtLocation(x)).isEmpty(); }