import javascript
private import semmle.javascript.dataflow.InferredTypes

/**
 * A custom abstract value representing the DOM object `document`.
 */
class Document extends CustomAbstractValueTag {
  Document() { this = "document" }

  override boolean getBooleanValue() { result = true }
  override InferredType getType() { result = TTObject() }
  override predicate isCoercibleToNumber() { none() }
  override PrimitiveAbstractValue toPrimitive() { result.getType() = TTString() }
  override string describe() { result = "document" }
}

/**
 * A custom abstract value representing the DOM object `document.all`,
 * which is falsy.
 *
 * Note that `getType()` isn't quite right, since `typeof document.all === 'undefined'`,
 * but that's fine for the purposes of this test.
 */
class DocumentAll extends CustomAbstractValueTag {
  DocumentAll() { this = "document.all" }

  override boolean getBooleanValue() { result = false }
  override InferredType getType() { result = TTObject() }
  override predicate isCoercibleToNumber() { none() }
  override PrimitiveAbstractValue toPrimitive() { result.getType() = TTString() }
  override string describe() { result = "document.all" }
}

class DocumentRef extends DataFlow::AnalyzedNode, DataFlow::ValueNode {
  override GlobalVarAccess astNode;
  DocumentRef() { astNode.getName() = "document" }
  override AbstractValue getALocalValue() {
    result = DataFlow::AnalyzedNode.super.getALocalValue() or
    result.(CustomAbstractValue).getTag() instanceof Document
  }
}

class DocumentAllRef extends DataFlow::AnalyzedNode, DataFlow::ValueNode {
  override PropAccess astNode;
  DocumentAllRef() { astNode.getPropertyName() = "all" }
  override AbstractValue getAValue() {
    result = DataFlow::AnalyzedNode.super.getAValue()
    or
    astNode.getBase().analyze().getALocalValue().(CustomAbstractValue).getTag() instanceof Document and
    result.(CustomAbstractValue).getTag() instanceof DocumentAll
  }
}

from VariableDeclarator vd, DataFlow::AnalyzedNode init
where init = vd.getInit().analyze()
select vd.getBindingPattern(), init, init.getAValue()
