@@ -17,7 +17,7 @@ For example, to declare a module ``M`` as private, you could use:
1717
1818 Note that some annotations act on an entity itself, whilst others act on a particular *name * for the entity:
1919 - Act on an **entity **: ``abstract ``, ``bindingset ``, ``cached ``, ``extensible ``, ``external ``, ``language ``,
20- ``override ``, ``pragma ``, and ``transient ``
20+ ``overlay ``, `` override ``, ``pragma ``, and ``transient ``
2121 - Act on a **name **: ``additional ``, ``deprecated ``, ``final ``, ``library ``, ``private ``, and ``query ``
2222
2323For example, if you annotate an entity with ``private ``, then only that particular name is
@@ -502,6 +502,181 @@ The ``bindingset`` annotation takes a comma-separated list of variables.
502502 For more information, see ":ref: `predicate-binding `."
503503- When you annotate a class, each variable must be ``this `` or a field in the class.
504504
505+ .. _overlay :
506+
507+ Overlay annotations
508+ ===================
509+
510+ Overlay annotations control how predicates behave during **overlay evaluation **, a feature
511+ that enables efficient incremental analysis by dividing QL code into *local * and *global *
512+ parts. During overlay evaluation, local predicates are evaluated separately on "base" (cached
513+ from previous analysis) and "overlay" (newly changed files) data. When a global predicate
514+ calls a local predicate, results from both the base and overlay evaluations are combined,
515+ with stale base results filtered out through a process called "discarding."
516+
517+ Overlay evaluation is primarily used internally by GitHub Code Scanning to speed up
518+ pull request analysis. Most QL developers do not need to use these annotations directly,
519+ but understanding them can help resolve compilation errors that may occur when overlay
520+ support is enabled for a language.
521+
522+ .. note ::
523+
524+ Overlay annotations only affect evaluation when overlay compilation is enabled for a
525+ QL pack (via ``compileForOverlayEval: true `` in ``qlpack.yml ``) and the evaluator is
526+ running in overlay mode. Otherwise, these annotations are validated but have no effect
527+ on evaluation.
528+
529+ ``overlay[local] ``
530+ ------------------
531+
532+ **Available for **: |modules |, |classes |, |algebraic datatypes |, |type unions |, |characteristic predicates |, |member predicates |, |non-member predicates |
533+
534+ The ``overlay[local] `` annotation declares that a predicate is local. Local predicates are
535+ evaluated separately on base and overlay data and may only depend on other local predicates.
536+ The compiler reports an error if a local predicate depends on a global predicate.
537+
538+ .. code-block :: ql
539+
540+ // All dependencies are database extensionals, so this can be local
541+ overlay[local]
542+ predicate stmtInFile(@stmt s, string path) {
543+ exists(@file f, @location loc |
544+ hasLocation(s, loc) and
545+ locations_default(loc, f, _, _, _, _) and
546+ files(f, path)
547+ )
548+ }
549+
550+ ``overlay[local?] ``
551+ -------------------
552+
553+ **Available for **: |modules |, |classes |, |algebraic datatypes |, |type unions |, |characteristic predicates |, |member predicates |, |non-member predicates |
554+
555+ The ``overlay[local?] `` annotation declares that a predicate should be local if all of
556+ its dependencies are local, and global otherwise. This is particularly useful in
557+ parameterized modules, where different instantiations may have different locality
558+ depending on the module parameters.
559+
560+ .. code-block :: ql
561+
562+ // Locality depends on whether Expr.getType() and Type.getName() are local
563+ overlay[local?]
564+ predicate exprTypeName(Expr e, string name) {
565+ name = e.getType().getName()
566+ }
567+
568+ ``overlay[global] ``
569+ -------------------
570+
571+ **Available for **: |modules |, |classes |, |algebraic datatypes |, |type unions |, |characteristic predicates |, |member predicates |, |non-member predicates |
572+
573+ The ``overlay[global] `` annotation explicitly declares that a predicate is global. This
574+ is the default behavior, so this annotation is typically used to override an inherited
575+ ``overlay[local] `` or ``overlay[local?] `` annotation from an enclosing module or class.
576+ See `Annotation inheritance `_ for an example.
577+
578+ ``overlay[caller] ``
579+ -------------------
580+
581+ **Available for **: |modules |, |classes |, |algebraic datatypes |, |type unions |, |characteristic predicates |, |member predicates |, |non-member predicates |
582+
583+ The ``overlay[caller] `` annotation declares that the locality of a predicate depends on
584+ its caller. The compiler may internally duplicate the predicate, creating separate local
585+ and global versions. Local callers use the local version; global callers use the global
586+ version.
587+
588+ .. code-block :: ql
589+
590+ overlay[caller]
591+ predicate utilityPredicate(int x) {
592+ x in [1..100]
593+ }
594+
595+ ``overlay[caller?] ``
596+ --------------------
597+
598+ **Available for **: |modules |, |classes |, |algebraic datatypes |, |type unions |, |characteristic predicates |, |member predicates |, |non-member predicates |
599+
600+ The ``overlay[caller?] `` annotation is like ``overlay[caller] ``, but only applies if none
601+ of the predicate's dependencies are global. If any dependency is global, the predicate
602+ becomes global regardless of its callers, and calling it from a local predicate will
603+ result in a compilation error. Like ``overlay[local?] ``, this is useful in parameterized
604+ modules where locality may vary between instantiations.
605+
606+ ``overlay[discard_entity] ``
607+ ---------------------------
608+
609+ **Available for **: |non-member predicates | (unary predicates on database types only)
610+
611+ The ``overlay[discard_entity] `` annotation designates an *entity discard predicate *.
612+ These predicates identify database entities that should be filtered out from cached base
613+ results when combining with overlay results during overlay evaluation.
614+
615+ Entity discard predicates must be:
616+
617+ - Unary predicates (taking exactly one argument)
618+ - Defined on a database type (a type from the database schema, prefixed with ``@ ``)
619+ - Only dependent on local predicates and other non-discarding predicates
620+
621+ .. code-block :: ql
622+
623+ overlay[discard_entity]
624+ private predicate discardExpr(@expr e) {
625+ exists(string file | discardableExpr(file, e) and overlayChangedFiles(file))
626+ }
627+
628+ overlay[local]
629+ private predicate discardableExpr(string file, @expr e) {
630+ not isOverlay() and
631+ file = getFile(e)
632+ }
633+
634+ overlay[local]
635+ predicate isOverlay() { databaseMetadata("isOverlay", "true") }
636+
637+ Annotation inheritance
638+ ----------------------
639+
640+ Overlay annotations can be applied to modules and types, in which case they are
641+ inherited by enclosed declarations. Declarations without explicit overlay annotations
642+ inherit from their innermost enclosing declaration that has an overlay annotation.
643+
644+ .. code-block :: ql
645+
646+ overlay[local?]
647+ module M {
648+ predicate foo(@expr x) { ... } // Inherits overlay[local?]
649+
650+ class C extends @expr {
651+ predicate bar() { ... } // Inherits overlay[local?]
652+
653+ overlay[global]
654+ predicate baz() { ... } // Explicitly global
655+ }
656+ }
657+
658+ Resolving overlay-related errors
659+ --------------------------------
660+
661+ When overlay support is enabled for a language, you may encounter compilation errors in
662+ custom QL libraries or queries. Here are common errors and their solutions:
663+
664+ **"Declaration is annotated overlay[local] but depends on global entity" **
665+
666+ A predicate marked ``overlay[local] `` or ``overlay[caller] `` depends on a global predicate.
667+ Solutions:
668+
669+ - Change the annotation to ``overlay[local?] `` if the predicate doesn't strictly need to be local
670+ - Add appropriate overlay annotations to the dependency chain to make dependencies local
671+ - Use the ``forceLocal `` higher-order predicate if you need to call global code from local code (advanced)
672+
673+ **"Cannot apply forceLocal to relation that is annotated overlay[...]" **
674+
675+ The ``forceLocal `` higher-order predicate cannot be applied to predicates that have overlay
676+ annotations such as ``overlay[local] ``, ``overlay[local?] ``, ``overlay[caller] ``, or
677+ ``overlay[caller?] ``. The input to ``forceLocal `` must be a predicate without such annotations
678+ (i.e., a global predicate or one with ``overlay[global] ``).
679+
505680.. Links to use in substitutions
506681
507682 .. |classes | replace :: :ref: `classes <classes >`
0 commit comments