Skip to content

Commit e1697a2

Browse files
committed
add overlay documentation to handbook and language spec
1 parent 077bbb2 commit e1697a2

File tree

2 files changed

+198
-1
lines changed

2 files changed

+198
-1
lines changed

docs/codeql/ql-language-reference/annotations.rst

Lines changed: 177 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

2323
For example, if you annotate an entity with ``private``, then only that particular name is
@@ -502,6 +502,182 @@ 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+
overlay[local]
541+
predicate localPredicate(@expr e) {
542+
// Can only call other local predicates
543+
exprs(e, _, _, _, _)
544+
}
545+
546+
``overlay[local?]``
547+
-------------------
548+
549+
**Available for**: |modules|, |classes|, |algebraic datatypes|, |type unions|, |characteristic predicates|, |member predicates|, |non-member predicates|
550+
551+
The ``overlay[local?]`` annotation declares that a predicate should be local if all of
552+
its dependencies are local, and global otherwise.
553+
554+
.. code-block:: ql
555+
556+
overlay[local?]
557+
predicate maybeLocalPredicate(@expr e) {
558+
// Local if all callees are local, global otherwise
559+
someOtherPredicate(e)
560+
}
561+
562+
``overlay[global]``
563+
-------------------
564+
565+
**Available for**: |modules|, |classes|, |algebraic datatypes|, |type unions|, |characteristic predicates|, |member predicates|, |non-member predicates|
566+
567+
The ``overlay[global]`` annotation explicitly declares that a predicate is global. This
568+
is the default behavior, so this annotation is typically used to override an inherited
569+
``overlay[local]`` or ``overlay[local?]`` annotation from an enclosing module or class.
570+
571+
.. code-block:: ql
572+
573+
overlay[local?]
574+
module M {
575+
predicate foo(@expr x) { ... } // Inherits local?
576+
577+
overlay[global]
578+
predicate bar(@expr x) { foo(x) } // Explicitly global
579+
}
580+
581+
``overlay[caller]``
582+
-------------------
583+
584+
**Available for**: |modules|, |classes|, |algebraic datatypes|, |type unions|, |characteristic predicates|, |member predicates|, |non-member predicates|
585+
586+
The ``overlay[caller]`` annotation declares that the locality of a predicate depends on
587+
its caller. The compiler may internally duplicate the predicate, creating separate local
588+
and global versions. Local callers use the local version; global callers use the global
589+
version.
590+
591+
.. code-block:: ql
592+
593+
overlay[caller]
594+
predicate utilityPredicate(int x) {
595+
x in [1..100]
596+
}
597+
598+
``overlay[caller?]``
599+
--------------------
600+
601+
**Available for**: |modules|, |classes|, |algebraic datatypes|, |type unions|, |characteristic predicates|, |member predicates|, |non-member predicates|
602+
603+
The ``overlay[caller?]`` annotation is like ``overlay[caller]``, but only applies if none
604+
of the predicate's dependencies are global. If any dependency is global, the predicate
605+
becomes global regardless of its callers.
606+
607+
``overlay[discard_entity]``
608+
---------------------------
609+
610+
**Available for**: |non-member predicates| (unary predicates on database types only)
611+
612+
The ``overlay[discard_entity]`` annotation designates an *entity discard predicate*.
613+
These predicates identify database entities that should be filtered out from cached base
614+
results when combining with overlay results during overlay evaluation.
615+
616+
Entity discard predicates must be:
617+
618+
- Unary predicates (taking exactly one argument)
619+
- Defined on a database type (a type from the database schema, prefixed with ``@``)
620+
- Only dependent on local predicates and other non-discarding predicates
621+
622+
.. code-block:: ql
623+
624+
overlay[discard_entity]
625+
private predicate discardExpr(@expr e) {
626+
exists(string file | discardableExpr(file, e) and overlayChangedFiles(file))
627+
}
628+
629+
overlay[local]
630+
private predicate discardableExpr(string file, @expr e) {
631+
not isOverlay() and
632+
file = getFile(e)
633+
}
634+
635+
overlay[local]
636+
predicate isOverlay() { databaseMetadata("isOverlay", "true") }
637+
638+
Annotation inheritance
639+
----------------------
640+
641+
Overlay annotations can be applied to modules and types, in which case they are
642+
inherited by enclosed declarations. Declarations without explicit overlay annotations
643+
inherit from their innermost enclosing declaration that has an overlay annotation.
644+
645+
.. code-block:: ql
646+
647+
overlay[local?]
648+
module M {
649+
predicate foo(@expr x) { ... } // Inherits overlay[local?]
650+
651+
class C extends @expr {
652+
predicate bar() { ... } // Inherits overlay[local?]
653+
654+
overlay[global]
655+
predicate baz() { ... } // Explicitly global
656+
}
657+
}
658+
659+
Resolving overlay-related errors
660+
--------------------------------
661+
662+
When overlay support is enabled for a language, you may encounter compilation errors in
663+
custom QL libraries or queries. Here are common errors and their solutions:
664+
665+
**"Declaration is annotated overlay[local] but depends on global entity"**
666+
667+
A predicate marked ``overlay[local]`` or ``overlay[caller]`` depends on a global predicate.
668+
Solutions:
669+
670+
- Change the annotation to ``overlay[local?]`` if the predicate doesn't strictly need to be local
671+
- Add appropriate overlay annotations to the dependency chain to make dependencies local
672+
- Use the ``forceLocal`` higher-order predicate if you need to call global code from local code (advanced)
673+
674+
**"Cannot apply forceLocal to relation that is annotated overlay[...]"**
675+
676+
The ``forceLocal`` higher-order predicate cannot be applied to predicates that have overlay
677+
annotations such as ``overlay[local]``, ``overlay[local?]``, ``overlay[caller]``, or
678+
``overlay[caller?]``. The input to ``forceLocal`` must be a predicate without such annotations
679+
(i.e., a global predicate or one with ``overlay[global]``).
680+
505681
.. Links to use in substitutions
506682
507683
.. |classes| replace:: :ref:`classes <classes>`

