/* Wayne@dfh 4777291
Need to discover variables A & B such that B is a child of A

a) A is declared first
b) A is initialized first
d) B is not assigned to anything at any point
c) B is initialized from A -> A's lifetime is longer than B
*/

function VarTrack(v) {
  this.v = v
  //list of parents
  this.initialized_from = []
}

function recordDecl(v) {
  if(!_state)
    _state = []
  v = new VarTrack(extract(flatten_item(v, true))[0])
  _state.push(v)
  return v
}

function recordOfVar(v) {
  for each (var s in _state)
    if (s.v.id == v.id)
      return s
}

Object.prototype.toString = function () {return uneval(this)}

function recordAsRelatedTo(child, parent) {
  var p = recordOfVar(parent);
  var c = recordOfVar(child);
  print("a)"+child.name + " to " + parent.name + "("+parent.id+"). existing parentcount:"+c.initialized_from+". ")
  // if c is already related to p, keep as is
  if(c.initialized_from.length == 1 && c.initialized_from[0].v.id == parent.id)
    return
//    print("b)"+child.name + " to " + parent.name + ". existing parentcount:"+c.initialized_from.length)

  //this keyword is handled funny because it is never declared
  if(p == undefined && parent.name == "this") {
    p = recordDecl(parent)
  }
  if(p != undefined)
    c.initialized_from.push(p)
}

function process_vars(v) {
  if(v.isDecl && (/^nsCOMPtr/(v.type) || v.isParam && /^class nsI.*\*$/(v.type))) {
    var decl = recordDecl(v);
  } else if (v.isFcall) {
    parent = getVar(v)
    for each (var p in v.params) {
      if(p.name == "already_AddRefed") {
        p.params.map(function (x) {recordAsRelatedTo(x, parent)});
      }
    }
  }
}

function uno_check(vars, state) {
  vars.map(process_vars);
}

var results = []
function path_end(state) {
  // add variables that follow our usage pattern in this path
  for each (var v in state) {
    if(v.initialized_from.length >= 1) {
      if(results.every(function (x) {return x.v.id != v.v.id})) {
        results.push(v)
      }
    }
  }
  // verify that there aren't any stored vars which change the usage pattern
  for each (var r in results) {
    for each (var v in state) {
      if (r.v.id == v.v.id) {
        var vin = v.initialized_from[0]
        if (v.initialized_from.length != 1) {
          //if the vars were unused in this path, that's good..dont discard previous paths
          if (v.initialized_from.length != 0) {
            r.crappy = true
            graph("/tmp/"+v.v.name+".dot")
          }
          // the parent may go out of scope..that's not good
        } else if (vin.v.id != r.initialized_from[0].v.id || vin.initialized_from.length > 1) {
          print(v.initialized_from[0].v.id + " vs " + r.initialized_from[0].v.id)
          r.crappy = true
        }
      }
    }
  }
}

function graph_end() {
  for each (var v in results) {
    if(v.crappy)
      continue;
    print("Candidate found: " + v.v.name + " initialized from " + v.initialized_from[0].v.name)
  }
  results = []
}
