packages feed

glean-0.1.0.0: glean/schema/source/codemarkup.angle

# Copyright (c) Meta Platforms, Inc. and affiliates.

schema codemarkup.30 {
import src
import code.24
import codemarkup.buck
import codemarkup.csharp
import codemarkup.cxx
import codemarkup.dataswarm
import codemarkup.yaml
import codemarkup.erlang
import codemarkup.fbthrift
import codemarkup.flow
import codemarkup.graphql.1
import codemarkup.hack
import codemarkup.haskell
import codemarkup.java
import codemarkup.kotlin
import codemarkup.lsif
import codemarkup.pp
import codemarkup.python
import codemarkup.scip
import codemarkup.types
import codemarkup.anglelang

# one direct use of python.Declaration, flow.Declaration
import python
import flow

#
# Public API
#

# Public language-agnostic API

# Associates an entity with a symbol kind.
# Note: available for partial indices where EntityInfo is incomplete.
# this is used directly by Glass in Query.searchByLocalName
predicate EntityKind:
  {
    entity: code.Entity,
    kind: codemarkup.types.SymbolKind,
  }
  { Entity, Kind } where
    (codemarkup.python.PythonEntityKind { E, Kind }; { python = E } = Entity) |
    (codemarkup.cxx.CxxEntityKind { E, Kind }; { cxx = E } = Entity) |
    (codemarkup.pp.PpEntityKind { E, Kind }; { pp = E } = Entity) |
    (codemarkup.hack.HackEntityKind { E, Kind }; { hack = E } = Entity) |
    (codemarkup.erlang.ErlangEntityKind { E, Kind }; { erlang = E } = Entity) |
    (codemarkup.lsif.EntityInfo { E, { kind = Kind }}; { lsif = E } = Entity) |
    (codemarkup.scip.EntityInfo { E, { kind = Kind }}; { scip = E } = Entity) |
    (codemarkup.flow.FlowEntityKind { E, Kind }; { flow = E } = Entity) |
    (codemarkup.java.JavaEntityKind { E, Kind }; { java = E } = Entity) |
    (codemarkup.kotlin.KotlinEntityKind { E, Kind }; { kotlin = E } = Entity) |
    (codemarkup.fbthrift.ThriftEntityKind { E, Kind }; { fbthrift = E } = Entity) |
    (codemarkup.buck.BuckEntityKind { E, Kind }; { buck = E } = Entity) |
    (codemarkup.csharp.CSharpEntityKind { E, Kind }; { csharp = E } = Entity) |
    (codemarkup.graphql.GraphQLEntityKind { E, Kind }; { graphql = E } = Entity) ;

# Retrieve information about an entity
predicate EntityInfo:
  {
    entity: code.Entity,
    info: codemarkup.types.SymbolInfo,
  }
  { Entity, Info } where
    ( { kind = Kind, isAbstract = false } = Info;
      ((codemarkup.python.PythonEntityKind { E, Kind };
        { python = E } = Entity) |
       (codemarkup.pp.PpEntityKind { E, Kind };
        { pp = E } = Entity) |
       (codemarkup.erlang.ErlangEntityKind { E, Kind };
        { erlang = E } = Entity) |
       (codemarkup.flow.FlowEntityKind { E, Kind };
        { flow = E } = Entity) |
       (codemarkup.java.JavaEntityKind { E, Kind };
        { java = E } = Entity) |
       (codemarkup.kotlin.KotlinEntityKind { E, Kind };
        { kotlin = E } = Entity) |
       (codemarkup.buck.BuckEntityKind { E, Kind };
        { buck = E } = Entity) |
       (codemarkup.csharp.CSharpEntityKind { E, Kind };
        { csharp = E } = Entity) |
       (codemarkup.graphql.GraphQLEntityKind { E, Kind };
        { graphql = E } = Entity);
      )
    ) |
    (codemarkup.cxx.CxxEntityInfo { E, Info }; { cxx = E } = Entity) |
    (codemarkup.hack.HackEntityInfo { E, Info }; { hack = E } = Entity) |
    (codemarkup.lsif.EntityInfo { E, Info }; { lsif = E } = Entity) |
    (codemarkup.scip.EntityInfo { E, Info }; { scip = E } = Entity);

# Source code digests produced by unspecified hash function
predicate FileEntityDigest:
  { file: src.File
  , entity: code.Entity,
  } -> string

# All entities defined in a src.File and their locations
predicate FileEntityLocations:
  {
    file: src.File,
    location: codemarkup.types.Location,
    entity: code.Entity,
  }
  { File, Location, Entity } where
    codemarkup.types.Location { file = File } = Location;
    ResolveLocation { Location, Entity };

# All entities defined in a src.File, and their kinds
predicate FileEntityKinds:
  {
    file: src.File,
    entity: code.Entity,
    kind: codemarkup.types.SymbolKind,
  }
  { File, Entity, Kind } where
    FileEntityLocations { File, _, Entity };
    EntityKind { Entity, Kind };

predicate FileEntityInfos:
  {
    file: src.File,
    entity: code.Entity,
    info: codemarkup.types.SymbolInfo,
  }
  { File, Entity, Info } where
    FileEntityLocations { File, _, Entity };
    EntityInfo { Entity, Info };

# Map a location to the Entity declared there
predicate ResolveLocation:
  {
    location: codemarkup.types.Location,
    entity: code.Entity,
  }
  { Location, Entity } where
    (codemarkup.hack.HackResolveLocation { Location, E };
     { hack = E } = Entity) |
    (codemarkup.python.PythonResolveLocation { Location, E };
     { python = E } = Entity) |
    (codemarkup.flow.FlowResolveLocation { Location, E };
     { flow = E } = Entity) |
    (codemarkup.cxx.CxxResolveLocation { Location, E };
     { cxx = E } = Entity) |
    (codemarkup.pp.PpResolveLocation { Location, E };
     { pp = E } = Entity) |
    (codemarkup.haskell.HaskellResolveLocation { Location, E };
     { hs = E } = Entity) |
    (codemarkup.buck.BuckResolveLocation { Location, E };
     { buck = E } = Entity) |
    (codemarkup.fbthrift.ThriftResolveLocation { Location, E };
     { fbthrift = E } = Entity) |
    (codemarkup.erlang.ErlangResolveLocation { Location, E };
     { erlang = E } = Entity) |
    (codemarkup.lsif.LsifResolveLocation { Location, E };
     { lsif = E } = Entity) |
    (codemarkup.scip.ScipResolveLocation { Location, E };
     { scip = E } = Entity) |
    (codemarkup.java.JavaResolveLocation { Location, E };
     { java = E } = Entity) |
    (codemarkup.kotlin.KotlinResolveLocation { Location, E };
     { kotlin = E } = Entity) |
    (codemarkup.csharp.CSharpResolveLocation { Location, E };
     { csharp = E } = Entity) |
    (codemarkup.graphql.GraphQLResolveLocation { Location, E };
     { graphql = E } = Entity) |
    (codemarkup.anglelang.AngleResolveLocation { Location, E };
     { angle = E } = Entity);

predicate EntityLocation:
  {
    entity: code.Entity,
    location: codemarkup.types.Location,
  }
  { Entity, Location } where
    (codemarkup.hack.HackEntityLocation { E, Location };
     { hack = E } = Entity) |
    (codemarkup.python.PythonEntityLocation { E, Location };
     { python = E } = Entity) |
    (codemarkup.flow.FlowEntityLocation { E, Location };
     { flow = E } = Entity) |
    (codemarkup.cxx.CxxEntityLocation { E, Location };
     { cxx = E } = Entity) |
    (codemarkup.pp.PPEntityLocation { E, Location };
     { pp = E } = Entity) |
    (codemarkup.haskell.HaskellEntityLocation { E, Location };
     { hs = E } = Entity) |
    (codemarkup.buck.BuckEntityLocation { E, Location };
     { buck = E } = Entity) |
    (codemarkup.fbthrift.ThriftEntityLocation { E, Location };
     { fbthrift = E } = Entity) |
    (codemarkup.erlang.ErlangEntityLocation { E, Location };
     { erlang = E } = Entity) |
    (codemarkup.lsif.LsifEntityLocation { E, Location };
     { lsif = E } = Entity) |
    (codemarkup.scip.ScipEntityLocation { E, Location };
     { scip = E } = Entity) |
    (codemarkup.java.JavaEntityLocation { E, Location };
     { java = E } = Entity) |
    (codemarkup.kotlin.KotlinEntityLocation { E, Location };
     { kotlin = E } = Entity) |
    (codemarkup.csharp.CSharpEntityLocation { E, Location };
     { csharp = E } = Entity) |
    (codemarkup.graphql.GraphQLEntityLocation { E, Location };
     { graphql = E } = Entity) |
    (codemarkup.anglelang.AngleEntityLocation { E, Location };
     { angle = E } = Entity);

# Maps a generated entity to its source definition
predicate GeneratedEntityToIdlEntity:
  {
    entity: code.Entity,
    idlEntity: code.IdlEntity,
  }
  { Entity, IdlEntity } where
    (codemarkup.hack.HackEntityIdl { E, IdlEntity };
     { hack = E } = Entity) |
    (codemarkup.cxx.CxxEntityIdl { E, IdlEntity };
     { cxx = E } = Entity)

# generic entities are either
#  - plainEntity: regular entities within the same db as the source file
#  - xlang entities for which target location may not be known (need to be
#    resolved client side)
type GenericEntity = {
  plainEntity: { xref: codemarkup.types.XRefLocation, entity : code.Entity } |
  xlangEntity: { source : codemarkup.types.RangeSpan, entity : code.IdlEntity } |
  xlangSymbol: { source : codemarkup.types.RangeSpan, symbol : code.SymbolId }
}

# Finding xrefs to generic entities. Same thing as
# FileEntityXRefLocations, but allows references to cross-language entities
# for which we can't compute # the target span directly (see code.IdlEntity)
predicate FileXRefsGenericEntities: {
    file: src.File,
    genEntity: GenericEntity
} { File, GenEntity } where
  (codemarkup.hack.HackFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { hack = E } } } = GenEntity ) |
  (codemarkup.hack.HackFileEntityXRefLocations { File, { source = Source }, E };
   codemarkup.hack.HackEntityIdl { E, IdlEntity };
   { xlangEntity = { source = Source, entity = IdlEntity } } = GenEntity ) |
  (codemarkup.flow.FlowFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { flow = E } } } = GenEntity ) |
  (codemarkup.python.PythonFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { python = E } } } = GenEntity ) |
  (codemarkup.cxx.CxxFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { cxx = E } } }  = GenEntity ) |
  (codemarkup.pp.PpFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { pp = E } } } = GenEntity ) |
  (codemarkup.haskell.HaskellFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { hs = E } } } = GenEntity ) |
  (codemarkup.buck.BuckFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { buck = E } } } = GenEntity) |
  (codemarkup.fbthrift.ThriftFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { fbthrift = E } } } = GenEntity) |
  (codemarkup.erlang.ErlangFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { erlang = E } } } = GenEntity) |
  (codemarkup.lsif.LsifFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { lsif = E } } } = GenEntity)
  | ( codemarkup.scip.ScipFileEntityXRefLocations { File, XRef, E }
      ; { plainEntity = { xref = XRef, entity = { scip = E } } } = GenEntity )
  | ( codemarkup.scip.FileXLangSymbolRefs { File, Source, Symbol }
      ; { xlangSymbol = { source = Source, symbol = { scip = Symbol } } } = GenEntity )
  |
  (codemarkup.java.JavalFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { java = E } } } = GenEntity) |
  (codemarkup.kotlin.KotlinFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { kotlin = E } } } = GenEntity) |
  (codemarkup.csharp.CSharpFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { csharp = E } } } = GenEntity) |
  (codemarkup.graphql.GraphQLFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { graphql = E } } } = GenEntity) |
  (codemarkup.dataswarm.DataswarmFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { dataswarm = E } } } = GenEntity) |
  (codemarkup.yaml.YamlFileEntityXLangXRefLocations { File, Source, E };
  { xlangEntity = { source = Source, entity = E } } = GenEntity) |
  (codemarkup.anglelang.AngleFileEntityXRefLocations { File, XRef, E };
  { plainEntity = { xref = XRef, entity = { angle = E } } } = GenEntity)

