Writing toString() for an algebraic data type with parameters in Semmle QL

58 Views Asked by At

After reading about support for algebraic datatypes in QL, I'm trying to define a List type in the lgtm console:

newtype TList =
  TNil()
  or
  TCons(int x,TList xs)

This seems to work. But then I try to define auxiliary classes in order to have a toString() predicate:

class List extends TList {
    abstract string toString();
}
class Nil extends List,TNil {
    override string toString() {
      result = "Nil"
    }
}
class Cons extends List,TCons {
    override string toString() {
        // what to put here?
        // I would like something like result = x.toString() + ':' + xs.toString()
    }
}

And here I'm stumped. I don't know how to refer to the constructor parameters x and xs from within Cons. I tried this.x and this.xs, but it doesn't seem to work.

How can I refer to constructor parameters inside a member predicate?

1

There are 1 best solutions below

0
On BEST ANSWER

Since Cons extends TCons, you can treat this as an instance of TCons anywhere within a member predicate of Cons. This means that you can compare this to a particular instance of TCons, and bind variables to the constructor parameters.

    override string toString() {
        exists(int x, List xs |
            this = TCons(x, xs) and
            result = x.toString() + ":" + xs.toString()
        )
    }

Since you'll likely want to use the constructor parameters in other member predicates of Cons as well, you could instead declare fields to capture the constructor parameters once in the characteristic predicate, and then use them in member predicates:

class Cons extends List, TCons {
    int x;
    List xs;

    Cons() {
        this = TCons(x, xs)
    }

    override string toString() {
        result = x.toString() + ":" + xs.toString()
    }
}

Just a reminder: As the QL handbook page you link to indicates, the syntax for algebraic datatypes in QL is still experimental and subject to change.