Class: Codex
- Inherits:
-
Object
- Object
- Codex
- Defined in:
- lib/codex.rb
Instance Attribute Summary collapse
-
#block ⇒ Object
Returns the value of attribute block.
-
#cond ⇒ Object
Returns the value of attribute cond.
-
#func ⇒ Object
Returns the value of attribute func.
-
#func_chain ⇒ Object
Returns the value of attribute func_chain.
-
#ident ⇒ Object
Returns the value of attribute ident.
Instance Method Summary collapse
-
#initialize(db, agg_db) ⇒ Codex
constructor
A new instance of Codex.
- #normal_node(node) {|norm.rewrite_ast(node), norm| ... } ⇒ Object
- #normalize_nodes(nodes) ⇒ Object
- #without_caller(node) ⇒ Object
Constructor Details
#initialize(db, agg_db) ⇒ Codex
Returns a new instance of Codex.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/codex.rb', line 7 def initialize(db,agg_db) # helper procs info = Proc.new do |node| normal_node(node) do |n, norm| norm.pretty_complexity.map { |k,v| v }.reduce(:+) end end func_info = Proc.new do |node| normal_node(node) do |n, norm| norm.pretty_complexity[:send] || 0 end end type = Proc.new { |node| node.is_a?(AST::Node) ? node.type.to_s : node.class.to_s } func_name = Proc.new do |node| if type.call(node.children.first) == "const" node.children.first.children[1].to_s + "." + node.children[1].to_s else node.children[1].to_s end end key = { :type => type } data_core = { :file => Proc.new { |node, f, p| f }, :project => Proc.new { |node, f, p| p }, :line => Proc.new { |node, f, p| node.loc ? node.loc.line : nil }, :info => info, :func_info => func_info, :orig_code => Proc.new { |node, f, p| Unparser.unparse(node) rescue nil }, } combine = { :files => Proc.new { |v| v.map { |x| x[:file] }.uniq }, :file_count => Proc.new { |v| v.map { |x| x[:file] }.uniq.count }, :projects => Proc.new { |v| v.map { |x| x[:project] }.uniq }, :project_count => Proc.new { |v| v.map { |x| x[:project] }.uniq.count }, :orig_code => Proc.new { |v| v.sample(10).map do |x| {:code => x[:orig_code], :file => x[:file], :line => x[:line]} end.uniq }, :count => Proc.new { |v| v.map { |x| x[:orig_code] }.count }, :info => Proc.new { |v| v.first[:info] }, # some process may overwrite :func_info => Proc.new { |v| v.first[:func_info] } } @block = DataNode.new( db, agg_db, Proc.new { |x| x.type == :block}, key.merge({ :func => Proc.new { |x| func_name.call(x.children.first) }, :body => Proc.new { |x| normalize_nodes(x.children.last) }, :arg_size => Proc.new { |x| x.children[1].children.size }, :ret_val => Proc.new do |x| body = x.children.last ret = type.call(body) == "begin" ? body.children.last : body typ = type.call(ret) typ == "send" ? func_name.call(ret) : typ end, :norm_code => Proc.new { |x| normal_node(x) do |x| Unparser.unparse(x.updated(nil, x.children.map.with_index do |y,i| i == 0 ? without_caller(y) : y end)) rescue nil end } }), data_core.merge({ :args => Proc.new { |x| x.children[1].children.map{ |y| y.children[0].to_s }} }), combine.merge({ :args_list => Proc.new { |v| v.map { |x| x[:args] } } }), Proc.new { |db,keys,vals| query = db.where(:type => keys[:type], :func => keys[:func], :ret_val => keys[:ret_val]).first query_count = query.nil? ? 0 : query.count blocks = db.where(:type => keys[:type], :func => keys[:func]).sum(:count) rets = db.where(:type => keys[:type], :ret_val => keys[:ret_val]).sum(:count) if query_count <= 0 { :keys => keys, :message => "We've seen #{keys[:func]} blocks returning #{keys[:ret_val]} only #{query_count.to_s} " + "times, though we've seen #{keys[:func]} blocks #{blocks.to_s} times and #{keys[:ret_val]} " + "returned #{rets.to_s} times." } if blocks > 0 && rets > 0 end } ) @func = DataNode.new( db, agg_db, Proc.new { |x| x.type == :send}, key.merge({ :func => Proc.new { |x| func_name.call(x) }, :norm_code => Proc.new { |x| normal_node(x) { |x| Unparser.unparse(without_caller(x)) rescue nil } }, :sig => Proc.new { |x| x.children.drop(2).map { |y| type.call(y) } } }), data_core, combine, Proc.new { |db,keys,values| query = db.where(keys).first query_count = query.nil? ? 0 : query.count func = db.where(:type => keys[:type], :func => keys[:func]).sort(:count => -1).limit(1).first alt_count = func.nil? ? 0 : func.count { :keys => keys, :message => "Function call #{keys[:norm_code]} has appeared #{query_count.to_s} times, but " + "#{func.norm_code} has appeared #{alt_count.to_s} times." } if alt_count > 10 * (query_count + 1) } ) @func_chain = func = DataNode.new( db, agg_db, Proc.new { |x| x.type == :send && type.call(x.children.first) == "send" }, key.merge({ :type => Proc.new { "func_chain" }, :f1 => Proc.new { |x| func_name.call(x) }, :f2 => Proc.new { |x| func_name.call(x.children.first) } }), data_core.merge({ :info => Proc.new { 0 }, :func_info => Proc.new { 0 } }), combine, Proc.new do |db,keys,data| query = db.where(keys).first if query.nil? || query.count <= 0 fs = [:f1,:f2].map { |f| db.where(:type => "send", :func => keys[f]).size } { :keys => keys, :message => "Function #{keys[:f1]} has appeared #{fs[0].to_s} times " + "and #{keys[:f2]} has appeared #{fs[1].to_s} times, but " + "they haven't appeared together." } unless fs[0] <= 0 || fs[1] <= 0 end end ) @cond = DataNode.new( db, agg_db, Proc.new { |x| x.type == :if }, key.merge({ :norm_code => Proc.new { |x| normalize_nodes(x) }, :cond => Proc.new { |x| normal_node(x) { |n| Unparser.unparse(n.children.first) }}, :iftrue => Proc.new { |x| normal_node(x) { |n| Unparser.unparse(n.children[1]) }}, :iffalse => Proc.new { |x| normal_node(x) { |n| Unparser.unparse(n.children[2]) }}, }), data_core, combine ) @ident = DataNode.new( db, agg_db, Proc.new { |x| [:lvasgn, :ivasgn, :cvasgn, :gvasgn].include?(x.type) }, key.merge({ :type => Proc.new { "ident" }, :ident => Proc.new { |x| x.children.first.to_s }, }), data_core.merge({ :ident_type => Proc.new { |x| type.call(x.children[1]) rescue nil }, :info => Proc.new { 0 }, :func_info => Proc.new { 0 } }), combine.merge({ :ident_types => Proc.new { |v| v.group_by { |y| y[:ident_type] }.map_hash { |x| x.size } } }), Proc.new { |db, keys, data| query = db.where(keys).first if query types = query.ident_types.select { |k,v| ["str","int","float","array","hash"].include? k } types.default = 0 pp types first, second = types.sort_by{ |k,v| v*-1 }.take(2) if first[1] > 10 * (second[1] + 1) { :keys => keys, :message => "The identifier #{keys[:ident]} has appeared #{first[1].to_s} " + "times as #{first[0].to_s}, but only #{types[data[:ident_type]].to_s} " + "times as #{data[:ident_type].to_s}" } unless first[0].to_s == data[:ident_type] end end } ) end |
Instance Attribute Details
#block ⇒ Object
Returns the value of attribute block.
5 6 7 |
# File 'lib/codex.rb', line 5 def block @block end |
#cond ⇒ Object
Returns the value of attribute cond.
5 6 7 |
# File 'lib/codex.rb', line 5 def cond @cond end |
#func ⇒ Object
Returns the value of attribute func.
5 6 7 |
# File 'lib/codex.rb', line 5 def func @func end |
#func_chain ⇒ Object
Returns the value of attribute func_chain.
5 6 7 |
# File 'lib/codex.rb', line 5 def func_chain @func_chain end |
#ident ⇒ Object
Returns the value of attribute ident.
5 6 7 |
# File 'lib/codex.rb', line 5 def ident @ident end |
Instance Method Details
#normal_node(node) {|norm.rewrite_ast(node), norm| ... } ⇒ Object
201 202 203 204 |
# File 'lib/codex.rb', line 201 def normal_node(node) norm = ASTNormalizer.new yield norm.rewrite_ast(node), norm end |
#normalize_nodes(nodes) ⇒ Object
206 207 208 209 210 |
# File 'lib/codex.rb', line 206 def normalize_nodes(nodes) normal_node(nodes) do |n| Unparser.unparse(n) rescue nil end end |
#without_caller(node) ⇒ Object
195 196 197 198 199 |
# File 'lib/codex.rb', line 195 def without_caller(node) node.updated(nil, node.children.map.with_index do |x,i| i == 0 ? nil : x end) end |