predicate SymbolToEntity:
  {
    symbol: code.SymbolId,
    entity: code.Entity,
  }
  { Symbol, Entity } where
  { cxx = CxxSymbol } = Symbol
    ; codemarkup.cxx.SymbolToEntity { CxxSymbol, CxxEntity }
    ; { cxx = CxxEntity } = Entity;

# Finding xrefs. All references in a file and their targets
predicate FileEntityXRefLocations:
  {
    file: src.File,
    xref: codemarkup.types.XRefLocation,
    entity: code.Entity,
  }
  { File, XRef, Entity } where
    (codemarkup.hack.HackFileEntityXRefLocations { File, XRef, E };
     { hack = E } = Entity) |
    (codemarkup.flow.FlowFileEntityXRefLocations { File, XRef, E };
     { flow = E } = Entity) |
    (codemarkup.python.PythonFileEntityXRefLocations { File, XRef, E };
     { python = E } = Entity) |
    (codemarkup.cxx.CxxFileEntityXRefLocations { File, XRef, E };
     { cxx = E } = Entity) |
    (codemarkup.pp.PpFileEntityXRefLocations { File, XRef, E };
     { pp = E } = Entity) |
    (codemarkup.haskell.HaskellFileEntityXRefLocations { File, XRef, E };
     { hs = E } = Entity) |
    (codemarkup.buck.BuckFileEntityXRefLocations { File, XRef, E };
     { buck = E } = Entity) |
    (codemarkup.fbthrift.ThriftFileEntityXRefLocations { File, XRef, E };
     { fbthrift = E } = Entity) |
    (codemarkup.erlang.ErlangFileEntityXRefLocations { File, XRef, E };
     { erlang = E } = Entity) |
    (codemarkup.lsif.LsifFileEntityXRefLocations { File, XRef, E };
     { lsif = E } = Entity) |
    (codemarkup.scip.ScipFileEntityXRefLocations { File, XRef, E };
     { scip = E } = Entity) |
    (codemarkup.java.JavalFileEntityXRefLocations { File, XRef, E };
     { java = E } = Entity) |
    (codemarkup.kotlin.KotlinFileEntityXRefLocations { File, XRef, E };
     { kotlin = E } = Entity) |
    (codemarkup.csharp.CSharpFileEntityXRefLocations { File, XRef, E };
     { csharp = E } = Entity) |
    (codemarkup.graphql.GraphQLFileEntityXRefLocations { File, XRef, E };
     { graphql = E } = Entity) |
    (codemarkup.dataswarm.DataswarmFileEntityXRefLocations { File, XRef, E };
     { dataswarm = E } = Entity) |
     (codemarkup.anglelang.AngleFileEntityXRefLocations { File, XRef, E };
     { angle = E } = Entity);

