Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: reformat once again to not to have the headers

...

Event nameDescription
setup
Called WhenCalled after the type checker finished initialization
Arguments 
Usage
Code Block
setup {
   // initialization
}

Can be used to perform setup of your extension

finish
Called WhenCalled after the type checker completed type checking
Arguments 
Usage
Code Block
finish {
   // finalization block
}

Can be used to perform additional checks after the type checker has finished its job.

unresolvedVariable
Called WhenCalled when the type checker finds an unresolved variable
ArgumentsVariableExpression var
Usage
Code Block
unresolvedVariable { var ->
  if ('foo'==var.name) {
     storeType(var, classNodeFor(List))
     handled = true
  }
}

Allows the developer to help the type checker with user-injected variables.

 

unresolvedProperty
Called WhenCalled when the type checker cannot find a property on the receiver
ArgumentsPropertyExpression pexp
Usage
Code Block
unresolvedProperty { pexp ->
  if (getType(pexp.objectExpression)==classNodeFor(Foo)) {
    storeType(pexp, classNodeFor(String)
    handled = true
}
}

Allows the developer to handle "dynamic" properties

unresolvedAttribute
Called WhenCalled when the type checker cannot find an attribute on the receiver
ArgumentsAttributeExpression aex
Usage
Code Block
unresolvedAttribute { aex ->
  if (getType(aex.objectExpression)==classNodeFor(Foo)) {
    storeType(aex, classNodeFor(String)
    handled = true
}
}

Allows the developer to handle missing attributes

beforeMethodCall
Called WhenCalled before the type checker starts type checking a method call expression
ArgumentsMethodCall call
Usage
Code Block
beforeMethodCall { call ->
   if (call instanceof StaticMethodCall) {
      // ...
      handled = true
   }
}

Allows you to intercept method calls before the type checker performs its own checks. This is useful if you want to replace the default type checking with a custom one for a limited scope. In that case, you must set the handled flag to true, so that the type checker skips its own checks.

afterMethodCall
Called WhenCalled once the type checker has finished type checking a method call
ArgumentsMethodCall call
Usage
Code Block
afterMethodCall { call ->
   // ...
}

Allow you to perform additional checks after the type checker has done its own checks. This is in particular useful if you want to perform the standard type checking tests but also want to ensure additional type safety, for example checking the arguments against each other.

Note that afterMethodCall is called even if you did beforeMethodCall and set the handled flag to true.

onMethodSelection
Called WhenCalled by the type checker when it finds a method appropriate for a method call
Arguments

Expression expr, MethodNode node

Usage
Code Block
onMethodSelection { expr, node ->
   if (node.declaringClass.name == 'Foo') {
      // calling a method on 'Foo', let's perform additional checks!
   }
}

The type checker works by inferring argument types of a method call, then chooses a target method. If it finds one that corresponds, then it triggers this event. It is for example interesting if you want to react on a specific method call, such as entering the scope of a method that takes a closure as argument (as in builders).

Please note that this event may be thrown for various types of expressions, not only method calls (binary expressions for example).

methodNotFound
Called WhenCalled by the type checker when it fails to find an appropriate method for a method call
Arguments

ClassNode receiver, String name, ArgumentListExpression argList, ClassNode[] argTypes, MethodCall call

Usage
Code Block
methodNotFound { receiver, name, argList, argTypes, call ->
    // receiver is the inferred type of the receiver
    // name is the name of the called method
    // argList is the list of arguments the method was called with
    // argTypes is the array of inferred types for each argument
    // call is the method call for which we couldn't find a target method
}

Unlike onMethodSelection, this event is sent when the type checker cannot find a target method for a method call (instance or static). It gives you the chance to intercept the error before it is sent to the user, but also set the target method.

For this, you need to return a list of MethodNode. In most situations, you would either return:

  • an empty list, meaning that you didn't find a corresponding method
  • a list with exactly one element, saying that there's no doubt about the target method
If you return more than one MethodNode, then the compiler would throw an error to the user stating that the method call is ambiguous, listing the possible methods.
For convenience, if you want to return only one method, you are allowed to return it directly instead of wrapping it into a list.
beforeVisitMethod
Called WhenCalled by the type checker before type checking a method body
ArgumentsMethodNode node
Usage
Code Block
beforeVisitMethod { methodNode ->
   handled = true // tell the type checker we will handle the body by ourselves
}

The type checker will call this method before starting to type check a method body. If you want, for example, to perform type checking by yourself instead of letting the type checker do it, you have to set the handled flag to true.

This event can also be used to help defining the scope of your extension (for example, applying it only if you are inside method foo).

afterVisitMethod
Called WhenCalled by the type checker after type checking a method body
ArgumentsMethodNode node
Usage
Code Block
afterVisitMethod { methodNode ->
   // ...
}

Gives you the opportunity to perform additional checks after a method body is visited by the type checker. This is useful if you collect information, for example, and want to perform additional checks once everything has been collected.

beforeVisitClass
Called WhenCalled by the type checker before type checking a class
ArgumentsClassNode node
Usage
Code Block
beforeVisitClass { classNode ->
 // ...
}

If a class is annotated with @TypeChecked, then before visiting the class, this event will be sent. It is also the case for inner classes defined inside a class annotated with @TypeChecked. It can help you define the scope of your extension, or you can even totally replace the visit of the type checker with a custom type checking implementation. For that, you would have to set the handled flag to true.

 

afterVisitClass
Called WhenCalled by the type checker after having finished the visit of a type checked class
ArgumentsClassNode node
Usage
Code Block
afterVisitClass { classNode ->
  // perform additional checks
}

Called for every class being type checked after the type checker finished its work. This includes classes annotated with @TypeChecked and any inner/anonymous class defined in the same class with is not skipped.

incompatibleAssignment
Called WhenCalled when the type checker thinks that an assignment is incorrect, meaning that the right hand side of an assignment is incompatible with the left hand side.
Arguments

ClassNode lhsType, ClassNode rhsType,  Expression assignment

Usage
Code Block
incompatibleAssignment { lhsType, rhsType, expr ->
   if (isBinaryExpression(expr) && isAssignment(expr)) { ... }
}

Gives the developper the ability to handle incorrect assignments. This is for example useful if a class overrides setProperty, because in that case it is possible that assigning a variable of one type to a property of another type is handled through that runtime mechanism.

In that case, you can help the type checker just by telling it that the assignment is valid (using handled set to true).

...