Skip to content

Commit

Permalink
Merge pull request PaulTaykalo#2 from PaulTaykalo/unused-variables
Browse files Browse the repository at this point in the history
Switch to Ruby
  • Loading branch information
PaulTaykalo committed Nov 2, 2017
2 parents a47b9bc + 018b378 commit b49f8c7
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 68 deletions.
41 changes: 10 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,23 @@
# Unused
`unused.sh` Searches for unused swift functions at specified path
`unused.rb` Searches for unused swift functions, and variable at specified path

## Usage
```
cd <path-to-the-project>
<path-to-unused.sh>/unused.sh
<path-to-unused.sh>/unused.rb
```

## Generated files
- `raw_functions.txt` - a list of all found (declared) functions
- `filtered_functions.txt`- a list of all found functions filtered by some euristics like (override, @IBAction, testXXX)
- `unique_functions.txt`- unique functions names
- `usage.txt` - functions usage (ATM only functions that appeared once are shown)
- `sorted_usage.txt` - functions sorted by the usage (and name)
- `delete_me.txt` - file that contains information about the function and where it is used

## output
```
Gathering functions
There are 1898 potential functions found
Gathering usage information
There are 32 potential functions to be deleted found
Gathering usage per each of them
It took 197 seconds.
```

## delete_me.txt
This is an example of how outptut can look like
```
---- selectionColor ----
ProjectPath/UIColorExtensions.swift- return UIColor(red: 220.0/255, green: 220.0/255, blue: 220.0/255, alpha: 1)
ProjectPath/UIColorExtensions.swift- }
ProjectPath/UIColorExtensions.swift-
ProjectPath/UIColorExtensions.swift: static func selectionColor() -> UIColor {
ProjectPath/UIColorExtensions.swift- return UIColor(red: 240.0/255, green: 240.0/255, blue: 240.0/255, alpha: 1)
ProjectPath/UIColorExtensions.swift- }
ProjectPath/UIColorExtensions.swift-
Item< func loadWebViewTos [private] from:File.swift:23:0>
Total items to be checked 4276
Total unique items to be checked 1697
Starting searching globally it can take a while
Item< func applicationHasUnitTestTargetInjected [] from:AnotherFile.swift:31:0>
Item< func getSelectedIds [] from: AnotherFile.swift:82:0>
```

## Known issues:
- Fully text search (no fancy stuff)
- A lot of false-positives (protocol functions and overrides)
- A lot of false-negatives (text search, yep)
- A lot of false-positives (protocols, functions, objc interoop, System delegate methods)
- A lot of false-negatives (text search, yep)
140 changes: 140 additions & 0 deletions unused.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/usr/bin/ruby

class Item
def initialize(file, line, at)
@file = file
@line = line
@at = at - 1
if match = line.match(/(func|let|var|class|enum|struct|protocol)\s+(\w+)/)
@type = match.captures[0]
@name = match.captures[1]
end
end

def modifiers
return @modifiers if @modifiers
@modifiers = []
if match = @line.match(/(.*?)#{@type}/)
@modifiers = match.captures[0].split(" ")
end
return @modifiers
end

def name
@name
end

def file
@file
end

def to_s
serialize
end
def to_str
serialize
end

def serialize
"Item< #{@type.to_s.green} #{@name.to_s.yellow} [#{modifiers.join(" ").cyan}] from: #{@file}:#{@at}:0>"
end

end
class Unused
def find
items = []
all_files = Dir.glob("**/*.swift")

all_files.each { |my_text_file|
file_items = grab_items(my_text_file)
file_items = filter_items(file_items)

non_private_items, private_items = file_items.partition { |f| !f.modifiers.include?("private") && !f.modifiers.include?("fileprivate") }
items += non_private_items

# Usage within the file
if private_items.length > 0
find_usages_in_files([my_text_file], private_items)
end

}
puts "Total items to be checked #{items.length}"

items = items.uniq { |f| f.name }
puts "Total unique items to be checked #{items.length}"

puts "Starting searching globally it can take a while".green

find_usages_in_files(all_files, items)

end

def find_usages_in_files(files, items_in)
items = items_in
usages = items.map { |f| 0 }
files.each { |file|
lines = File.readlines(file).select { |line| !line.match(/^\s*\/\//) }
words = lines.join("\n").split(/\W+/)
words_arrray = words.group_by { |w| w }.map { |w, ws| [w, ws.length] }.flatten

wf = Hash[*words_arrray]

items.each_with_index { |f, i|
usages[i] += (wf[f.name] || 0)
}
# Remove all items which has usage 2+
indexes = usages.each_with_index.select { |u, i| u >= 2 }.map { |f, i| i }

# reduce usage array if we found some functions already
indexes.reverse.each { |i| usages.delete_at(i) && items.delete_at(i) }
}


items = items.select { |f| !f.file.start_with?("Pods/") && !f.file.end_with?("Tests.swift") && !f.file.end_with?("Spec.swift") }
if items.length > 0
puts " #{items.map { |e| e.to_s }.join("\n ")}"
end
end

def grab_items(file)
result = []
lines = File.readlines(file).select { |line| !line.match(/^\s*\/\//) }
items = lines.each_with_index.select { |line, i| line[/(func|let|var|class|enum|struct|protocol)\s+\w+/] }.map { |line, i| Item.new(file, line, i)}
end

def filter_items(items)
items.select { |f|
!f.name.start_with?("test") && !f.modifiers.include?("@IBAction") && !f.modifiers.include?("override") && !f.modifiers.include?("@objc") && !f.modifiers.include?("@IBInspectable")
}
end

end

class String
def black; "\e[30m#{self}\e[0m" end
def red; "\e[31m#{self}\e[0m" end
def green; "\e[32m#{self}\e[0m" end
def yellow; "\e[33m#{self}\e[0m" end
def blue; "\e[34m#{self}\e[0m" end
def magenta; "\e[35m#{self}\e[0m" end
def cyan; "\e[36m#{self}\e[0m" end
def gray; "\e[37m#{self}\e[0m" end

def bg_black; "\e[40m#{self}\e[0m" end
def bg_red; "\e[41m#{self}\e[0m" end
def bg_green; "\e[42m#{self}\e[0m" end
def bg_brown; "\e[43m#{self}\e[0m" end
def bg_blue; "\e[44m#{self}\e[0m" end
def bg_magenta; "\e[45m#{self}\e[0m" end
def bg_cyan; "\e[46m#{self}\e[0m" end
def bg_gray; "\e[47m#{self}\e[0m" end

def bold; "\e[1m#{self}\e[22m" end
def italic; "\e[3m#{self}\e[23m" end
def underline; "\e[4m#{self}\e[24m" end
def blink; "\e[5m#{self}\e[25m" end
def reverse_color; "\e[7m#{self}\e[27m" end
end


Unused.new.find
37 changes: 0 additions & 37 deletions unused.sh

This file was deleted.

0 comments on commit b49f8c7

Please sign in to comment.