# Xrefs without the target location. This can be useful in cases
# where we don't have a target location, but we don't need it. This
# happens when indexing a subset of Hack files in a repo, for example.
predicate FileEntityXRefRangeSpans:
  {
    file: src.File,
    location: codemarkup.types.RangeSpan,
    entity: code.Entity,
  }
  { File, RangeSpan, Entity } where
    ( codemarkup.hack.HackFileEntityXRefSpans { File, Span, E };
      { hack = E } = Entity;
      { span = Span } = RangeSpan) |
    (
      (codemarkup.flow.FlowFileEntityXRefLocations { File, XRef, E };
       { flow = E } = Entity) |
      (codemarkup.python.PythonFileEntityXRefLocations { File, XRef, E };
       { python = E } = Entity) |
      (codemarkup.cxx.CxxFileEntityXRefLocations { File, XRef, E };
       { cxx = E } = Entity) |
      (codemarkup.haskell.HaskellFileEntityXRefLocations { File, XRef, E };
       { hs = E } = Entity) |
      (codemarkup.buck.BuckFileEntityXRefLocations { File, XRef, E };
       { buck = E } = Entity) |
      (codemarkup.fbthrift.ThriftFileEntityXRefLocations { File, XRef, E };
       { fbthrift = E } = Entity) |
      (codemarkup.erlang.ErlangFileEntityXRefLocations { File, XRef, E };
       { erlang = E } = Entity) |
      (codemarkup.lsif.LsifFileEntityXRefLocations { File, XRef, E };
       { lsif = E } = Entity) |
      (codemarkup.scip.ScipFileEntityXRefLocations { File, XRef, E };
       { scip = E } = Entity) |
      (codemarkup.java.JavalFileEntityXRefLocations { File, XRef, E };
       { java = E } = Entity) |
      (codemarkup.kotlin.KotlinFileEntityXRefLocations { File, XRef, E };
       { kotlin = E } = Entity) |
      (codemarkup.csharp.CSharpFileEntityXRefLocations { File, XRef, E };
       { csharp = E } = Entity);
      { source = RangeSpan} = XRef
    )

