/**
 * A library for reasoning about thread creation events in C#.
 */
import Concurrency

/**
 * A method or constructor which starts a thread based on one of its parameters.
 */
class ThreadStartingCallable extends Callable {
  ThreadStartingCallable() {
    this.(Constructor).getDeclaringType().getQualifiedName() = "System.Threading.Tasks.Task" or
    this.(Method).getQualifiedName() = "System.Threading.Tasks.Task.Run" or
    this.(Constructor).getDeclaringType().getQualifiedName() = "System.Threading.Thread" or
    this.(Method).getQualifiedName() = "System.Threading.Thread.Start" or
    this.(Constructor).getDeclaringType().getQualifiedName().matches("System.Threading.Tasks.Task<%>")
  }
}

/**
 * A callable which may be the starting point of a concurrently executing thread.
 * This is an abstract class; subclasses provide different ways of recognizing
 * such entry points.
 */
abstract class ConcurrentEntryPoint extends Callable { }

/**
 * Methods annotated with the `async` keyword are concurrent entry points.
 */
class AsyncMethod extends ConcurrentEntryPoint {
  AsyncMethod() { this.(Modifiable).isAsync() }
}

/**
 * Lambdas or methods passed into the thread or task creation library functions
 * will execute at the beginning of a new thread.
 */
class LibraryTask extends ConcurrentEntryPoint {
  LibraryTask() {
    exists(Call c, Expr arg |
      c.getTarget() instanceof ThreadStartingCallable and
      arg = c.getAnArgument() |
      this = arg or
      this = arg.(DelegateCreation).getArgument().(CallableAccess).getTarget()
    )
  }
}

/**
 * A method which takes some measures to control concurrent execution can be taken
 * as an indication that the code is expected to run concurrently.
 */
class ConcurrencyAwareMethod extends ConcurrentEntryPoint {
  ConcurrencyAwareMethod() {
    this = any(LockStmt l).getEnclosingCallable() or
    this = any(LockingCall c).getEnclosingCallable()
  }
}
