-
Notifications
You must be signed in to change notification settings - Fork 47
fix(python): class variables and global variables now stored in Fields instead of duplicated in functions #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…s instead of duplicated in functions Fixes #32 Previously, class variables and global variables in procedural files were incorrectly added to every function's LocalVariables. This was because all variable assignments were being tracked in a shared localVars map that was never cleared between functions. Changes: - Added isInsideFunction flag to track function scope - Added classFields and moduleFields lists to store class and module-level variables - Modified buildExprStmt to determine variable scope and store accordingly: * Inside function -> localVars (function LocalVariables) * Inside class but not function -> classFields (class Fields) * At module level -> moduleFields (default node Fields) - Clear localVars when entering/exiting functions - Populate Fields property of CodeDataStruct for classes and default node Test coverage: - Added test for class variables in Fields - Added test for global variables in procedural files - All existing tests continue to pass
WalkthroughRefactored Python AST parsing to properly track variable scope context by introducing state-tracking fields (isInsideFunction, classFields, moduleFields) and updating variable assignment handling to route variables to appropriate collections based on whether they are declared at function, class, or module scope. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
|
augment review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review completed. 1 suggestions posted.
Comment augment review to trigger a new review at any time.
|
|
||
| override fun exitClassdef(ctx: PythonParser.ClassdefContext?) { | ||
| // Add class fields to the current node | ||
| currentNode.Fields = classFields.toList() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using a single shared classFields list here will misattribute fields when classes are nested: fields collected in the outer class before entering an inner class will be assigned to the inner class and then cleared, causing them to be missing from the outer class upon its exit (also applies to other locations in the PR).
🤖 Was this useful? React with 👍 or 👎
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
chapi-ast-python/src/main/kotlin/chapi/ast/pythonast/PythonAstBaseListener.kt (1)
111-126: Potential duplicate entries inclassFieldsandmoduleFieldswhen a variable is reassigned.Unlike
localVarswhich is a map (and thus overwrites duplicates),classFieldsandmoduleFieldsare lists. If a variable is assigned multiple times at class or module level (e.g.,x = 1followed byx = 2), both assignments will be added as separateCodeFieldentries.This may or may not be the intended behavior depending on your use case. If you want unique fields by name, consider using a map or deduplicating before returning.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
chapi-ast-python/src/main/kotlin/chapi/ast/pythonast/PythonAstBaseListener.kt(3 hunks)chapi-ast-python/src/main/kotlin/chapi/ast/pythonast/PythonFullIdentListener.kt(4 hunks)chapi-ast-python/src/test/kotlin/chapi/ast/pythonast/PythonFullIdentListenerTest.kt(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: build (macos-latest)
- GitHub Check: build (ubuntu-latest)
- GitHub Check: build (windows-latest)
🔇 Additional comments (8)
chapi-ast-python/src/main/kotlin/chapi/ast/pythonast/PythonAstBaseListener.kt (1)
12-14: LGTM!The new state-tracking fields are appropriately declared for the scope classification logic. The design correctly separates concerns: the base class provides storage, while the subclass (
PythonFullIdentListener) manages the lifecycle (setting/clearing flags and collecting fields).chapi-ast-python/src/test/kotlin/chapi/ast/pythonast/PythonFullIdentListenerTest.kt (2)
376-422: LGTM! Comprehensive test for class variable scope.This test effectively validates that class-level variables (
USER_NOT_FOUND,MAX_RETRIES) are correctly stored inFieldsand not duplicated into functionLocalVariables. The assertions verify both positive cases (what should be present) and negative cases (what should not be present via size checks).
424-463: LGTM! Thorough test for module-level variable scope.This test properly validates that global/module-level variables (
DATABASE_URL,MAX_CONNECTIONS,DEBUG) are stored in the default node'sFieldsrather than being duplicated into each function'sLocalVariables. The test correctly verifies that functions only capture their own local variables.chapi-ast-python/src/main/kotlin/chapi/ast/pythonast/PythonFullIdentListener.kt (5)
76-78: Correctly assigns class-level variables to Fields.The assignment of classFields to currentNode.Fields is correct, and the subsequent clearing ensures class variables don't leak into subsequent classes. The .toList() creates a defensive copy.
123-126: LGTM: Proper cleanup sequencing.Clearing
isInsideFunctionandlocalVarsafter adding them to the function ensures proper state management and prevents variable leakage between functions.
133-133: LGTM: Passing scope context for variable classification.The additional
hasEnterClassparameter enablesbuildExprStmtto correctly route variable assignments to classFields, moduleFields, or localVars based on scope.
143-145: LGTM: Correctly assigns module-level variables to default node.The check for
moduleFields.isNotEmpty()ensures the default node is added when there are module-level variables, and the assignment correctly populates them. Note thatmoduleFieldsis not cleared after assignment, which is acceptable given the listener is typically instantiated per file.
109-112: Nested function support is a pre-existing architectural limitation, not a regression from this fix.The review concern about nested functions losing access to outer function variables is technically accurate but conflates two separate issues:
The fix (lines 109-112) is correct. Clearing
localVarson function entry fixes the actual bug: preventing class/module-level variables from being incorrectly captured as function-local variables. The recent tests (shouldIdentifyClassVariablesAsFieldsandshouldIdentifyGlobalVariablesInProceduralFiles) explicitly validate this behavior.Nested functions are a pre-existing architectural limitation. The codebase uses a single
currentFunctionvariable that is overwritten per function, and there are no test cases for nested functions anywhere in the test suite. This design limitation predates the current fix and is not introduced by it.The
localVars.clear()is necessary and correct. Nested function support would require broader architectural changes (e.g., a function stack instead of a singlecurrentFunctionvariable), which is separate from this fix.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #37 +/- ##
============================================
+ Coverage 77.33% 77.43% +0.10%
- Complexity 1036 1042 +6
============================================
Files 68 68
Lines 3935 3953 +18
Branches 672 674 +2
============================================
+ Hits 3043 3061 +18
Misses 504 504
Partials 388 388 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Improvements inspired by Augment Code Review comments from: - phodal/chapi#37 (nested scope tracking) - phodal/chapi#38 (complete syntax coverage) Added new rules: - scope_tracking_correctness: Prevent misattribution in nested scopes - complete_syntax_coverage: Handle all syntax variants in parsers - edge_case_coverage: Ensure comprehensive test coverage - test_completeness: Verify complete behavior, not just happy path - data_structure_choice: Use appropriate data structures for the problem - state_management: Proper scoping of mutable state Enhanced existing rules: - ast_parsing_correctness: Added grammar alternatives consideration - analysis_result_validation: Emphasized no data loss during parsing
Improvements inspired by Augment Code Review comments from: - phodal/chapi#37 (nested scope tracking) - phodal/chapi#38 (complete syntax coverage) Added new rules: - scope_tracking_correctness: Prevent misattribution in nested scopes - complete_syntax_coverage: Handle all syntax variants in parsers - edge_case_coverage: Ensure comprehensive test coverage - test_completeness: Verify complete behavior, not just happy path - data_structure_choice: Use appropriate data structures for the problem - state_management: Proper scoping of mutable state Enhanced existing rules: - ast_parsing_correctness: Added grammar alternatives consideration - analysis_result_validation: Emphasized no data loss during parsing
Description
Fixes #32
This PR fixes a bug where class variables and global variables in Python files were being incorrectly captured in every function's
LocalVariablesinstead of being stored in theFieldsproperty of theCodeDataStruct.Problem
Previously, when parsing Python code like this:
The class variable
USER_NOT_FOUNDwould incorrectly appear in theLocalVariablesof bothcreate_userandget_usersfunctions. The same issue occurred with global variables in procedural files.Root Cause
The issue was in the Python parser's variable tracking mechanism:
localVarsmaplocalVarswere added to that function'sLocalVariablesSolution
Modified the Python parser to properly track variable scope:
Changes to
PythonAstBaseListener.kt:isInsideFunction: Booleanflag to track function scopeclassFields: MutableList<CodeField>to store class-level variablesmoduleFields: MutableList<CodeField>to store module-level variablesbuildExprStmt()to determine variable scope and store accordingly:localVars(function'sLocalVariables)classFields(class'sFields)moduleFields(default node'sFields)Changes to
PythonFullIdentListener.kt:isInsideFunction = trueand clearlocalVarswhen entering a functionisInsideFunction = falseand clearlocalVarswhen exiting a functioncurrentNode.FieldswithclassFieldswhen exiting a classdefaultNode.FieldswithmoduleFieldsfor procedural fileshasEnterClassparameter tobuildExprStmt()Test Coverage
Added two comprehensive tests in
PythonFullIdentListenerTest.kt:shouldIdentifyClassVariablesAsFields()- Verifies class variables are in Fields, not in function LocalVariablesshouldIdentifyGlobalVariablesInProceduralFiles()- Verifies global variables in procedural files are in the default node's FieldsResults
✅ All 27 existing tests continue to pass
✅ 2 new tests added and passing
✅ Class variables now correctly appear in
CodeDataStruct.Fields✅ Global variables in procedural files now correctly appear in the default node's
Fields✅ Function local variables remain in
CodeFunction.LocalVariables✅ No duplication of variables across functions
Files Changed
chapi-ast-python/src/main/kotlin/chapi/ast/pythonast/PythonAstBaseListener.ktchapi-ast-python/src/main/kotlin/chapi/ast/pythonast/PythonFullIdentListener.ktchapi-ast-python/src/test/kotlin/chapi/ast/pythonast/PythonFullIdentListenerTest.ktPull Request opened by Augment Code with guidance from the PR author
Summary by CodeRabbit
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.