# Finding xrefs. All references in a file, and their kinds
predicate FileEntityXRefKinds:
  {
    file: src.File,
    entity: code.Entity,
    kind: codemarkup.types.SymbolKind,
  }
  { File, Entity, Kind } where
    FileEntityXRefLocations { File, _, Entity };
    EntityKind { Entity, Kind };

predicate FileEntityXRefInfos:
  {
    file: src.File,
    entity: code.Entity,
    info: codemarkup.types.SymbolInfo,
  }
  { File, Entity, Info } where
    FileEntityXRefLocations { File, _, Entity };
    EntityInfo { Entity, Info };

# Find references to a language entity
# (deprecated in favor of more general codemarkup.EntityReferences)
predicate EntityUses:
  {
    target: code.Entity,
    file: src.File,
    span: src.ByteSpan
  }
  {Entity, File, Span} where
    codemarkup.EntityReferences { Entity, File, { span = Span }}

# Find references to a language entity (same as EntityUses but with RangeSpans)
predicate EntityReferences:
  {
    target: code.Entity,
    file: src.File,
    range: codemarkup.types.RangeSpan
  }
  {Entity, File, RangeSpan} where
  (
    (codemarkup.hack.HackEntityUses { E, File, Span };
     { hack = E } = Entity) |
    (codemarkup.flow.FlowEntityUses { E, File, Span };
     { flow = E } = Entity) |
    (codemarkup.python.PythonEntityUses { E, File, Span };
     { python = E } = Entity) |
    (codemarkup.cxx.CxxEntityUses { E, File, Span };
     { cxx = E } = Entity) |
    (codemarkup.haskell.HaskellEntityUses { E, File, Span };
     { hs = E } = Entity) |
    (codemarkup.buck.BuckEntityUses { E, File, Span };
     { buck = E } = Entity) |
    (codemarkup.erlang.ErlangEntityUses { E, File, Span };
     { erlang = E } = Entity) |
    (codemarkup.java.JavaEntityUses { E, File, Span };
     { java = E } = Entity) |
    (codemarkup.kotlin.KotlinEntityUses { E, File, Span };
     { kotlin = E } = Entity) |
    (codemarkup.pp.PpEntityUses { E, File, Span };
     { pp = E } = Entity) |
    (codemarkup.graphql.GraphQLEntityUses { E, File, Span };
    { graphql = E } = Entity);
    { span = Span } = RangeSpan;
  ) | (
    codemarkup.lsif.LsifEntityUses { E, File, Range };
    { lsif = E } = Entity;
    { range = Range } = RangeSpan;
  ) | (
    codemarkup.scip.ScipEntityUses { E, File, Range };
    { scip = E } = Entity;
    { range = Range } = RangeSpan;
  ) | (
    codemarkup.fbthrift.FbthriftEntityUses { E, File, Range };
    { fbthrift = E } = Entity;
    { range = Range } = RangeSpan;
  ) | (
    codemarkup.anglelang.AngleEntityUses { E, File, Span };
    { span = Span } = RangeSpan;
    { angle = E } = Entity;
  ) | (
    codemarkup.hack.HackIdlEntityUses { Entity, File, Span };
    { span = Span } = RangeSpan;
  ) | (
    codemarkup.cxx.CxxIdlEntityUses { Entity, File, Span };
    { span = Span } = RangeSpan;
  );

