Semmle 1.19
Skip to end of metadata
Go to start of metadata

This topic describes the basic structure of query files (.ql) and defines the properties supported by query files. For information about the QL language and writing your own queries, see Semmle QL.

Purpose

Each query file defines a query to run on a project snapshot. Queries are used to:

  • Calculate metrics for display in a client application.
  • Identify code that breaks a rule and display a relevant alert message.
  • Filter the results of another query.
 

Structure

Each query file (.ql) has two distinct areas:

  • Properties area - displayed at the top of the file. Contains metadata that defines how a client application displays results for the query.
  • Query definition - defined using the QL language.

Properties area

The properties area at the top of the query file includes metadata that is used by client applications. Apart from the properties listed below, you can also define additional custom properties. These are displayed in certain result output formats, for example in SARIF.

Core properties

The following properties are supported by all query files:

PropertyValueExampleNotes
@name<text>@name TODO/FIXME commentsMandatory, defines a label for the query. Displayed in client applications.
@description<text>@description A comment that contains 'TODO' or similar keywords may indicate code that is incomplete or broken, or it may highlight an ambiguity in the software's specification.Mandatory, defines a brief help message for the metric. Displayed in client applications as a tooltip.
@id<text>@id js/todo-comment

Mandatory in certain client applications, and highly recommended in general. Defines a unique identifier for the query. Used to identify and classify queries in client applications.

To ensure uniqueness, it may be helpful to use a fixed structure for each ID. For example, the @id for a standard Semmle query has the following format: <language>/<brief-description>.

@kind<type>

@kind metric
@kind problem
@kind path-problem

Mandatory, defines how the results of the query should be processed. Use:

  • metric for a query that returns numeric data about a location (in older queries you may also see @kind treemap).
  • problem for a query that identifies alerts, returning a location and an alert message.
  • path-problem for alert queries that return additional information about data flow.

For filter queries, the @kind must match the type of data to be filtered.

@tags<type>correctness 
maintainability 
readability 
security 
...
Optional, these tags group queries together in broad categories to make it easier to search for them and identify them. In addition to the common tags listed here, you can define any number of more specific categories that may be useful in your organization.

Additional properties for metric queries

In addition to the core properties, metric queries support the following properties:

PropertyValueExampleNotes
@metricType<type>

@metricType file
@metricType callable
@metricType package
@metricType project
@metricType reftype

Mandatory, defines the code element that the query acts on. This information is used by client applications; it should match the type of result returned by the query.
@metricAggregate<method>

@metricAggregate avg sum min max

Mandatory, defines the allowable aggregations for this metric. A space separated list of the four possibilities sum, avg, min and max. If it is not present, it defaults to sum avg.
@treemap.threshold<number>@treemap.threshold 10Optional, defines a metric threshold. Used with @treemap.warnOn to define a "danger area" on the metric charts displayed in client applications.
@treemap.warnOn<type>@treemap.warnOn highValues
@treemap.warnOn lowValues
Optional, defines whether high or low values are dangerous. Used with @treemap.threshold to define a "danger area" on the metric charts displayed in client applications.

Additional properties for problem queries

In addition to the core properties, rule queries support the following properties:

PropertyValueExampleNotes
@precision<type>medium 
high 
very high
Mandatory, indicates the percentage of query results that are true positives (as opposed to false positive results). This controls how alerts for problems found by the query are displayed in client applications.
@problem.severity<type>

@problem.severity error
@problem.severity warning
@problem.severity recommendation

Mandatory, defines the level of severity of any alerts generated by the query. This controls how alerts are displayed in client applications.

Additional properties for filter queries

None available.

Query definition requirements

The query definition must generate results of the form defined by the @kind property, that is, if the properties define the query as a metric then the result of running the query must be numeric.

Query type@kindQuery definition requirements
Metric@kind metric

Query must contain a select statement that reports:

  • The location of an element of code.
  • The associated numeric value.
Problem (alert)@kind problem

Query must contain a select statement that reports:

  • The location of an element of code.
  • A string that defines an error message. The string may include placeholders.
Filter@kind metricAs for a metric query. This filter will only be applied to other queries with @kind metric.
@kind problemAs for a problem query. This filter will only be applied to other queries with @kind problem.

Examples

This topic contains a simple example of each type of query. For other examples of standard queries, you can use the QL for Eclipse plugin to explore the standard queries (see QL plugins and extensions). For information about writing your own queries, see Learning QL.

Example of a metric query

The following example is the core query used to report the number of lines of code in a Java snapshot, FLinesOfCode.ql:

/**
 * @name Lines of code in files
 * @description The number of lines of code in a file.
 * @kind metric
 * @treemap.warnOn highValues
 * @metricType file
 * @metricAggregate avg sum max
 * @id java/lines-of-code-in-files
 * @tags maintainability
 *       complexity
 */

import java

from File f, int n
where n = f.getNumberOfLinesOfCode()
select f, n
order by n desc

Notice that the query properties include the optional property: @treemap.warnOn highValues. This defines the query as one where lower values indicate better quality. However, no threshold has been set so charts in the client applications will not display any ‘danger’ zones; instead, the display will be recalibrated so that the largest file is displayed in full red.

Example of a problem query

The following example is one of the core queries used to generate alerts for TODO and FIXME comments in JavaScript snapshots, TodoComments.ql:

/**
 * @name TODO comment
 * @description A comment that contains 'TODO' or similar keywords may indicate code that is incomplete or
 *              broken, or it may highlight an ambiguity in the software's specification.
 * @kind problem
 * @problem.severity recommendation
 * @id js/todo-comment
 * @tags maintainability
 *       external/cwe/cwe-546
 * @precision medium
 */

import javascript

from Comment c
where c.getText().regexpMatch("(?s).*FIXME.*|.*TODO.*|.*(?<!=)\\s*XXX.*")
select c, "TODO comments should be addressed."

Notice that the second part of the select statement reports a string, which will be used as the text of the alert message. See Defining the content of query results for more detailed information about writing queries and using placeholders to define alert messages.

Example of a filter query

The following query is a filter that has been created to exclude alerts found in autogenerated code. Notice that the filter is defined as @kind problem because it is designed to filter the results of problem queries. In addition, the output is of the type expected for a problem query: <entity>, string.

/**
 * @name Filter: exclude results from files that are autogenerated
 * @description Use this filter to return results only if they are
 *              located in files that are maintained manually.
 * @kind problem
 * @id cpp/filter-autogenerated
 */
 
import cpp
import semmle.code.cpp.AutogeneratedFile
import external.DefectFilter

from DefectResult res
where not res.getFile() instanceof AutogeneratedFile
select res,
       res.getMessage()