This document presents a florilège of LKQL-based checks inspired on GNATCheck and kp-toolkit.
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
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.
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.
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.
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.
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.
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
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.