# Information for all calls, organized by file and callee_span
predicate FileCall :
  {
    file: src.File,
    span: src.ByteSpan,
    arguments: [code.CallArgument],
    callee_xref: maybe code.Entity,
    dispatch_arg: maybe code.CallArgument,
    receiver_type: maybe code.Entity,
  } {File, Span, CodeArgs, Callee, DispatchArg, StaticType} where
  ( (codemarkup.python.PythonFileCall{File, Span, CodeArgs};
     nothing = Callee;
     nothing = DispatchArg;
     nothing = StaticType)
  | codemarkup.hack.HackFileCall{File, Span, CodeArgs, Callee, DispatchArg, StaticType}
  )


# Look up entities that reference the given target.
# This can be used, for example, to find calling functions
# (by narrowing the results using `FileEntityKinds`).
predicate ReferencingEntity :
  {
    target: code.Entity,
    referrer: code.Entity,
    reference_file: src.File,
    reference_range: codemarkup.types.RangeSpan,
    referrer_location: codemarkup.types.Location,
  }
  { Target, Referrer, File, Span, RLocation } where
    EntityReferences { Target, File, Span };
    FileEntityLocations { File, RLocation, Referrer };
    { location = RSpan } = RLocation;
    codemarkup.types.RangeSpanContains { RSpan, Span }

# Lookup entities referring to the given target
# Less general version of ReferencingEntity that omits the reference range
predicate EntitySource:
  {
    target: code.Entity,
    source: code.Entity,
  }
  { Target, Referrer} where
    ( {cxx = CxxTarget} = Target ;
      codemarkup.cxx.CxxEntitySource { CxxTarget, CxxReferrer};
      {cxx = CxxReferrer} = Referrer
    ) | (
      {hack = HackTarget} = Target ;
      codemarkup.hack.HackEntitySource { HackTarget, HackReferrer};
      {hack = HackReferrer} = Referrer

    )


#
# Annotations. decorates, attributes or other symbols/strings associated with
# symbols. e.g. @nullsafe or <<__Memoize>>
#

predicate EntityToAnnotations :
  {
    entity: code.Entity,
    annotations : code.Annotations,
  }
  { Entity, Annotations } where
    ( { cxx = Ent } = Entity;
      codemarkup.cxx.CxxAnnotation { Ent, Anns };
      { cxx = Anns } = Annotations
    ) | (
      { hack = Ent } = Entity;
      codemarkup.hack.HackAnnotation { Ent, Anns };
      { hack = Anns } = Annotations
    ) | (
      { python = Ent } = Entity;
      codemarkup.python.PythonAnnotation { Ent, Anns };
      { python = Anns } = Annotations
    ) | (
      { java = Ent } = Entity;
      codemarkup.java.JavaAnnotation { Ent, Anns };
      { java = Anns } = Annotations
    );

#
# Visibility and other keywords
#

