Overview
The Rename Pass is Refractor’s identifier obfuscation system. It rewrites user-defined names (classes, methods, fields, variables) to short, meaningless identifiers like_$0, _$1, _$2.
Rename runs first in the pass pipeline so other passes operate on already-obfuscated identifiers.
How It Works
The Rename Pass uses a three-phase approach (lib/src/engine/passes/rename/rename_pass.dart:16):Phase 1: Collection
Walk the entire kernel Component using
RenameVisitor to collect all renameable declarations (classes, methods, fields). Assign each a new obfuscated name from the NameGenerator.Phase 2: Application
Apply all renames using
RenameTransformer. This updates both the declarations and all references throughout the codebase in a single traversal.Why Three Phases?
This design prevents reference errors:- Collecting all renames first ensures no collisions
- Using identity-based maps (not string-based) means lookups work even after mutation
- Unbinding canonical names ensures the serialized
.dillfile has correct metadata
Configuration
Enable with Defaults
Full Configuration
What Gets Renamed
The pass renames:- Classes:
UserProfile→_$0 - Methods:
calculateTotal()→_$1() - Fields:
userName→_$2 - Top-level functions:
validateEmail()→_$3() - Getters and setters:
get fullName→get _$4
What Gets Skipped
Dart SDK Libraries
Dart SDK Libraries
All
dart:* libraries are skipped automatically. dart:core, dart:io, dart:async, etc. remain unchanged.External Dependencies
External Dependencies
Package dependencies from pub.dev are not obfuscated. Only your project code (matching
pubspec.yaml name and working directory) is in scope.Excluded Files
Excluded Files
Files matching patterns in the
refractor.exclude list are skipped:Pragma Annotations
Pragma Annotations
Declarations with
pragma annotations are preserved (lib/src/engine/passes/rename/rename_visitor.dart:80):Main Function (Optional)
Main Function (Optional)
By default, the
main function is preserved. Set preserve_main: false to rename it (not recommended).Name Generation
Obfuscated names follow the pattern_$0, _$1, _$2, … generated sequentially by the NameGenerator.
Deduplication
The pass deduplicates names within the same library (lib/src/engine/passes/rename/rename_visitor.dart:15):Private Names
Dart private names (starting with_) remain private but get obfuscated:
Before and After Examples
Example 1: Simple Class
Before:Example 2: Inheritance
Before:The pass correctly handles inheritance — overridden methods keep the same obfuscated name as their parent declaration.
Example 3: Preserved Main
Before:Implementation Details
Collection Phase
TheRenameVisitor extends RecursiveVisitor to walk the kernel AST (lib/src/engine/passes/rename/rename_visitor.dart:4):
- Uses identity-based maps (
Map<Class, String>) so lookups work after mutation - Records mappings in
SymbolTablefor the symbol map output - Checks
_hasEntryPointPragma()to skip@pragmaannotated declarations
Application Phase
TheRenameTransformer extends Transformer to mutate the AST:
- Declaration names (
class Foo→class _$0) - All references (
new Foo()→new _$0()) - Type annotations (
Foo bar→_$0 bar)
Canonical Name Cleanup
The final phase unbinds canonical names (lib/src/engine/passes/rename/rename_pass.dart:40):Canonical names are Dart kernel’s internal naming system. Unbinding them after renaming ensures the BinaryPrinter recomputes them correctly when writing the
.dill file.Symbol Map Output
Whenrefractor.symbol_map is configured, the Rename Pass records all mappings:
- Debugging: Map obfuscated crash stack traces back to original names
- Auditing: Verify which identifiers were renamed
- Reversing: Understand decompiled code during security reviews
Performance Impact
Runtime: Zero cost. Renaming only changes identifiers; the compiled code is functionally identical. Binary Size: Reduces size by 1-5%. Shorter identifiers mean less metadata in the.dill file.
Limitations
Reflection
Dart reflection (mirrors) breaks with identifier obfuscation:FFI and Native Bindings
Native code expects specific function names. Always use@pragma('vm:entry-point') for FFI:
JSON Serialization
JSON serialization libraries likejson_serializable generate code that references field names:
Next Steps
String Encryption
Hide string literals with XOR encryption
Dead Code Injection
Insert unreachable branches to confuse decompilers