Skip to content

Latest commit

 

History

History
197 lines (126 loc) · 6.15 KB

LKQL_scripts.rst

File metadata and controls

197 lines (126 loc) · 6.15 KB

LKQL Checks

This document presents a florilège of LKQL-based checks inspired on GNATCheck and kp-toolkit.

1. Deep inheritance hierarchies

LKQL Script:

selector super_types
    | TypeDecl          => skip it.type_def
    | InterfaceTypeDef  => skip it.interfaces
    | RecordTypeDef     => ()
    | DerivedTypeDef    => skip it.subtype_indication <> skip it.interfaces
    | SubtypeIndication => skip it.name
    | Name              => rec it.referenced_decl(true)
    | ParentList        => skip *it.children
    | *                 => ()

let result = query TypeDecl(any super_types(depth=3): *)

print(result)

Lists the type declarations which depth is greater or equal to 3.

Deep inheritance hierarchyies test

2. Deep Library

LKQL Script:

let targetDepth = 5

let result =
    query PackageDecl (package_name: DefiningName(any children(depth=targetDepth): Name))

print(result)

Lists the package declations that have more than targetDepth parents.

Deep library test

3. Implicit Small

LKQL Script:

let result =
    query TypeDecl(any children: OrdinaryFixedPointDef, get_attribute("Small"): null)

print(result)

Lists the ordinary fixed point type declarations that lack an explicit representation clause defining it's 'Small value.

Implicit small test

4. KP R517_023: Wrong value returned for unconstrained packed array formal

LKQL Script:

let result = query CallExpr(
                        is_call(): true,
                        any children(depth=2): p@ParamAssoc when isFlagArg(p)
                   )
print(result)

fun isFlagArg(actual) =
    val formal = getFormal(actual);
    if formal == null
    then false
    else isInOutOrOut(formal) &&
         isUnConstrainedArrayWithPacked(typeOfParamSpec(formal)) &&
         isReprRecordComponent(argumentDecl(actual.r_expr))

fun getFormal(actual) =
    val params = actual.get_params();
    if params.length == 0 then null else params[1]?.parent?.parent

fun isReprRecordComponent(decl) =
    decl is ComponentDecl(any parent:
                TypeDecl(get_record_representation_clause(): RecordRepClause)
            )

fun argumentDecl(argExpr) =
    match argExpr
        | DottedName => it.referenced_decl()
        | *          => null

fun typeOfParamSpec(spec) =
    spec?.type_expr?.name?.referenced_decl()

fun isInOutOrOut(spec) =
    spec?.mode is ModeOut || spec?.mode is ModeInOut

fun isUnConstrainedArrayWithPacked(decl) =
    decl is TypeDecl(
                type_def: ArrayTypeDef(any children(depth=6): BoxExpr),
                get_attribute("Pack"): AdaNode
            )

The compiler generates wrong code for the call to a subprogram with an In Out or Out formal parameter of an unconstrained packed array type, when the actual parameter is a component of a record subject to a representation clause.

This LKQL script lists the occurrences of the aforementioned issue.

KP R517_023 test

5. Multiple entries in protected definitions

LKQL Script:

let result = query ProtectedDef any children EntryDecl(any prev_siblings is EntryDecl)
print(result)

Lists the entries that belong to a protected definition containing multiple entries. The first entry of the definition will not be flagged.

Multiple entries test

6. No explicit real range

LKQL Script:

let result = query t @ *
                when isRealWithoutRange(t) ||
                    t is SubtypeDecl(any super_types: s@_ when isRealWithoutRange(s))
print(result)

fun isRealWithoutRange(decl) =
    decl is TypeDecl(type_def: RealTypeDef(no children: RangeSpec))

Lists the floating point type definitions that do not include an explicit range.

No real range test

7. Parameters out of order

LKQL Script:

let result =
    query p@ParamSpec(any next_siblings is sib@ParamSpec when priority(sib) > priority(p))

print(result)

fun priority(paramSpec) =
    if paramSpec.default_expr != null then 0
    else match paramSpec.mode
            | ModeOut     => 1
            | ModeInOut   => 2
            | ModeIn      => 3
            | ModeDefault => 3
Flag each subprogram and entry declaration whose formal parameters are not ordered according to the following scheme:
  • in and access parameters first, then in out parameters, and then out parameters;
  • for in mode, parameters with default initialization expressions occur last

Parameters out of order test

8. Raise predefined exception

LKQL Script:

let result = query r@RaiseStmt when isPredefinedName(r.exception_name)

print(result)

fun isPredefinedName(id) =
    val name = id?.text;
    name == "Program_Error" || name == "Constraint_Error" ||
    name == "Numeric_Error" || name == "Storage_Error"    ||
    name == "Tasking_Error"

List raise statements that raise a predefined exception.

Raise predefined exception test