predicate EntityVisibility : code.Entity -> codemarkup.types.Visibility
  Entity -> Visibility where
    ( { cxx = E } = Entity;
      codemarkup.cxx.CxxVisibility { E, Visibility }
    ) | (
      { hack = E } = Entity;
      codemarkup.hack.HackVisibility { E, Visibility }
    ) | (
      { python = E } = Entity;
      codemarkup.python.PythonVisibility { E, Visibility }
    ) | (
      { java = E } = Entity;
      codemarkup.java.JavaVisibility { E, Visibility }
    )

# Language keywords like `static` or `final`, or `mutable` ..
predicate EntityModifiers:
  {
    entity: code.Entity,
    modifiers: codemarkup.types.Modifiers
  } { Entity, Modifiers } where
    ( { hack = E } = Entity;
      codemarkup.hack.HackModifiers { E, Modifiers }
    ) | (
      { cxx = E } = Entity;
      codemarkup.cxx.CxxModifiers { E, Modifiers }
    ) | (
      { python = E } = Entity;
      codemarkup.python.PythonModifiers { E, Modifiers }
    ) | (
      { java = E } = Entity;
      codemarkup.java.JavaModifiers { E, Modifiers }
    );

# Entities that represent the canonical definition of the thing. Does
# not hold for declarations in C++, imports in Python, or imports in JS
predicate EntityIsDefinition: code.Entity
  ({ cxx = D } where { defn = _ } = D) |
  ({ python = { decl = D }} where D : python.Declaration; !({ imp = _ } = D)) |
  ({ hack = _ }) |
  ({ pp = _ }) |
  ({ erlang = _ }) |
  ({ lsif = _ }) |
  ({ scip = _ }) |
  ({ flow = { decl = { localDecl = D }}} where
     D : flow.Declaration;
     !(flow.ImportDeclaration { declaration = D })) |
  ({ buck = _ }) |
  ({ java = _ }) |
  ({ fbthrift = _ }) |
  ({ kotlin = _ })

# If an entity is a declaration, try to find its definition, which
# might be in a different file. There can be multiple definitions.
# If `entity` has no separate definition, `definition == entity`.
predicate FindEntityDefinition:
  {
    entity: code.Entity,
    definition: code.Entity
  }
  { Decl, Defn } where
    if (
      { cxx = E } = Decl;
    ) then (
      codemarkup.cxx.CxxFindDefinitionOfEntity { E, CxxDefn };
      { cxx = CxxDefn } = Defn
    ) else (
      Decl = Defn
    )

#
# Relations todo to code.search.*
#

# A child `extends` a parent
predicate ExtendsParentEntity :
  {
    child: code.Entity,
    parent: code.Entity
  }
  { Child, Parent } where
    ( { hack = C } = Child;
      codemarkup.hack.HackExtendsParentEntity { C, P };
      { hack = P } = Parent
    ) | (
      { cxx = C } = Child;
      codemarkup.cxx.CxxExtendsParentEntity { C, P };
      { cxx = P } = Parent
    ) | (
      { python = C } = Child;
      codemarkup.python.PythonExtendsParentEntity { C, P };
      { python = P } = Parent
    ) | (
      { fbthrift = C } = Child;
      codemarkup.fbthrift.ThriftExtendsParentEntity { C, P };
      { fbthrift = P } = Parent
    ) | (
      { java = C } = Child;
      codemarkup.java.JavaExtendsParentEntity { C, P };
      { java = P } = Parent
    ) | (
      { kotlin = C } = Child;
      codemarkup.kotlin.KotlinExtendsParentEntity { C, P };
      { kotlin = P } = Parent
    )

# This implements the ExtendsParentEntity relation, but for "interesting"
# parents only. I.e. with this you are allowed to implement server-side
# filtering of containers we wouldn't include as they are boring. E.g. because
# they are tests, code gen'd or verbose.
predicate ExtendsParentEntityConcise :
  {
    child: code.Entity,
    parent: code.Entity
  }
  { Child, Parent } where
    if ( { hack = C } = Child )
    then (
      codemarkup.hack.HackExtendsParentEntityConcise { C, P };
      { hack = P } = Parent;
    ) else ( # generic implementation
      ExtendsParentEntity { Child, Parent };
    )

# A parent `is extended by` a child
predicate ExtendsChildEntity :
  {
    parent: code.Entity,
    child: code.Entity
  }
  { Parent, Child } where
    ( { hack = P } = Parent;
      codemarkup.hack.HackExtendsChildEntity { P, C };
      { hack = C } = Child
    ) | (
      { cxx = P } = Parent;
      codemarkup.cxx.CxxExtendsChildEntity { P, C };
      { cxx = C } = Child
    ) | (
      { python = P } = Parent;
      codemarkup.python.PythonExtendsChildEntity { P, C };
      { python = C } = Child
    ) | (
      { fbthrift = P } = Parent;
      codemarkup.fbthrift.ThriftExtendsChildEntity { P, C };
      { fbthrift = C } = Child
    ) | (
      { java = P } = Parent;
      codemarkup.java.JavaExtendsChildEntity { P, C };
      { java = C } = Child
    )