docs/codeql/ql-language-reference/ql-language-specification.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ Various kinds of syntax can have *annotations* applied to them. Annotations are
776776
argsAnnotation ::= "pragma" "[" ("inline" | "inline_late" | "noinline" | "nomagic" | "noopt" | "assume_small_delta") "]"
777777
| "language" "[" "monotonicAggregates" "]"
778778
| "bindingset" "[" (variable ( "," variable)*)? "]"
779+
| "overlay" "[" ("local" | "local?" | "global" | "caller" | "caller?" | "discard_entity") "]"
779780

780781
Each simple annotation adds a same-named attribute to the syntactic entity it precedes. For example, if a class is preceded by the ``abstract`` annotation, then the class is said to be abstract.
781782

@@ -873,6 +874,26 @@ A predicate may have several different binding sets, which can be stated by usin
873874

874875
The ``bindingset`` pragma is usable with type signatures and predicate signatures, but not with module signatures.
875876

877+
The parameterized annotation ``overlay`` controls predicate behavior during overlay evaluation, which is a feature for incremental analysis. Overlay annotations apply at the scope level, and are inherited by nested scopes.
878+
879+
+---------------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
880+
| Overlay | Classes | Characters | Member predicates | Non-member predicates | Imports | Fields | Modules | Aliases |
881+
+=====================+=========+============+===================+=======================+=========+========+=========+=========+
882+
| ``local`` | yes | yes | yes | yes | | | yes | |
883+
+---------------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
884+
| ``local?`` | yes | yes | yes | yes | | | yes | |
885+
+---------------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
886+
| ``global`` | yes | yes | yes | yes | | | yes | |
887+
+---------------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
888+
| ``caller`` | yes | yes | yes | yes | | | yes | |
889+
+---------------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
890+
| ``caller?`` | yes | yes | yes | yes | | | yes | |
891+
+---------------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
892+
| ``discard_entity`` | | | | yes | | | | |
893+
+---------------------+---------+------------+-------------------+-----------------------+---------+--------+---------+---------+
894+
895+
The ``overlay[discard_entity]`` annotation is only valid on unary non-member predicates whose argument is a database type.
896+
876897
QLDoc
877898
-----
878899

0 commit comments

Comments
 (0)