From 06e5df4327d3090ce522bd09d40d29a132e7d2d4 Mon Sep 17 00:00:00 2001 From: Paul Taykalo Date: Tue, 31 Oct 2017 23:02:00 +0200 Subject: [PATCH 1/8] Base example of unused --- .gitignore | 2 + unused-via-ast/Gemfile | 2 + unused-via-ast/Gemfile.lock | 13 + unused-via-ast/XcodeProj/Unused/Unused.ast | 167 ++++++++++ .../Unused/Unused.xcodeproj/project.pbxproj | 307 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../XcodeProj/Unused/Unused/A.swift | 3 + .../XcodeProj/Unused/Unused/AppDelegate.swift | 19 ++ .../AppIcon.appiconset/Contents.json | 93 ++++++ .../XcodeProj/Unused/Unused/Info.plist | 41 +++ .../Unused/Unused/ViewController.swift | 25 ++ unused-via-ast/bin/swift-unused | 6 + unused-via-ast/lib/swift-unused.rb | 5 + unused-via-ast/swift_unused.gemspec | 17 + unused-via-ast/unused-ast.rb | 4 + 15 files changed, 711 insertions(+) create mode 100644 .gitignore create mode 100644 unused-via-ast/Gemfile create mode 100644 unused-via-ast/Gemfile.lock create mode 100644 unused-via-ast/XcodeProj/Unused/Unused.ast create mode 100644 unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.pbxproj create mode 100644 unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 unused-via-ast/XcodeProj/Unused/Unused/A.swift create mode 100644 unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift create mode 100644 unused-via-ast/XcodeProj/Unused/Unused/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 unused-via-ast/XcodeProj/Unused/Unused/Info.plist create mode 100644 unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift create mode 100755 unused-via-ast/bin/swift-unused create mode 100644 unused-via-ast/lib/swift-unused.rb create mode 100644 unused-via-ast/swift_unused.gemspec create mode 100755 unused-via-ast/unused-ast.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d4102ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/xcuserdata +unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.xcworkspace/xcuserdata diff --git a/unused-via-ast/Gemfile b/unused-via-ast/Gemfile new file mode 100644 index 0000000..3343b59 --- /dev/null +++ b/unused-via-ast/Gemfile @@ -0,0 +1,2 @@ +source 'https://rubygems.org' +gem 'objc-dependency-tree-generator', '~> 0.1.0' \ No newline at end of file diff --git a/unused-via-ast/Gemfile.lock b/unused-via-ast/Gemfile.lock new file mode 100644 index 0000000..44e748a --- /dev/null +++ b/unused-via-ast/Gemfile.lock @@ -0,0 +1,13 @@ +GEM + remote: https://rubygems.org/ + specs: + objc-dependency-tree-generator (0.1.1) + +PLATFORMS + ruby + +DEPENDENCIES + objc-dependency-tree-generator (~> 0.1.0) + +BUNDLED WITH + 1.16.0 diff --git a/unused-via-ast/XcodeProj/Unused/Unused.ast b/unused-via-ast/XcodeProj/Unused/Unused.ast new file mode 100644 index 0000000..5d92708 --- /dev/null +++ b/unused-via-ast/XcodeProj/Unused/Unused.ast @@ -0,0 +1,167 @@ +(source_file + (import_decl 'UIKit') + (class_decl "ViewController" interface type='ViewController.Type' access=internal @objc @_fixed_layout inherits: UIViewController + (func_decl "viewDidLoad()" interface type='(ViewController) -> () -> ()' access=internal override=UIKit.(file).UIViewController.viewDidLoad() @objc dynamic + (parameter_list + (parameter "self" type='ViewController' interface type='ViewController')) + (parameter_list) + (brace_stmt + (call_expr type='Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 - line:14:27] nothrow arg_labels= + (dot_syntax_call_expr type='() -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 - line:14:15] super nothrow + (declref_expr type='(UIViewController) -> () -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 - line:14:15] decl=UIKit.(file).UIViewController.viewDidLoad() function_ref=single) + (super_ref_expr type='UIViewController' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 - line:14:9])) + (tuple_expr type='()' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:26 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:26 - line:14:27])))) + (func_decl "didReceiveMemoryWarning()" interface type='(ViewController) -> () -> ()' access=internal override=UIKit.(file).UIViewController.didReceiveMemoryWarning() @objc dynamic + (parameter_list + (parameter "self" type='ViewController' interface type='ViewController')) + (parameter_list) + (brace_stmt + (call_expr type='Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 - line:19:39] nothrow arg_labels= + (dot_syntax_call_expr type='() -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 - line:19:15] super nothrow + (declref_expr type='(UIViewController) -> () -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 - line:19:15] decl=UIKit.(file).UIViewController.didReceiveMemoryWarning() function_ref=single) + (super_ref_expr type='UIViewController' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 - line:19:9])) + (tuple_expr type='()' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:38 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:38 - line:19:39])))) + (destructor_decl implicit "deinit" interface type='(ViewController) -> () -> ()' access=internal @objc + (parameter_list + (parameter "self" type='ViewController' interface type='ViewController')) + (brace_stmt)) + (constructor_decl implicit "init(nibName:bundle:)" interface type='(ViewController.Type) -> (String?, Bundle?) -> ViewController' access=internal override=UIKit.(file).UIViewController.init(nibName:bundle:) @objc designated + (parameter_list + (parameter "self" type='ViewController' interface type='ViewController')) + (parameter_list + (parameter "nibNameOrNil" apiName=nibName type='String?' interface type='String?') + (parameter "nibBundleOrNil" apiName=bundle type='Bundle?' interface type='Bundle?')) + (brace_stmt + (rebind_self_in_constructor_expr implicit type='()' + (call_expr implicit type='UIViewController' nothrow arg_labels=nibName:bundle: + (dot_syntax_call_expr implicit type='(String?, Bundle?) -> UIViewController' super nothrow + (other_constructor_ref_expr implicit type='(UIViewController) -> (String?, Bundle?) -> UIViewController' decl=UIKit.(file).UIViewController.init(nibName:bundle:)) + (super_ref_expr implicit type='UIViewController')) + (tuple_expr implicit type='(nibName: String?, bundle: Bundle?)' names=nibName,bundle + (declref_expr implicit type='String?' decl=Unused.(file).ViewController.init(nibName:bundle:).nibNameOrNil function_ref=unapplied) + (declref_expr implicit type='Bundle?' decl=Unused.(file).ViewController.init(nibName:bundle:).nibBundleOrNil function_ref=unapplied)))) + (return_stmt implicit))) + (constructor_decl implicit "init(coder:)" interface type='(ViewController.Type) -> (NSCoder) -> ViewController?' access=internal override=UIKit.(file).UIViewController.init(coder:) @objc required designated failable=Optional + (parameter_list + (parameter "self" type='ViewController' interface type='ViewController')) + (parameter_list + (parameter "aDecoder" apiName=coder type='NSCoder' interface type='NSCoder')) + (brace_stmt + (rebind_self_in_constructor_expr implicit type='()' + (call_expr implicit type='UIViewController?' nothrow arg_labels=coder: + (dot_syntax_call_expr implicit type='(NSCoder) -> UIViewController?' super nothrow + (other_constructor_ref_expr implicit type='(UIViewController) -> (NSCoder) -> UIViewController?' decl=UIKit.(file).UIViewController.init(coder:)) + (super_ref_expr implicit type='UIViewController')) + (tuple_expr implicit type='(coder: NSCoder)' names=coder + (declref_expr implicit type='NSCoder' decl=Unused.(file).ViewController.init(coder:).aDecoder function_ref=unapplied)))) + (return_stmt implicit))))) +(source_file + (import_decl 'Foundation') + (class_decl "A" interface type='A.Type' access=internal @_fixed_layout + (destructor_decl implicit "deinit" interface type='(A) -> () -> ()' access=internal @objc + (parameter_list + (parameter "self" type='A' interface type='A')) + (brace_stmt)) + (constructor_decl implicit "init()" interface type='(A.Type) -> () -> A' access=internal designated + (parameter_list + (parameter "self" type='A' interface type='A')) + (parameter_list) + (brace_stmt + (return_stmt implicit))))) +(source_file + (import_decl 'UIKit') + (class_decl "AppDelegate" interface type='AppDelegate.Type' access=internal @objc @_fixed_layout inherits: UIResponder, UIApplicationDelegate + (pattern_binding_decl + (pattern_typed type='UIWindow?' + (pattern_named type='UIWindow?' 'window') +) + (call_expr implicit type='UIWindow?' nothrow arg_labels=nilLiteral: + (constructor_ref_call_expr implicit type='(()) -> UIWindow?' nothrow + (declref_expr implicit type='(Optional.Type) -> (()) -> Optional' decl=Swift.(file).Optional.init(nilLiteral:) [with UIWindow] function_ref=single) + (type_expr implicit type='UIWindow?.Type' typerepr='<>')) + (tuple_expr implicit type='(nilLiteral: ())' names=nilLiteral + (tuple_expr implicit type='()')))) + (var_decl "window" type='UIWindow?' interface type='UIWindow?' access=internal @objc storage_kind=stored_with_trivial_accessors + (func_decl implicit 'anonname=0x7fafa08acd80' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list) + (brace_stmt + (return_stmt implicit + (load_expr implicit type='UIWindow?' + (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=read decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage + (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))))) + (func_decl implicit 'anonname=0x7fafa08b2400' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list + (parameter "value" type='UIWindow?' interface type='UIWindow?')) + (brace_stmt + (assign_expr + (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=write decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage + (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)) + (declref_expr implicit type='UIWindow?' decl=Unused.(file).AppDelegate..value@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))) + (func_decl implicit 'anonname=0x7fafa08b29c0' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list + (parameter "buffer" type='Builtin.RawPointer' interface type='Builtin.RawPointer') + (parameter "callbackStorage" type='inout Builtin.UnsafeValueBuffer' interface type='inout Builtin.UnsafeValueBuffer' mutable)))) + (func_decl implicit 'anonname=0x7fafa08acd80' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list) + (brace_stmt + (return_stmt implicit + (load_expr implicit type='UIWindow?' + (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=read decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage + (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))))) + (func_decl implicit 'anonname=0x7fafa08b2400' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list + (parameter "value" type='UIWindow?' interface type='UIWindow?')) + (brace_stmt + (assign_expr + (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=write decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage + (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)) + (declref_expr implicit type='UIWindow?' decl=Unused.(file).AppDelegate..value@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))) + (func_decl implicit 'anonname=0x7fafa08b29c0' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list + (parameter "buffer" type='Builtin.RawPointer' interface type='Builtin.RawPointer') + (parameter "callbackStorage" type='inout Builtin.UnsafeValueBuffer' interface type='inout Builtin.UnsafeValueBuffer' mutable))) + (func_decl "application(_:didFinishLaunchingWithOptions:)" interface type='(AppDelegate) -> (UIApplication, [UIApplicationLaunchOptionsKey : Any]?) -> Bool' access=internal @objc + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list + (parameter "application" type='UIApplication' interface type='UIApplication') + (parameter "launchOptions" apiName=didFinishLaunchingWithOptions type='[UIApplicationLaunchOptionsKey : Any]?' interface type='[UIApplicationLaunchOptionsKey : Any]?')) + (result + (type_ident + (component id='Bool' bind=Swift.(file).Bool))) + (brace_stmt + (return_stmt + (call_expr implicit type='Bool' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] nothrow arg_labels=_builtinBooleanLiteral: + (constructor_ref_call_expr implicit type='(Int1) -> Bool' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] nothrow + (declref_expr implicit type='(Bool.Type) -> (Int1) -> Bool' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] decl=Swift.(file).Bool.init(_builtinBooleanLiteral:) function_ref=single) + (type_expr implicit type='Bool.Type' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] typerepr='Bool')) + (tuple_expr implicit type='(_builtinBooleanLiteral: Builtin.Int1)' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] names=_builtinBooleanLiteral + (boolean_literal_expr type='Builtin.Int1' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] value=true)))))) + (destructor_decl implicit "deinit" interface type='(AppDelegate) -> () -> ()' access=internal @objc + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (brace_stmt)) + (constructor_decl implicit "init()" interface type='(AppDelegate.Type) -> () -> AppDelegate' access=internal override=UIKit.(file).UIResponder.init() @objc designated + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list) + (brace_stmt + (rebind_self_in_constructor_expr implicit type='()' + (call_expr implicit type='UIResponder' nothrow arg_labels= + (dot_syntax_call_expr implicit type='() -> UIResponder' super nothrow + (other_constructor_ref_expr implicit type='(UIResponder) -> () -> UIResponder' decl=UIKit.(file).UIResponder.init()) + (super_ref_expr implicit type='UIResponder')) + (tuple_expr implicit type='()'))) + (return_stmt implicit))))) diff --git a/unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.pbxproj b/unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.pbxproj new file mode 100644 index 0000000..19f0ce4 --- /dev/null +++ b/unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.pbxproj @@ -0,0 +1,307 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + E448E2D81FA9162F00B7D4FE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E448E2D71FA9162F00B7D4FE /* AppDelegate.swift */; }; + E448E2DA1FA9162F00B7D4FE /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E448E2D91FA9162F00B7D4FE /* ViewController.swift */; }; + E448E2DF1FA9162F00B7D4FE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E448E2DE1FA9162F00B7D4FE /* Assets.xcassets */; }; + E448E2EA1FA916D000B7D4FE /* A.swift in Sources */ = {isa = PBXBuildFile; fileRef = E448E2E91FA916D000B7D4FE /* A.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + E448E2D41FA9162F00B7D4FE /* Unused.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Unused.app; sourceTree = BUILT_PRODUCTS_DIR; }; + E448E2D71FA9162F00B7D4FE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + E448E2D91FA9162F00B7D4FE /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + E448E2DE1FA9162F00B7D4FE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + E448E2E31FA9162F00B7D4FE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E448E2E91FA916D000B7D4FE /* A.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = A.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + E448E2D11FA9162F00B7D4FE /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + E448E2CB1FA9162F00B7D4FE = { + isa = PBXGroup; + children = ( + E448E2D61FA9162F00B7D4FE /* Unused */, + E448E2D51FA9162F00B7D4FE /* Products */, + ); + sourceTree = ""; + }; + E448E2D51FA9162F00B7D4FE /* Products */ = { + isa = PBXGroup; + children = ( + E448E2D41FA9162F00B7D4FE /* Unused.app */, + ); + name = Products; + sourceTree = ""; + }; + E448E2D61FA9162F00B7D4FE /* Unused */ = { + isa = PBXGroup; + children = ( + E448E2D71FA9162F00B7D4FE /* AppDelegate.swift */, + E448E2D91FA9162F00B7D4FE /* ViewController.swift */, + E448E2DE1FA9162F00B7D4FE /* Assets.xcassets */, + E448E2E31FA9162F00B7D4FE /* Info.plist */, + E448E2E91FA916D000B7D4FE /* A.swift */, + ); + path = Unused; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + E448E2D31FA9162F00B7D4FE /* Unused */ = { + isa = PBXNativeTarget; + buildConfigurationList = E448E2E61FA9162F00B7D4FE /* Build configuration list for PBXNativeTarget "Unused" */; + buildPhases = ( + E448E2D01FA9162F00B7D4FE /* Sources */, + E448E2D11FA9162F00B7D4FE /* Frameworks */, + E448E2D21FA9162F00B7D4FE /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Unused; + productName = Unused; + productReference = E448E2D41FA9162F00B7D4FE /* Unused.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + E448E2CC1FA9162F00B7D4FE /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0910; + LastUpgradeCheck = 0910; + ORGANIZATIONNAME = DepViz; + TargetAttributes = { + E448E2D31FA9162F00B7D4FE = { + CreatedOnToolsVersion = 9.1; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = E448E2CF1FA9162F00B7D4FE /* Build configuration list for PBXProject "Unused" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = E448E2CB1FA9162F00B7D4FE; + productRefGroup = E448E2D51FA9162F00B7D4FE /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + E448E2D31FA9162F00B7D4FE /* Unused */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + E448E2D21FA9162F00B7D4FE /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E448E2DF1FA9162F00B7D4FE /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + E448E2D01FA9162F00B7D4FE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E448E2EA1FA916D000B7D4FE /* A.swift in Sources */, + E448E2DA1FA9162F00B7D4FE /* ViewController.swift in Sources */, + E448E2D81FA9162F00B7D4FE /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + E448E2E41FA9162F00B7D4FE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + "AST_DUMP_FILE=\"$(SRCROOT)/$(TARGET_NAME).ast\"", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.1; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + E448E2E51FA9162F00B7D4FE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.1; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + E448E2E71FA9162F00B7D4FE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 4X57JB7M6V; + INFOPLIST_FILE = Unused/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.DepViz.Unused; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EXEC = "/Users/paultaykalo/Projects/xcode-ast-dump/ast.py"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + E448E2E81FA9162F00B7D4FE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 4X57JB7M6V; + INFOPLIST_FILE = Unused/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.DepViz.Unused; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EXEC = "/Users/paultaykalo/Projects/xcode-ast-dump/ast.py"; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + E448E2CF1FA9162F00B7D4FE /* Build configuration list for PBXProject "Unused" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E448E2E41FA9162F00B7D4FE /* Debug */, + E448E2E51FA9162F00B7D4FE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E448E2E61FA9162F00B7D4FE /* Build configuration list for PBXNativeTarget "Unused" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E448E2E71FA9162F00B7D4FE /* Debug */, + E448E2E81FA9162F00B7D4FE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = E448E2CC1FA9162F00B7D4FE /* Project object */; +} diff --git a/unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..84ff8a7 --- /dev/null +++ b/unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/unused-via-ast/XcodeProj/Unused/Unused/A.swift b/unused-via-ast/XcodeProj/Unused/Unused/A.swift new file mode 100644 index 0000000..9df0446 --- /dev/null +++ b/unused-via-ast/XcodeProj/Unused/Unused/A.swift @@ -0,0 +1,3 @@ +import Foundation + +class A {} // unused diff --git a/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift b/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift new file mode 100644 index 0000000..209900c --- /dev/null +++ b/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift @@ -0,0 +1,19 @@ +// +// AppDelegate.swift +// Unused +// +// Created by Paul Taykalo on 10/31/17. +// Copyright © 2017 DepViz. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } +} + diff --git a/unused-via-ast/XcodeProj/Unused/Unused/Assets.xcassets/AppIcon.appiconset/Contents.json b/unused-via-ast/XcodeProj/Unused/Unused/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..1d060ed --- /dev/null +++ b/unused-via-ast/XcodeProj/Unused/Unused/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/unused-via-ast/XcodeProj/Unused/Unused/Info.plist b/unused-via-ast/XcodeProj/Unused/Unused/Info.plist new file mode 100644 index 0000000..9a1a6cb --- /dev/null +++ b/unused-via-ast/XcodeProj/Unused/Unused/Info.plist @@ -0,0 +1,41 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift b/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift new file mode 100644 index 0000000..dc6b615 --- /dev/null +++ b/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift @@ -0,0 +1,25 @@ +// +// ViewController.swift +// Unused +// +// Created by Paul Taykalo on 10/31/17. +// Copyright © 2017 DepViz. All rights reserved. +// + +import UIKit + +class ViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view, typically from a nib. + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + +} + diff --git a/unused-via-ast/bin/swift-unused b/unused-via-ast/bin/swift-unused new file mode 100755 index 0000000..4ac9ae4 --- /dev/null +++ b/unused-via-ast/bin/swift-unused @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# encoding: UTF-8 + +require 'swift-unused' + +SwiftUnused.hi diff --git a/unused-via-ast/lib/swift-unused.rb b/unused-via-ast/lib/swift-unused.rb new file mode 100644 index 0000000..009924f --- /dev/null +++ b/unused-via-ast/lib/swift-unused.rb @@ -0,0 +1,5 @@ +class SwiftUnused + def self.hi + puts "Hello world!" + end +end \ No newline at end of file diff --git a/unused-via-ast/swift_unused.gemspec b/unused-via-ast/swift_unused.gemspec new file mode 100644 index 0000000..fe11ec4 --- /dev/null +++ b/unused-via-ast/swift_unused.gemspec @@ -0,0 +1,17 @@ +Gem::Specification.new do |s| + s.name = 'swift-unused' + s.version = '0.0.1' + s.date = '2017-10-31' + s.summary = 'Gem for searching for unused code in Swift via ast file' + s.description = <<-THEEND +Tool that allows to search for unused code in swift +THEEND + s.authors = ['Paul Taykalo'] + s.email = 'tt.kilew@gmail.com' + s.files = Dir['lib/**/*.rb'] + s.homepage = + 'https://github.com/PaulTaykalo/swift-scripts' + s.license = 'MIT' + s.executables << 'swift-unused' + s.add_runtime_dependency 'objc-dependency-tree-generator', '~> 0.1.0' +end \ No newline at end of file diff --git a/unused-via-ast/unused-ast.rb b/unused-via-ast/unused-ast.rb new file mode 100755 index 0000000..7141d0a --- /dev/null +++ b/unused-via-ast/unused-ast.rb @@ -0,0 +1,4 @@ +require "swift-ast-dump/swift_ast_parser" + +tree = SwiftAST::Parser.new().parse_build_log_output(File.read("/Users/paultaykalo/Projects/rageon/ios-app2/RageOn-old.ast")) +tree.dump() From 06088bd1ae8b6f257de700ad8376e16df1b3b890 Mon Sep 17 00:00:00 2001 From: Paul Taykalo Date: Tue, 31 Oct 2017 23:30:54 +0200 Subject: [PATCH 2/8] Unused configuration --- unused-via-ast/Gemfile | 5 +- unused-via-ast/Gemfile.lock | 6 +- unused-via-ast/Rakefile | 10 + .../Unused/Unused.xcodeproj/project.pbxproj | 2 +- .../XcodeProj/Unused/Unused/A.swift | 1 + unused-via-ast/lib/swift-unused.rb | 19 +- unused-via-ast/test/fixtures/Unused.ast | 178 ++++++++++++++++++ unused-via-ast/test/swift-unused_test.rb | 22 +++ unused-via-ast/unused-ast.rb | 6 +- 9 files changed, 240 insertions(+), 9 deletions(-) create mode 100644 unused-via-ast/Rakefile create mode 100644 unused-via-ast/test/fixtures/Unused.ast create mode 100644 unused-via-ast/test/swift-unused_test.rb diff --git a/unused-via-ast/Gemfile b/unused-via-ast/Gemfile index 3343b59..a4745c7 100644 --- a/unused-via-ast/Gemfile +++ b/unused-via-ast/Gemfile @@ -1,2 +1,5 @@ source 'https://rubygems.org' -gem 'objc-dependency-tree-generator', '~> 0.1.0' \ No newline at end of file + +gem 'objc-dependency-tree-generator', '~> 0.1.1' +gem 'rake' +gem 'minitest' \ No newline at end of file diff --git a/unused-via-ast/Gemfile.lock b/unused-via-ast/Gemfile.lock index 44e748a..96061ae 100644 --- a/unused-via-ast/Gemfile.lock +++ b/unused-via-ast/Gemfile.lock @@ -1,13 +1,17 @@ GEM remote: https://rubygems.org/ specs: + minitest (5.10.3) objc-dependency-tree-generator (0.1.1) + rake (12.2.1) PLATFORMS ruby DEPENDENCIES - objc-dependency-tree-generator (~> 0.1.0) + minitest + objc-dependency-tree-generator (~> 0.1.1) + rake BUNDLED WITH 1.16.0 diff --git a/unused-via-ast/Rakefile b/unused-via-ast/Rakefile new file mode 100644 index 0000000..1add0f6 --- /dev/null +++ b/unused-via-ast/Rakefile @@ -0,0 +1,10 @@ +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.libs << 'test' + t.test_files = FileList['test/**/*_test.rb'] + t.verbose = true +end + +desc 'Run tests' +task :default => :test \ No newline at end of file diff --git a/unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.pbxproj b/unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.pbxproj index 19f0ce4..93932d9 100644 --- a/unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.pbxproj +++ b/unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.pbxproj @@ -181,7 +181,7 @@ GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", - "AST_DUMP_FILE=\"$(SRCROOT)/$(TARGET_NAME).ast\"", + "AST_DUMP_FILE=\"$(SRCROOT)/../../test/fixtures/$(TARGET_NAME).ast\"", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; diff --git a/unused-via-ast/XcodeProj/Unused/Unused/A.swift b/unused-via-ast/XcodeProj/Unused/Unused/A.swift index 9df0446..9591f6a 100644 --- a/unused-via-ast/XcodeProj/Unused/Unused/A.swift +++ b/unused-via-ast/XcodeProj/Unused/Unused/A.swift @@ -1,3 +1,4 @@ import Foundation class A {} // unused +class B {} // unused diff --git a/unused-via-ast/lib/swift-unused.rb b/unused-via-ast/lib/swift-unused.rb index 009924f..5490158 100644 --- a/unused-via-ast/lib/swift-unused.rb +++ b/unused-via-ast/lib/swift-unused.rb @@ -1,5 +1,20 @@ +require 'swift-ast-dump/swift_ast_parser' class SwiftUnused - def self.hi - puts "Hello world!" + + def initialize(ast_path) + @ast_path = ast_path + @tree = SwiftAST::Parser.new().parse_build_log_output(File.read(ast_path)) end + + def classes + result = [] + classes = @tree.find_nodes("class_decl") + classes.each { |node| + next unless classname = node.parameters.first + result += [classname] + } + + result + end + end \ No newline at end of file diff --git a/unused-via-ast/test/fixtures/Unused.ast b/unused-via-ast/test/fixtures/Unused.ast new file mode 100644 index 0000000..049054b --- /dev/null +++ b/unused-via-ast/test/fixtures/Unused.ast @@ -0,0 +1,178 @@ +(source_file + (import_decl 'Foundation') + (class_decl "A" interface type='A.Type' access=internal @_fixed_layout + (destructor_decl implicit "deinit" interface type='(A) -> () -> ()' access=internal @objc + (parameter_list + (parameter "self" type='A' interface type='A')) + (brace_stmt)) + (constructor_decl implicit "init()" interface type='(A.Type) -> () -> A' access=internal designated + (parameter_list + (parameter "self" type='A' interface type='A')) + (parameter_list) + (brace_stmt + (return_stmt implicit)))) + (class_decl "B" interface type='B.Type' access=internal @_fixed_layout + (destructor_decl implicit "deinit" interface type='(B) -> () -> ()' access=internal @objc + (parameter_list + (parameter "self" type='B' interface type='B')) + (brace_stmt)) + (constructor_decl implicit "init()" interface type='(B.Type) -> () -> B' access=internal designated + (parameter_list + (parameter "self" type='B' interface type='B')) + (parameter_list) + (brace_stmt + (return_stmt implicit))))) +(source_file + (import_decl 'UIKit') + (class_decl "ViewController" interface type='ViewController.Type' access=internal @objc @_fixed_layout inherits: UIViewController + (func_decl "viewDidLoad()" interface type='(ViewController) -> () -> ()' access=internal override=UIKit.(file).UIViewController.viewDidLoad() @objc dynamic + (parameter_list + (parameter "self" type='ViewController' interface type='ViewController')) + (parameter_list) + (brace_stmt + (call_expr type='Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 - line:14:27] nothrow arg_labels= + (dot_syntax_call_expr type='() -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 - line:14:15] super nothrow + (declref_expr type='(UIViewController) -> () -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 - line:14:15] decl=UIKit.(file).UIViewController.viewDidLoad() function_ref=single) + (super_ref_expr type='UIViewController' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 - line:14:9])) + (tuple_expr type='()' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:26 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:26 - line:14:27])))) + (func_decl "didReceiveMemoryWarning()" interface type='(ViewController) -> () -> ()' access=internal override=UIKit.(file).UIViewController.didReceiveMemoryWarning() @objc dynamic + (parameter_list + (parameter "self" type='ViewController' interface type='ViewController')) + (parameter_list) + (brace_stmt + (call_expr type='Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 - line:19:39] nothrow arg_labels= + (dot_syntax_call_expr type='() -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 - line:19:15] super nothrow + (declref_expr type='(UIViewController) -> () -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 - line:19:15] decl=UIKit.(file).UIViewController.didReceiveMemoryWarning() function_ref=single) + (super_ref_expr type='UIViewController' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 - line:19:9])) + (tuple_expr type='()' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:38 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:38 - line:19:39])))) + (destructor_decl implicit "deinit" interface type='(ViewController) -> () -> ()' access=internal @objc + (parameter_list + (parameter "self" type='ViewController' interface type='ViewController')) + (brace_stmt)) + (constructor_decl implicit "init(nibName:bundle:)" interface type='(ViewController.Type) -> (String?, Bundle?) -> ViewController' access=internal override=UIKit.(file).UIViewController.init(nibName:bundle:) @objc designated + (parameter_list + (parameter "self" type='ViewController' interface type='ViewController')) + (parameter_list + (parameter "nibNameOrNil" apiName=nibName type='String?' interface type='String?') + (parameter "nibBundleOrNil" apiName=bundle type='Bundle?' interface type='Bundle?')) + (brace_stmt + (rebind_self_in_constructor_expr implicit type='()' + (call_expr implicit type='UIViewController' nothrow arg_labels=nibName:bundle: + (dot_syntax_call_expr implicit type='(String?, Bundle?) -> UIViewController' super nothrow + (other_constructor_ref_expr implicit type='(UIViewController) -> (String?, Bundle?) -> UIViewController' decl=UIKit.(file).UIViewController.init(nibName:bundle:)) + (super_ref_expr implicit type='UIViewController')) + (tuple_expr implicit type='(nibName: String?, bundle: Bundle?)' names=nibName,bundle + (declref_expr implicit type='String?' decl=Unused.(file).ViewController.init(nibName:bundle:).nibNameOrNil function_ref=unapplied) + (declref_expr implicit type='Bundle?' decl=Unused.(file).ViewController.init(nibName:bundle:).nibBundleOrNil function_ref=unapplied)))) + (return_stmt implicit))) + (constructor_decl implicit "init(coder:)" interface type='(ViewController.Type) -> (NSCoder) -> ViewController?' access=internal override=UIKit.(file).UIViewController.init(coder:) @objc required designated failable=Optional + (parameter_list + (parameter "self" type='ViewController' interface type='ViewController')) + (parameter_list + (parameter "aDecoder" apiName=coder type='NSCoder' interface type='NSCoder')) + (brace_stmt + (rebind_self_in_constructor_expr implicit type='()' + (call_expr implicit type='UIViewController?' nothrow arg_labels=coder: + (dot_syntax_call_expr implicit type='(NSCoder) -> UIViewController?' super nothrow + (other_constructor_ref_expr implicit type='(UIViewController) -> (NSCoder) -> UIViewController?' decl=UIKit.(file).UIViewController.init(coder:)) + (super_ref_expr implicit type='UIViewController')) + (tuple_expr implicit type='(coder: NSCoder)' names=coder + (declref_expr implicit type='NSCoder' decl=Unused.(file).ViewController.init(coder:).aDecoder function_ref=unapplied)))) + (return_stmt implicit))))) +(source_file + (import_decl 'UIKit') + (class_decl "AppDelegate" interface type='AppDelegate.Type' access=internal @objc @_fixed_layout inherits: UIResponder, UIApplicationDelegate + (pattern_binding_decl + (pattern_typed type='UIWindow?' + (pattern_named type='UIWindow?' 'window') +) + (call_expr implicit type='UIWindow?' nothrow arg_labels=nilLiteral: + (constructor_ref_call_expr implicit type='(()) -> UIWindow?' nothrow + (declref_expr implicit type='(Optional.Type) -> (()) -> Optional' decl=Swift.(file).Optional.init(nilLiteral:) [with UIWindow] function_ref=single) + (type_expr implicit type='UIWindow?.Type' typerepr='<>')) + (tuple_expr implicit type='(nilLiteral: ())' names=nilLiteral + (tuple_expr implicit type='()')))) + (var_decl "window" type='UIWindow?' interface type='UIWindow?' access=internal @objc storage_kind=stored_with_trivial_accessors + (func_decl implicit 'anonname=0x7fe790220980' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list) + (brace_stmt + (return_stmt implicit + (load_expr implicit type='UIWindow?' + (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=read decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage + (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))))) + (func_decl implicit 'anonname=0x7fe790225800' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list + (parameter "value" type='UIWindow?' interface type='UIWindow?')) + (brace_stmt + (assign_expr + (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=write decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage + (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)) + (declref_expr implicit type='UIWindow?' decl=Unused.(file).AppDelegate..value@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))) + (func_decl implicit 'anonname=0x7fe790225dc0' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list + (parameter "buffer" type='Builtin.RawPointer' interface type='Builtin.RawPointer') + (parameter "callbackStorage" type='inout Builtin.UnsafeValueBuffer' interface type='inout Builtin.UnsafeValueBuffer' mutable)))) + (func_decl implicit 'anonname=0x7fe790220980' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list) + (brace_stmt + (return_stmt implicit + (load_expr implicit type='UIWindow?' + (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=read decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage + (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))))) + (func_decl implicit 'anonname=0x7fe790225800' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list + (parameter "value" type='UIWindow?' interface type='UIWindow?')) + (brace_stmt + (assign_expr + (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=write decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage + (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)) + (declref_expr implicit type='UIWindow?' decl=Unused.(file).AppDelegate..value@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))) + (func_decl implicit 'anonname=0x7fe790225dc0' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list + (parameter "buffer" type='Builtin.RawPointer' interface type='Builtin.RawPointer') + (parameter "callbackStorage" type='inout Builtin.UnsafeValueBuffer' interface type='inout Builtin.UnsafeValueBuffer' mutable))) + (func_decl "application(_:didFinishLaunchingWithOptions:)" interface type='(AppDelegate) -> (UIApplication, [UIApplicationLaunchOptionsKey : Any]?) -> Bool' access=internal @objc + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list + (parameter "application" type='UIApplication' interface type='UIApplication') + (parameter "launchOptions" apiName=didFinishLaunchingWithOptions type='[UIApplicationLaunchOptionsKey : Any]?' interface type='[UIApplicationLaunchOptionsKey : Any]?')) + (result + (type_ident + (component id='Bool' bind=Swift.(file).Bool))) + (brace_stmt + (return_stmt + (call_expr implicit type='Bool' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] nothrow arg_labels=_builtinBooleanLiteral: + (constructor_ref_call_expr implicit type='(Int1) -> Bool' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] nothrow + (declref_expr implicit type='(Bool.Type) -> (Int1) -> Bool' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] decl=Swift.(file).Bool.init(_builtinBooleanLiteral:) function_ref=single) + (type_expr implicit type='Bool.Type' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] typerepr='Bool')) + (tuple_expr implicit type='(_builtinBooleanLiteral: Builtin.Int1)' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] names=_builtinBooleanLiteral + (boolean_literal_expr type='Builtin.Int1' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] value=true)))))) + (destructor_decl implicit "deinit" interface type='(AppDelegate) -> () -> ()' access=internal @objc + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (brace_stmt)) + (constructor_decl implicit "init()" interface type='(AppDelegate.Type) -> () -> AppDelegate' access=internal override=UIKit.(file).UIResponder.init() @objc designated + (parameter_list + (parameter "self" type='AppDelegate' interface type='AppDelegate')) + (parameter_list) + (brace_stmt + (rebind_self_in_constructor_expr implicit type='()' + (call_expr implicit type='UIResponder' nothrow arg_labels= + (dot_syntax_call_expr implicit type='() -> UIResponder' super nothrow + (other_constructor_ref_expr implicit type='(UIResponder) -> () -> UIResponder' decl=UIKit.(file).UIResponder.init()) + (super_ref_expr implicit type='UIResponder')) + (tuple_expr implicit type='()'))) + (return_stmt implicit))))) diff --git a/unused-via-ast/test/swift-unused_test.rb b/unused-via-ast/test/swift-unused_test.rb new file mode 100644 index 0000000..f5391a7 --- /dev/null +++ b/unused-via-ast/test/swift-unused_test.rb @@ -0,0 +1,22 @@ +require 'minitest/autorun' +require 'swift-unused' + +class SwiftUnusedTest < Minitest::Test + def setup + @unused = create_sut + end + + def test_initial_state + assert(!@unused.nil?, "Should be able to create instance of unused") + end + + def test_unused_classes + assert_includes(@unused.classes, 'A') + assert_includes(@unused.classes, 'B') + end + + def create_sut + SwiftUnused.new("./test/fixtures/Unused.ast") + end + +end diff --git a/unused-via-ast/unused-ast.rb b/unused-via-ast/unused-ast.rb index 7141d0a..f2042ae 100755 --- a/unused-via-ast/unused-ast.rb +++ b/unused-via-ast/unused-ast.rb @@ -1,4 +1,2 @@ -require "swift-ast-dump/swift_ast_parser" - -tree = SwiftAST::Parser.new().parse_build_log_output(File.read("/Users/paultaykalo/Projects/rageon/ios-app2/RageOn-old.ast")) -tree.dump() +#!/bin/bash +ruby -Ilib ./bin/swift-unused "$@" From 6ab26a9b3610eda75caaf9dba19f382648d49ec9 Mon Sep 17 00:00:00 2001 From: Paul Taykalo Date: Tue, 31 Oct 2017 23:41:12 +0200 Subject: [PATCH 3/8] Showing unused classes by inheritance --- .../XcodeProj/Unused/Unused/A.swift | 4 ++ unused-via-ast/lib/swift-unused.rb | 19 ++++++++- unused-via-ast/test/fixtures/Unused.ast | 40 ++++++++++++++++--- unused-via-ast/test/swift-unused_test.rb | 5 +++ 4 files changed, 61 insertions(+), 7 deletions(-) diff --git a/unused-via-ast/XcodeProj/Unused/Unused/A.swift b/unused-via-ast/XcodeProj/Unused/Unused/A.swift index 9591f6a..5ab65d9 100644 --- a/unused-via-ast/XcodeProj/Unused/Unused/A.swift +++ b/unused-via-ast/XcodeProj/Unused/Unused/A.swift @@ -2,3 +2,7 @@ import Foundation class A {} // unused class B {} // unused + + +class C {} // used by inheritance +class D: C {} // unused diff --git a/unused-via-ast/lib/swift-unused.rb b/unused-via-ast/lib/swift-unused.rb index 5490158..0b6df97 100644 --- a/unused-via-ast/lib/swift-unused.rb +++ b/unused-via-ast/lib/swift-unused.rb @@ -4,17 +4,34 @@ class SwiftUnused def initialize(ast_path) @ast_path = ast_path @tree = SwiftAST::Parser.new().parse_build_log_output(File.read(ast_path)) + @used_classes = Hash.new end def classes result = [] classes = @tree.find_nodes("class_decl") + classes.each { |classnode| + register_inheritance(classnode) + } classes.each { |node| next unless classname = node.parameters.first + next unless @used_classes[classname].nil? #// skip already used classes result += [classname] } - result end + def register_inheritance(node) + inheritance = node.parameters.drop_while { |el| el != "inherits:" } + inheritance = inheritance.drop(1) + inheritance.each { |inh| + inh_name = inh.chomp(",") + add_usage(inh_name, "inheritance") + } + end + + def add_usage(inh_name, type) + @used_classes[inh_name] = type + end + end \ No newline at end of file diff --git a/unused-via-ast/test/fixtures/Unused.ast b/unused-via-ast/test/fixtures/Unused.ast index 049054b..0ef7e30 100644 --- a/unused-via-ast/test/fixtures/Unused.ast +++ b/unused-via-ast/test/fixtures/Unused.ast @@ -21,6 +21,34 @@ (parameter "self" type='B' interface type='B')) (parameter_list) (brace_stmt + (return_stmt implicit)))) + (class_decl "C" interface type='C.Type' access=internal @_fixed_layout + (destructor_decl implicit "deinit" interface type='(C) -> () -> ()' access=internal @objc + (parameter_list + (parameter "self" type='C' interface type='C')) + (brace_stmt)) + (constructor_decl implicit "init()" interface type='(C.Type) -> () -> C' access=internal designated + (parameter_list + (parameter "self" type='C' interface type='C')) + (parameter_list) + (brace_stmt + (return_stmt implicit)))) + (class_decl "D" interface type='D.Type' access=internal @_fixed_layout inherits: C + (destructor_decl implicit "deinit" interface type='(D) -> () -> ()' access=internal @objc + (parameter_list + (parameter "self" type='D' interface type='D')) + (brace_stmt)) + (constructor_decl implicit "init()" interface type='(D.Type) -> () -> D' access=internal override=Unused.(file).C.init()@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/A.swift:7:7 designated + (parameter_list + (parameter "self" type='D' interface type='D')) + (parameter_list) + (brace_stmt + (rebind_self_in_constructor_expr implicit type='()' + (call_expr implicit type='C' nothrow arg_labels= + (dot_syntax_call_expr implicit type='() -> C' super nothrow + (other_constructor_ref_expr implicit type='(C) -> () -> C' decl=Unused.(file).C.init()@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/A.swift:7:7) + (super_ref_expr implicit type='C')) + (tuple_expr implicit type='()'))) (return_stmt implicit))))) (source_file (import_decl 'UIKit') @@ -93,7 +121,7 @@ (tuple_expr implicit type='(nilLiteral: ())' names=nilLiteral (tuple_expr implicit type='()')))) (var_decl "window" type='UIWindow?' interface type='UIWindow?' access=internal @objc storage_kind=stored_with_trivial_accessors - (func_decl implicit 'anonname=0x7fe790220980' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window + (func_decl implicit 'anonname=0x7fbde9274980' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list) @@ -102,7 +130,7 @@ (load_expr implicit type='UIWindow?' (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=read decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))))) - (func_decl implicit 'anonname=0x7fe790225800' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window + (func_decl implicit 'anonname=0x7fbde927a800' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list @@ -112,13 +140,13 @@ (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=write decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)) (declref_expr implicit type='UIWindow?' decl=Unused.(file).AppDelegate..value@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))) - (func_decl implicit 'anonname=0x7fe790225dc0' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window + (func_decl implicit 'anonname=0x7fbde927adc0' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list (parameter "buffer" type='Builtin.RawPointer' interface type='Builtin.RawPointer') (parameter "callbackStorage" type='inout Builtin.UnsafeValueBuffer' interface type='inout Builtin.UnsafeValueBuffer' mutable)))) - (func_decl implicit 'anonname=0x7fe790220980' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window + (func_decl implicit 'anonname=0x7fbde9274980' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list) @@ -127,7 +155,7 @@ (load_expr implicit type='UIWindow?' (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=read decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))))) - (func_decl implicit 'anonname=0x7fe790225800' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window + (func_decl implicit 'anonname=0x7fbde927a800' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list @@ -137,7 +165,7 @@ (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=write decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)) (declref_expr implicit type='UIWindow?' decl=Unused.(file).AppDelegate..value@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))) - (func_decl implicit 'anonname=0x7fe790225dc0' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window + (func_decl implicit 'anonname=0x7fbde927adc0' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list diff --git a/unused-via-ast/test/swift-unused_test.rb b/unused-via-ast/test/swift-unused_test.rb index f5391a7..de78f74 100644 --- a/unused-via-ast/test/swift-unused_test.rb +++ b/unused-via-ast/test/swift-unused_test.rb @@ -15,6 +15,11 @@ def test_unused_classes assert_includes(@unused.classes, 'B') end + def test_used_by_inheritance + assert_includes(@unused.classes, 'D') + refute_includes(@unused.classes, 'C') + end + def create_sut SwiftUnused.new("./test/fixtures/Unused.ast") end From a166224d3ff82b9be6589dda970801f0cd803127 Mon Sep 17 00:00:00 2001 From: Paul Taykalo Date: Wed, 1 Nov 2017 00:10:55 +0200 Subject: [PATCH 4/8] Unused protocols --- .../XcodeProj/Unused/Unused/A.swift | 6 ++- unused-via-ast/bin/swift-unused | 5 ++- unused-via-ast/lib/swift-unused.rb | 44 +++++++++++++++---- unused-via-ast/test/fixtures/Unused.ast | 21 +++++---- unused-via-ast/test/swift-unused_test.rb | 12 ++++- 5 files changed, 68 insertions(+), 20 deletions(-) diff --git a/unused-via-ast/XcodeProj/Unused/Unused/A.swift b/unused-via-ast/XcodeProj/Unused/Unused/A.swift index 5ab65d9..34d5a48 100644 --- a/unused-via-ast/XcodeProj/Unused/Unused/A.swift +++ b/unused-via-ast/XcodeProj/Unused/Unused/A.swift @@ -3,6 +3,10 @@ import Foundation class A {} // unused class B {} // unused - class C {} // used by inheritance class D: C {} // unused + +protocol E {} // unused +protocol F {} // used by inheritance +protocol G: F {} // unused + diff --git a/unused-via-ast/bin/swift-unused b/unused-via-ast/bin/swift-unused index 4ac9ae4..b617c7d 100755 --- a/unused-via-ast/bin/swift-unused +++ b/unused-via-ast/bin/swift-unused @@ -3,4 +3,7 @@ require 'swift-unused' -SwiftUnused.hi +unused = SwiftUnused.new(ARGV[0]) +unused.search +puts "Classes: #{unused.classes}" +puts "Protocols: #{unused.protocols}" diff --git a/unused-via-ast/lib/swift-unused.rb b/unused-via-ast/lib/swift-unused.rb index 0b6df97..2677d93 100644 --- a/unused-via-ast/lib/swift-unused.rb +++ b/unused-via-ast/lib/swift-unused.rb @@ -4,29 +4,57 @@ class SwiftUnused def initialize(ast_path) @ast_path = ast_path @tree = SwiftAST::Parser.new().parse_build_log_output(File.read(ast_path)) - @used_classes = Hash.new + end - def classes - result = [] + def search + @used_classes = Hash.new + @used_protocols = Hash.new + + unused_classes = [] + unused_protocols = [] classes = @tree.find_nodes("class_decl") + protocols = @tree.find_nodes("protocol") + + classes.each { |classnode| - register_inheritance(classnode) + register_inheritance(classnode) { |inh| @used_classes[inh] = "inherited" } + } + + protocols.each { |protocolnode| + register_inheritance(protocolnode) { |inh| @used_protocols[inh] = "inherited"} } + classes.each { |node| next unless classname = node.parameters.first next unless @used_classes[classname].nil? #// skip already used classes - result += [classname] + unused_classes += [classname] + } + + protocols.each { |node| + next unless protocol_name = node.parameters.first + next unless @used_protocols[protocol_name].nil? #// skip already used classes + unused_protocols += [protocol_name] } - result + + @classes = unused_classes + @protocols = unused_protocols end - def register_inheritance(node) + def classes + @classes + end + + def protocols + @protocols + end + + def register_inheritance(node, &block) inheritance = node.parameters.drop_while { |el| el != "inherits:" } inheritance = inheritance.drop(1) inheritance.each { |inh| inh_name = inh.chomp(",") - add_usage(inh_name, "inheritance") + yield inh_name } end diff --git a/unused-via-ast/test/fixtures/Unused.ast b/unused-via-ast/test/fixtures/Unused.ast index 0ef7e30..9ecbc46 100644 --- a/unused-via-ast/test/fixtures/Unused.ast +++ b/unused-via-ast/test/fixtures/Unused.ast @@ -38,7 +38,7 @@ (parameter_list (parameter "self" type='D' interface type='D')) (brace_stmt)) - (constructor_decl implicit "init()" interface type='(D.Type) -> () -> D' access=internal override=Unused.(file).C.init()@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/A.swift:7:7 designated + (constructor_decl implicit "init()" interface type='(D.Type) -> () -> D' access=internal override=Unused.(file).C.init()@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/A.swift:6:7 designated (parameter_list (parameter "self" type='D' interface type='D')) (parameter_list) @@ -46,10 +46,13 @@ (rebind_self_in_constructor_expr implicit type='()' (call_expr implicit type='C' nothrow arg_labels= (dot_syntax_call_expr implicit type='() -> C' super nothrow - (other_constructor_ref_expr implicit type='(C) -> () -> C' decl=Unused.(file).C.init()@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/A.swift:7:7) + (other_constructor_ref_expr implicit type='(C) -> () -> C' decl=Unused.(file).C.init()@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/A.swift:6:7) (super_ref_expr implicit type='C')) (tuple_expr implicit type='()'))) - (return_stmt implicit))))) + (return_stmt implicit)))) + (protocol "E" interface type='E.Protocol' access=internal @_fixed_layout requirement signature=) + (protocol "F" interface type='F.Protocol' access=internal @_fixed_layout requirement signature=) + (protocol "G" interface type='G.Protocol' access=internal @_fixed_layout requirement signature= inherits: F)) (source_file (import_decl 'UIKit') (class_decl "ViewController" interface type='ViewController.Type' access=internal @objc @_fixed_layout inherits: UIViewController @@ -121,7 +124,7 @@ (tuple_expr implicit type='(nilLiteral: ())' names=nilLiteral (tuple_expr implicit type='()')))) (var_decl "window" type='UIWindow?' interface type='UIWindow?' access=internal @objc storage_kind=stored_with_trivial_accessors - (func_decl implicit 'anonname=0x7fbde9274980' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window + (func_decl implicit 'anonname=0x7ffa443018e0' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list) @@ -130,7 +133,7 @@ (load_expr implicit type='UIWindow?' (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=read decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))))) - (func_decl implicit 'anonname=0x7fbde927a800' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window + (func_decl implicit 'anonname=0x7ffa44301b50' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list @@ -140,13 +143,13 @@ (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=write decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)) (declref_expr implicit type='UIWindow?' decl=Unused.(file).AppDelegate..value@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))) - (func_decl implicit 'anonname=0x7fbde927adc0' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window + (func_decl implicit 'anonname=0x7ffa44302110' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list (parameter "buffer" type='Builtin.RawPointer' interface type='Builtin.RawPointer') (parameter "callbackStorage" type='inout Builtin.UnsafeValueBuffer' interface type='inout Builtin.UnsafeValueBuffer' mutable)))) - (func_decl implicit 'anonname=0x7fbde9274980' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window + (func_decl implicit 'anonname=0x7ffa443018e0' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list) @@ -155,7 +158,7 @@ (load_expr implicit type='UIWindow?' (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=read decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))))) - (func_decl implicit 'anonname=0x7fbde927a800' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window + (func_decl implicit 'anonname=0x7ffa44301b50' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list @@ -165,7 +168,7 @@ (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=write decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)) (declref_expr implicit type='UIWindow?' decl=Unused.(file).AppDelegate..value@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))) - (func_decl implicit 'anonname=0x7fbde927adc0' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window + (func_decl implicit 'anonname=0x7ffa44302110' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window (parameter_list (parameter "self" type='AppDelegate' interface type='AppDelegate')) (parameter_list diff --git a/unused-via-ast/test/swift-unused_test.rb b/unused-via-ast/test/swift-unused_test.rb index de78f74..af3e812 100644 --- a/unused-via-ast/test/swift-unused_test.rb +++ b/unused-via-ast/test/swift-unused_test.rb @@ -4,6 +4,7 @@ class SwiftUnusedTest < Minitest::Test def setup @unused = create_sut + @unused.search end def test_initial_state @@ -15,11 +16,20 @@ def test_unused_classes assert_includes(@unused.classes, 'B') end - def test_used_by_inheritance + def test_used_classes_by_inheritance assert_includes(@unused.classes, 'D') refute_includes(@unused.classes, 'C') end + def test_unused_protocols + assert_includes(@unused.protocols, 'E') + end + + def test_used_protocols_by_inheritance + assert_includes(@unused.protocols, 'G') + refute_includes(@unused.protocols, 'F') + end + def create_sut SwiftUnused.new("./test/fixtures/Unused.ast") end From 0eaea5fa0e833bdaa615dc59f9daeab34d5645dd Mon Sep 17 00:00:00 2001 From: Paul Taykalo Date: Mon, 13 Nov 2017 23:35:44 +0200 Subject: [PATCH 5/8] Add tests on inheritance, classes, enums --- .gitignore | 1 + unused-via-ast/bin/swift-unused | 11 +- unused-via-ast/lib/swift-unused.rb | 53 +++++- unused-via-ast/test/fixtures/Unused.ast | 209 ----------------------- unused-via-ast/test/swift-unused_test.rb | 83 +++++++-- 5 files changed, 130 insertions(+), 227 deletions(-) delete mode 100644 unused-via-ast/test/fixtures/Unused.ast diff --git a/.gitignore b/.gitignore index d4102ee..a84624a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/xcuserdata unused-via-ast/XcodeProj/Unused/Unused.xcodeproj/project.xcworkspace/xcuserdata +unused-via-ast/test/fixtures/generated diff --git a/unused-via-ast/bin/swift-unused b/unused-via-ast/bin/swift-unused index b617c7d..45a143b 100755 --- a/unused-via-ast/bin/swift-unused +++ b/unused-via-ast/bin/swift-unused @@ -3,7 +3,16 @@ require 'swift-unused' -unused = SwiftUnused.new(ARGV[0]) +unused = SwiftUnused.new({:ast_path => ARGV[0]}) unused.search puts "Classes: #{unused.classes}" puts "Protocols: #{unused.protocols}" +puts "Structs: #{unused.structs}" +puts "Enums: #{unused.enums}" + +puts """ +Unused Classes #{unused.classes.length}, +Protocos: #{unused.protocols.length}, +Structs: #{unused.structs.length} +Enums: #{unused.enums.length} +""" \ No newline at end of file diff --git a/unused-via-ast/lib/swift-unused.rb b/unused-via-ast/lib/swift-unused.rb index 2677d93..3a1db22 100644 --- a/unused-via-ast/lib/swift-unused.rb +++ b/unused-via-ast/lib/swift-unused.rb @@ -1,30 +1,49 @@ require 'swift-ast-dump/swift_ast_parser' class SwiftUnused - def initialize(ast_path) - @ast_path = ast_path - @tree = SwiftAST::Parser.new().parse_build_log_output(File.read(ast_path)) - + def initialize(options) + ast_path = options[:ast_path] + source = options[:source] + @tree = SwiftAST::Parser.new().parse_build_log_output(File.read(ast_path)) if ast_path + @tree = SwiftAST::Parser.new().parse_build_log_output(source) if source end def search @used_classes = Hash.new @used_protocols = Hash.new + @used_structs = Hash.new + @used_enums = Hash.new unused_classes = [] unused_protocols = [] + unused_structs = [] + unused_enums = [] classes = @tree.find_nodes("class_decl") protocols = @tree.find_nodes("protocol") - + extensions = @tree.find_nodes("extension_decl") + structs = @tree.find_nodes("struct_decl") + enums = @tree.find_nodes("enum_decl") classes.each { |classnode| - register_inheritance(classnode) { |inh| @used_classes[inh] = "inherited" } + register_inheritance(classnode) { |inh| + @used_classes[inh] = "inherited" + @used_protocols[inh] = "inherited" # we aren't gathering info what string is, so we'll just mark the as P and Classes + } } protocols.each { |protocolnode| register_inheritance(protocolnode) { |inh| @used_protocols[inh] = "inherited"} } + extensions.each { |extension_node| + register_inheritance(extension_node) { |inh| @used_protocols[inh] = "inherited"} + } + + structs.each { |struct_node| + register_inheritance(struct_node) { |inh| @used_protocols[inh] = "inherited"} + } + + classes.each { |node| next unless classname = node.parameters.first next unless @used_classes[classname].nil? #// skip already used classes @@ -37,8 +56,22 @@ def search unused_protocols += [protocol_name] } + structs.each { |node| + next unless struct_name = node.parameters.first + next unless @used_structs[struct_name].nil? #// skip already used structs + unused_structs += [struct_name] + } + + enums.each { |node| + next unless enum_name = node.parameters.first + next unless @used_enums[enum_name].nil? #// skip already used structs + unused_enums += [enum_name] + } + @classes = unused_classes @protocols = unused_protocols + @structs = unused_structs + @enums = unused_enums end def classes @@ -49,6 +82,14 @@ def protocols @protocols end + def structs + @structs + end + + def enums + @enums + end + def register_inheritance(node, &block) inheritance = node.parameters.drop_while { |el| el != "inherits:" } inheritance = inheritance.drop(1) diff --git a/unused-via-ast/test/fixtures/Unused.ast b/unused-via-ast/test/fixtures/Unused.ast deleted file mode 100644 index 9ecbc46..0000000 --- a/unused-via-ast/test/fixtures/Unused.ast +++ /dev/null @@ -1,209 +0,0 @@ -(source_file - (import_decl 'Foundation') - (class_decl "A" interface type='A.Type' access=internal @_fixed_layout - (destructor_decl implicit "deinit" interface type='(A) -> () -> ()' access=internal @objc - (parameter_list - (parameter "self" type='A' interface type='A')) - (brace_stmt)) - (constructor_decl implicit "init()" interface type='(A.Type) -> () -> A' access=internal designated - (parameter_list - (parameter "self" type='A' interface type='A')) - (parameter_list) - (brace_stmt - (return_stmt implicit)))) - (class_decl "B" interface type='B.Type' access=internal @_fixed_layout - (destructor_decl implicit "deinit" interface type='(B) -> () -> ()' access=internal @objc - (parameter_list - (parameter "self" type='B' interface type='B')) - (brace_stmt)) - (constructor_decl implicit "init()" interface type='(B.Type) -> () -> B' access=internal designated - (parameter_list - (parameter "self" type='B' interface type='B')) - (parameter_list) - (brace_stmt - (return_stmt implicit)))) - (class_decl "C" interface type='C.Type' access=internal @_fixed_layout - (destructor_decl implicit "deinit" interface type='(C) -> () -> ()' access=internal @objc - (parameter_list - (parameter "self" type='C' interface type='C')) - (brace_stmt)) - (constructor_decl implicit "init()" interface type='(C.Type) -> () -> C' access=internal designated - (parameter_list - (parameter "self" type='C' interface type='C')) - (parameter_list) - (brace_stmt - (return_stmt implicit)))) - (class_decl "D" interface type='D.Type' access=internal @_fixed_layout inherits: C - (destructor_decl implicit "deinit" interface type='(D) -> () -> ()' access=internal @objc - (parameter_list - (parameter "self" type='D' interface type='D')) - (brace_stmt)) - (constructor_decl implicit "init()" interface type='(D.Type) -> () -> D' access=internal override=Unused.(file).C.init()@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/A.swift:6:7 designated - (parameter_list - (parameter "self" type='D' interface type='D')) - (parameter_list) - (brace_stmt - (rebind_self_in_constructor_expr implicit type='()' - (call_expr implicit type='C' nothrow arg_labels= - (dot_syntax_call_expr implicit type='() -> C' super nothrow - (other_constructor_ref_expr implicit type='(C) -> () -> C' decl=Unused.(file).C.init()@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/A.swift:6:7) - (super_ref_expr implicit type='C')) - (tuple_expr implicit type='()'))) - (return_stmt implicit)))) - (protocol "E" interface type='E.Protocol' access=internal @_fixed_layout requirement signature=) - (protocol "F" interface type='F.Protocol' access=internal @_fixed_layout requirement signature=) - (protocol "G" interface type='G.Protocol' access=internal @_fixed_layout requirement signature= inherits: F)) -(source_file - (import_decl 'UIKit') - (class_decl "ViewController" interface type='ViewController.Type' access=internal @objc @_fixed_layout inherits: UIViewController - (func_decl "viewDidLoad()" interface type='(ViewController) -> () -> ()' access=internal override=UIKit.(file).UIViewController.viewDidLoad() @objc dynamic - (parameter_list - (parameter "self" type='ViewController' interface type='ViewController')) - (parameter_list) - (brace_stmt - (call_expr type='Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 - line:14:27] nothrow arg_labels= - (dot_syntax_call_expr type='() -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 - line:14:15] super nothrow - (declref_expr type='(UIViewController) -> () -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:15 - line:14:15] decl=UIKit.(file).UIViewController.viewDidLoad() function_ref=single) - (super_ref_expr type='UIViewController' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:9 - line:14:9])) - (tuple_expr type='()' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:26 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:14:26 - line:14:27])))) - (func_decl "didReceiveMemoryWarning()" interface type='(ViewController) -> () -> ()' access=internal override=UIKit.(file).UIViewController.didReceiveMemoryWarning() @objc dynamic - (parameter_list - (parameter "self" type='ViewController' interface type='ViewController')) - (parameter_list) - (brace_stmt - (call_expr type='Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 - line:19:39] nothrow arg_labels= - (dot_syntax_call_expr type='() -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 - line:19:15] super nothrow - (declref_expr type='(UIViewController) -> () -> Void' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:15 - line:19:15] decl=UIKit.(file).UIViewController.didReceiveMemoryWarning() function_ref=single) - (super_ref_expr type='UIViewController' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:9 - line:19:9])) - (tuple_expr type='()' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:38 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/ViewController.swift:19:38 - line:19:39])))) - (destructor_decl implicit "deinit" interface type='(ViewController) -> () -> ()' access=internal @objc - (parameter_list - (parameter "self" type='ViewController' interface type='ViewController')) - (brace_stmt)) - (constructor_decl implicit "init(nibName:bundle:)" interface type='(ViewController.Type) -> (String?, Bundle?) -> ViewController' access=internal override=UIKit.(file).UIViewController.init(nibName:bundle:) @objc designated - (parameter_list - (parameter "self" type='ViewController' interface type='ViewController')) - (parameter_list - (parameter "nibNameOrNil" apiName=nibName type='String?' interface type='String?') - (parameter "nibBundleOrNil" apiName=bundle type='Bundle?' interface type='Bundle?')) - (brace_stmt - (rebind_self_in_constructor_expr implicit type='()' - (call_expr implicit type='UIViewController' nothrow arg_labels=nibName:bundle: - (dot_syntax_call_expr implicit type='(String?, Bundle?) -> UIViewController' super nothrow - (other_constructor_ref_expr implicit type='(UIViewController) -> (String?, Bundle?) -> UIViewController' decl=UIKit.(file).UIViewController.init(nibName:bundle:)) - (super_ref_expr implicit type='UIViewController')) - (tuple_expr implicit type='(nibName: String?, bundle: Bundle?)' names=nibName,bundle - (declref_expr implicit type='String?' decl=Unused.(file).ViewController.init(nibName:bundle:).nibNameOrNil function_ref=unapplied) - (declref_expr implicit type='Bundle?' decl=Unused.(file).ViewController.init(nibName:bundle:).nibBundleOrNil function_ref=unapplied)))) - (return_stmt implicit))) - (constructor_decl implicit "init(coder:)" interface type='(ViewController.Type) -> (NSCoder) -> ViewController?' access=internal override=UIKit.(file).UIViewController.init(coder:) @objc required designated failable=Optional - (parameter_list - (parameter "self" type='ViewController' interface type='ViewController')) - (parameter_list - (parameter "aDecoder" apiName=coder type='NSCoder' interface type='NSCoder')) - (brace_stmt - (rebind_self_in_constructor_expr implicit type='()' - (call_expr implicit type='UIViewController?' nothrow arg_labels=coder: - (dot_syntax_call_expr implicit type='(NSCoder) -> UIViewController?' super nothrow - (other_constructor_ref_expr implicit type='(UIViewController) -> (NSCoder) -> UIViewController?' decl=UIKit.(file).UIViewController.init(coder:)) - (super_ref_expr implicit type='UIViewController')) - (tuple_expr implicit type='(coder: NSCoder)' names=coder - (declref_expr implicit type='NSCoder' decl=Unused.(file).ViewController.init(coder:).aDecoder function_ref=unapplied)))) - (return_stmt implicit))))) -(source_file - (import_decl 'UIKit') - (class_decl "AppDelegate" interface type='AppDelegate.Type' access=internal @objc @_fixed_layout inherits: UIResponder, UIApplicationDelegate - (pattern_binding_decl - (pattern_typed type='UIWindow?' - (pattern_named type='UIWindow?' 'window') -) - (call_expr implicit type='UIWindow?' nothrow arg_labels=nilLiteral: - (constructor_ref_call_expr implicit type='(()) -> UIWindow?' nothrow - (declref_expr implicit type='(Optional.Type) -> (()) -> Optional' decl=Swift.(file).Optional.init(nilLiteral:) [with UIWindow] function_ref=single) - (type_expr implicit type='UIWindow?.Type' typerepr='<>')) - (tuple_expr implicit type='(nilLiteral: ())' names=nilLiteral - (tuple_expr implicit type='()')))) - (var_decl "window" type='UIWindow?' interface type='UIWindow?' access=internal @objc storage_kind=stored_with_trivial_accessors - (func_decl implicit 'anonname=0x7ffa443018e0' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window - (parameter_list - (parameter "self" type='AppDelegate' interface type='AppDelegate')) - (parameter_list) - (brace_stmt - (return_stmt implicit - (load_expr implicit type='UIWindow?' - (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=read decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage - (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))))) - (func_decl implicit 'anonname=0x7ffa44301b50' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window - (parameter_list - (parameter "self" type='AppDelegate' interface type='AppDelegate')) - (parameter_list - (parameter "value" type='UIWindow?' interface type='UIWindow?')) - (brace_stmt - (assign_expr - (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=write decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage - (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)) - (declref_expr implicit type='UIWindow?' decl=Unused.(file).AppDelegate..value@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))) - (func_decl implicit 'anonname=0x7ffa44302110' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window - (parameter_list - (parameter "self" type='AppDelegate' interface type='AppDelegate')) - (parameter_list - (parameter "buffer" type='Builtin.RawPointer' interface type='Builtin.RawPointer') - (parameter "callbackStorage" type='inout Builtin.UnsafeValueBuffer' interface type='inout Builtin.UnsafeValueBuffer' mutable)))) - (func_decl implicit 'anonname=0x7ffa443018e0' interface type='(AppDelegate) -> () -> UIWindow?' access=internal @objc getter_for=window - (parameter_list - (parameter "self" type='AppDelegate' interface type='AppDelegate')) - (parameter_list) - (brace_stmt - (return_stmt implicit - (load_expr implicit type='UIWindow?' - (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=read decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage - (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))))) - (func_decl implicit 'anonname=0x7ffa44301b50' interface type='(AppDelegate) -> (UIWindow?) -> ()' access=internal @objc setter_for=window - (parameter_list - (parameter "self" type='AppDelegate' interface type='AppDelegate')) - (parameter_list - (parameter "value" type='UIWindow?' interface type='UIWindow?')) - (brace_stmt - (assign_expr - (member_ref_expr implicit type='@lvalue UIWindow?' accessKind=write decl=Unused.(file).AppDelegate.window@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 direct_to_storage - (declref_expr implicit type='AppDelegate' decl=Unused.(file).AppDelegate..self@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)) - (declref_expr implicit type='UIWindow?' decl=Unused.(file).AppDelegate..value@/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:13:9 function_ref=unapplied)))) - (func_decl implicit 'anonname=0x7ffa44302110' interface type='(AppDelegate) -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, Builtin.RawPointer?)' access=internal materializeForSet_for=window - (parameter_list - (parameter "self" type='AppDelegate' interface type='AppDelegate')) - (parameter_list - (parameter "buffer" type='Builtin.RawPointer' interface type='Builtin.RawPointer') - (parameter "callbackStorage" type='inout Builtin.UnsafeValueBuffer' interface type='inout Builtin.UnsafeValueBuffer' mutable))) - (func_decl "application(_:didFinishLaunchingWithOptions:)" interface type='(AppDelegate) -> (UIApplication, [UIApplicationLaunchOptionsKey : Any]?) -> Bool' access=internal @objc - (parameter_list - (parameter "self" type='AppDelegate' interface type='AppDelegate')) - (parameter_list - (parameter "application" type='UIApplication' interface type='UIApplication') - (parameter "launchOptions" apiName=didFinishLaunchingWithOptions type='[UIApplicationLaunchOptionsKey : Any]?' interface type='[UIApplicationLaunchOptionsKey : Any]?')) - (result - (type_ident - (component id='Bool' bind=Swift.(file).Bool))) - (brace_stmt - (return_stmt - (call_expr implicit type='Bool' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] nothrow arg_labels=_builtinBooleanLiteral: - (constructor_ref_call_expr implicit type='(Int1) -> Bool' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] nothrow - (declref_expr implicit type='(Bool.Type) -> (Int1) -> Bool' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] decl=Swift.(file).Bool.init(_builtinBooleanLiteral:) function_ref=single) - (type_expr implicit type='Bool.Type' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] typerepr='Bool')) - (tuple_expr implicit type='(_builtinBooleanLiteral: Builtin.Int1)' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] names=_builtinBooleanLiteral - (boolean_literal_expr type='Builtin.Int1' location=/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 range=[/Users/paultaykalo/Projects/swift-scripts/unused-via-ast/XcodeProj/Unused/Unused/AppDelegate.swift:16:16 - line:16:16] value=true)))))) - (destructor_decl implicit "deinit" interface type='(AppDelegate) -> () -> ()' access=internal @objc - (parameter_list - (parameter "self" type='AppDelegate' interface type='AppDelegate')) - (brace_stmt)) - (constructor_decl implicit "init()" interface type='(AppDelegate.Type) -> () -> AppDelegate' access=internal override=UIKit.(file).UIResponder.init() @objc designated - (parameter_list - (parameter "self" type='AppDelegate' interface type='AppDelegate')) - (parameter_list) - (brace_stmt - (rebind_self_in_constructor_expr implicit type='()' - (call_expr implicit type='UIResponder' nothrow arg_labels= - (dot_syntax_call_expr implicit type='() -> UIResponder' super nothrow - (other_constructor_ref_expr implicit type='(UIResponder) -> () -> UIResponder' decl=UIKit.(file).UIResponder.init()) - (super_ref_expr implicit type='UIResponder')) - (tuple_expr implicit type='()'))) - (return_stmt implicit))))) diff --git a/unused-via-ast/test/swift-unused_test.rb b/unused-via-ast/test/swift-unused_test.rb index af3e812..729ffaf 100644 --- a/unused-via-ast/test/swift-unused_test.rb +++ b/unused-via-ast/test/swift-unused_test.rb @@ -2,36 +2,97 @@ require 'swift-unused' class SwiftUnusedTest < Minitest::Test - def setup - @unused = create_sut - @unused.search - end - - def test_initial_state - assert(!@unused.nil?, "Should be able to create instance of unused") - end - def test_unused_classes + with_swift_ast "0000", """ + class A {} + class B {} + """ #, skip_cache=true assert_includes(@unused.classes, 'A') assert_includes(@unused.classes, 'B') end def test_used_classes_by_inheritance + with_swift_ast "0001", """ + class C {} // used by inheritance + class D: C {} // unused + """ #, skip_cache=true assert_includes(@unused.classes, 'D') refute_includes(@unused.classes, 'C') end def test_unused_protocols + with_swift_ast "0002", """ + protocol E {} // unused + protocol F {} // unused + """ #, skip_cache=true assert_includes(@unused.protocols, 'E') + assert_includes(@unused.protocols, 'F') end def test_used_protocols_by_inheritance + with_swift_ast "0003", """ + protocol F {} + protocol G: F {} + + protocol H {} + class I: H {} + + protocol J {} + struct K: J {} + """ #, skip_cache=true assert_includes(@unused.protocols, 'G') refute_includes(@unused.protocols, 'F') + refute_includes(@unused.protocols, 'H') + refute_includes(@unused.protocols, 'J') + + end + + def test_used_protocol_by_extension + with_swift_ast "0004", """ + class C {} // unused + protocol F {} // used by extension + extension C: F {} + """ #, skip_cache=true + refute_includes(@unused.protocols, 'F') + assert_includes(@unused.classes, 'C') + end - def create_sut - SwiftUnused.new("./test/fixtures/Unused.ast") + def test_unused_structs + with_swift_ast "0005", """ + struct A {} // unused + struct B {} // unused + """#, skip_cache=true + assert_includes(@unused.structs, 'A') + assert_includes(@unused.structs, 'B') + + end + + def test_unused_enums + with_swift_ast "0006", """ + enum A {} // unused + enum B {} // unused + """#, skip_cache=true + assert_includes(@unused.enums, 'A') + assert_includes(@unused.enums, 'B') + end + + + + def with_swift_ast(id, source, skip_cache = false) + require 'tempfile' + generated_path = "./test/fixtures/generated/" + outpath = generated_path + "#{id}.ast" + if !File.exist?(outpath) || skip_cache + inpath = generated_path + "#{id}.swift" + file = File.new(inpath, "w") + # file = Tempfile.new(['unused-test', '.swift']) + file.write(source) + file.close + %x(swiftc -dump-ast #{inpath} &> #{outpath} ) + end + @unused = SwiftUnused.new({:ast_path => outpath}) + @unused.search end end From ecdfe3379d0c12078f875d05b8fa8c1f855e6db7 Mon Sep 17 00:00:00 2001 From: Paul Taykalo Date: Tue, 14 Nov 2017 23:29:29 +0200 Subject: [PATCH 6/8] Function usage handling --- unused-via-ast/lib/swift-unused.rb | 55 ++++++++++++++++++++++++ unused-via-ast/test/swift-unused_test.rb | 45 +++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/unused-via-ast/lib/swift-unused.rb b/unused-via-ast/lib/swift-unused.rb index 3a1db22..6368116 100644 --- a/unused-via-ast/lib/swift-unused.rb +++ b/unused-via-ast/lib/swift-unused.rb @@ -29,6 +29,20 @@ def search @used_classes[inh] = "inherited" @used_protocols[inh] = "inherited" # we aren't gathering info what string is, so we'll just mark the as P and Classes } + register_variables(classnode) { |var_type| + # Here we don't know what type it was... yet + @used_classes[var_type] = "inherited" + @used_protocols[var_type] = "inherited" + @used_structs[var_type] = "inherited" + @used_enums[var_type] = "inherited" + } + register_func_types(classnode) { |var_type| + @used_classes[var_type] = "inherited" + @used_protocols[var_type] = "inherited" + @used_structs[var_type] = "inherited" + @used_enums[var_type] = "inherited" + } + } protocols.each { |protocolnode| @@ -41,6 +55,13 @@ def search structs.each { |struct_node| register_inheritance(struct_node) { |inh| @used_protocols[inh] = "inherited"} + register_variables(struct_node) { |var_type| + # Here we don't know what type it was... yet + @used_classes[var_type] = "inherited" + @used_protocols[var_type] = "inherited" + @used_structs[var_type] = "inherited" + @used_enums[var_type] = "inherited" + } } @@ -99,6 +120,40 @@ def register_inheritance(node, &block) } end + def register_variables(node, &block) + node.on_node("var_decl") { |var_node| + return unless type_decl = var_node.parameters.detect { |el| el.start_with?("type=")} + type = type_decl.split('=').last[1..-2] + yield type + } + end + + def register_func_types(node, &block) + node.on_node("func_decl") { |func_decl| + func_decl.on_node("parameter_list") { |parameter_list| + parameter_list.on_node("parameter") { |parameter| + type = type_from_node(parameter, 'type') + yield type if type + } + } + + func_decl.on_node("result") { |result| + result.on_node("type_ident") { |type_ident| + type_ident.on_node("component") { |component| + type = type_from_node(component, 'id') + yield type if type + } + } + } + } + end + + + def type_from_node(node, attribute = "type") + return nil unless type_decl = node.parameters.detect { |el| el.start_with?("#{attribute}=")} + type = type_decl.split('=').last[1..-2] + end + def add_usage(inh_name, type) @used_classes[inh_name] = type end diff --git a/unused-via-ast/test/swift-unused_test.rb b/unused-via-ast/test/swift-unused_test.rb index 729ffaf..cdd2994 100644 --- a/unused-via-ast/test/swift-unused_test.rb +++ b/unused-via-ast/test/swift-unused_test.rb @@ -77,7 +77,52 @@ def test_unused_enums assert_includes(@unused.enums, 'B') end + def test_used_items_in_lets_and_vars + with_swift_ast "0007", """ + protocol A {} + class B {} + struct C {} + enum D {} + + struct E { + let a: A + var b: B + let c: C + var d: D + } + """#, skip_cache=true + refute_includes(@unused.protocols, 'A') + refute_includes(@unused.classes, 'B') + refute_includes(@unused.structs, 'C') + refute_includes(@unused.enums, 'D') + + end + + def test_used_items_in_function_return_types + with_swift_ast "0009", """ + class A {} + class C { + func a() -> A { + return A() + } + } + """#, skip_cache=true + refute_includes(@unused.classes, 'A') + end + + + def test_used_items_in_function_parameters + with_swift_ast "0010", """ + class A {} + + class C { + func a(param: A){ + } + } + """#, skip_cache=true + refute_includes(@unused.classes, 'A') + end def with_swift_ast(id, source, skip_cache = false) require 'tempfile' From 457a2972bd642134e6a315b432a241a76e9de763 Mon Sep 17 00:00:00 2001 From: Paul Taykalo Date: Tue, 14 Nov 2017 23:45:28 +0200 Subject: [PATCH 7/8] Used in variables and functions fix --- unused-via-ast/lib/swift-unused.rb | 39 ++++++++++++------------ unused-via-ast/test/swift-unused_test.rb | 13 ++++++++ 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/unused-via-ast/lib/swift-unused.rb b/unused-via-ast/lib/swift-unused.rb index 6368116..6b3754b 100644 --- a/unused-via-ast/lib/swift-unused.rb +++ b/unused-via-ast/lib/swift-unused.rb @@ -29,39 +29,29 @@ def search @used_classes[inh] = "inherited" @used_protocols[inh] = "inherited" # we aren't gathering info what string is, so we'll just mark the as P and Classes } - register_variables(classnode) { |var_type| - # Here we don't know what type it was... yet - @used_classes[var_type] = "inherited" - @used_protocols[var_type] = "inherited" - @used_structs[var_type] = "inherited" - @used_enums[var_type] = "inherited" - } - register_func_types(classnode) { |var_type| - @used_classes[var_type] = "inherited" - @used_protocols[var_type] = "inherited" - @used_structs[var_type] = "inherited" - @used_enums[var_type] = "inherited" - } + register_variables(classnode, &method(:mark_as_used)) + register_func_types(classnode, &method(:mark_as_used)) } protocols.each { |protocolnode| register_inheritance(protocolnode) { |inh| @used_protocols[inh] = "inherited"} + register_func_types(protocolnode, &method(:mark_as_used)) } extensions.each { |extension_node| register_inheritance(extension_node) { |inh| @used_protocols[inh] = "inherited"} + register_func_types(extension_node, &method(:mark_as_used)) + register_variables(extension_node, &method(:mark_as_used)) } structs.each { |struct_node| register_inheritance(struct_node) { |inh| @used_protocols[inh] = "inherited"} - register_variables(struct_node) { |var_type| - # Here we don't know what type it was... yet - @used_classes[var_type] = "inherited" - @used_protocols[var_type] = "inherited" - @used_structs[var_type] = "inherited" - @used_enums[var_type] = "inherited" - } + register_variables(struct_node, &method(:mark_as_used)) + } + + @tree.on_node('func_decl') { |func_decl| + register_variables(func_decl, &method(:mark_as_used)) } @@ -158,4 +148,13 @@ def add_usage(inh_name, type) @used_classes[inh_name] = type end + def mark_as_used(type) + @used_classes[type] = "inherited" + @used_protocols[type] = "inherited" + @used_structs[type] = "inherited" + @used_enums[type] = "inherited" + end + + + end \ No newline at end of file diff --git a/unused-via-ast/test/swift-unused_test.rb b/unused-via-ast/test/swift-unused_test.rb index cdd2994..17360b8 100644 --- a/unused-via-ast/test/swift-unused_test.rb +++ b/unused-via-ast/test/swift-unused_test.rb @@ -124,6 +124,19 @@ class C { refute_includes(@unused.classes, 'A') end + def test_used_items_in_internal_variables + with_swift_ast "0011", """ + class A {} + + func a(){ + let p = A() + print(p) + } + """#, skip_cache=true + refute_includes(@unused.classes, 'A') + end + + def with_swift_ast(id, source, skip_cache = false) require 'tempfile' generated_path = "./test/fixtures/generated/" From df9c955ea34ef1a96300e71918e69f2ba5b0cc74 Mon Sep 17 00:00:00 2001 From: Paul Taykalo Date: Fri, 17 Nov 2017 00:06:32 +0200 Subject: [PATCH 8/8] Fixed some usage cases, added correct generics handling, skipping implicit functions declaraions --- unused-via-ast/lib/swift-unused.rb | 46 ++++++++- unused-via-ast/test/swift-unused_test.rb | 124 +++++++++++++++++++++++ 2 files changed, 168 insertions(+), 2 deletions(-) diff --git a/unused-via-ast/lib/swift-unused.rb b/unused-via-ast/lib/swift-unused.rb index 6b3754b..be4a5fd 100644 --- a/unused-via-ast/lib/swift-unused.rb +++ b/unused-via-ast/lib/swift-unused.rb @@ -31,27 +31,36 @@ def search } register_variables(classnode, &method(:mark_as_used)) register_func_types(classnode, &method(:mark_as_used)) - + register_calls(classnode, &method(:mark_as_used)) + register_pattern_bindings(classnode, &method(:mark_as_used)) } protocols.each { |protocolnode| register_inheritance(protocolnode) { |inh| @used_protocols[inh] = "inherited"} register_func_types(protocolnode, &method(:mark_as_used)) + register_pattern_bindings(protocolnode, &method(:mark_as_used)) } extensions.each { |extension_node| register_inheritance(extension_node) { |inh| @used_protocols[inh] = "inherited"} register_func_types(extension_node, &method(:mark_as_used)) register_variables(extension_node, &method(:mark_as_used)) + register_calls(extension_node, &method(:mark_as_used)) + register_pattern_bindings(extension_node, &method(:mark_as_used)) } structs.each { |struct_node| register_inheritance(struct_node) { |inh| @used_protocols[inh] = "inherited"} register_variables(struct_node, &method(:mark_as_used)) + register_calls(struct_node, &method(:mark_as_used)) + register_pattern_bindings(struct_node, &method(:mark_as_used)) } @tree.on_node('func_decl') { |func_decl| register_variables(func_decl, &method(:mark_as_used)) + register_calls(func_decl, &method(:mark_as_used)) + register_pattern_bindings(func_decl, &method(:mark_as_used)) + } @@ -101,11 +110,16 @@ def enums @enums end + def tree + @tree + end + def register_inheritance(node, &block) inheritance = node.parameters.drop_while { |el| el != "inherits:" } inheritance = inheritance.drop(1) inheritance.each { |inh| inh_name = inh.chomp(",") + inh_name = inh_name[/(\w|_)+/] yield inh_name } end @@ -120,10 +134,14 @@ def register_variables(node, &block) def register_func_types(node, &block) node.on_node("func_decl") { |func_decl| + + # skip implicit functions + next if func_decl.parameters.first == "implicit" + func_decl.on_node("parameter_list") { |parameter_list| parameter_list.on_node("parameter") { |parameter| type = type_from_node(parameter, 'type') - yield type if type + yield type if type } } @@ -138,10 +156,34 @@ def register_func_types(node, &block) } end + def register_calls(node, &block) + node.on_node('call_expr') { |call_expr| + type = type_from_node(call_expr, 'type') + yield type if type + + call_expr.on_node("type_expr") { |type_expr| + dot_type = type_from_node(type_expr, 'typerepr') + yield dot_type if dot_type + } + + } + end + + def register_pattern_bindings(node, &block) + node.on_node('pattern_binding_decl') { |pattern_binding_decl| + pattern_binding_decl.on_node('type_expr') {|type_expr| + dot_type = type_from_node(type_expr, 'typerepr') + yield dot_type if dot_type + } + } + end + def type_from_node(node, attribute = "type") return nil unless type_decl = node.parameters.detect { |el| el.start_with?("#{attribute}=")} type = type_decl.split('=').last[1..-2] + type = type[/\w+/] + return type end def add_usage(inh_name, type) diff --git a/unused-via-ast/test/swift-unused_test.rb b/unused-via-ast/test/swift-unused_test.rb index 17360b8..5a8fbbf 100644 --- a/unused-via-ast/test/swift-unused_test.rb +++ b/unused-via-ast/test/swift-unused_test.rb @@ -136,6 +136,130 @@ class A {} refute_includes(@unused.classes, 'A') end + def test_used_items_in_internal_calls + with_swift_ast "0012", """ + protocol B {} + class A: B {} + + func a(){ + let p: B = A() + print(p) + } + """#, skip_cache=true + refute_includes(@unused.classes, 'A') + refute_includes(@unused.protocols, 'B') + + end + + def test_used_items_in_static_calls + with_swift_ast "0013", """ + class A { + static func parse() { } + } + + func a(){ + A.parse() + } + """#, skip_cache=true + refute_includes(@unused.classes, 'A') + + end + + def test_used_items_in_static_lets + with_swift_ast "0014", """ + class A { + static let some: String = \"12\" + } + + func a(){ + print(A.some) + } + """#, skip_cache=true + refute_includes(@unused.classes, 'A') + + end + + def test_used_items_in_static_lets_in_stored_variables + with_swift_ast "0015", """ + class A { + static let some: String = \"12\" + } + + class B { + let item = A.some + } + """#, skip_cache=true + refute_includes(@unused.classes, 'A') + + end + + def test_used_items_by_function_refs + with_swift_ast "0016", """ + class A { + static func foo(value: String) -> String? { return \"12\"} + } + + class B { + static func do() { + let a = A.foo + a(\"13\") + } + } + """#, skip_cache=true + refute_includes(@unused.classes, 'A') + + end + + def test_generic_classes_are_used + with_swift_ast "0017", """ + class B { + let t: T + } + class C: B {} + """#, skip_cache=true + refute_includes(@unused.classes, 'B') + assert_includes(@unused.classes, 'C') + + end + + def test_lazy_var_fix + with_swift_ast "0019", """ + + class A {} + struct B { + let a: A + } + class C { + static func s(value: Int) -> A { return A()} + } + class D { + static func getB() -> B { + let products: [Int] = [1] + return B(a: products.map(C.s)) + } + } + + """#, skip_cache=true + refute_includes(@unused.classes, 'C') + refute_includes(@unused.classes, 'A') + refute_includes(@unused.classes, 'B') + + end + + def test_generic_classes_are_used_in_lazy_props + with_swift_ast "0020", """ + class B { + let t: T + } + class C { + lazy var b = B(t: 1) + } + """, skip_cache=true + refute_includes(@unused.classes, 'B') + assert_includes(@unused.classes, 'C') + + end + def with_swift_ast(id, source, skip_cache = false) require 'tempfile'