# A child `is contained by` a parent
predicate ContainsParentEntity :
  {
    child: code.Entity,
    parent: code.Entity,
  }
  { Child, Parent } where
    ( { hack = C } = Child;
      codemarkup.hack.HackContainsParentEntity { C, P };
      { hack = P } = Parent
    ) | (
      { cxx = C } = Child;
      codemarkup.cxx.CxxContainsParentEntity { C, P };
      { cxx = P } = Parent
    ) | (
      { python = C } = Child;
      codemarkup.python.PythonContainsParentEntity { C, P };
      { python = P } = Parent
    ) | (
      { flow = C } = Child;
      codemarkup.flow.FlowContainsParentEntity { C, P };
      { flow = P } = Parent
    ) | (
      { fbthrift = C } = Child;
      codemarkup.fbthrift.ThriftContainsParentEntity { C, P };
      { fbthrift = P } = Parent
    ) | (
      { java = C } = Child;
      codemarkup.java.JavaContainsParentEntity { C, P };
      { java = P } = Parent
    ) | (
      { kotlin = C } = Child;
      codemarkup.kotlin.KotlinContainsParentEntity { C, P };
      { kotlin = P } = Parent
    ) | (
      { hs = C } = Child;
      codemarkup.haskell.HaskellContainsParentEntity { C, P };
      { hs = P } = Parent
    )

# A parent `contains` a child
predicate ContainsChildEntity :
  {
    parent: code.Entity,
    child: code.Entity
  }
  { Parent, Child } where
    ( { hack = P } = Parent;
      codemarkup.hack.HackContainsChildEntity { P, C };
      { hack = C } = Child
    ) | (
      {cxx = P} = Parent;
      codemarkup.cxx.CxxContainsChildEntity { P, C };
      { cxx = C } = Child
    ) | (
      { python = P } = Parent;
      codemarkup.python.PythonContainsChildEntity { P, C };
      { python = C } = Child
    ) | (
      { flow = P } = Parent;
      codemarkup.flow.FlowContainsChildEntity { P, C };
      { flow = C } = Child
    ) | (
      { fbthrift = P } = Parent;
      codemarkup.fbthrift.ThriftContainsChildEntity { P, C };
      { fbthrift = C } = Child
    ) | (
      { java = P } = Parent;
      codemarkup.java.JavaContainsChildEntity { P, C };
      { java = C } = Child
    ) | (
      { kotlin = P } = Parent;
      codemarkup.kotlin.KotlinContainsChildEntity { P, C };
      { kotlin = C } = Child
    ) | (
      { hs = P } = Parent;
      codemarkup.haskell.HaskellContainsChildEntity { P, C };
      { hs = C } = Child
    )

#
# Generic relational search API, so you can call different searches
# in a uniform way
#

# useful newtypes for a bit of client-side type safety in relational queries
type ParentEntity = {
  parent: code.Entity,
  location: codemarkup.types.Location
}
type ChildEntity = {
  child: code.Entity,
  location: codemarkup.types.Location
}
# hide different relation types and directions under a search flag
type RelationType = enum {
  ExtendsParentOfChild |
  ExtendsChildOfParent |
  ContainsChildOfParent |
  ContainsParentOfChild |
  # Trait And Interface Requirements, Hack specific
  # https://docs.hhvm.com/hack/traits-and-interfaces/trait-and-interface-requirements
  RequireExtendsParentOfChild |
  RequireImplementsParentOfChild |
  RequireClassParentOfChild |
}

# we can prune some of the relationships by hiding "uninteresting" results
type SearchStyle = enum {
  ShowAll |
  HideUninteresting | # perhaps us to drop language specific uninteresting cases
}


# given a container entity, get all its (located) inherited member, including origin location,
predicate SearchInheritedEntities:
  {
      base: code.Entity,
      parent: ParentEntity,
      child: ChildEntity,
      style: SearchStyle, # all results or hide uninteresting
  }
   { CE, { parent = PE, location = PELoc } , { child = ME, location = MELoc }, Style } where
    codemarkup.hack.HackInheritedEntities { container = HCD, member = HD };
    { hack = { decl = { container = HCD } } } = CE : code.Entity;
    { hack = { decl = HD } } = ME : code.Entity;
    codemarkup.hack.HackContainsParentEntity { child = { decl = HD }, parent = Parent };
    { hack = Parent } = PE : code.Entity;
    codemarkup.EntityLocation {PE, PELoc};
    codemarkup.EntityLocation {ME, MELoc};
    ( ( HideUninteresting = Style;
      !(codemarkup.hack.EntityHasHideFromDocsAttr Parent)
      ) | (
        ShowAll = Style
      ) )

# find parent/child semantic relationships
predicate SearchRelatedEntities:
  {
    query: RelationType, # extends or contains, parent or child direction
    parent: ParentEntity,
    child: ChildEntity,
    style: SearchStyle, # all results or hide uninteresting
  }
  { Query, {parent = P, location = PLoc}, {child = C, location = CLoc}, Style } where
    ( ShowAll = Style;
      ( ExtendsParentOfChild = Query;
        ExtendsParentEntity { C, P }) | # child key
      ( ExtendsChildOfParent = Query;
        ExtendsChildEntity { P, C } ) | # parent key
      ( ContainsParentOfChild = Query;
        ContainsParentEntity { C, P }) | # child key
      ( ContainsChildOfParent = Query;
        ContainsChildEntity { P, C }) | # parent key
      ( RequireExtendsParentOfChild = Query;
        { hack = HC } = C;
        { hack = HP } = P;
        codemarkup.hack.HackRequiredConstraint { HC, extends_, HP }) |
      ( RequireImplementsParentOfChild = Query;
        { hack = HC } = C;
        { hack = HP } = P;
        codemarkup.hack.HackRequiredConstraint { HC, implements_, HP }) |
      ( RequireClassParentOfChild = Query;
        { hack = HC } = C;
        { hack = HP } = P;
        codemarkup.hack.HackRequiredConstraint { HC, class_, HP });
    ) | (
      HideUninteresting = Style; # only one hide unteresting relation style atm
      ExtendsParentOfChild = Query;
      ExtendsParentEntityConcise { C, P }
    );
    codemarkup.EntityLocation {C, CLoc};
    codemarkup.EntityLocation {P, PLoc};

#
# Expanded version of codemarkup.EntityDocumentation that knows about
# docs stored in the index itself. Indexers are still required to support
# the span/file format. Optionally, they may provide pre-rendered comments in
# markdown format
#
predicate EntityComments:
  {
    entity : code.Entity,
    file : src.File,
    span : src.ByteSpan,
    text : maybe string,
  }
  { Entity, File, Span, Text } where
    ( { cxx = Decl } = Entity;
      codemarkup.cxx.CxxEntityDocumentation { Decl, File, Span };
      nothing = Text
    ) | (
      { hack = Decl } = Entity;
      codemarkup.hack.HackEntityDocumentation { Decl, File, Span };
      nothing = Text
    ) | (
      { flow = Decl } = Entity;
      codemarkup.flow.FlowEntityDocumentation { Decl, File, Span };
      nothing = Text
    ) | (
      { python = Decl } = Entity;
      codemarkup.python.PythonEntityComments { Decl, File, Span, Text }
    ) | (
      { java = Decl } = Entity;
      codemarkup.java.JavaEntityDocumentation { Decl, File, Span };
      nothing = Text
    ) | (
      { erlang = Decl } = Entity;
      codemarkup.erlang.ErlangEntityDocumentation { Decl, File, Span, Text}
    ) | (
      { fbthrift = Decl } = Entity;
      codemarkup.fbthrift.FbthriftEntityDocumentation { Decl, File, Span };
      nothing = Text
    )

# Find module name as string given entity.
# No result if the entity is a non-module.
predicate EntityModuleName:
  {
    entity: code.Entity,
    name: string,
  }
  { Entity, Name } where
    ( { hack = Decl } = Entity;
      codemarkup.hack.HackEntityModuleName { Decl, Name }
    ) | (
      { flow = Decl } = Entity;
      codemarkup.flow.FlowEntityModuleName { Decl, Name }
    ) | (
      { python = Decl } = Entity;
      codemarkup.python.PythonEntityModuleName { Decl, Name }
    ) | (
      { lsif = Decl } = Entity;
      codemarkup.lsif.LsifEntityModuleName { Decl, Name }
    )

# Identifies indexed files
predicate IndexedFile: src.File
   File where
    codemarkup.cxx.CxxDataAvailable File |
    codemarkup.EntityDataAvailable File |
    # All Yaml files are indexable, even though they don't
    # contain entities
    codemarkup.yaml.YamlDataAvailable File

# Identifies files with indexed entities.
# You should not use this, instead use codemarkup.IndexedFile
predicate EntityDataAvailable:  src.File
    File where
      src.File _ = File; # bind File as demanded by the schema consistency check
      # double negation is used to check for existence
      # (even if the Angle compiler could notice and optimize)
      !(!(codemarkup.FileEntityLocations { file = File } |
          codemarkup.FileEntityXRefRangeSpans {file = File }
        ))

# end
}