This commit is contained in:
Raul Garcia (MSFT)
2020-07-14 11:16:51 -07:00
2816 changed files with 141798 additions and 64453 deletions

View File

@@ -0,0 +1,9 @@
{
"extensions": [
"github.vscode-codeql",
"slevesque.vscode-zipexplorer"
],
"settings": {
"codeQL.experimentalBqrsParsing": true
}
}

9
.github/codeql/codeql-config.yml vendored Normal file
View File

@@ -0,0 +1,9 @@
name: "CodeQL config"
queries:
- uses: security-and-quality
paths-ignore:
- '/cpp/'
- '/java/'
- '/python/'

52
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
name: "Code scanning - action"
on:
push:
pull_request:
schedule:
- cron: '0 9 * * 1'
jobs:
CodeQL-Build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
with:
languages: csharp
config-file: ./.github/codeql/codeql-config.yml
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -2,7 +2,7 @@
We welcome contributions to our CodeQL libraries and queries. Got an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [Writing CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/writing-queries.html) on [help.semmle.com](https://help.semmle.com).
There is lots of useful documentation to help you write queries, ranging from information about query file structure to tutorials for specific target languages. For more information on the documentation available, see [CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/writing-queries.html) on [help.semmle.com](https://help.semmle.com).
## Submitting a new experimental query
@@ -32,7 +32,7 @@ If you have an idea for a query that you would like to share with other CodeQL u
For details, see the [guide on query metadata](docs/query-metadata-style-guide.md).
Make sure the `select` statement is compatible with the query `@kind`. See [Introduction to query files](https://help.semmle.com/QL/learn-ql/writing-queries/introduction-to-queries.html#select-clause) on help.semmle.com.
Make sure the `select` statement is compatible with the query `@kind`. See [About CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/introduction-to-queries.html#select-clause) on help.semmle.com.
3. **Formatting**
@@ -53,14 +53,6 @@ After the experimental query is merged, we welcome pull requests to improve it.
## Using your personal data
If you contribute to this project, we will record your name and email
address (as provided by you with your contributions) as part of the code
repositories, which are public. We might also use this information
to contact you in relation to your contributions, as well as in the
normal course of software development. We also store records of your
CLA agreements. Under GDPR legislation, we do this
on the basis of our legitimate interest in creating the CodeQL product.
Please do get in touch (privacy@github.com) if you have any questions about
this or our data protection policies.
If you contribute to this project, we will record your name and email address (as provided by you with your contributions) as part of the code repositories, which are public. We might also use this information to contact you in relation to your contributions, as well as in the normal course of software development. We also store records of CLA agreements signed in the past, but no longer require contributors to sign a CLA. Under GDPR legislation, we do this on the basis of our legitimate interest in creating the CodeQL product.
Please do get in touch (privacy@github.com) if you have any questions about this or our data protection policies.

View File

@@ -1,6 +1,6 @@
# CodeQL
This open source repository contains the standard CodeQL libraries and queries that power [LGTM](https://lgtm.com) and the other CodeQL products that [GitHub](https://github.com) makes available to its customers worldwide.
This open source repository contains the standard CodeQL libraries and queries that power [LGTM](https://lgtm.com) and the other CodeQL products that [GitHub](https://github.com) makes available to its customers worldwide. For the queries, libraries, and extractor that power Go analysis, visit the [CodeQL for Go repository](https://github.com/github/codeql-go).
## How do I learn CodeQL and run queries?

View File

@@ -0,0 +1,46 @@
# Improvements to C/C++ analysis
The following changes in version 1.25 affect C/C++ analysis in all applications.
## General improvements
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------------------------------------------------------------|
| Uncontrolled format string (`cpp/tainted-format-string`) | | This query is now displayed by default on LGTM. |
| Uncontrolled format string (through global variable) (`cpp/tainted-format-string-through-global`) | | This query is now displayed by default on LGTM. |
## Changes to libraries
* The library `VCS.qll` and all queries that imported it have been removed.
* The data-flow library has been improved, which affects most security queries by potentially
adding more results. Flow through functions now takes nested field reads/writes into account.
For example, the library is able to track flow from `taint()` to `sink()` via the method
`getf2f1()` in
```c
struct C {
int f1;
};
struct C2
{
C f2;
int getf2f1() {
return f2.f1; // Nested field read
}
void m() {
f2.f1 = taint();
sink(getf2f1()); // NEW: taint() reaches here
}
};
```
* The security pack taint tracking library (`semmle.code.cpp.security.TaintTracking`) now considers that equality checks may block the flow of taint. This results in fewer false positive results from queries that use this library.
* The length of a tainted string (such as the return value of a call to `strlen` or `strftime` with tainted parameters) is no longer itself considered tainted by the `models` library. This leads to fewer false positive results in queries that use any of our taint libraries.

View File

@@ -0,0 +1,54 @@
# Improvements to C# analysis
The following changes in version 1.25 affect C# analysis in all applications.
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|------------------------------|------------------------|-----------------------------------|
## Removal of old queries
## Changes to code extraction
* Index initializers, of the form `{ [1] = "one" }`, are extracted correctly. Previously, the kind of the
expression was incorrect, and the index was not extracted.
## Changes to libraries
* The class `UnboundGeneric` has been refined to only be those declarations that actually
have type parameters. This means that non-generic nested types inside constructed types,
such as `A<int>.B`, no longer are considered unbound generics. (Such nested types do,
however, still have relevant `.getSourceDeclaration()`s, for example `A<>.B`.)
* The data-flow library has been improved, which affects most security queries by potentially
adding more results. Flow through methods now takes nested field reads/writes into account.
For example, the library is able to track flow from `"taint"` to `Sink()` via the method
`GetF2F1()` in
```csharp
class C1
{
string F1;
}
class C2
{
C1 F2;
string GetF2F1() => F2.F1; // Nested field read
void M()
{
F2 = new C1() { F1 = "taint" };
Sink(GetF2F1()); // NEW: "taint" reaches here
}
}
```
## Changes to autobuilder

View File

@@ -0,0 +1,41 @@
# Improvements to Java analysis
The following changes in version 1.25 affect Java analysis in all applications.
## General improvements
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|------------------------------|------------------------|-----------------------------------|
## Changes to libraries
* The data-flow library has been improved, which affects most security queries by potentially
adding more results. Flow through methods now takes nested field reads/writes into account.
For example, the library is able to track flow from `"taint"` to `sink()` via the method
`getF2F1()` in
```java
class C1 {
String f1;
C1(String f1) { this.f1 = f1; }
}
class C2 {
C1 f2;
String getF2F1() {
return this.f2.f1; // Nested field read
}
void m() {
this.f2 = new C1("taint");
sink(this.getF2F1()); // NEW: "taint" reaches here
}
}
```

View File

@@ -3,24 +3,106 @@
## General improvements
* Support for the following frameworks and libraries has been improved:
- [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
- [bluebird](http://bluebirdjs.com/)
- [express](https://www.npmjs.com/package/express)
- [fancy-log](https://www.npmjs.com/package/fancy-log)
- [fastify](https://www.npmjs.com/package/fastify)
- [fstream](https://www.npmjs.com/package/fstream)
- [jGrowl](https://github.com/stanlemon/jGrowl)
- [jQuery](https://jquery.com/)
- [marsdb](https://www.npmjs.com/package/marsdb)
- [micro](https://www.npmjs.com/package/micro/)
- [minimongo](https://www.npmjs.com/package/minimongo/)
- [mssql](https://www.npmjs.com/package/mssql)
- [mysql](https://www.npmjs.com/package/mysql)
- [npmlog](https://www.npmjs.com/package/npmlog)
- [pg](https://www.npmjs.com/package/pg)
- [sequelize](https://www.npmjs.com/package/sequelize)
- [spanner](https://www.npmjs.com/package/spanner)
- [sqlite](https://www.npmjs.com/package/sqlite)
- [ssh2-streams](https://www.npmjs.com/package/ssh2-streams)
- [ssh2](https://www.npmjs.com/package/ssh2)
- [vue](https://www.npmjs.com/package/vue)
- [yargs](https://www.npmjs.com/package/yargs)
- [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server)
* TypeScript 3.9 is now supported.
* TypeScript code embedded in HTML and Vue files is now extracted and analyzed.
* The analysis of sanitizers has improved, leading to more accurate
results from the security queries.
## New queries
| **Query** | **Tags** | **Purpose** |
|---------------------------------------------------------------------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Cross-site scripting through DOM (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are not shown on LGTM by default. |
| DOM text reinterpreted as HTML (`js/xss-through-dom`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities where existing text from the DOM is used as HTML. Results are shown on LGTM by default. |
| Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. |
| Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. |
| Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. |
| Download of sensitive file through insecure connection (`js/insecure-download`) | security, external/cwe/cwe-829 | Highlights downloads of sensitive files through an unencrypted protocol. Results are shown on LGTM by default. |
| Exposure of private files (`js/exposure-of-private-files`) | security, external/cwe/cwe-200 | Highlights servers that serve private files. Results are shown on LGTM by default. |
| Creating biased random numbers from a cryptographically secure source (`js/biased-cryptographic-random`) | security, external/cwe/cwe-327 | Highlights mathematical operations on cryptographically secure numbers that can create biased results. Results are shown on LGTM by default. |
| Storage of sensitive information in build artifact (`js/build-artifact-leak`) | security, external/cwe/cwe-312 | Highlights storage of sensitive information in build artifacts. Results are shown on LGTM by default. |
| Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. |
| Disabling certificate validation (`js/disabling-certificate-validation`) | security, external/cwe-295 | Highlights locations where SSL certificate validation is disabled. Results are shown on LGTM by default. |
| Incomplete multi-character sanitization (`js/incomplete-multi-character-sanitization`) | correctness, security, external/cwe/cwe-20, external/cwe/cwe-116 | Highlights sanitizers that fail to remove dangerous substrings completely. Results are shown on LGTM by default. |
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
| Client-side cross-site scripting (`js/xss`) | Fewer results | This query now recognizes additional safe patterns of constructing HTML. |
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. |
| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. |
| Exception text reinterpreted as HTML (`js/exception-xss`) | Rephrased and changed visibility | Rephrased name and alert message. Severity lowered from error to warning. Results are now shown on LGTM by default. |
| Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. |
| Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. |
| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. |
| Insecure randomness (`js/insecure-randomness`) | Fewer results | This query now recognizes when an insecure random value is used as a fallback when secure random values are unsupported. |
| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. |
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. |
| Non-linear pattern (`js/non-linear-pattern`) | Fewer duplicates and message changed | This query now generates fewer duplicate alerts and has a clearer explanation in case of type annotations used in a pattern. |
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. |
| Uncontrolled command line (`js/command-line-injection`) | More results | This query now recognizes additional command execution calls. |
| Uncontrolled data used in path expression (`js/path-injection`) | More results | This query now recognizes additional file system calls. |
| Uncontrolled data used in path expression (`js/path-injection`) | Fewer results | This query no longer flags paths that have been checked to be part of a collection. |
| Unknown directive (`js/unknown-directive`) | Fewer results | This query no longer flags directives generated by the Babel compiler. |
| Unneeded defensive code (`js/unneeded-defensive-code`) | Fewer false-positive results | This query now recognizes checks meant to handle the `document.all` object. |
| Unused property (`js/unused-property`) | Fewer results | This query no longer flags properties of objects that are operands of `yield` expressions. |
| Zip Slip (`js/zipslip`) | More results | This query now recognizes additional vulnerabilities. |
The following low-precision queries are no longer run by default on LGTM (their results already were not displayed):
- `js/angular/dead-event-listener`
- `js/angular/unused-dependency`
- `js/bitwise-sign-check`
- `js/comparison-of-identical-expressions`
- `js/conflicting-html-attribute`
- `js/ignored-setter-parameter`
- `js/jsdoc/malformed-param-tag`
- `js/jsdoc/missing-parameter`
- `js/jsdoc/unknown-parameter`
- `js/json-in-javascript-file`
- `js/misspelled-identifier`
- `js/nested-loops-with-same-variable`
- `js/node/cyclic-import`
- `js/node/unused-npm-dependency`
- `js/omitted-array-element`
- `js/return-outside-function`
- `js/single-run-loop`
- `js/too-many-parameters`
- `js/unused-property`
- `js/useless-assignment-to-global`
## Changes to libraries
* A library `semmle.javascript.explore.CallGraph` has been added to help write queries for exploring the call graph.
* Added data flow for `Map` and `Set`, and added matching type-tracking steps that can accessed using the `CollectionsTypeTracking` module.
* The data-flow node representing a parameter or destructuring pattern is now always the `ValueNode` corresponding to that AST node. This has a few consequences:
- `Parameter.flow()` now gets the correct data flow node for a parameter. Previously this had a result, but the node was disconnected from the data flow graph.
- `ParameterNode.asExpr()` and `.getAstNode()` now gets the parameter's AST node, whereas previously it had no result.
- `Expr.flow()` now has a more meaningful result for destructuring patterns. Previously this node was disconnected from the data flow graph. Now it represents the values being destructured by the pattern.
* The global data-flow and taint-tracking libraries now model indirect parameter accesses through the `arguments` object in some cases, which may lead to additional results from some of the security queries, particularly "Prototype pollution in utility function".
* The predicates `Type.getProperty()` and variants of `Type.getMethod()` have been deprecated due to lack of use-cases. Looking up a named property of a static type is no longer supported, favoring faster extraction times instead.

View File

@@ -0,0 +1,22 @@
# Improvements to Python analysis
The following changes in version 1.25 affect Python analysis in all applications.
## General improvements
## New queries
| **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------|
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|----------------------------|------------------------|------------------------------------------------------------------|
## Changes to libraries
* Importing `semmle.python.web.HttpRequest` will no longer import `UntrustedStringKind` transitively. `UntrustedStringKind` is the most commonly used non-abstract subclass of `ExternalStringKind`. If not imported (by one mean or another), taint-tracking queries that concern `ExternalStringKind` will not produce any results. Please ensure such queries contain an explicit import (`import semmle.python.security.strings.Untrusted`).

View File

@@ -1,5 +1,5 @@
{
"DataFlow Java/C++/C#": [
"DataFlow Java/C++/C#/Python": [
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll",
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll",
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll",
@@ -18,15 +18,18 @@
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll"
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll",
"python/ql/src/experimental/dataflow/internal/DataFlowImpl.qll",
"python/ql/src/experimental/dataflow/internal/DataFlowImpl2.qll"
],
"DataFlow Java/C++/C# Common": [
"DataFlow Java/C++/C#/Python Common": [
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll"
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll",
"python/ql/src/experimental/dataflow/internal/DataFlowImplCommon.qll"
],
"TaintTracking::Configuration Java/C++/C#": [
"TaintTracking::Configuration Java/C++/C#/Python": [
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
@@ -37,13 +40,15 @@
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll"
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
"python/ql/src/experimental/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
],
"DataFlow Java/C++/C# Consistency checks": [
"DataFlow Java/C++/C#/Python Consistency checks": [
"java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
"cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll",
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll",
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll"
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll",
"python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll"
],
"C++ SubBasicBlocks": [
"cpp/ql/src/semmle/code/cpp/controlflow/SubBasicBlocks.qll",
@@ -53,114 +58,122 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll"
"csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll"
],
"IR IRBlock": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRBlock.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRBlock.qll"
"csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll"
],
"IR IRVariable": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRVariable.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRVariable.qll"
"csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll"
],
"IR IRFunction": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRFunction.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRFunction.qll"
"csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll"
],
"IR Operand": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll"
"csharp/ql/src/experimental/ir/implementation/raw/Operand.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll"
],
"IR IRType": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll"
"csharp/ql/src/experimental/ir/implementation/IRType.qll"
],
"IR IRConfiguration": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/IRConfiguration.qll"
"csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll"
],
"IR UseSoundEscapeAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/UseSoundEscapeAnalysis.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/UseSoundEscapeAnalysis.qll"
"csharp/ql/src/experimental/ir/implementation/UseSoundEscapeAnalysis.qll"
],
"IR IRFunctionBase": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/IRFunctionBase.qll",
"csharp/ql/src/experimental/ir/implementation/internal/IRFunctionBase.qll"
],
"IR Operand Tag": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/internal/OperandTag.qll"
"csharp/ql/src/experimental/ir/implementation/internal/OperandTag.qll"
],
"IR TInstruction":[
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TInstruction.qll",
"csharp/ql/src/experimental/ir/implementation/internal/TInstruction.qll"
],
"IR TIRVariable":[
"cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TIRVariable.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/internal/TIRVariable.qll"
"csharp/ql/src/experimental/ir/implementation/internal/TIRVariable.qll"
],
"IR IR": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IR.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IR.qll"
"csharp/ql/src/experimental/ir/implementation/raw/IR.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll"
],
"IR IRSanity": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRSanity.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRSanity.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRSanity.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/IRSanity.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/IRSanity.qll"
"IR IRConsistency": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRConsistency.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRConsistency.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRConsistency.qll",
"csharp/ql/src/experimental/ir/implementation/raw/IRConsistency.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRConsistency.qll"
],
"IR PrintIR": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/PrintIR.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/PrintIR.qll"
"csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll"
],
"IR IntegerConstant": [
"cpp/ql/src/semmle/code/cpp/ir/internal/IntegerConstant.qll",
"csharp/ql/src/semmle/code/csharp/ir/internal/IntegerConstant.qll"
"csharp/ql/src/experimental/ir/internal/IntegerConstant.qll"
],
"IR IntegerInteval": [
"cpp/ql/src/semmle/code/cpp/ir/internal/IntegerInterval.qll",
"csharp/ql/src/semmle/code/csharp/ir/internal/IntegerInterval.qll"
"csharp/ql/src/experimental/ir/internal/IntegerInterval.qll"
],
"IR IntegerPartial": [
"cpp/ql/src/semmle/code/cpp/ir/internal/IntegerPartial.qll",
"csharp/ql/src/semmle/code/csharp/ir/internal/IntegerPartial.qll"
"csharp/ql/src/experimental/ir/internal/IntegerPartial.qll"
],
"IR Overlap": [
"cpp/ql/src/semmle/code/cpp/ir/internal/Overlap.qll",
"csharp/ql/src/semmle/code/csharp/ir/internal/Overlap.qll"
"csharp/ql/src/experimental/ir/internal/Overlap.qll"
],
"IR EdgeKind": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/EdgeKind.qll"
"csharp/ql/src/experimental/ir/implementation/EdgeKind.qll"
],
"IR MemoryAccessKind": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/MemoryAccessKind.qll"
"csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll"
],
"IR TempVariableTag": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/TempVariableTag.qll"
"csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll"
],
"IR Opcode": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/Opcode.qll"
"csharp/ql/src/experimental/ir/implementation/Opcode.qll"
],
"IR SSASanity": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSASanity.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSASanity.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSASanity.qll"
"IR SSAConsistency": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConsistency.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConsistency.qll"
],
"C++ IR InstructionImports": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionImports.qll",
@@ -177,6 +190,11 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRBlockImports.qll"
],
"C++ IR IRFunctionImports": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRFunctionImports.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/IRFunctionImports.qll"
],
"C++ IR IRVariableImports": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRVariableImports.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll",
@@ -199,7 +217,7 @@
"SSA AliasAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll"
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll"
],
"C++ SSA AliasAnalysisImports": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysisImports.qll",
@@ -212,42 +230,42 @@
],
"IR SSA SimpleSSA": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll"
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SimpleSSA.qll"
],
"IR AliasConfiguration (unaliased_ssa)": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll"
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/AliasConfiguration.qll"
],
"IR SSA SSAConstruction": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll"
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll"
],
"IR SSA PrintSSA": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/PrintSSA.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintSSA.qll"
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintSSA.qll"
],
"IR ValueNumberInternal": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/internal/ValueNumberingInternal.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll"
"csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingInternal.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingInternal.qll"
],
"C++ IR ValueNumber": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/ValueNumbering.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/ValueNumbering.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll"
"csharp/ql/src/experimental/ir/implementation/raw/gvn/ValueNumbering.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/ValueNumbering.qll"
],
"C++ IR PrintValueNumbering": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/gvn/PrintValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll",
"cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/gvn/PrintValueNumbering.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/PrintValueNumbering.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll"
"csharp/ql/src/experimental/ir/implementation/raw/gvn/PrintValueNumbering.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/PrintValueNumbering.qll"
],
"C++ IR ConstantAnalysis": [
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/constant/ConstantAnalysis.qll",
@@ -276,32 +294,36 @@
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/PrintDominance.qll"
],
"C# IR InstructionImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/InstructionImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/InstructionImports.qll"
"csharp/ql/src/experimental/ir/implementation/raw/internal/InstructionImports.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/InstructionImports.qll"
],
"C# IR IRImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRImports.qll"
"csharp/ql/src/experimental/ir/implementation/raw/internal/IRImports.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRImports.qll"
],
"C# IR IRBlockImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRBlockImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll"
"csharp/ql/src/experimental/ir/implementation/raw/internal/IRBlockImports.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRBlockImports.qll"
],
"C# IR IRFunctionImports": [
"csharp/ql/src/experimental/ir/implementation/raw/internal/IRFunctionImports.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRFunctionImports.qll"
],
"C# IR IRVariableImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRVariableImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll"
"csharp/ql/src/experimental/ir/implementation/raw/internal/IRVariableImports.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/IRVariableImports.qll"
],
"C# IR OperandImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/OperandImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/OperandImports.qll"
"csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll"
],
"C# IR PrintIRImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/PrintIRImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll"
"csharp/ql/src/experimental/ir/implementation/raw/internal/PrintIRImports.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/PrintIRImports.qll"
],
"C# IR ValueNumberingImports": [
"csharp/ql/src/semmle/code/csharp/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
"csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll"
"csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll",
"csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll"
],
"XML": [
"cpp/ql/src/semmle/code/cpp/XML.qll",

102
config/opcode-qldoc.py Normal file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env python3
import os
import re
path = os.path
needs_an_re = re.compile(r'^(?!Unary)[AEIOU]') # Name requiring "an" instead of "a".
start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment
end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment
blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*'
instruction_class_re = re.compile(r'^class (?P<name>[A-aa-z0-9]+)Instruction\s') # Declaration of an `Instruction` class
opcode_base_class_re = re.compile(r'^abstract class (?P<name>[A-aa-z0-9]+)Opcode\s') # Declaration of an `Opcode` base class
opcode_class_re = re.compile(r'^ class (?P<name>[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class
script_dir = path.realpath(path.dirname(__file__))
instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll'))
opcode_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll'))
# Scan `Instruction.qll`, keeping track of the QLDoc comment attached to each declaration of a class
# whose name ends with `Instruction`.
instruction_comments = {}
in_qldoc = False
saw_blank_line_in_qldoc = False
qldoc_lines = []
with open(instruction_path, 'r', encoding='utf-8') as instr:
for line in instr:
if in_qldoc:
if end_qldoc_re.search(line):
qldoc_lines.append(line)
in_qldoc = False
elif blank_qldoc_line_re.search(line):
# We're going to skip any lines after the first blank line, to avoid duplicating all
# of the verbose description.
saw_blank_line_in_qldoc = True
elif not saw_blank_line_in_qldoc:
qldoc_lines.append(line)
else:
if start_qldoc_re.search(line):
# Starting a new QLDoc comment.
saw_blank_line_in_qldoc = False
qldoc_lines.append(line)
if not end_qldoc_re.search(line):
in_qldoc = True
else:
instruction_match = instruction_class_re.search(line)
if instruction_match:
# Found the declaration of an `Instruction` class. Record the QLDoc comments.
instruction_comments[instruction_match.group('name')] = qldoc_lines
qldoc_lines = []
# Scan `Opcode.qll`. Whenever we see the declaration of an `Opcode` class for which we have a
# corresponding `Instruction` class, we'll attach a copy of the `Instruction`'s QLDoc comment.
in_qldoc = False
qldoc_lines = []
output_lines = []
with open(opcode_path, 'r', encoding='utf-8') as opcode:
for line in opcode:
if in_qldoc:
qldoc_lines.append(line)
if end_qldoc_re.search(line):
in_qldoc = False
else:
if start_qldoc_re.search(line):
qldoc_lines.append(line)
if not end_qldoc_re.search(line):
in_qldoc = True
else:
name_without_suffix = None
name = None
indent = ''
opcode_base_match = opcode_base_class_re.search(line)
if opcode_base_match:
name_without_suffix = opcode_base_match.group('name')
name = name_without_suffix + 'Opcode'
else:
opcode_match = opcode_class_re.search(line)
if opcode_match:
name_without_suffix = opcode_match.group('name')
name = name_without_suffix
# Indent by two additional spaces, since opcodes are declared in the
# `Opcode` module.
indent = ' '
if name_without_suffix:
# Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with
# a copy of the one from the `Instruction`.
if instruction_comments.get(name_without_suffix):
article = 'an' if needs_an_re.search(name_without_suffix) else 'a'
qldoc_lines = [
indent + '/**\n',
indent + ' * The `Opcode` for ' + article + ' `' + name_without_suffix + 'Instruction`.\n',
indent + ' *\n',
indent + ' * See the `' + name_without_suffix + 'Instruction` documentation for more details.\n',
indent + ' */\n'
]
output_lines.extend(qldoc_lines)
qldoc_lines = []
output_lines.append(line)
# Write out the updated `Opcode.qll`
with open(opcode_path, 'w', encoding='utf-8') as opcode:
opcode.writelines(output_lines)

View File

@@ -59,21 +59,32 @@ def file_checksum(filename):
return hashlib.sha1(file_handle.read()).hexdigest()
def check_group(group_name, files, master_file_picker, emit_error):
checksums = {file_checksum(f) for f in files}
if len(checksums) == 1:
extant_files = [f for f in files if path.isfile(f)]
if len(extant_files) == 0:
emit_error(__file__, 0, "No files found from group '" + group_name + "'.")
emit_error(__file__, 0,
"Create one of the following files, and then run this script with "
"the --latest switch to sync it to the other file locations.")
for filename in files:
emit_error(__file__, 0, " " + filename)
return
master_file = master_file_picker(files)
checksums = {file_checksum(f) for f in extant_files}
if len(checksums) == 1 and len(extant_files) == len(files):
# All files are present and identical.
return
master_file = master_file_picker(extant_files)
if master_file is None:
emit_error(__file__, 0,
"Files from group '"+ group_name +"' not in sync.")
emit_error(__file__, 0,
"Run this script with a file-name argument among the "
"following to overwrite the remaining files with the contents "
"of that file or run with the --latest switch to update each "
"of that file, or run with the --latest switch to update each "
"group of files from the most recently modified file in the group.")
for filename in files:
for filename in extant_files:
emit_error(__file__, 0, " " + filename)
else:
print(" Syncing others from", master_file)
@@ -81,7 +92,8 @@ def check_group(group_name, files, master_file_picker, emit_error):
if filename == master_file:
continue
print(" " + filename)
os.replace(filename, filename + '~')
if path.isfile(filename):
os.replace(filename, filename + '~')
shutil.copy(master_file, filename)
print(" Backups written with '~' appended to file names")

13
cpp/autobuilder/.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
obj/
TestResults/
*.manifest
*.pdb
*.suo
*.mdb
*.vsmdi
csharp.log
**/bin/Debug
**/bin/Release
*.tlog
.vs
*.user

View File

@@ -0,0 +1,296 @@
using Xunit;
using Semmle.Autobuild.Shared;
using System.Collections.Generic;
using System;
using System.Linq;
using Microsoft.Build.Construction;
using System.Xml;
namespace Semmle.Autobuild.Cpp.Tests
{
/// <summary>
/// Test class to script Autobuilder scenarios.
/// For most methods, it uses two fields:
/// - an IList to capture the the arguments passed to it
/// - an IDictionary of possible return values.
/// </summary>
class TestActions : IBuildActions
{
/// <summary>
/// List of strings passed to FileDelete.
/// </summary>
public IList<string> FileDeleteIn = new List<string>();
void IBuildActions.FileDelete(string file)
{
FileDeleteIn.Add(file);
}
public IList<string> FileExistsIn = new List<string>();
public IDictionary<string, bool> FileExists = new Dictionary<string, bool>();
bool IBuildActions.FileExists(string file)
{
FileExistsIn.Add(file);
if (FileExists.TryGetValue(file, out var ret))
return ret;
if (FileExists.TryGetValue(System.IO.Path.GetFileName(file), out ret))
return ret;
throw new ArgumentException("Missing FileExists " + file);
}
public IList<string> RunProcessIn = new List<string>();
public IDictionary<string, int> RunProcess = new Dictionary<string, int>();
public IDictionary<string, string> RunProcessOut = new Dictionary<string, string>();
public IDictionary<string, string> RunProcessWorkingDirectory = new Dictionary<string, string>();
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env, out IList<string> stdOut)
{
var pattern = cmd + " " + args;
RunProcessIn.Add(pattern);
if (RunProcessOut.TryGetValue(pattern, out var str))
stdOut = str.Split("\n");
else
throw new ArgumentException("Missing RunProcessOut " + pattern);
RunProcessWorkingDirectory.TryGetValue(pattern, out var wd);
if (wd != workingDirectory)
throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern);
if (RunProcess.TryGetValue(pattern, out var ret))
return ret;
throw new ArgumentException("Missing RunProcess " + pattern);
}
int IBuildActions.RunProcess(string cmd, string args, string? workingDirectory, IDictionary<string, string>? env)
{
var pattern = cmd + " " + args;
RunProcessIn.Add(pattern);
RunProcessWorkingDirectory.TryGetValue(pattern, out var wd);
if (wd != workingDirectory)
throw new ArgumentException("Missing RunProcessWorkingDirectory " + pattern);
if (RunProcess.TryGetValue(pattern, out var ret))
return ret;
throw new ArgumentException("Missing RunProcess " + pattern);
}
public IList<string> DirectoryDeleteIn = new List<string>();
void IBuildActions.DirectoryDelete(string dir, bool recursive)
{
DirectoryDeleteIn.Add(dir);
}
public IDictionary<string, bool> DirectoryExists = new Dictionary<string, bool>();
public IList<string> DirectoryExistsIn = new List<string>();
bool IBuildActions.DirectoryExists(string dir)
{
DirectoryExistsIn.Add(dir);
if (DirectoryExists.TryGetValue(dir, out var ret))
return ret;
throw new ArgumentException("Missing DirectoryExists " + dir);
}
public IDictionary<string, string?> GetEnvironmentVariable = new Dictionary<string, string?>();
string? IBuildActions.GetEnvironmentVariable(string name)
{
if (GetEnvironmentVariable.TryGetValue(name, out var ret))
return ret;
throw new ArgumentException("Missing GetEnvironmentVariable " + name);
}
public string GetCurrentDirectory = "";
string IBuildActions.GetCurrentDirectory()
{
return GetCurrentDirectory;
}
public IDictionary<string, string> EnumerateFiles = new Dictionary<string, string>();
IEnumerable<string> IBuildActions.EnumerateFiles(string dir)
{
if (EnumerateFiles.TryGetValue(dir, out var str))
return str.Split("\n");
throw new ArgumentException("Missing EnumerateFiles " + dir);
}
public IDictionary<string, string> EnumerateDirectories = new Dictionary<string, string>();
IEnumerable<string> IBuildActions.EnumerateDirectories(string dir)
{
if (EnumerateDirectories.TryGetValue(dir, out var str))
return string.IsNullOrEmpty(str) ? Enumerable.Empty<string>() : str.Split("\n");
throw new ArgumentException("Missing EnumerateDirectories " + dir);
}
public bool IsWindows;
bool IBuildActions.IsWindows() => IsWindows;
string IBuildActions.PathCombine(params string[] parts)
{
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
}
string IBuildActions.GetFullPath(string path) => path;
void IBuildActions.WriteAllText(string filename, string contents)
{
}
public IDictionary<string, XmlDocument> LoadXml = new Dictionary<string, XmlDocument>();
XmlDocument IBuildActions.LoadXml(string filename)
{
if (LoadXml.TryGetValue(filename, out var xml))
return xml;
throw new ArgumentException("Missing LoadXml " + filename);
}
public string EnvironmentExpandEnvironmentVariables(string s)
{
foreach (var kvp in GetEnvironmentVariable)
s = s.Replace($"%{kvp.Key}%", kvp.Value);
return s;
}
}
/// <summary>
/// A fake solution to build.
/// </summary>
class TestSolution : ISolution
{
public IEnumerable<SolutionConfigurationInSolution> Configurations => throw new NotImplementedException();
public string DefaultConfigurationName => "Release";
public string DefaultPlatformName => "x86";
public string FullPath { get; set; }
public Version ToolsVersion => new Version("14.0");
public IEnumerable<IProjectOrSolution> IncludedProjects => throw new NotImplementedException();
public TestSolution(string path)
{
FullPath = path;
}
}
public class BuildScriptTests
{
TestActions Actions = new TestActions();
// Records the arguments passed to StartCallback.
IList<string> StartCallbackIn = new List<string>();
void StartCallback(string s, bool silent)
{
StartCallbackIn.Add(s);
}
// Records the arguments passed to EndCallback
IList<string> EndCallbackIn = new List<string>();
IList<int> EndCallbackReturn = new List<int>();
void EndCallback(int ret, string s, bool silent)
{
EndCallbackReturn.Add(ret);
EndCallbackIn.Add(s);
}
CppAutobuilder CreateAutoBuilder(bool isWindows,
string? buildless = null, string? solution = null, string? buildCommand = null, string? ignoreErrors = null,
string? msBuildArguments = null, string? msBuildPlatform = null, string? msBuildConfiguration = null, string? msBuildTarget = null,
string? dotnetArguments = null, string? dotnetVersion = null, string? vsToolsVersion = null,
string? nugetRestore = null, string? allSolutions = null,
string cwd = @"C:\Project")
{
string codeqlUpperLanguage = Language.Cpp.UpperCaseName;
Actions.GetEnvironmentVariable[$"CODEQL_AUTOBUILDER_{codeqlUpperLanguage}_NO_INDEXING"] = "false";
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_TRAP_DIR"] = "";
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_SOURCE_ARCHIVE_DIR"] = "";
Actions.GetEnvironmentVariable[$"CODEQL_EXTRACTOR_{codeqlUpperLanguage}_ROOT"] = $@"C:\codeql\{codeqlUpperLanguage.ToLowerInvariant()}";
Actions.GetEnvironmentVariable["CODEQL_JAVA_HOME"] = @"C:\codeql\tools\java";
Actions.GetEnvironmentVariable["SEMMLE_DIST"] = @"C:\odasa";
Actions.GetEnvironmentVariable["SEMMLE_JAVA_HOME"] = @"C:\odasa\tools\java";
Actions.GetEnvironmentVariable["SEMMLE_PLATFORM_TOOLS"] = @"C:\odasa\tools";
Actions.GetEnvironmentVariable["LGTM_INDEX_VSTOOLS_VERSION"] = vsToolsVersion;
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_ARGUMENTS"] = msBuildArguments;
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_PLATFORM"] = msBuildPlatform;
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_CONFIGURATION"] = msBuildConfiguration;
Actions.GetEnvironmentVariable["LGTM_INDEX_MSBUILD_TARGET"] = msBuildTarget;
Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_ARGUMENTS"] = dotnetArguments;
Actions.GetEnvironmentVariable["LGTM_INDEX_DOTNET_VERSION"] = dotnetVersion;
Actions.GetEnvironmentVariable["LGTM_INDEX_BUILD_COMMAND"] = buildCommand;
Actions.GetEnvironmentVariable["LGTM_INDEX_SOLUTION"] = solution;
Actions.GetEnvironmentVariable["LGTM_INDEX_IGNORE_ERRORS"] = ignoreErrors;
Actions.GetEnvironmentVariable["LGTM_INDEX_BUILDLESS"] = buildless;
Actions.GetEnvironmentVariable["LGTM_INDEX_ALL_SOLUTIONS"] = allSolutions;
Actions.GetEnvironmentVariable["LGTM_INDEX_NUGET_RESTORE"] = nugetRestore;
Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = isWindows ? @"C:\Program Files (x86)" : null;
Actions.GetCurrentDirectory = cwd;
Actions.IsWindows = isWindows;
var options = new AutobuildOptions(Actions, Language.Cpp);
return new CppAutobuilder(Actions, options);
}
void TestAutobuilderScript(Autobuilder autobuilder, int expectedOutput, int commandsRun)
{
Assert.Equal(expectedOutput, autobuilder.GetBuildScript().Run(Actions, StartCallback, EndCallback));
// Check expected commands actually ran
Assert.Equal(commandsRun, StartCallbackIn.Count);
Assert.Equal(commandsRun, EndCallbackIn.Count);
Assert.Equal(commandsRun, EndCallbackReturn.Count);
var action = Actions.RunProcess.GetEnumerator();
for (int cmd = 0; cmd < commandsRun; ++cmd)
{
Assert.True(action.MoveNext());
Assert.Equal(action.Current.Key, StartCallbackIn[cmd]);
Assert.Equal(action.Current.Value, EndCallbackReturn[cmd]);
}
}
[Fact]
public void TestDefaultCppAutobuilder()
{
Actions.EnumerateFiles[@"C:\Project"] = "";
Actions.EnumerateDirectories[@"C:\Project"] = "";
var autobuilder = CreateAutoBuilder(true);
var script = autobuilder.GetBuildScript();
// Fails due to no solutions present.
Assert.NotEqual(0, script.Run(Actions, StartCallback, EndCallback));
}
[Fact]
public void TestCppAutobuilderSuccess()
{
Actions.RunProcess[@"cmd.exe /C C:\odasa\tools\csharp\nuget\nuget.exe restore C:\Project\test.sln"] = 1;
Actions.RunProcess[@"cmd.exe /C CALL ^""C:\Program Files ^(x86^)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat^"" && set Platform=&& type NUL && C:\odasa\tools\odasa index --auto msbuild C:\Project\test.sln /p:UseSharedCompilation=false /t:rebuild /p:Platform=""x86"" /p:Configuration=""Release"" /p:MvcBuildViews=true"] = 0;
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "";
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 1;
Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0;
Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = "";
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"] = true;
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"] = true;
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat"] = true;
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"] = true;
Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true;
Actions.EnumerateFiles[@"C:\Project"] = "foo.cs\ntest.slx";
Actions.EnumerateDirectories[@"C:\Project"] = "";
var autobuilder = CreateAutoBuilder(true);
var solution = new TestSolution(@"C:\Project\test.sln");
autobuilder.ProjectsOrSolutionsToBuild.Add(solution);
TestAutobuilderScript(autobuilder, 0, 2);
}
}
}

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Semmle.Autobuild.Cpp\Semmle.Autobuild.Cpp.csproj" />
<ProjectReference Include="..\..\..\csharp\autobuilder\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,23 @@
using Semmle.Autobuild.Shared;
namespace Semmle.Autobuild.Cpp
{
public class CppAutobuilder : Autobuilder
{
public CppAutobuilder(IBuildActions actions, AutobuildOptions options) : base(actions, options) { }
public override BuildScript GetBuildScript()
{
if (Options.BuildCommand != null)
return new BuildCommandRule((_, f) => f(null)).Analyse(this, false);
return
// First try MSBuild
new MsBuildRule().Analyse(this, true) |
// Then look for a script that might be a build script
(() => new BuildCommandAutoRule((_, f) => f(null)).Analyse(this, true)) |
// All attempts failed: print message
AutobuildFailure();
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using Semmle.Autobuild.Shared;
namespace Semmle.Autobuild
namespace Semmle.Autobuild.Cpp
{
class Program
{
@@ -10,11 +11,11 @@ namespace Semmle.Autobuild
try
{
var actions = SystemBuildActions.Instance;
var options = new AutobuildOptions(actions);
var options = new AutobuildOptions(actions, Language.Cpp);
try
{
Console.WriteLine($"Semmle autobuilder for {options.Language}");
var builder = new Autobuilder(actions, options);
Console.WriteLine("CodeQL C++ autobuilder");
var builder = new CppAutobuilder(actions, options);
return builder.AttemptBuild();
}
catch(InvalidEnvironmentException ex)

View File

@@ -4,12 +4,12 @@ using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Semmle.Autobuild.Tests")]
[assembly: AssemblyTitle("Semmle.Autobuild.Cpp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Semmle.Extraction.Tests")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyCompany("GitHub")]
[assembly: AssemblyProduct("CodeQL autobuilder for C++")]
[assembly: AssemblyCopyright("Copyright © GitHub 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

View File

@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<AssemblyName>Semmle.Autobuild.Cpp</AssemblyName>
<RootNamespace>Semmle.Autobuild.Cpp</RootNamespace>
<ApplicationIcon />
<OutputType>Exe</OutputType>
<StartupObject />
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="16.0.461" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\csharp\extractor\Semmle.Util\Semmle.Util.csproj" />
<ProjectReference Include="..\..\..\csharp\autobuilder\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
</ItemGroup>
</Project>

View File

@@ -4,6 +4,10 @@
import cpp
/**
* Gets a string representation of the comment `c` containing the caption 'TODO' or 'FIXME'.
* If `c` spans multiple lines, all lines after the first are abbreviated as [...].
*/
string getCommentTextCaptioned(Comment c, string caption) {
(caption = "TODO" or caption = "FIXME") and
exists(

View File

@@ -1,3 +1,7 @@
/**
* Provides classes and predicates for identifying C/C++ comments that look like code.
*/
import cpp
/**
@@ -137,8 +141,14 @@ class CommentBlock extends Comment {
)
}
/**
* Gets the last comment associated with this comment block.
*/
Comment lastComment() { result = this.getComment(max(int i | exists(this.getComment(i)))) }
/**
* Gets the contents of the `i`'th comment associated with this comment block.
*/
string getLine(int i) {
this instanceof CStyleComment and
result = this.getContents().regexpCapture("(?s)/\\*+(.*)\\*+/", 1).splitAt("\n", i)
@@ -146,14 +156,24 @@ class CommentBlock extends Comment {
this instanceof CppStyleComment and result = this.getComment(i).getContents().suffix(2)
}
/**
* Gets the number of lines in the comments associated with this comment block.
*/
int numLines() {
result = strictcount(int i, string line | line = this.getLine(i) and line.trim() != "")
}
/**
* Gets the number of lines that look like code in the comments associated with this comment block.
*/
int numCodeLines() {
result = strictcount(int i, string line | line = this.getLine(i) and looksLikeCode(line))
}
/**
* Holds if the comment block is a C-style comment, and each
* comment line starts with a *.
*/
predicate isDocumentation() {
// If a C-style comment starts each line with a *, then it's
// probably documentation rather than code.
@@ -161,6 +181,12 @@ class CommentBlock extends Comment {
forex(int i | i in [1 .. this.numLines() - 1] | this.getLine(i).trim().matches("*%"))
}
/**
* Holds if this comment block looks like code that has been commented out. Specifically:
* 1. It does not look like documentation (see `isDocumentation`).
* 2. It is not in a header file without any declaration entries or top level declarations.
* 3. More than half of the lines in the comment block look like code.
*/
predicate isCommentedOutCode() {
not this.isDocumentation() and
not this.getFile().(HeaderFile).noTopLevelCode() and

View File

@@ -15,6 +15,15 @@ import cpp
import semmle.code.cpp.models.implementations.Strcpy
import semmle.code.cpp.dataflow.DataFlow
/**
* A string copy function that returns a string, rather than an error code (for
* example, `strcpy` returns a string, whereas `strcpy_s` returns an error
* code).
*/
class InterestingStrcpyFunction extends StrcpyFunction {
InterestingStrcpyFunction() { getType().getUnspecifiedType() instanceof PointerType }
}
predicate isBoolean(Expr e1) {
exists(Type t1 |
t1 = e1.getType() and
@@ -25,12 +34,12 @@ predicate isBoolean(Expr e1) {
predicate isStringCopyCastedAsBoolean(FunctionCall func, Expr expr1, string msg) {
DataFlow::localExprFlow(func, expr1) and
isBoolean(expr1.getConversion*()) and
func.getTarget() instanceof StrcpyFunction and
func.getTarget() instanceof InterestingStrcpyFunction and
msg = "Return value of " + func.getTarget().getName() + " used as a Boolean."
}
predicate isStringCopyUsedInLogicalOperationOrCondition(FunctionCall func, Expr expr1, string msg) {
func.getTarget() instanceof StrcpyFunction and
func.getTarget() instanceof InterestingStrcpyFunction and
(
(
// it is being used in an equality or logical operation

View File

@@ -23,7 +23,7 @@ import semmle.code.cpp.ir.ValueNumbering
class NullInstruction extends ConstantValueInstruction {
NullInstruction() {
this.getValue() = "0" and
this.getResultType().getUnspecifiedType() instanceof PointerType
this.getResultIRType() instanceof IRAddressType
}
}
@@ -44,8 +44,8 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) {
bool =
any(ConvertInstruction convert |
checked = convert.getUnary() and
convert.getResultType() instanceof BoolType and
checked.getResultType() instanceof PointerType
convert.getResultIRType() instanceof IRBooleanType and
checked.getResultIRType() instanceof IRAddressType
)
}

View File

@@ -6,29 +6,50 @@
import cpp
// True if function was ()-declared, but not (void)-declared or K&R-defined
/**
* Holds if `fde` has a parameter declaration that's clear on the minimum
* number of parameters. This is essentially true for everything except
* `()`-declarations.
*/
private predicate hasDefiniteNumberOfParameters(FunctionDeclarationEntry fde) {
fde.hasVoidParamList()
or
fde.getNumberOfParameters() > 0
or
fde.isDefinition()
}
/* Holds if function was ()-declared, but not (void)-declared or K&R-defined. */
private predicate hasZeroParamDecl(Function f) {
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
not hasDefiniteNumberOfParameters(fde)
)
}
// True if this file (or header) was compiled as a C file
/* Holds if this file (or header) was compiled as a C file. */
private predicate isCompiledAsC(File f) {
f.compiledAsC()
or
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
}
/** Holds if `fc` is a call to `f` with too few arguments. */
predicate tooFewArguments(FunctionCall fc, Function f) {
f = fc.getTarget() and
not f.isVarargs() and
not f instanceof BuiltInFunction and
// This query should only have results on C (not C++) functions that have a
// `()` parameter list somewhere. If it has results on other functions, then
// it's probably because the extractor only saw a partial compilation.
hasZeroParamDecl(f) and
isCompiledAsC(f.getFile()) and
// There is an explicit declaration of the function whose parameter count is larger
// than the number of call arguments
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
// Produce an alert when all declarations that are authoritative on the
// parameter count specify a parameter count larger than the number of call
// arguments.
forex(FunctionDeclarationEntry fde |
fde = f.getADeclarationEntry() and
hasDefiniteNumberOfParameters(fde)
|
fde.getNumberOfParameters() > fc.getNumberOfArguments()
)
}

View File

@@ -1,27 +0,0 @@
/**
* @name Churned lines per file
* @description Number of churned lines per file, across the revision
* history in the database.
* @kind treemap
* @id cpp/historical-churn
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f, int n
where
n =
sum(Commit entry, int churn |
churn = entry.getRecentChurnForFile(f) and
not artificialChange(entry)
|
churn
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
select f, n order by n desc

View File

@@ -1,27 +0,0 @@
/**
* @name Added lines per file
* @description Number of added lines per file, across the revision
* history in the database.
* @kind treemap
* @id cpp/historical-lines-added
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f, int n
where
n =
sum(Commit entry, int churn |
churn = entry.getRecentAdditionsForFile(f) and
not artificialChange(entry)
|
churn
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
select f, n order by n desc

View File

@@ -1,27 +0,0 @@
/**
* @name Deleted lines per file
* @description Number of deleted lines per file, across the revision
* history in the database.
* @kind treemap
* @id cpp/historical-lines-deleted
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg sum max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f, int n
where
n =
sum(Commit entry, int churn |
churn = entry.getRecentDeletionsForFile(f) and
not artificialChange(entry)
|
churn
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
select f, n order by n desc

View File

@@ -1,18 +0,0 @@
/**
* @name Number of authors
* @description Number of distinct authors for each file.
* @kind treemap
* @id cpp/historical-number-of-authors
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f
where exists(f.getMetrics().getNumberOfLinesOfCode())
select f, count(Author author | author.getAnEditedFile() = f)

View File

@@ -1,19 +0,0 @@
/**
* @name Number of file-level changes
* @description The number of file-level changes made (by version
* control history).
* @kind treemap
* @id cpp/historical-number-of-changes
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max sum
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f
where exists(f.getMetrics().getNumberOfLinesOfCode())
select f, count(Commit svn | f = svn.getAnAffectedFile() and not artificialChange(svn))

View File

@@ -1,21 +0,0 @@
/**
* @name Number of co-committed files
* @description The average number of other files that are touched
* whenever a file is affected by a commit.
* @kind treemap
* @id cpp/historical-number-of-co-commits
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
int committedFiles(Commit commit) { result = count(commit.getAnAffectedFile()) }
from File f
where exists(f.getMetrics().getNumberOfLinesOfCode())
select f, avg(Commit commit | commit.getAnAffectedFile() = f | committedFiles(commit) - 1)

View File

@@ -1,37 +0,0 @@
/**
* @name Number of re-commits for each file
* @description A re-commit is taken to mean a commit to a file that
* was touched less than five days ago.
* @kind treemap
* @id cpp/historical-number-of-re-commits
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
predicate inRange(Commit first, Commit second) {
first.getAnAffectedFile() = second.getAnAffectedFile() and
first != second and
exists(int n |
n = first.getDate().daysTo(second.getDate()) and
n >= 0 and
n < 5
)
}
int recommitsForFile(File f) {
result =
count(Commit recommit |
f = recommit.getAnAffectedFile() and
exists(Commit prev | inRange(prev, recommit))
)
}
from File f
where exists(f.getMetrics().getNumberOfLinesOfCode())
select f, recommitsForFile(f)

View File

@@ -1,27 +0,0 @@
/**
* @name Number of recent authors
* @description Number of distinct authors that have recently made
* changes.
* @kind treemap
* @id cpp/historical-number-of-recent-authors
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f
where exists(f.getMetrics().getNumberOfLinesOfCode())
select f,
count(Author author |
exists(Commit e |
e = author.getACommit() and
f = e.getAnAffectedFile() and
e.daysToNow() <= 180 and
not artificialChange(e)
)
)

View File

@@ -1,24 +0,0 @@
/**
* @name Recently changed files
* @description Number of files recently edited.
* @kind treemap
* @id cpp/historical-number-of-recent-changed-files
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max sum
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f
where
exists(Commit e |
e.getAnAffectedFile() = f and
e.daysToNow() <= 180 and
not artificialChange(e)
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
select f, 1

View File

@@ -1,25 +0,0 @@
/**
* @name Recent changes
* @description Number of recent commits to this file.
* @kind treemap
* @id cpp/historical-number-of-recent-changes
* @treemap.warnOn highValues
* @metricType file
* @metricAggregate avg min max sum
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
from File f, int n
where
n =
count(Commit e |
e.getAnAffectedFile() = f and
e.daysToNow() <= 180 and
not artificialChange(e)
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
select f, n order by n desc

View File

@@ -5,7 +5,7 @@
* or data representation problems.
* @kind path-problem
* @problem.severity warning
* @precision medium
* @precision high
* @id cpp/tainted-format-string
* @tags reliability
* security

View File

@@ -5,7 +5,7 @@
* or data representation problems.
* @kind path-problem
* @problem.severity warning
* @precision medium
* @precision high
* @id cpp/tainted-format-string-through-global
* @tags reliability
* security

View File

@@ -18,7 +18,7 @@ abstract class InsecureCryptoSpec extends Locatable {
}
Function getAnInsecureFunction() {
result.getName().regexpMatch(algorithmBlacklistRegex()) and
result.getName().regexpMatch(getInsecureAlgorithmRegex()) and
exists(result.getACallToThisFunction())
}
@@ -33,7 +33,7 @@ class InsecureFunctionCall extends InsecureCryptoSpec, FunctionCall {
}
Macro getAnInsecureMacro() {
result.getName().regexpMatch(algorithmBlacklistRegex()) and
result.getName().regexpMatch(getInsecureAlgorithmRegex()) and
exists(result.getAnInvocation())
}

View File

@@ -2,3 +2,5 @@
- qlpack: codeql-cpp
- apply: code-scanning-selectors.yml
from: codeql-suite-helpers
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql-cpp

View File

@@ -2,13 +2,10 @@
- qlpack: codeql-cpp
- apply: lgtm-selectors.yml
from: codeql-suite-helpers
# These queries are infeasible to compute on large projects:
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql-cpp
# These are only for IDE use.
- exclude:
query path:
- Security/CWE/CWE-497/ExposedSystemData.ql
- Critical/DescriptorMayNotBeClosed.ql
- Critical/DescriptorNeverClosed.ql
- Critical/FileMayNotBeClosed.ql
- Critical/FileNeverClosed.ql
- Critical/MemoryMayNotBeFreed.ql
- Critical/MemoryNeverFreed.ql
tags contain:
- ide-contextual-queries/local-definitions
- ide-contextual-queries/local-references

View File

@@ -0,0 +1,6 @@
- description: Security-and-quality queries for C and C++
- qlpack: codeql-cpp
- apply: security-and-quality-selectors.yml
from: codeql-suite-helpers
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql-cpp

View File

@@ -0,0 +1,6 @@
- description: Security-extended queries for C and C++
- qlpack: codeql-cpp
- apply: security-extended-selectors.yml
from: codeql-suite-helpers
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql-cpp

View File

@@ -0,0 +1,11 @@
- description: C/C++ queries which are infeasible to compute on large projects
# These queries are infeasible to compute on large projects:
- exclude:
query path:
- Security/CWE/CWE-497/ExposedSystemData.ql
- Critical/DescriptorMayNotBeClosed.ql
- Critical/DescriptorNeverClosed.ql
- Critical/FileMayNotBeClosed.ql
- Critical/FileNeverClosed.ql
- Critical/MemoryMayNotBeFreed.ql
- Critical/MemoryNeverFreed.ql

View File

@@ -32,6 +32,7 @@ import semmle.code.cpp.Enum
import semmle.code.cpp.Member
import semmle.code.cpp.Field
import semmle.code.cpp.Function
import semmle.code.cpp.MemberFunction
import semmle.code.cpp.Parameter
import semmle.code.cpp.Variable
import semmle.code.cpp.Initializer

View File

@@ -1 +1,7 @@
/**
* DEPRECATED: use `import cpp` instead of `import default`.
*
* Provides classes and predicates for working with C/C++ code.
*/
import cpp

View File

@@ -132,6 +132,7 @@ private predicate constructorCallTypeMention(ConstructorCall cc, TypeMention tm)
* - `"X"` for macro accesses
* - `"I"` for import / include directives
*/
cached
Top definitionOf(Top e, string kind) {
(
// call -> function called
@@ -213,3 +214,11 @@ Top definitionOf(Top e, string kind) {
// later on.
strictcount(result.getLocation()) < 10
}
/**
* Returns an appropriately encoded version of a filename `name`
* passed by the VS Code extension in order to coincide with the
* output of `.getFile()` on locatable entities.
*/
cached
File getEncodedFile(string name) { result.getAbsolutePath().replaceAll(":", "_") = name }

View File

@@ -20,7 +20,7 @@ import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.internal.CppType
private import semmle.code.cpp.models.interfaces.Allocation
private import semmle.code.cpp.rangeanalysis.RangeUtils
private import experimental.semmle.code.cpp.rangeanalysis.RangeUtils
private newtype TLength =
TZeroLength() or

View File

@@ -8,8 +8,8 @@ private newtype TBound =
exists(Instruction i |
vn.getAnInstruction() = i and
(
i.getResultType() instanceof IntegralType or
i.getResultType() instanceof PointerType
i.getResultIRType() instanceof IRIntegerType or
i.getResultIRType() instanceof IRAddressType
) and
not vn.getAnInstruction() instanceof ConstantInstruction
|
@@ -68,7 +68,7 @@ class ValueNumberBound extends Bound, TBoundValueNumber {
ValueNumberBound() { this = TBoundValueNumber(vn) }
/** Gets the SSA variable that equals this bound. */
/** Gets an `Instruction` that equals this bound. */
override Instruction getInstruction(int delta) {
this = TBoundValueNumber(valueNumber(result)) and delta = 0
}
@@ -76,4 +76,7 @@ class ValueNumberBound extends Bound, TBoundValueNumber {
override string toString() { result = vn.getExampleInstruction().toString() }
override Location getLocation() { result = vn.getLocation() }
/** Gets the value number that equals this bound. */
ValueNumber getValueNumber() { result = vn }
}

View File

@@ -0,0 +1,105 @@
/**
* This library proves that a subset of pointer dereferences in a program are
* safe, i.e. in-bounds.
* It does so by first defining what a pointer dereference is (on the IR
* `Instruction` level), and then using the array length analysis and the range
* analysis together to prove that some of these pointer dereferences are safe.
*
* The analysis is soundy, i.e. it is sound if no undefined behaviour is present
* in the program.
* Furthermore, it crucially depends on the soundiness of the range analysis and
* the array length analysis.
*/
import cpp
private import experimental.semmle.code.cpp.rangeanalysis.ArrayLengthAnalysis
private import experimental.semmle.code.cpp.rangeanalysis.RangeAnalysis
/**
* Gets the instruction that computes the address of memory that `i` accesses.
* Only holds if `i` dereferences a pointer, not when the computation of the
* memory address is constant, or if the address of a local variable is loaded/stored to.
*/
private Instruction getMemoryAddressInstruction(Instruction i) {
(
result = i.(FieldAddressInstruction).getObjectAddress() or
result = i.(LoadInstruction).getSourceAddress() or
result = i.(StoreInstruction).getDestinationAddress()
) and
not result instanceof FieldAddressInstruction and
not result instanceof VariableAddressInstruction and
not result instanceof ConstantValueInstruction
}
/**
* All instructions that dereference a pointer.
*/
class PointerDereferenceInstruction extends Instruction {
PointerDereferenceInstruction() { exists(getMemoryAddressInstruction(this)) }
Instruction getAddress() { result = getMemoryAddressInstruction(this) }
}
/**
* Holds if `ptrDeref` can be proven to always access allocated memory.
*/
predicate inBounds(PointerDereferenceInstruction ptrDeref) {
exists(Length length, int lengthDelta, Offset offset, int offsetDelta |
knownArrayLength(ptrDeref.getAddress(), length, lengthDelta, offset, offsetDelta) and
// lower bound - note that we treat a pointer that accesses an array of
// length 0 as on upper-bound violation, but not as a lower-bound violation
(
offset instanceof ZeroOffset and
offsetDelta >= 0
or
offset instanceof OpOffset and
exists(int lowerBoundDelta |
boundedOperand(offset.(OpOffset).getOperand(), any(ZeroBound b), lowerBoundDelta,
/*upper*/ false, _) and
lowerBoundDelta + offsetDelta >= 0
)
) and
// upper bound
(
// both offset and length are only integers
length instanceof ZeroLength and
offset instanceof ZeroOffset and
offsetDelta < lengthDelta
or
exists(int lengthBound |
// array length is variable+integer, and there's a fixed (integer-only)
// lower bound on the variable, so we can guarantee this access is always in-bounds
length instanceof VNLength and
offset instanceof ZeroOffset and
boundedInstruction(length.(VNLength).getInstruction(), any(ZeroBound b), lengthBound,
/* upper*/ false, _) and
offsetDelta < lengthBound + lengthDelta
)
or
exists(int offsetBoundDelta |
length instanceof ZeroLength and
offset instanceof OpOffset and
boundedOperand(offset.(OpOffset).getOperand(), any(ZeroBound b), offsetBoundDelta,
/* upper */ true, _) and
// offset <= offsetBoundDelta, so offset + offsetDelta <= offsetDelta + offsetBoundDelta
// Thus, in-bounds if offsetDelta + offsetBoundDelta < lengthDelta
// as we have length instanceof ZeroLength
offsetDelta + offsetBoundDelta < lengthDelta
)
or
exists(ValueNumberBound b, int offsetBoundDelta |
length instanceof VNLength and
offset instanceof OpOffset and
b.getValueNumber() = length.(VNLength).getValueNumber() and
// It holds that offset <= length + offsetBoundDelta
boundedOperand(offset.(OpOffset).getOperand(), b, offsetBoundDelta, /*upper*/ true, _) and
// it also holds that
offsetDelta < lengthDelta - offsetBoundDelta
// taking both inequalities together we get
// offset <= length + offsetBoundDelta
// => offset + offsetDelta <= length + offsetBoundDelta + offsetDelta < length + offsetBoundDelta + lengthDelta - offsetBoundDelta
// as required
)
)
)
}

View File

@@ -244,14 +244,14 @@ class CondReason extends Reason, TCondReason {
/**
* Holds if `typ` is a small integral type with the given lower and upper bounds.
*/
private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) {
typ.isSigned() and typ.getSize() = 1 and lowerbound = -128 and upperbound = 127
private predicate typeBound(IRIntegerType typ, int lowerbound, int upperbound) {
typ.isSigned() and typ.getByteSize() = 1 and lowerbound = -128 and upperbound = 127
or
typ.isUnsigned() and typ.getSize() = 1 and lowerbound = 0 and upperbound = 255
typ.isUnsigned() and typ.getByteSize() = 1 and lowerbound = 0 and upperbound = 255
or
typ.isSigned() and typ.getSize() = 2 and lowerbound = -32768 and upperbound = 32767
typ.isSigned() and typ.getByteSize() = 2 and lowerbound = -32768 and upperbound = 32767
or
typ.isUnsigned() and typ.getSize() = 2 and lowerbound = 0 and upperbound = 65535
typ.isUnsigned() and typ.getByteSize() = 2 and lowerbound = 0 and upperbound = 65535
}
/**
@@ -260,14 +260,14 @@ private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) {
private class NarrowingCastInstruction extends ConvertInstruction {
NarrowingCastInstruction() {
not this instanceof SafeCastInstruction and
typeBound(getResultType(), _, _)
typeBound(getResultIRType(), _, _)
}
/** Gets the lower bound of the resulting type. */
int getLowerBound() { typeBound(getResultType(), result, _) }
int getLowerBound() { typeBound(getResultIRType(), result, _) }
/** Gets the upper bound of the resulting type. */
int getUpperBound() { typeBound(getResultType(), _, result) }
int getUpperBound() { typeBound(getResultIRType(), _, result) }
}
/**

View File

@@ -86,15 +86,15 @@ predicate backEdge(PhiInstruction phi, PhiInputOperand op) {
* range analysis.
*/
pragma[inline]
private predicate safeCast(IntegralType fromtyp, IntegralType totyp) {
fromtyp.getSize() < totyp.getSize() and
private predicate safeCast(IRIntegerType fromtyp, IRIntegerType totyp) {
fromtyp.getByteSize() < totyp.getByteSize() and
(
fromtyp.isUnsigned()
or
totyp.isSigned()
)
or
fromtyp.getSize() <= totyp.getSize() and
fromtyp.getByteSize() <= totyp.getByteSize() and
(
fromtyp.isSigned() and
totyp.isSigned()
@@ -109,8 +109,8 @@ private predicate safeCast(IntegralType fromtyp, IntegralType totyp) {
*/
class PtrToPtrCastInstruction extends ConvertInstruction {
PtrToPtrCastInstruction() {
getResultType() instanceof PointerType and
getUnary().getResultType() instanceof PointerType
getResultIRType() instanceof IRAddressType and
getUnary().getResultIRType() instanceof IRAddressType
}
}
@@ -119,7 +119,7 @@ class PtrToPtrCastInstruction extends ConvertInstruction {
* that cannot overflow or underflow.
*/
class SafeIntCastInstruction extends ConvertInstruction {
SafeIntCastInstruction() { safeCast(getUnary().getResultType(), getResultType()) }
SafeIntCastInstruction() { safeCast(getUnary().getResultIRType(), getResultIRType()) }
}
/**

View File

@@ -278,8 +278,6 @@ private predicate unknownSign(Instruction i) {
// non-positive, non-zero}, which would mean that the representation of the sign of an unknown
// value would be the empty set.
(
i instanceof UnmodeledDefinitionInstruction
or
i instanceof UninitializedInstruction
or
i instanceof InitializeParameterInstruction
@@ -471,7 +469,7 @@ module SignAnalysisCached {
not exists(certainInstructionSign(i)) and
not (
result = TNeg() and
i.getResultType().(IntegralType).isUnsigned()
i.getResultIRType().(IRIntegerType).isUnsigned()
) and
(
unknownSign(i)
@@ -479,9 +477,13 @@ module SignAnalysisCached {
exists(ConvertInstruction ci, Instruction prior, boolean fromSigned, boolean toSigned |
i = ci and
prior = ci.getUnary() and
(if ci.getResultType().(IntegralType).isSigned() then toSigned = true else toSigned = false) and
(
if prior.getResultType().(IntegralType).isSigned()
if ci.getResultIRType().(IRIntegerType).isSigned()
then toSigned = true
else toSigned = false
) and
(
if prior.getResultIRType().(IRIntegerType).isSigned()
then fromSigned = true
else fromSigned = false
) and
@@ -514,11 +516,11 @@ module SignAnalysisCached {
i instanceof ShiftLeftInstruction and result = s1.lshift(s2)
or
i instanceof ShiftRightInstruction and
i.getResultType().(IntegralType).isSigned() and
i.getResultIRType().(IRIntegerType).isSigned() and
result = s1.rshift(s2)
or
i instanceof ShiftRightInstruction and
not i.getResultType().(IntegralType).isSigned() and
not i.getResultIRType().(IRIntegerType).isSigned() and
result = s1.urshift(s2)
)
or

View File

@@ -1,3 +1,5 @@
/** Provides classes for detecting duplicate or similar code. */
import cpp
private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") }
@@ -8,9 +10,12 @@ private predicate tokenLocation(string path, int sl, int sc, int ec, int el, Cop
tokens(copy, index, sl, sc, ec, el)
}
/** A token block used for detection of duplicate and similar code. */
class Copy extends @duplication_or_similarity {
/** Gets the index of the last token in this block. */
private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) }
/** Gets the index of the token in this block starting at the location `loc`, if any. */
int tokenStartingAt(Location loc) {
exists(string filepath, int startline, int startcol |
loc.hasLocationInfo(filepath, startline, startcol, _, _) and
@@ -18,6 +23,7 @@ class Copy extends @duplication_or_similarity {
)
}
/** Gets the index of the token in this block ending at the location `loc`, if any. */
int tokenEndingAt(Location loc) {
exists(string filepath, int endline, int endcol |
loc.hasLocationInfo(filepath, _, _, endline, endcol) and
@@ -25,24 +31,38 @@ class Copy extends @duplication_or_similarity {
)
}
/** Gets the line on which the first token in this block starts. */
int sourceStartLine() { tokens(this, 0, result, _, _, _) }
/** Gets the column on which the first token in this block starts. */
int sourceStartColumn() { tokens(this, 0, _, result, _, _) }
/** Gets the line on which the last token in this block ends. */
int sourceEndLine() { tokens(this, lastToken(), _, _, result, _) }
/** Gets the column on which the last token in this block ends. */
int sourceEndColumn() { tokens(this, lastToken(), _, _, _, result) }
/** Gets the number of lines containing at least (part of) one token in this block. */
int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() }
/** Gets an opaque identifier for the equivalence class of this block. */
int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) }
/** Gets the source file in which this block appears. */
File sourceFile() {
exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) |
name.replaceAll("\\", "/") = relativePath(result)
)
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
@@ -53,25 +73,30 @@ class Copy extends @duplication_or_similarity {
endcolumn = sourceEndColumn()
}
/** Gets a textual representation of this element. */
string toString() { none() }
}
/** A block of duplicated code. */
class DuplicateBlock extends Copy, @duplication {
override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." }
}
/** A block of similar code. */
class SimilarBlock extends Copy, @similarity {
override string toString() {
result = "Similar code: " + sourceLines() + " almost duplicated lines."
}
}
/** Gets a function with a body and a location. */
FunctionDeclarationEntry sourceMethod() {
result.isDefinition() and
exists(result.getLocation()) and
numlines(unresolveElement(result.getFunction()), _, _, _)
}
/** Gets the number of member functions in `c` with a body and a location. */
int numberOfSourceMethods(Class c) {
result =
count(FunctionDeclarationEntry m |
@@ -108,6 +133,10 @@ private predicate duplicateStatement(
)
}
/**
* Holds if `m1` is a function with `total` lines, and `m2` is a function
* that has `duplicate` lines in common with `m1`.
*/
predicate duplicateStatements(
FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, int duplicate, int total
) {
@@ -115,13 +144,16 @@ predicate duplicateStatements(
total = strictcount(statementInMethod(m1))
}
/**
* Find pairs of methods are identical
*/
/** Holds if `m` and other are identical functions. */
predicate duplicateMethod(FunctionDeclarationEntry m, FunctionDeclarationEntry other) {
exists(int total | duplicateStatements(m, other, total, total))
}
/**
* INTERNAL: do not use.
*
* Holds if `line` in `f` is similar to a line somewhere else.
*/
predicate similarLines(File f, int line) {
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
}
@@ -152,6 +184,7 @@ private predicate similarLinesCoveredFiles(File f, File otherFile) {
)
}
/** Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`. */
predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
similarLinesCoveredFiles(f, otherFile) and
@@ -166,6 +199,11 @@ predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
)
}
/**
* INTERNAL: do not use.
*
* Holds if `line` in `f` is duplicated by a line somewhere else.
*/
predicate duplicateLines(File f, int line) {
exists(DuplicateBlock b |
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
@@ -182,6 +220,7 @@ private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, F
)
}
/** Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`. */
predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
exists(int coveredApprox |
@@ -206,6 +245,7 @@ predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
)
}
/** Holds if most of `f` (`percent`%) is similar to `other`. */
predicate similarFiles(File f, File other, int percent) {
exists(int covered, int total |
similarLinesCovered(f, covered, other) and
@@ -216,6 +256,7 @@ predicate similarFiles(File f, File other, int percent) {
not duplicateFiles(f, other, _)
}
/** Holds if most of `f` (`percent`%) is duplicated by `other`. */
predicate duplicateFiles(File f, File other, int percent) {
exists(int covered, int total |
duplicateLinesCovered(f, covered, other) and
@@ -225,6 +266,10 @@ predicate duplicateFiles(File f, File other, int percent) {
)
}
/**
* Holds if most member functions of `c` (`numDup` out of `total`) are
* duplicates of member functions in `other`.
*/
predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) {
numDup =
strictcount(FunctionDeclarationEntry m1 |
@@ -240,6 +285,11 @@ predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total)
(numDup * 100) / total > 80
}
/**
* Holds if most member functions of `c` are duplicates of member functions in
* `other`. Provides the human-readable `message` to describe the amount of
* duplication.
*/
predicate mostlyDuplicateClass(Class c, Class other, string message) {
exists(int numDup, int total |
mostlyDuplicateClassBase(c, other, numDup, total) and
@@ -264,12 +314,21 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) {
)
}
/** Holds if `f` and `other` are similar or duplicates. */
predicate fileLevelDuplication(File f, File other) {
similarFiles(f, other, _) or duplicateFiles(f, other, _)
}
/**
* Holds if most member functions of `c` are duplicates of member functions in
* `other`.
*/
predicate classLevelDuplication(Class c, Class other) { mostlyDuplicateClass(c, other, _) }
/**
* Holds if `line` in `f` should be allowed to be duplicated. This is the case
* for `#include` directives.
*/
predicate whitelistedLineForDuplication(File f, int line) {
exists(Include i | i.getFile() = f and i.getLocation().getStartLine() = line)
}

View File

@@ -1,31 +1,52 @@
/** Provides a class for working with defect query results stored in dashboard databases. */
import cpp
/**
* Holds if `id` in the opaque identifier of a result reported by query `queryPath`,
* such that `message` is the associated message and the location of the result spans
* column `startcolumn` of line `startline` to column `endcolumn` of line `endline`
* in file `filepath`.
*
* For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
external predicate defectResults(
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
string message
);
/**
* A defect query result stored in a dashboard database.
*/
class DefectResult extends int {
DefectResult() { defectResults(this, _, _, _, _, _, _, _) }
/** Gets the path of the query that reported the result. */
string getQueryPath() { defectResults(this, result, _, _, _, _, _, _) }
/** Gets the file in which this query result was reported. */
File getFile() {
exists(string path |
defectResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path
)
}
/** Gets the line on which the location of this query result starts. */
int getStartLine() { defectResults(this, _, _, result, _, _, _, _) }
/** Gets the column on which the location of this query result starts. */
int getStartColumn() { defectResults(this, _, _, _, result, _, _, _) }
/** Gets the line on which the location of this query result ends. */
int getEndLine() { defectResults(this, _, _, _, _, result, _, _) }
/** Gets the column on which the location of this query result ends. */
int getEndColumn() { defectResults(this, _, _, _, _, _, result, _) }
/** Gets the message associated with this query result. */
string getMessage() { defectResults(this, _, _, _, _, _, _, result) }
/** Gets the URL corresponding to the location of this query result. */
string getURL() {
result =
"file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" +

View File

@@ -1,26 +1,45 @@
/**
* Provides classes for working with external data.
*/
import cpp
/**
* An external data item.
*/
class ExternalData extends @externalDataElement {
/** Gets the path of the file this data was loaded from. */
string getDataPath() { externalData(this, result, _, _) }
/**
* Gets the path of the file this data was loaded from, with its
* extension replaced by `.ql`.
*/
string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") }
/** Gets the number of fields in this data item. */
int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) }
string getField(int index) { externalData(this, _, index, result) }
/** Gets the value of the `i`th field of this data item. */
string getField(int i) { externalData(this, _, i, result) }
int getFieldAsInt(int index) { result = getField(index).toInt() }
/** Gets the integer value of the `i`th field of this data item. */
int getFieldAsInt(int i) { result = getField(i).toInt() }
float getFieldAsFloat(int index) { result = getField(index).toFloat() }
/** Gets the floating-point value of the `i`th field of this data item. */
float getFieldAsFloat(int i) { result = getField(i).toFloat() }
date getFieldAsDate(int index) { result = getField(index).toDate() }
/** Gets the value of the `i`th field of this data item, interpreted as a date. */
date getFieldAsDate(int i) { result = getField(i).toDate() }
/** Gets a textual representation of this data item. */
string toString() { result = getQueryPath() + ": " + buildTupleString(0) }
private string buildTupleString(int start) {
start = getNumFields() - 1 and result = getField(start)
/** Gets a textual representation of this data item, starting with the `n`th field. */
private string buildTupleString(int n) {
n = getNumFields() - 1 and result = getField(n)
or
start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1)
n < getNumFields() - 1 and result = getField(n) + "," + buildTupleString(n + 1)
}
}
@@ -33,7 +52,9 @@ class DefectExternalData extends ExternalData {
this.getNumFields() = 2
}
/** Gets the URL associated with this data item. */
string getURL() { result = getField(0) }
/** Gets the message associated with this data item. */
string getMessage() { result = getField(1) }
}

View File

@@ -1,31 +1,58 @@
/** Provides a class for working with metric query results stored in dashboard databases. */
import cpp
/**
* Holds if `id` in the opaque identifier of a result reported by query `queryPath`,
* such that `value` is the reported metric value and the location of the result spans
* column `startcolumn` of line `startline` to column `endcolumn` of line `endline`
* in file `filepath`.
*
* For more information, see [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
*/
external predicate metricResults(
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
float value
);
/**
* A metric query result stored in a dashboard database.
*/
class MetricResult extends int {
MetricResult() { metricResults(this, _, _, _, _, _, _, _) }
/** Gets the path of the query that reported the result. */
string getQueryPath() { metricResults(this, result, _, _, _, _, _, _) }
/** Gets the file in which this query result was reported. */
File getFile() {
exists(string path |
metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path
)
}
/** Gets the line on which the location of this query result starts. */
int getStartLine() { metricResults(this, _, _, result, _, _, _, _) }
/** Gets the column on which the location of this query result starts. */
int getStartColumn() { metricResults(this, _, _, _, result, _, _, _) }
/** Gets the line on which the location of this query result ends. */
int getEndLine() { metricResults(this, _, _, _, _, result, _, _) }
/** Gets the column on which the location of this query result ends. */
int getEndColumn() { metricResults(this, _, _, _, _, _, result, _) }
/**
* Holds if there is a `Location` entity whose location is the same as
* the location of this query result.
*/
predicate hasMatchingLocation() { exists(this.getMatchingLocation()) }
/**
* Gets the `Location` entity whose location is the same as the location
* of this query result.
*/
Location getMatchingLocation() {
result.getFile() = this.getFile() and
result.getStartLine() = this.getStartLine() and
@@ -34,8 +61,10 @@ class MetricResult extends int {
result.getEndColumn() = this.getEndColumn()
}
/** Gets the value associated with this query result. */
float getValue() { metricResults(this, _, _, _, _, _, _, result) }
/** Gets the URL corresponding to the location of this query result. */
string getURL() {
result =
"file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" +

View File

@@ -1,92 +0,0 @@
import cpp
class Commit extends @svnentry {
Commit() {
svnaffectedfiles(this, _, _) and
exists(date svnDate, date snapshotDate |
svnentries(this, _, _, svnDate, _) and
snapshotDate(snapshotDate) and
svnDate <= snapshotDate
)
}
string toString() { result = this.getRevisionName() }
string getRevisionName() { svnentries(this, result, _, _, _) }
string getAuthor() { svnentries(this, _, result, _, _) }
date getDate() { svnentries(this, _, _, result, _) }
int getChangeSize() { svnentries(this, _, _, _, result) }
string getMessage() { svnentrymsg(this, result) }
string getAnAffectedFilePath(string action) {
exists(File rawFile | svnaffectedfiles(this, unresolveElement(rawFile), action) |
result = rawFile.getAbsolutePath()
)
}
string getAnAffectedFilePath() { result = getAnAffectedFilePath(_) }
File getAnAffectedFile(string action) {
// Workaround for incorrect keys in SVN data
exists(File svnFile | svnFile.getAbsolutePath() = result.getAbsolutePath() |
svnaffectedfiles(this, unresolveElement(svnFile), action)
) and
exists(result.getMetrics().getNumberOfLinesOfCode())
}
File getAnAffectedFile() { exists(string action | result = this.getAnAffectedFile(action)) }
private predicate churnForFile(File f, int added, int deleted) {
// Workaround for incorrect keys in SVN data
exists(File svnFile | svnFile.getAbsolutePath() = f.getAbsolutePath() |
svnchurn(this, unresolveElement(svnFile), added, deleted)
) and
exists(f.getMetrics().getNumberOfLinesOfCode())
}
int getRecentChurnForFile(File f) {
exists(int added, int deleted | churnForFile(f, added, deleted) and result = added + deleted)
}
int getRecentAdditionsForFile(File f) { churnForFile(f, result, _) }
int getRecentDeletionsForFile(File f) { churnForFile(f, _, result) }
predicate isRecent() { recentCommit(this) }
int daysToNow() {
exists(date now | snapshotDate(now) | result = getDate().daysTo(now) and result >= 0)
}
}
class Author extends string {
Author() { exists(Commit e | this = e.getAuthor()) }
Commit getACommit() { result.getAuthor() = this }
File getAnEditedFile() { result = this.getACommit().getAnAffectedFile() }
}
predicate recentCommit(Commit e) {
exists(date snapshotDate, date commitDate, int days |
snapshotDate(snapshotDate) and
e.getDate() = commitDate and
days = commitDate.daysTo(snapshotDate) and
days >= 0 and
days <= 60
)
}
date firstChange(File f) {
result = min(Commit e, date toMin | f = e.getAnAffectedFile() and toMin = e.getDate() | toMin)
}
predicate firstCommit(Commit e) {
not exists(File f | f = e.getAnAffectedFile() | firstChange(f) < e.getDate())
}
predicate artificialChange(Commit e) { firstCommit(e) or e.getChangeSize() >= 50000 }

View File

@@ -1,20 +0,0 @@
/**
* @name Defect from SVN
* @description A test case for creating a defect from SVN data.
* @kind problem
* @problem.severity warning
* @tags external-data
* @deprecated
*/
import cpp
import external.ExternalArtifact
import external.VCS
predicate numCommits(File f, int i) { i = count(Commit e | e.getAnAffectedFile() = f) }
predicate maxCommits(int i) { i = max(File f, int j | numCommits(f, j) | j) }
from File f, int i
where numCommits(f, i) and maxCommits(i)
select f, "This file has " + i + " commits."

View File

@@ -1,17 +0,0 @@
/**
* @name Metric from SVN
* @description Find number of commits for a file
* @treemap.warnOn lowValues
* @metricType file
* @tags external-data
* @deprecated
*/
import cpp
import external.VCS
predicate numCommits(File f, int i) { i = count(Commit e | e.getAnAffectedFile() = f) }
from File f, int i
where numCommits(f, i)
select f, i

View File

@@ -1,25 +0,0 @@
/**
* @name Filter: exclude results from files that have not recently been
* edited
* @description Use this filter to return results only if they are
* located in files that have been modified in the 60 days
* before the date of the snapshot.
* @kind problem
* @id cpp/recent-defects-filter
* @tags filter
* external-data
* @deprecated
*/
import cpp
import external.DefectFilter
import external.VCS
pragma[noopt]
private predicate recent(File file) {
exists(Commit e | file = e.getAnAffectedFile() | e.isRecent() and not artificialChange(e))
}
from DefectResult res
where recent(res.getFile())
select res, res.getMessage()

View File

@@ -1,25 +0,0 @@
/**
* @name Metric filter: exclude results from files that have not
* recently been edited
* @description Use this filter to return results only if they are
* located in files that have been modified in the 60 days
* before the snapshot.
* @kind treemap
* @id cpp/recent-defects-for-metric-filter
* @tags filter
* external-data
* @deprecated
*/
import cpp
import external.MetricFilter
import external.VCS
pragma[noopt]
private predicate recent(File file) {
exists(Commit e | file = e.getAnAffectedFile() | e.isRecent() and not artificialChange(e))
}
from MetricResult res
where recent(res.getFile())
select res, res.getValue()

View File

@@ -0,0 +1,16 @@
/**
* @name Jump-to-definition links
* @description Generates use-definition pairs that provide the data
* for jump-to-definition in the code viewer.
* @kind definitions
* @id cpp/ide-jump-to-definition
* @tags ide-contextual-queries/local-definitions
*/
import definitions
external string selectedSourceFile();
from Top e, Top def, string kind
where def = definitionOf(e, kind) and e.getFile() = getEncodedFile(selectedSourceFile())
select e, def, kind

View File

@@ -0,0 +1,16 @@
/**
* @name Find-references links
* @description Generates use-definition pairs that provide the data
* for find-references in the code viewer.
* @kind definitions
* @id cpp/ide-find-references
* @tags ide-contextual-queries/local-references
*/
import definitions
external string selectedSourceFile();
from Top e, Top def, string kind
where def = definitionOf(e, kind) and def.getFile() = getEncodedFile(selectedSourceFile())
select e, def, kind

View File

@@ -1 +1,7 @@
/**
* DEPRECATED: Objective C is no longer supported.
*
* Import `cpp` instead of `objc`.
*/
import cpp

27
cpp/ql/src/printAst.ql Normal file
View File

@@ -0,0 +1,27 @@
/**
* @name Print AST
* @description Outputs a representation of a file's Abstract Syntax Tree. This
* query is used by the VS Code extension.
* @id cpp/print-ast
* @kind graph
* @tags ide-contextual-queries/print-ast
*/
import cpp
import semmle.code.cpp.PrintAST
import definitions
/**
* The source file to generate an AST from.
*/
external string selectedSourceFile();
class Cfg extends PrintASTConfiguration {
/**
* Holds if the AST for `func` should be printed.
* Print All functions from the selected file.
*/
override predicate shouldPrintFunction(Function func) {
func.getFile() = getEncodedFile(selectedSourceFile())
}
}

View File

@@ -0,0 +1,9 @@
/**
* @name AST Consistency Check
* @description Performs consistency checks on the Abstract Syntax Tree. This query should have no results.
* @kind table
* @id cpp/ast-consistency-check
*/
import cpp
import CastConsistency

View File

@@ -1,9 +0,0 @@
/**
* @name AST Sanity Check
* @description Performs sanity checks on the Abstract Syntax Tree. This query should have no results.
* @kind table
* @id cpp/ast-sanity-check
*/
import cpp
import CastSanity

View File

@@ -1,3 +1,8 @@
/**
* Provides a class and predicate for recognizing files that are likely to have been generated
* automatically.
*/
import semmle.code.cpp.Comments
import semmle.code.cpp.File
import semmle.code.cpp.Preprocessor

View File

@@ -1,3 +1,7 @@
/**
* Provides classes representing C++ classes, including structs, unions, and template classes.
*/
import semmle.code.cpp.Type
import semmle.code.cpp.UserType
import semmle.code.cpp.metrics.MetricClass
@@ -29,7 +33,7 @@ private import semmle.code.cpp.internal.ResolveClass
class Class extends UserType {
Class() { isClass(underlyingElement(this)) }
override string getCanonicalQLClass() { result = "Class" }
override string getAPrimaryQlClass() { result = "Class" }
/** Gets a child declaration of this class, struct or union. */
override Declaration getADeclaration() { result = this.getAMember() }
@@ -764,7 +768,7 @@ class ClassDerivation extends Locatable, @derivation {
*/
Class getBaseClass() { result = getBaseType().getUnderlyingType() }
override string getCanonicalQLClass() { result = "ClassDerivation" }
override string getAPrimaryQlClass() { result = "ClassDerivation" }
/**
* Gets the type from which we are deriving, without resolving any
@@ -845,9 +849,7 @@ class ClassDerivation extends Locatable, @derivation {
class LocalClass extends Class {
LocalClass() { isLocal() }
override string getCanonicalQLClass() {
not this instanceof LocalStruct and result = "LocalClass"
}
override string getAPrimaryQlClass() { not this instanceof LocalStruct and result = "LocalClass" }
override Function getEnclosingAccessHolder() { result = this.getEnclosingFunction() }
}
@@ -868,7 +870,7 @@ class LocalClass extends Class {
class NestedClass extends Class {
NestedClass() { this.isMember() }
override string getCanonicalQLClass() {
override string getAPrimaryQlClass() {
not this instanceof NestedStruct and result = "NestedClass"
}
@@ -889,7 +891,7 @@ class NestedClass extends Class {
class AbstractClass extends Class {
AbstractClass() { exists(PureVirtualFunction f | this.getAMemberFunction() = f) }
override string getCanonicalQLClass() { result = "AbstractClass" }
override string getAPrimaryQlClass() { result = "AbstractClass" }
}
/**
@@ -930,7 +932,7 @@ class TemplateClass extends Class {
exists(result.getATemplateArgument())
}
override string getCanonicalQLClass() { result = "TemplateClass" }
override string getAPrimaryQlClass() { result = "TemplateClass" }
}
/**
@@ -951,7 +953,7 @@ class ClassTemplateInstantiation extends Class {
ClassTemplateInstantiation() { tc.getAnInstantiation() = this }
override string getCanonicalQLClass() { result = "ClassTemplateInstantiation" }
override string getAPrimaryQlClass() { result = "ClassTemplateInstantiation" }
/**
* Gets the class template from which this instantiation was instantiated.
@@ -992,7 +994,7 @@ abstract class ClassTemplateSpecialization extends Class {
count(int i | exists(result.getTemplateArgument(i)))
}
override string getCanonicalQLClass() { result = "ClassTemplateSpecialization" }
override string getAPrimaryQlClass() { result = "ClassTemplateSpecialization" }
}
/**
@@ -1021,7 +1023,7 @@ class FullClassTemplateSpecialization extends ClassTemplateSpecialization {
not this instanceof ClassTemplateInstantiation
}
override string getCanonicalQLClass() { result = "FullClassTemplateSpecialization" }
override string getAPrimaryQlClass() { result = "FullClassTemplateSpecialization" }
}
/**
@@ -1060,7 +1062,7 @@ class PartialClassTemplateSpecialization extends ClassTemplateSpecialization {
count(int i | exists(getTemplateArgument(i)))
}
override string getCanonicalQLClass() { result = "PartialClassTemplateSpecialization" }
override string getAPrimaryQlClass() { result = "PartialClassTemplateSpecialization" }
}
/**
@@ -1085,7 +1087,7 @@ deprecated class Interface extends Class {
)
}
override string getCanonicalQLClass() { result = "Interface" }
override string getAPrimaryQlClass() { result = "Interface" }
}
/**
@@ -1100,7 +1102,7 @@ deprecated class Interface extends Class {
class VirtualClassDerivation extends ClassDerivation {
VirtualClassDerivation() { hasSpecifier("virtual") }
override string getCanonicalQLClass() { result = "VirtualClassDerivation" }
override string getAPrimaryQlClass() { result = "VirtualClassDerivation" }
}
/**
@@ -1120,7 +1122,7 @@ class VirtualClassDerivation extends ClassDerivation {
class VirtualBaseClass extends Class {
VirtualBaseClass() { exists(VirtualClassDerivation cd | cd.getBaseClass() = this) }
override string getCanonicalQLClass() { result = "VirtualBaseClass" }
override string getAPrimaryQlClass() { result = "VirtualBaseClass" }
/** A virtual class derivation of which this class/struct is the base. */
VirtualClassDerivation getAVirtualDerivation() { result.getBaseClass() = this }
@@ -1142,7 +1144,7 @@ class VirtualBaseClass extends Class {
class ProxyClass extends UserType {
ProxyClass() { usertypes(underlyingElement(this), _, 9) }
override string getCanonicalQLClass() { result = "ProxyClass" }
override string getAPrimaryQlClass() { result = "ProxyClass" }
/** Gets the location of the proxy class. */
override Location getLocation() { result = getTemplateParameter().getDefinitionLocation() }

View File

@@ -1,3 +1,7 @@
/**
* Provides classes representing C and C++ comments.
*/
import semmle.code.cpp.Location
import semmle.code.cpp.Element

View File

@@ -1,3 +1,7 @@
/**
* Provides a class representing individual compiler invocations that occurred during the build.
*/
import semmle.code.cpp.File
/*

View File

@@ -1,3 +1,7 @@
/**
* Provides classes for working with C and C++ declarations.
*/
import semmle.code.cpp.Element
import semmle.code.cpp.Specifier
import semmle.code.cpp.Namespace
@@ -98,7 +102,12 @@ class Declaration extends Locatable, @declaration {
this.hasQualifiedName(namespaceQualifier, "", baseName)
}
override string toString() { result = this.getName() }
/**
* Gets a description of this `Declaration` for display purposes.
*/
string getDescription() { result = this.getName() }
final override string toString() { result = this.getDescription() }
/**
* Gets the name of this declaration.
@@ -115,7 +124,7 @@ class Declaration extends Locatable, @declaration {
* To test whether this declaration has a particular name in the global
* namespace, use `hasGlobalName`.
*/
abstract string getName();
string getName() { none() } // overridden in subclasses
/** Holds if this declaration has the given name. */
predicate hasName(string name) { name = this.getName() }
@@ -131,7 +140,7 @@ class Declaration extends Locatable, @declaration {
}
/** Gets a specifier of this declaration. */
abstract Specifier getASpecifier();
Specifier getASpecifier() { none() } // overridden in subclasses
/** Holds if this declaration has a specifier with the given name. */
predicate hasSpecifier(string name) { this.getASpecifier().hasName(name) }
@@ -147,7 +156,7 @@ class Declaration extends Locatable, @declaration {
* Gets the location of a declaration entry corresponding to this
* declaration.
*/
abstract Location getADeclarationLocation();
Location getADeclarationLocation() { none() } // overridden in subclasses
/**
* Gets the declaration entry corresponding to this declaration that is a
@@ -156,7 +165,7 @@ class Declaration extends Locatable, @declaration {
DeclarationEntry getDefinition() { none() }
/** Gets the location of the definition, if any. */
abstract Location getDefinitionLocation();
Location getDefinitionLocation() { none() } // overridden in subclasses
/** Holds if the declaration has a definition. */
predicate hasDefinition() { exists(this.getDefinition()) }
@@ -280,6 +289,8 @@ class Declaration extends Locatable, @declaration {
}
}
private class TDeclarationEntry = @var_decl or @type_decl or @fun_decl;
/**
* A C/C++ declaration entry. For example the following code contains five
* declaration entries:
@@ -295,9 +306,9 @@ class Declaration extends Locatable, @declaration {
* See the comment above `Declaration` for an explanation of the relationship
* between `Declaration` and `DeclarationEntry`.
*/
abstract class DeclarationEntry extends Locatable {
class DeclarationEntry extends Locatable, TDeclarationEntry {
/** Gets a specifier associated with this declaration entry. */
abstract string getASpecifier();
string getASpecifier() { none() } // overridden in subclasses
/**
* Gets the name associated with the corresponding definition (where
@@ -320,10 +331,10 @@ abstract class DeclarationEntry extends Locatable {
* `I.getADeclarationEntry()` returns `D`
* but `D.getDeclaration()` only returns `C`
*/
abstract Declaration getDeclaration();
Declaration getDeclaration() { none() } // overridden in subclasses
/** Gets the name associated with this declaration entry, if any. */
abstract string getName();
string getName() { none() } // overridden in subclasses
/**
* Gets the type associated with this declaration entry.
@@ -332,7 +343,7 @@ abstract class DeclarationEntry extends Locatable {
* For function declarations, get the return type of the function.
* For type declarations, get the type being declared.
*/
abstract Type getType();
Type getType() { none() } // overridden in subclasses
/**
* Gets the type associated with this declaration entry after specifiers
@@ -350,7 +361,7 @@ abstract class DeclarationEntry extends Locatable {
predicate hasSpecifier(string specifier) { getASpecifier() = specifier }
/** Holds if this declaration entry is a definition. */
abstract predicate isDefinition();
predicate isDefinition() { none() } // overridden in subclasses
override string toString() {
if isDefinition()
@@ -362,6 +373,8 @@ abstract class DeclarationEntry extends Locatable {
}
}
private class TAccessHolder = @function or @usertype;
/**
* A declaration that can potentially have more C++ access rights than its
* enclosing element. This comprises `Class` (they have access to their own
@@ -383,7 +396,7 @@ abstract class DeclarationEntry extends Locatable {
* the informal phrase "_R_ occurs in a member or friend of class C", where
* `AccessHolder` corresponds to this _R_.
*/
abstract class AccessHolder extends Declaration {
class AccessHolder extends Declaration, TAccessHolder {
/**
* Holds if `this` can access private members of class `c`.
*
@@ -401,7 +414,7 @@ abstract class AccessHolder extends Declaration {
/**
* Gets the nearest enclosing `AccessHolder`.
*/
abstract AccessHolder getEnclosingAccessHolder();
AccessHolder getEnclosingAccessHolder() { none() } // overridden in subclasses
/**
* Holds if a base class `base` of `derived` _is accessible at_ `this` (N4140

View File

@@ -1,3 +1,7 @@
/**
* Provides classes representing warnings generated during compilation.
*/
import semmle.code.cpp.Location
/** A compiler-generated error, warning or remark. */

View File

@@ -1,3 +1,8 @@
/**
* Provides the `Element` class, which is the base class for all classes representing C or C++
* program elements.
*/
import semmle.code.cpp.Location
private import semmle.code.cpp.Enclosing
private import semmle.code.cpp.internal.ResolveClass
@@ -50,12 +55,21 @@ class ElementBase extends @element {
cached
string toString() { none() }
/** DEPRECATED: use `getAPrimaryQlClass` instead. */
deprecated string getCanonicalQLClass() { result = this.getAPrimaryQlClass() }
/**
* Canonical QL class corresponding to this element.
* Gets the name of a primary CodeQL class to which this element belongs.
*
* ElementBase is the root class for this predicate.
* For most elements, this is simply the most precise syntactic category to
* which they belong; for example, `AddExpr` is a primary class, but
* `BinaryOperation` is not.
*
* This predicate always has a result. If no primary class can be
* determined, the result is `"???"`. If multiple primary classes match,
* this predicate can have multiple results.
*/
string getCanonicalQLClass() { result = "???" }
string getAPrimaryQlClass() { result = "???" }
}
/**
@@ -261,8 +275,14 @@ private predicate isFromUninstantiatedTemplateRec(Element e, Element template) {
class StaticAssert extends Locatable, @static_assert {
override string toString() { result = "static_assert(..., \"" + getMessage() + "\")" }
/**
* Gets the expression which this static assertion ensures is true.
*/
Expr getCondition() { static_asserts(underlyingElement(this), unresolveElement(result), _, _) }
/**
* Gets the message which will be reported by the compiler if this static assertion fails.
*/
string getMessage() { static_asserts(underlyingElement(this), _, result, _) }
override Location getLocation() { static_asserts(underlyingElement(this), _, _, result) }

View File

@@ -1,3 +1,7 @@
/**
* Provides predicates for finding the smallest element that encloses an expression or statement.
*/
import cpp
/**

View File

@@ -1,3 +1,7 @@
/**
* Provides classes representing C/C++ enums and enum constants.
*/
import semmle.code.cpp.Type
private import semmle.code.cpp.internal.ResolveClass
@@ -19,11 +23,22 @@ class Enum extends UserType, IntegralOrEnumType {
/** Gets an enumerator of this enumeration. */
EnumConstant getAnEnumConstant() { result.getDeclaringEnum() = this }
/**
* Gets the enumerator of this enumeration that was declared at the zero-based position `index`.
* For example, `zero` is at index 2 in the following declaration:
* ```
* enum ReversedOrder {
* two = 2,
* one = 1,
* zero = 0
* };
* ```
*/
EnumConstant getEnumConstant(int index) {
enumconstants(unresolveElement(result), underlyingElement(this), index, _, _, _)
}
override string getCanonicalQLClass() { result = "Enum" }
override string getAPrimaryQlClass() { result = "Enum" }
/**
* Gets a descriptive string for the enum. This method is only intended to
@@ -72,7 +87,7 @@ class Enum extends UserType, IntegralOrEnumType {
class LocalEnum extends Enum {
LocalEnum() { isLocal() }
override string getCanonicalQLClass() { result = "LocalEnum" }
override string getAPrimaryQlClass() { result = "LocalEnum" }
}
/**
@@ -90,7 +105,7 @@ class LocalEnum extends Enum {
class NestedEnum extends Enum {
NestedEnum() { this.isMember() }
override string getCanonicalQLClass() { result = "NestedEnum" }
override string getAPrimaryQlClass() { result = "NestedEnum" }
/** Holds if this member is private. */
predicate isPrivate() { this.hasSpecifier("private") }
@@ -115,7 +130,7 @@ class NestedEnum extends Enum {
class ScopedEnum extends Enum {
ScopedEnum() { usertypes(underlyingElement(this), _, 13) }
override string getCanonicalQLClass() { result = "ScopedEnum" }
override string getAPrimaryQlClass() { result = "ScopedEnum" }
}
/**
@@ -138,7 +153,7 @@ class EnumConstant extends Declaration, @enumconstant {
enumconstants(underlyingElement(this), unresolveElement(result), _, _, _, _)
}
override string getCanonicalQLClass() { result = "EnumConstant" }
override string getAPrimaryQlClass() { result = "EnumConstant" }
override Class getDeclaringType() { result = this.getDeclaringEnum().getDeclaringType() }

View File

@@ -1,3 +1,7 @@
/**
* Provides classes representing C structure members and C++ non-static member variables.
*/
import semmle.code.cpp.Variable
import semmle.code.cpp.Enum
import semmle.code.cpp.exprs.Access
@@ -19,7 +23,7 @@ import semmle.code.cpp.exprs.Access
class Field extends MemberVariable {
Field() { fieldoffsets(underlyingElement(this), _, _) }
override string getCanonicalQLClass() { result = "Field" }
override string getAPrimaryQlClass() { result = "Field" }
/**
* Gets the offset of this field in bytes from the start of its declaring
@@ -86,7 +90,7 @@ class Field extends MemberVariable {
class BitField extends Field {
BitField() { bitfield(underlyingElement(this), _, _) }
override string getCanonicalQLClass() { result = "BitField" }
override string getAPrimaryQlClass() { result = "BitField" }
/**
* Gets the size of this bitfield in bits (on the machine where facts

View File

@@ -1,9 +1,13 @@
/**
* Provides classes representing files and folders.
*/
import semmle.code.cpp.Element
import semmle.code.cpp.Declaration
import semmle.code.cpp.metrics.MetricFile
/** A file or folder. */
abstract class Container extends Locatable, @container {
class Container extends Locatable, @container {
/**
* Gets the absolute, canonical path of this container, using forward slashes
* as path separator.
@@ -28,7 +32,7 @@ abstract class Container extends Locatable, @container {
* a bare root prefix, that is, the path has no path segments. A container
* whose absolute path has no segments is always a `Folder`, not a `File`.
*/
abstract string getAbsolutePath();
string getAbsolutePath() { none() } // overridden by subclasses
/**
* DEPRECATED: Use `getLocation` instead.
@@ -36,7 +40,7 @@ abstract class Container extends Locatable, @container {
*
* For more information see [Providing URLs](https://help.semmle.com/QL/learn-ql/ql/locations.html#providing-urls).
*/
abstract deprecated string getURL();
deprecated string getURL() { none() } // overridden by subclasses
/**
* Gets the relative path of this file or folder from the root folder of the
@@ -174,7 +178,7 @@ class Folder extends Container, @folder {
result.hasLocationInfo(_, 0, 0, 0, 0)
}
override string getCanonicalQLClass() { result = "Folder" }
override string getAPrimaryQlClass() { result = "Folder" }
/**
* DEPRECATED: Use `getLocation` instead.
@@ -242,7 +246,7 @@ class File extends Container, @file {
override string toString() { result = Container.super.toString() }
override string getCanonicalQLClass() { result = "File" }
override string getAPrimaryQlClass() { result = "File" }
override Location getLocation() {
result.getContainer() = this and
@@ -261,18 +265,6 @@ class File extends Container, @file {
/** Holds if this file was compiled as C++ (at any point). */
predicate compiledAsCpp() { fileannotations(underlyingElement(this), 1, "compiled as c++", "1") }
/**
* DEPRECATED: Objective-C is no longer supported.
* Holds if this file was compiled as Objective C (at any point).
*/
deprecated predicate compiledAsObjC() { none() }
/**
* DEPRECATED: Objective-C is no longer supported.
* Holds if this file was compiled as Objective C++ (at any point).
*/
deprecated predicate compiledAsObjCpp() { none() }
/**
* Holds if this file was compiled by a Microsoft compiler (at any point).
*
@@ -316,14 +308,6 @@ class File extends Container, @file {
exists(Include i | i.getFile() = this and i.getIncludedFile() = result)
}
/**
* DEPRECATED: use `getParentContainer` instead.
* Gets the folder which contains this file.
*/
deprecated Folder getParent() {
containerparent(unresolveElement(result), underlyingElement(this))
}
/**
* Holds if this file may be from source. This predicate holds for all files
* except the dummy file, whose name is the empty string, which contains
@@ -341,28 +325,6 @@ class File extends Container, @file {
/** Gets the metric file. */
MetricFile getMetrics() { result = this }
/**
* DEPRECATED: Use `getAbsolutePath` instead.
* Gets the full name of this file, for example:
* "/usr/home/me/myprogram.c".
*/
deprecated string getName() { files(underlyingElement(this), result, _, _, _) }
/**
* DEPRECATED: Use `getAbsolutePath` instead.
* Holds if this file has the specified full name.
*
* Example usage: `f.hasName("/usr/home/me/myprogram.c")`.
*/
deprecated predicate hasName(string name) { name = this.getName() }
/**
* DEPRECATED: Use `getAbsolutePath` instead.
* Gets the full name of this file, for example
* "/usr/home/me/myprogram.c".
*/
deprecated string getFullName() { result = this.getName() }
/**
* Gets the remainder of the base name after the first dot character. Note
* that the name of this predicate is in plural form, unlike `getExtension`,
@@ -377,22 +339,6 @@ class File extends Container, @file {
*/
string getExtensions() { files(underlyingElement(this), _, _, result, _) }
/**
* DEPRECATED: Use `getBaseName` instead.
* Gets the name and extension(s), but not path, of a file. For example,
* if the full name is "/path/to/filename.a.bcd" then the filename is
* "filename.a.bcd".
*/
deprecated string getFileName() {
// [a/b.c/d/]fileName
// ^ beginAfter
exists(string fullName, int beginAfter |
fullName = this.getName() and
beginAfter = max(int i | i = -1 or fullName.charAt(i) = "/" | i) and
result = fullName.suffix(beginAfter + 1)
)
}
/**
* Gets the short name of this file, that is, the prefix of its base name up
* to (but not including) the first dot character if there is one, or the
@@ -436,7 +382,7 @@ class HeaderFile extends File {
exists(Include i | i.getIncludedFile() = this)
}
override string getCanonicalQLClass() { result = "HeaderFile" }
override string getAPrimaryQlClass() { result = "HeaderFile" }
/**
* Holds if this header file does not contain any declaration entries or top level
@@ -462,7 +408,7 @@ class HeaderFile extends File {
class CFile extends File {
CFile() { exists(string ext | ext = this.getExtension().toLowerCase() | ext = "c" or ext = "i") }
override string getCanonicalQLClass() { result = "CFile" }
override string getAPrimaryQlClass() { result = "CFile" }
}
/**
@@ -490,7 +436,7 @@ class CppFile extends File {
)
}
override string getCanonicalQLClass() { result = "CppFile" }
override string getAPrimaryQlClass() { result = "CppFile" }
}
/**

View File

@@ -1,3 +1,7 @@
/**
* Provides a class representing C++ `friend` declarations.
*/
import semmle.code.cpp.Declaration
private import semmle.code.cpp.internal.ResolveClass
@@ -23,7 +27,7 @@ class FriendDecl extends Declaration, @frienddecl {
*/
override Location getADeclarationLocation() { result = this.getLocation() }
override string getCanonicalQLClass() { result = "FriendDecl" }
override string getAPrimaryQlClass() { result = "FriendDecl" }
/**
* Implements the abstract method `Declaration.getDefinitionLocation`. A

View File

@@ -1,5 +1,8 @@
/**
* Provides classes for working with functions, including template functions.
*/
import semmle.code.cpp.Location
import semmle.code.cpp.Member
import semmle.code.cpp.Class
import semmle.code.cpp.Parameter
import semmle.code.cpp.exprs.Call
@@ -184,17 +187,8 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
* For example: for a function `int Foo(int p1, int p2)` this would
* return `int p1, int p2`.
*/
string getParameterString() { result = getParameterStringFrom(0) }
private string getParameterStringFrom(int index) {
index = getNumberOfParameters() and
result = ""
or
index = getNumberOfParameters() - 1 and
result = getParameter(index).getTypedName()
or
index < getNumberOfParameters() - 1 and
result = getParameter(index).getTypedName() + ", " + getParameterStringFrom(index + 1)
string getParameterString() {
result = concat(int i | | min(getParameter(i).getTypedName()), ", " order by i)
}
/** Gets a call to this function. */
@@ -519,7 +513,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
/** Gets the function which is being declared or defined. */
override Function getDeclaration() { result = getFunction() }
override string getCanonicalQLClass() { result = "FunctionDeclarationEntry" }
override string getAPrimaryQlClass() { result = "FunctionDeclarationEntry" }
/** Gets the function which is being declared or defined. */
Function getFunction() { fun_decls(underlyingElement(this), unresolveElement(result), _, _, _) }
@@ -616,18 +610,8 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
* For example: for a function 'int Foo(int p1, int p2)' this would
* return 'int p1, int p2'.
*/
string getParameterString() { result = getParameterStringFrom(0) }
private string getParameterStringFrom(int index) {
index = getNumberOfParameters() and
result = ""
or
index = getNumberOfParameters() - 1 and
result = getParameterDeclarationEntry(index).getTypedName()
or
index < getNumberOfParameters() - 1 and
result =
getParameterDeclarationEntry(index).getTypedName() + ", " + getParameterStringFrom(index + 1)
string getParameterString() {
result = concat(int i | | min(getParameterDeclarationEntry(i).getTypedName()), ", " order by i)
}
/**
@@ -714,428 +698,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl {
class TopLevelFunction extends Function {
TopLevelFunction() { not this.isMember() }
override string getCanonicalQLClass() { result = "TopLevelFunction" }
}
/**
* A C++ function declared as a member of a class [N4140 9.3]. This includes
* static member functions. For example the functions `MyStaticMemberFunction`
* and `MyMemberFunction` in:
* ```
* class MyClass {
* public:
* void MyMemberFunction() {
* DoSomething();
* }
*
* static void MyStaticMemberFunction() {
* DoSomething();
* }
* };
* ```
*/
class MemberFunction extends Function {
MemberFunction() { this.isMember() }
override string getCanonicalQLClass() {
not this instanceof CopyAssignmentOperator and
not this instanceof MoveAssignmentOperator and
result = "MemberFunction"
}
/**
* Gets the number of parameters of this function, including any implicit
* `this` parameter.
*/
override int getEffectiveNumberOfParameters() {
if isStatic() then result = getNumberOfParameters() else result = getNumberOfParameters() + 1
}
/** Holds if this member is private. */
predicate isPrivate() { this.hasSpecifier("private") }
/** Holds if this member is protected. */
predicate isProtected() { this.hasSpecifier("protected") }
/** Holds if this member is public. */
predicate isPublic() { this.hasSpecifier("public") }
/** Holds if this function overrides that function. */
predicate overrides(MemberFunction that) {
overrides(underlyingElement(this), unresolveElement(that))
}
/** Gets a directly overridden function. */
MemberFunction getAnOverriddenFunction() { this.overrides(result) }
/** Gets a directly overriding function. */
MemberFunction getAnOverridingFunction() { result.overrides(this) }
/**
* Gets the declaration entry for this member function that is within the
* class body.
*/
FunctionDeclarationEntry getClassBodyDeclarationEntry() {
if strictcount(getADeclarationEntry()) = 1
then result = getDefinition()
else (
result = getADeclarationEntry() and result != getDefinition()
)
}
}
/**
* A C++ virtual function. For example the two functions called
* `myVirtualFunction` in the following code are each a
* `VirtualFunction`:
* ```
* class A {
* public:
* virtual void myVirtualFunction() = 0;
* };
*
* class B: public A {
* public:
* virtual void myVirtualFunction() {
* doSomething();
* }
* };
* ```
*/
class VirtualFunction extends MemberFunction {
VirtualFunction() { this.hasSpecifier("virtual") or purefunctions(underlyingElement(this)) }
override string getCanonicalQLClass() { result = "VirtualFunction" }
/** Holds if this virtual function is pure. */
predicate isPure() { this instanceof PureVirtualFunction }
/**
* Holds if this function was declared with the `override` specifier
* [N4140 10.3].
*/
predicate isOverrideExplicit() { this.hasSpecifier("override") }
}
/**
* A C++ pure virtual function [N4140 10.4]. For example the first function
* called `myVirtualFunction` in the following code:
* ```
* class A {
* public:
* virtual void myVirtualFunction() = 0;
* };
*
* class B: public A {
* public:
* virtual void myVirtualFunction() {
* doSomething();
* }
* };
* ```
*/
class PureVirtualFunction extends VirtualFunction {
PureVirtualFunction() { purefunctions(underlyingElement(this)) }
override string getCanonicalQLClass() { result = "PureVirtualFunction" }
}
/**
* A const C++ member function [N4140 9.3.1/4]. A const function has the
* `const` specifier and does not modify the state of its class. For example
* the member function `day` in the following code:
* ```
* class MyClass {
* ...
*
* int day() const {
* return d;
* }
*
* ...
* };
* ```
*/
class ConstMemberFunction extends MemberFunction {
ConstMemberFunction() { this.hasSpecifier("const") }
override string getCanonicalQLClass() { result = "ConstMemberFunction" }
}
/**
* A C++ constructor [N4140 12.1]. For example the function `MyClass` in the
* following code is a constructor:
* ```
* class MyClass {
* public:
* MyClass() {
* ...
* }
* };
* ```
*/
class Constructor extends MemberFunction {
Constructor() { functions(underlyingElement(this), _, 2) }
override string getCanonicalQLClass() { result = "Constructor" }
/**
* Holds if this constructor serves as a default constructor.
*
* This holds for constructors with zero formal parameters. It also holds
* for constructors which have a non-zero number of formal parameters,
* provided that every parameter has a default value.
*/
predicate isDefault() { forall(Parameter p | p = this.getAParameter() | p.hasInitializer()) }
/**
* Gets an entry in the constructor's initializer list, or a
* compiler-generated action which initializes a base class or member
* variable.
*/
ConstructorInit getAnInitializer() { result = getInitializer(_) }
/**
* Gets an entry in the constructor's initializer list, or a
* compiler-generated action which initializes a base class or member
* variable. The index specifies the order in which the initializer is
* to be evaluated.
*/
ConstructorInit getInitializer(int i) {
exprparents(unresolveElement(result), i, underlyingElement(this))
}
}
/**
* A function that defines an implicit conversion.
*/
abstract class ImplicitConversionFunction extends MemberFunction {
abstract Type getSourceType();
abstract Type getDestType();
}
/**
* A C++ constructor that also defines an implicit conversion. For example the
* function `MyClass` in the following code is a `ConversionConstructor`:
* ```
* class MyClass {
* public:
* MyClass(const MyOtherClass &from) {
* ...
* }
* };
* ```
*/
class ConversionConstructor extends Constructor, ImplicitConversionFunction {
ConversionConstructor() {
strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and
not hasSpecifier("explicit") and
not this instanceof CopyConstructor
}
override string getCanonicalQLClass() {
not this instanceof MoveConstructor and result = "ConversionConstructor"
}
/** Gets the type this `ConversionConstructor` takes as input. */
override Type getSourceType() { result = this.getParameter(0).getType() }
/** Gets the type this `ConversionConstructor` is a constructor of. */
override Type getDestType() { result = this.getDeclaringType() }
}
private predicate hasCopySignature(MemberFunction f) {
f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType()
}
private predicate hasMoveSignature(MemberFunction f) {
f.getParameter(0).getUnspecifiedType().(RValueReferenceType).getBaseType() = f.getDeclaringType()
}
/**
* A C++ copy constructor [N4140 12.8]. For example the function `MyClass` in
* the following code is a `CopyConstructor`:
* ```
* class MyClass {
* public:
* MyClass(const MyClass &from) {
* ...
* }
* };
* ```
*
* As per the standard, a copy constructor of class `T` is a non-template
* constructor whose first parameter has type `T&`, `const T&`, `volatile
* T&`, or `const volatile T&`, and either there are no other parameters,
* or the rest of the parameters all have default values.
*
* For template classes, it can generally not be determined until instantiation
* whether a constructor is a copy constructor. For such classes, `CopyConstructor`
* over-approximates the set of copy constructors; if an under-approximation is
* desired instead, see the member predicate
* `mayNotBeCopyConstructorInInstantiation`.
*/
class CopyConstructor extends Constructor {
CopyConstructor() {
hasCopySignature(this) and
(
// The rest of the parameters all have default values
forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer())
or
// or this is a template class, in which case the default values have
// not been extracted even if they exist. In that case, we assume that
// there are default values present since that is the most common case
// in real-world code.
getDeclaringType() instanceof TemplateClass
) and
not exists(getATemplateArgument())
}
override string getCanonicalQLClass() { result = "CopyConstructor" }
/**
* Holds if we cannot determine that this constructor will become a copy
* constructor in all instantiations. Depending on template parameters of the
* enclosing class, this may become an ordinary constructor or a copy
* constructor.
*/
predicate mayNotBeCopyConstructorInInstantiation() {
// In general, default arguments of template classes can only be
// type-checked for each template instantiation; if an argument in an
// instantiation fails to type-check then the corresponding parameter has
// no default argument in the instantiation.
getDeclaringType() instanceof TemplateClass and
getNumberOfParameters() > 1
}
}
/**
* A C++ move constructor [N4140 12.8]. For example the function `MyClass` in
* the following code is a `MoveConstructor`:
* ```
* class MyClass {
* public:
* MyClass(MyClass &&from) {
* ...
* }
* };
* ```
*
* As per the standard, a move constructor of class `T` is a non-template
* constructor whose first parameter is `T&&`, `const T&&`, `volatile T&&`,
* or `const volatile T&&`, and either there are no other parameters, or
* the rest of the parameters all have default values.
*
* For template classes, it can generally not be determined until instantiation
* whether a constructor is a move constructor. For such classes, `MoveConstructor`
* over-approximates the set of move constructors; if an under-approximation is
* desired instead, see the member predicate
* `mayNotBeMoveConstructorInInstantiation`.
*/
class MoveConstructor extends Constructor {
MoveConstructor() {
hasMoveSignature(this) and
(
// The rest of the parameters all have default values
forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer())
or
// or this is a template class, in which case the default values have
// not been extracted even if they exist. In that case, we assume that
// there are default values present since that is the most common case
// in real-world code.
getDeclaringType() instanceof TemplateClass
) and
not exists(getATemplateArgument())
}
override string getCanonicalQLClass() { result = "MoveConstructor" }
/**
* Holds if we cannot determine that this constructor will become a move
* constructor in all instantiations. Depending on template parameters of the
* enclosing class, this may become an ordinary constructor or a move
* constructor.
*/
predicate mayNotBeMoveConstructorInInstantiation() {
// In general, default arguments of template classes can only be
// type-checked for each template instantiation; if an argument in an
// instantiation fails to type-check then the corresponding parameter has
// no default argument in the instantiation.
getDeclaringType() instanceof TemplateClass and
getNumberOfParameters() > 1
}
}
/**
* A C++ constructor that takes no arguments ('default' constructor). This
* is the constructor that is invoked when no initializer is given. For
* example the function `MyClass` in the following code is a
* `NoArgConstructor`:
* ```
* class MyClass {
* public:
* MyClass() {
* ...
* }
* };
* ```
*/
class NoArgConstructor extends Constructor {
NoArgConstructor() { this.getNumberOfParameters() = 0 }
}
/**
* A C++ destructor [N4140 12.4]. For example the function `~MyClass` in the
* following code is a destructor:
* ```
* class MyClass {
* public:
* ~MyClass() {
* ...
* }
* };
* ```
*/
class Destructor extends MemberFunction {
Destructor() { functions(underlyingElement(this), _, 3) }
override string getCanonicalQLClass() { result = "Destructor" }
/**
* Gets a compiler-generated action which destructs a base class or member
* variable.
*/
DestructorDestruction getADestruction() { result = getDestruction(_) }
/**
* Gets a compiler-generated action which destructs a base class or member
* variable. The index specifies the order in which the destruction should
* be evaluated.
*/
DestructorDestruction getDestruction(int i) {
exprparents(unresolveElement(result), i, underlyingElement(this))
}
}
/**
* A C++ conversion operator [N4140 12.3.2]. For example the function
* `operator int` in the following code is a `ConversionOperator`:
* ```
* class MyClass {
* public:
* operator int();
* };
* ```
*/
class ConversionOperator extends MemberFunction, ImplicitConversionFunction {
ConversionOperator() { functions(underlyingElement(this), _, 4) }
override string getCanonicalQLClass() { result = "ConversionOperator" }
override Type getSourceType() { result = this.getDeclaringType() }
override Type getDestType() { result = this.getType() }
override string getAPrimaryQlClass() { result = "TopLevelFunction" }
}
/**
@@ -1144,69 +707,11 @@ class ConversionOperator extends MemberFunction, ImplicitConversionFunction {
class Operator extends Function {
Operator() { functions(underlyingElement(this), _, 5) }
override string getCanonicalQLClass() {
override string getAPrimaryQlClass() {
not this instanceof MemberFunction and result = "Operator"
}
}
/**
* A C++ copy assignment operator [N4140 12.8]. For example the function
* `operator=` in the following code is a `CopyAssignmentOperator`:
* ```
* class MyClass {
* public:
* MyClass &operator=(const MyClass &other);
* };
* ```
*
* As per the standard, a copy assignment operator of class `T` is a
* non-template non-static member function with the name `operator=` that
* takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile
* T&`, or `const volatile T&`.
*/
class CopyAssignmentOperator extends Operator {
CopyAssignmentOperator() {
hasName("operator=") and
(
hasCopySignature(this)
or
// Unlike CopyConstructor, this member allows a non-reference
// parameter.
getParameter(0).getUnspecifiedType() = getDeclaringType()
) and
not exists(this.getParameter(1)) and
not exists(getATemplateArgument())
}
override string getCanonicalQLClass() { result = "CopyAssignmentOperator" }
}
/**
* A C++ move assignment operator [N4140 12.8]. For example the function
* `operator=` in the following code is a `MoveAssignmentOperator`:
* ```
* class MyClass {
* public:
* MyClass &operator=(MyClass &&other);
* };
* ```
*
* As per the standard, a move assignment operator of class `T` is a
* non-template non-static member function with the name `operator=` that
* takes exactly one parameter of type `T&&`, `const T&&`, `volatile T&&`,
* or `const volatile T&&`.
*/
class MoveAssignmentOperator extends Operator {
MoveAssignmentOperator() {
hasName("operator=") and
hasMoveSignature(this) and
not exists(this.getParameter(1)) and
not exists(getATemplateArgument())
}
override string getCanonicalQLClass() { result = "MoveAssignmentOperator" }
}
/**
* A C++ function which has a non-empty template argument list. For example
* the function `myTemplateFunction` in the following code:
@@ -1233,7 +738,7 @@ class TemplateFunction extends Function {
is_function_template(underlyingElement(this)) and exists(getATemplateArgument())
}
override string getCanonicalQLClass() { result = "TemplateFunction" }
override string getAPrimaryQlClass() { result = "TemplateFunction" }
/**
* Gets a compiler-generated instantiation of this function template.
@@ -1273,7 +778,7 @@ class FunctionTemplateInstantiation extends Function {
FunctionTemplateInstantiation() { tf.getAnInstantiation() = this }
override string getCanonicalQLClass() { result = "FunctionTemplateInstantiation" }
override string getAPrimaryQlClass() { result = "FunctionTemplateInstantiation" }
/**
* Gets the function template from which this instantiation was instantiated.
@@ -1318,7 +823,7 @@ class FunctionTemplateInstantiation extends Function {
class FunctionTemplateSpecialization extends Function {
FunctionTemplateSpecialization() { this.isSpecialization() }
override string getCanonicalQLClass() { result = "FunctionTemplateSpecialization" }
override string getAPrimaryQlClass() { result = "FunctionTemplateSpecialization" }
/**
* Gets the primary template for the specialization (the function template

View File

@@ -1,3 +1,8 @@
/**
* Provides classes representing C/C++ `#include`, `#include_next`, and `#import` preprocessor
* directives.
*/
import semmle.code.cpp.Preprocessor
/**

View File

@@ -1,3 +1,7 @@
/**
* Provides the `Initializer` class, representing C/C++ declaration initializers.
*/
import semmle.code.cpp.controlflow.ControlFlowGraph
/**
@@ -18,7 +22,7 @@ import semmle.code.cpp.controlflow.ControlFlowGraph
class Initializer extends ControlFlowNode, @initialiser {
override Location getLocation() { initialisers(underlyingElement(this), _, _, result) }
override string getCanonicalQLClass() { result = "Initializer" }
override string getAPrimaryQlClass() { result = "Initializer" }
/** Holds if this initializer is explicit in the source. */
override predicate fromSource() { not this.getLocation() instanceof UnknownLocation }

View File

@@ -1,3 +1,7 @@
/**
* Provides classes for loop iteration variables.
*/
import semmle.code.cpp.Variable
/**
@@ -7,14 +11,18 @@ import semmle.code.cpp.Variable
class LoopCounter extends Variable {
LoopCounter() { exists(ForStmt f | f.getAnIterationVariable() = this) }
// Gets an access of this variable within loop `f`.
/**
* Gets an access of this variable within loop `f`.
*/
VariableAccess getVariableAccessInLoop(ForStmt f) {
this.getALoop() = f and
result.getEnclosingStmt().getParent*() = f and
this = result.getTarget()
}
// Gets a loop which uses this variable as its counter.
/**
* Gets a loop which uses this variable as its counter.
*/
ForStmt getALoop() { result.getAnIterationVariable() = this }
}
@@ -25,14 +33,18 @@ class LoopCounter extends Variable {
class LoopControlVariable extends Variable {
LoopControlVariable() { this = loopControlVariable(_) }
// Gets an access of this variable within loop `f`.
/**
* Gets an access of this variable within loop `f`.
*/
VariableAccess getVariableAccessInLoop(ForStmt f) {
this.getALoop() = f and
result.getEnclosingStmt().getParent*() = f and
this = result.getTarget()
}
// Gets a loop which uses this variable as its control variable.
/**
* Gets a loop which uses this variable as its control variable.
*/
ForStmt getALoop() { this = loopControlVariable(result) }
}

View File

@@ -1,3 +1,7 @@
/**
* Proivdes the `LinkTarget` class representing linker invocations during the build process.
*/
import semmle.code.cpp.Class
import semmle.code.cpp.File
import semmle.code.cpp.Function

View File

@@ -1,3 +1,7 @@
/**
* Provides classes and predicates for locations in the source code.
*/
import semmle.code.cpp.Element
import semmle.code.cpp.File
@@ -11,16 +15,16 @@ class Location extends @location {
/** Gets the file corresponding to this location, if any. */
File getFile() { result = this.getContainer() }
/** Gets the start line of this location. */
/** Gets the 1-based line number (inclusive) where this location starts. */
int getStartLine() { this.fullLocationInfo(_, result, _, _, _) }
/** Gets the start column of this location. */
/** Gets the 1-based column number (inclusive) where this location starts. */
int getStartColumn() { this.fullLocationInfo(_, _, result, _, _) }
/** Gets the end line of this location. */
/** Gets the 1-based line number (inclusive) where this location ends. */
int getEndLine() { this.fullLocationInfo(_, _, _, result, _) }
/** Gets the end column of this location. */
/** Gets the 1-based column number (inclusive) where this location ends. */
int getEndColumn() { this.fullLocationInfo(_, _, _, _, result) }
/**

View File

@@ -13,7 +13,7 @@ class Macro extends PreprocessorDirective, @ppd_define {
*/
override string getHead() { preproctext(underlyingElement(this), result, _) }
override string getCanonicalQLClass() { result = "Macro" }
override string getAPrimaryQlClass() { result = "Macro" }
/**
* Gets the body of this macro. For example, `(((x)>(y))?(x):(y))` in
@@ -74,7 +74,7 @@ class MacroAccess extends Locatable, @macroinvocation {
*/
override Location getLocation() { result = this.getOutermostMacroAccess().getActualLocation() }
override string getCanonicalQLClass() { result = "MacroAccess" }
override string getAPrimaryQlClass() { result = "MacroAccess" }
/**
* Gets the location of this macro access. For a nested access, where
@@ -147,7 +147,7 @@ class MacroAccess extends Locatable, @macroinvocation {
class MacroInvocation extends MacroAccess {
MacroInvocation() { macroinvocations(underlyingElement(this), _, _, 1) }
override string getCanonicalQLClass() { result = "MacroInvocation" }
override string getAPrimaryQlClass() { result = "MacroInvocation" }
/**
* Gets an element that occurs in this macro invocation or a nested macro
@@ -179,6 +179,11 @@ class MacroInvocation extends MacroAccess {
result.(Stmt).getGeneratingMacro() = this
}
/**
* Gets a function that includes an expression that is affected by this macro
* invocation. If the macro expansion includes the end of one function and
* the beginning of another, this predicate will get both.
*/
Function getEnclosingFunction() {
result = this.getAnAffectedElement().(Expr).getEnclosingFunction()
}

View File

@@ -1,2 +1,6 @@
/**
* DEPRECATED: import `semmle.code.cpp.Element` and/or `semmle.code.cpp.Type` directly as required.
*/
import semmle.code.cpp.Element
import semmle.code.cpp.Type

View File

@@ -0,0 +1,495 @@
/**
* Provides classes for working with C++ member functions, constructors, destructors,
* and user-defined operators.
*/
import cpp
/**
* A C++ function declared as a member of a class [N4140 9.3]. This includes
* static member functions. For example the functions `MyStaticMemberFunction`
* and `MyMemberFunction` in:
* ```
* class MyClass {
* public:
* void MyMemberFunction() {
* DoSomething();
* }
*
* static void MyStaticMemberFunction() {
* DoSomething();
* }
* };
* ```
*/
class MemberFunction extends Function {
MemberFunction() { this.isMember() }
override string getAPrimaryQlClass() {
not this instanceof CopyAssignmentOperator and
not this instanceof MoveAssignmentOperator and
result = "MemberFunction"
}
/**
* Gets the number of parameters of this function, including any implicit
* `this` parameter.
*/
override int getEffectiveNumberOfParameters() {
if isStatic() then result = getNumberOfParameters() else result = getNumberOfParameters() + 1
}
/** Holds if this member is private. */
predicate isPrivate() { this.hasSpecifier("private") }
/** Holds if this member is protected. */
predicate isProtected() { this.hasSpecifier("protected") }
/** Holds if this member is public. */
predicate isPublic() { this.hasSpecifier("public") }
/** Holds if this function overrides that function. */
predicate overrides(MemberFunction that) {
overrides(underlyingElement(this), unresolveElement(that))
}
/** Gets a directly overridden function. */
MemberFunction getAnOverriddenFunction() { this.overrides(result) }
/** Gets a directly overriding function. */
MemberFunction getAnOverridingFunction() { result.overrides(this) }
/**
* Gets the declaration entry for this member function that is within the
* class body.
*/
FunctionDeclarationEntry getClassBodyDeclarationEntry() {
if strictcount(getADeclarationEntry()) = 1
then result = getDefinition()
else (
result = getADeclarationEntry() and result != getDefinition()
)
}
/**
* Gets the type of the `this` parameter associated with this member function, if any. The type
* may have `const` and/or `volatile` qualifiers, matching the function declaration.
*/
PointerType getTypeOfThis() {
member_function_this_type(underlyingElement(this), unresolveElement(result))
}
}
/**
* A C++ virtual function. For example the two functions called
* `myVirtualFunction` in the following code are each a
* `VirtualFunction`:
* ```
* class A {
* public:
* virtual void myVirtualFunction() = 0;
* };
*
* class B: public A {
* public:
* virtual void myVirtualFunction() {
* doSomething();
* }
* };
* ```
*/
class VirtualFunction extends MemberFunction {
VirtualFunction() { this.hasSpecifier("virtual") or purefunctions(underlyingElement(this)) }
override string getAPrimaryQlClass() { result = "VirtualFunction" }
/** Holds if this virtual function is pure. */
predicate isPure() { this instanceof PureVirtualFunction }
/**
* Holds if this function was declared with the `override` specifier
* [N4140 10.3].
*/
predicate isOverrideExplicit() { this.hasSpecifier("override") }
}
/**
* A C++ pure virtual function [N4140 10.4]. For example the first function
* called `myVirtualFunction` in the following code:
* ```
* class A {
* public:
* virtual void myVirtualFunction() = 0;
* };
*
* class B: public A {
* public:
* virtual void myVirtualFunction() {
* doSomething();
* }
* };
* ```
*/
class PureVirtualFunction extends VirtualFunction {
PureVirtualFunction() { purefunctions(underlyingElement(this)) }
override string getAPrimaryQlClass() { result = "PureVirtualFunction" }
}
/**
* A const C++ member function [N4140 9.3.1/4]. A const function has the
* `const` specifier and does not modify the state of its class. For example
* the member function `day` in the following code:
* ```
* class MyClass {
* ...
*
* int day() const {
* return d;
* }
*
* ...
* };
* ```
*/
class ConstMemberFunction extends MemberFunction {
ConstMemberFunction() { this.hasSpecifier("const") }
override string getAPrimaryQlClass() { result = "ConstMemberFunction" }
}
/**
* A C++ constructor [N4140 12.1]. For example the function `MyClass` in the
* following code is a constructor:
* ```
* class MyClass {
* public:
* MyClass() {
* ...
* }
* };
* ```
*/
class Constructor extends MemberFunction {
Constructor() { functions(underlyingElement(this), _, 2) }
override string getAPrimaryQlClass() { result = "Constructor" }
/**
* Holds if this constructor serves as a default constructor.
*
* This holds for constructors with zero formal parameters. It also holds
* for constructors which have a non-zero number of formal parameters,
* provided that every parameter has a default value.
*/
predicate isDefault() { forall(Parameter p | p = this.getAParameter() | p.hasInitializer()) }
/**
* Gets an entry in the constructor's initializer list, or a
* compiler-generated action which initializes a base class or member
* variable.
*/
ConstructorInit getAnInitializer() { result = getInitializer(_) }
/**
* Gets an entry in the constructor's initializer list, or a
* compiler-generated action which initializes a base class or member
* variable. The index specifies the order in which the initializer is
* to be evaluated.
*/
ConstructorInit getInitializer(int i) {
exprparents(unresolveElement(result), i, underlyingElement(this))
}
}
/**
* A function that defines an implicit conversion.
*/
abstract class ImplicitConversionFunction extends MemberFunction {
/** Gets the type this `ImplicitConversionFunction` takes as input. */
abstract Type getSourceType();
/** Gets the type this `ImplicitConversionFunction` converts to. */
abstract Type getDestType();
}
/**
* A C++ constructor that also defines an implicit conversion. For example the
* function `MyClass` in the following code is a `ConversionConstructor`:
* ```
* class MyClass {
* public:
* MyClass(const MyOtherClass &from) {
* ...
* }
* };
* ```
*/
class ConversionConstructor extends Constructor, ImplicitConversionFunction {
ConversionConstructor() {
strictcount(Parameter p | p = getAParameter() and not p.hasInitializer()) = 1 and
not hasSpecifier("explicit") and
not this instanceof CopyConstructor
}
override string getAPrimaryQlClass() {
not this instanceof MoveConstructor and result = "ConversionConstructor"
}
/** Gets the type this `ConversionConstructor` takes as input. */
override Type getSourceType() { result = this.getParameter(0).getType() }
/** Gets the type this `ConversionConstructor` is a constructor of. */
override Type getDestType() { result = this.getDeclaringType() }
}
private predicate hasCopySignature(MemberFunction f) {
f.getParameter(0).getUnspecifiedType().(LValueReferenceType).getBaseType() = f.getDeclaringType()
}
private predicate hasMoveSignature(MemberFunction f) {
f.getParameter(0).getUnspecifiedType().(RValueReferenceType).getBaseType() = f.getDeclaringType()
}
/**
* A C++ copy constructor [N4140 12.8]. For example the function `MyClass` in
* the following code is a `CopyConstructor`:
* ```
* class MyClass {
* public:
* MyClass(const MyClass &from) {
* ...
* }
* };
* ```
*
* As per the standard, a copy constructor of class `T` is a non-template
* constructor whose first parameter has type `T&`, `const T&`, `volatile
* T&`, or `const volatile T&`, and either there are no other parameters,
* or the rest of the parameters all have default values.
*
* For template classes, it can generally not be determined until instantiation
* whether a constructor is a copy constructor. For such classes, `CopyConstructor`
* over-approximates the set of copy constructors; if an under-approximation is
* desired instead, see the member predicate
* `mayNotBeCopyConstructorInInstantiation`.
*/
class CopyConstructor extends Constructor {
CopyConstructor() {
hasCopySignature(this) and
(
// The rest of the parameters all have default values
forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer())
or
// or this is a template class, in which case the default values have
// not been extracted even if they exist. In that case, we assume that
// there are default values present since that is the most common case
// in real-world code.
getDeclaringType() instanceof TemplateClass
) and
not exists(getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "CopyConstructor" }
/**
* Holds if we cannot determine that this constructor will become a copy
* constructor in all instantiations. Depending on template parameters of the
* enclosing class, this may become an ordinary constructor or a copy
* constructor.
*/
predicate mayNotBeCopyConstructorInInstantiation() {
// In general, default arguments of template classes can only be
// type-checked for each template instantiation; if an argument in an
// instantiation fails to type-check then the corresponding parameter has
// no default argument in the instantiation.
getDeclaringType() instanceof TemplateClass and
getNumberOfParameters() > 1
}
}
/**
* A C++ move constructor [N4140 12.8]. For example the function `MyClass` in
* the following code is a `MoveConstructor`:
* ```
* class MyClass {
* public:
* MyClass(MyClass &&from) {
* ...
* }
* };
* ```
*
* As per the standard, a move constructor of class `T` is a non-template
* constructor whose first parameter is `T&&`, `const T&&`, `volatile T&&`,
* or `const volatile T&&`, and either there are no other parameters, or
* the rest of the parameters all have default values.
*
* For template classes, it can generally not be determined until instantiation
* whether a constructor is a move constructor. For such classes, `MoveConstructor`
* over-approximates the set of move constructors; if an under-approximation is
* desired instead, see the member predicate
* `mayNotBeMoveConstructorInInstantiation`.
*/
class MoveConstructor extends Constructor {
MoveConstructor() {
hasMoveSignature(this) and
(
// The rest of the parameters all have default values
forall(int i | i > 0 and exists(getParameter(i)) | getParameter(i).hasInitializer())
or
// or this is a template class, in which case the default values have
// not been extracted even if they exist. In that case, we assume that
// there are default values present since that is the most common case
// in real-world code.
getDeclaringType() instanceof TemplateClass
) and
not exists(getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "MoveConstructor" }
/**
* Holds if we cannot determine that this constructor will become a move
* constructor in all instantiations. Depending on template parameters of the
* enclosing class, this may become an ordinary constructor or a move
* constructor.
*/
predicate mayNotBeMoveConstructorInInstantiation() {
// In general, default arguments of template classes can only be
// type-checked for each template instantiation; if an argument in an
// instantiation fails to type-check then the corresponding parameter has
// no default argument in the instantiation.
getDeclaringType() instanceof TemplateClass and
getNumberOfParameters() > 1
}
}
/**
* A C++ constructor that takes no arguments ('default' constructor). This
* is the constructor that is invoked when no initializer is given. For
* example the function `MyClass` in the following code is a
* `NoArgConstructor`:
* ```
* class MyClass {
* public:
* MyClass() {
* ...
* }
* };
* ```
*/
class NoArgConstructor extends Constructor {
NoArgConstructor() { this.getNumberOfParameters() = 0 }
}
/**
* A C++ destructor [N4140 12.4]. For example the function `~MyClass` in the
* following code is a destructor:
* ```
* class MyClass {
* public:
* ~MyClass() {
* ...
* }
* };
* ```
*/
class Destructor extends MemberFunction {
Destructor() { functions(underlyingElement(this), _, 3) }
override string getAPrimaryQlClass() { result = "Destructor" }
/**
* Gets a compiler-generated action which destructs a base class or member
* variable.
*/
DestructorDestruction getADestruction() { result = getDestruction(_) }
/**
* Gets a compiler-generated action which destructs a base class or member
* variable. The index specifies the order in which the destruction should
* be evaluated.
*/
DestructorDestruction getDestruction(int i) {
exprparents(unresolveElement(result), i, underlyingElement(this))
}
}
/**
* A C++ conversion operator [N4140 12.3.2]. For example the function
* `operator int` in the following code is a `ConversionOperator`:
* ```
* class MyClass {
* public:
* operator int();
* };
* ```
*/
class ConversionOperator extends MemberFunction, ImplicitConversionFunction {
ConversionOperator() { functions(underlyingElement(this), _, 4) }
override string getAPrimaryQlClass() { result = "ConversionOperator" }
override Type getSourceType() { result = this.getDeclaringType() }
override Type getDestType() { result = this.getType() }
}
/**
* A C++ copy assignment operator [N4140 12.8]. For example the function
* `operator=` in the following code is a `CopyAssignmentOperator`:
* ```
* class MyClass {
* public:
* MyClass &operator=(const MyClass &other);
* };
* ```
*
* As per the standard, a copy assignment operator of class `T` is a
* non-template non-static member function with the name `operator=` that
* takes exactly one parameter of type `T`, `T&`, `const T&`, `volatile
* T&`, or `const volatile T&`.
*/
class CopyAssignmentOperator extends Operator {
CopyAssignmentOperator() {
hasName("operator=") and
(
hasCopySignature(this)
or
// Unlike CopyConstructor, this member allows a non-reference
// parameter.
getParameter(0).getUnspecifiedType() = getDeclaringType()
) and
not exists(this.getParameter(1)) and
not exists(getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "CopyAssignmentOperator" }
}
/**
* A C++ move assignment operator [N4140 12.8]. For example the function
* `operator=` in the following code is a `MoveAssignmentOperator`:
* ```
* class MyClass {
* public:
* MyClass &operator=(MyClass &&other);
* };
* ```
*
* As per the standard, a move assignment operator of class `T` is a
* non-template non-static member function with the name `operator=` that
* takes exactly one parameter of type `T&&`, `const T&&`, `volatile T&&`,
* or `const volatile T&&`.
*/
class MoveAssignmentOperator extends Operator {
MoveAssignmentOperator() {
hasName("operator=") and
hasMoveSignature(this) and
not exists(this.getParameter(1)) and
not exists(getATemplateArgument())
}
override string getAPrimaryQlClass() { result = "MoveAssignmentOperator" }
}

View File

@@ -1,3 +1,8 @@
/**
* Provides classes for working with name qualifiers such as the `N::` in
* `N::f()`.
*/
import cpp
/**

View File

@@ -1,3 +1,7 @@
/**
* Provides classes for modeling namespaces, `using` directives and `using` declarations.
*/
import semmle.code.cpp.Element
import semmle.code.cpp.Type
import semmle.code.cpp.metrics.MetricNamespace
@@ -79,7 +83,10 @@ class Namespace extends NameQualifyingElement, @namespace {
/** Gets the metric namespace. */
MetricNamespace getMetrics() { result = this }
override string toString() { result = this.getQualifiedName() }
/** Gets a version of the `QualifiedName` that is more suitable for display purposes. */
string getFriendlyName() { result = this.getQualifiedName() }
final override string toString() { result = getFriendlyName() }
/** Gets a declaration of (part of) this namespace. */
NamespaceDeclarationEntry getADeclarationEntry() { result.getNamespace() = this }
@@ -104,7 +111,7 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl {
namespace_decls(underlyingElement(this), unresolveElement(result), _, _)
}
override string toString() { result = this.getNamespace().toString() }
override string toString() { result = this.getNamespace().getFriendlyName() }
/**
* Gets the location of the token preceding the namespace declaration
@@ -124,13 +131,13 @@ class NamespaceDeclarationEntry extends Locatable, @namespace_decl {
*/
Location getBodyLocation() { namespace_decls(underlyingElement(this), _, _, result) }
override string getCanonicalQLClass() { result = "NamespaceDeclarationEntry" }
override string getAPrimaryQlClass() { result = "NamespaceDeclarationEntry" }
}
/**
* A C++ `using` directive or `using` declaration.
*/
abstract class UsingEntry extends Locatable, @using {
class UsingEntry extends Locatable, @using {
override Location getLocation() { usings(underlyingElement(this), _, result) }
}
@@ -150,7 +157,7 @@ class UsingDeclarationEntry extends UsingEntry {
*/
Declaration getDeclaration() { usings(underlyingElement(this), unresolveElement(result), _) }
override string toString() { result = "using " + this.getDeclaration().toString() }
override string toString() { result = "using " + this.getDeclaration().getDescription() }
}
/**
@@ -169,7 +176,7 @@ class UsingDirectiveEntry extends UsingEntry {
*/
Namespace getNamespace() { usings(underlyingElement(this), unresolveElement(result), _) }
override string toString() { result = "using namespace " + this.getNamespace().toString() }
override string toString() { result = "using namespace " + this.getNamespace().getFriendlyName() }
}
/**
@@ -204,7 +211,7 @@ class GlobalNamespace extends Namespace {
*/
deprecated string getFullName() { result = this.getName() }
override string toString() { result = "(global namespace)" }
override string getFriendlyName() { result = "(global namespace)" }
}
/**

View File

@@ -1,3 +1,8 @@
/**
* Provides a class for reasoning about nested field accesses, for example
* the access `myLine.start.x`.
*/
import cpp
/**
@@ -25,7 +30,7 @@ private Expr getUltimateQualifier(FieldAccess fa) {
}
/**
* Accesses to nested fields.
* A nested field access, for example the access `myLine.start.x`.
*/
class NestedFieldAccess extends FieldAccess {
Expr ultimateQualifier;
@@ -35,6 +40,30 @@ class NestedFieldAccess extends FieldAccess {
getTarget() = getANestedField(ultimateQualifier.getType().stripType())
}
/** Gets the ultimate qualifier of this nested field access. */
/**
* Gets the outermost qualifier of this nested field access. In the
* following example, the access to `myLine.start.x` has outermost qualifier
* `myLine`:
* ```
* struct Point
* {
* float x, y;
* };
*
* struct Line
* {
* Point start, end;
* };
*
* void init()
* {
* Line myLine;
*
* myLine.start.x = 0.0f;
*
* // ...
* }
* ```
*/
Expr getUltimateQualifier() { result = ultimateQualifier }
}

View File

@@ -1,3 +1,7 @@
/**
* DEPRECATED: Objective-C is no longer supported.
*/
import semmle.code.cpp.Class
private import semmle.code.cpp.internal.ResolveClass

View File

@@ -1,3 +1,7 @@
/**
* Provides a class that models parameters to functions.
*/
import semmle.code.cpp.Location
import semmle.code.cpp.Declaration
private import semmle.code.cpp.internal.ResolveClass
@@ -45,7 +49,7 @@ class Parameter extends LocalScopeVariable, @parameter {
result = "p#" + this.getIndex().toString()
}
override string getCanonicalQLClass() { result = "Parameter" }
override string getAPrimaryQlClass() { result = "Parameter" }
/**
* Gets the name of this parameter, including it's type.
@@ -165,6 +169,7 @@ class Parameter extends LocalScopeVariable, @parameter {
class ParameterIndex extends int {
ParameterIndex() {
exists(Parameter p | this = p.getIndex()) or
exists(Call c | exists(c.getArgument(this))) // permit indexing varargs
exists(Call c | exists(c.getArgument(this))) or // permit indexing varargs
this = -1 // used for `this`
}
}

View File

@@ -33,11 +33,13 @@ class PreprocessorDirective extends Locatable, @preprocdirect {
}
}
private class TPreprocessorBranchDirective = @ppd_branch or @ppd_else or @ppd_endif;
/**
* A C/C++ preprocessor branch related directive: `#if`, `#ifdef`,
* `#ifndef`, `#elif`, `#else` or `#endif`.
*/
abstract class PreprocessorBranchDirective extends PreprocessorDirective {
class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBranchDirective {
/**
* Gets the `#if`, `#ifdef` or `#ifndef` directive which matches this
* branching directive.
@@ -152,7 +154,7 @@ class PreprocessorIf extends PreprocessorBranch, @ppd_if {
class PreprocessorIfdef extends PreprocessorBranch, @ppd_ifdef {
override string toString() { result = "#ifdef " + this.getHead() }
override string getCanonicalQLClass() { result = "PreprocessorIfdef" }
override string getAPrimaryQlClass() { result = "PreprocessorIfdef" }
}
/**

View File

@@ -1,3 +1,11 @@
/**
* Provides queries to pretty-print a C++ AST as a graph.
*
* By default, this will print the AST for all functions in the database. To change this behavior,
* extend `PrintASTConfiguration` and override `shouldPrintFunction` to hold for only the functions
* you wish to view the AST for.
*/
import cpp
private import semmle.code.cpp.Print
@@ -7,6 +15,9 @@ private newtype TPrintASTConfiguration = MkPrintASTConfiguration()
* The query can extend this class to control which functions are printed.
*/
class PrintASTConfiguration extends TPrintASTConfiguration {
/**
* Gets a textual representation of this `PrintASTConfiguration`.
*/
string toString() { result = "PrintASTConfiguration" }
/**
@@ -96,6 +107,9 @@ private newtype TPrintASTNode =
* A node in the output tree.
*/
class PrintASTNode extends TPrintASTNode {
/**
* Gets a textual representation of this node in the PrintAST output tree.
*/
abstract string toString();
/**
@@ -155,7 +169,7 @@ class PrintASTNode extends TPrintASTNode {
* Retrieves the canonical QL class(es) for entity `el`
*/
private string qlClass(ElementBase el) {
result = "[" + concat(el.getCanonicalQLClass(), ",") + "] "
result = "[" + concat(el.getAPrimaryQlClass(), ",") + "] "
// Alternative implementation -- do not delete. It is useful for QL class discovery.
//result = "["+ concat(el.getAQlClass(), ",") + "] "
}
@@ -208,6 +222,9 @@ class ExprNode extends ASTNode {
result = expr.getValueCategoryString()
}
/**
* Gets the value of this expression, if it is a constant.
*/
string getValue() { result = expr.getValue() }
}
@@ -373,6 +390,9 @@ class ParametersNode extends PrintASTNode, TParametersNode {
override ASTNode getChild(int childIndex) { result.getAST() = func.getParameter(childIndex) }
/**
* Gets the `Function` for which this node represents the parameters.
*/
final Function getFunction() { result = func }
}
@@ -392,6 +412,9 @@ class ConstructorInitializersNode extends PrintASTNode, TConstructorInitializers
result.getAST() = ctor.getInitializer(childIndex)
}
/**
* Gets the `Constructor` for which this node represents the initializer list.
*/
final Constructor getConstructor() { result = ctor }
}
@@ -411,6 +434,9 @@ class DestructorDestructionsNode extends PrintASTNode, TDestructorDestructionsNo
result.getAST() = dtor.getDestruction(childIndex)
}
/**
* Gets the `Destructor` for which this node represents the destruction list.
*/
final Destructor getDestructor() { result = dtor }
}
@@ -464,6 +490,9 @@ class FunctionNode extends ASTNode {
key = "semmle.order" and result = getOrder().toString()
}
/**
* Gets the `Function` this node represents.
*/
final Function getFunction() { result = func }
}
@@ -499,11 +528,16 @@ class ArrayAggregateLiteralNode extends ExprNode {
}
}
/** Holds if `node` belongs to the output tree, and its property `key` has the given `value`. */
query predicate nodes(PrintASTNode node, string key, string value) {
node.shouldPrint() and
value = node.getProperty(key)
}
/**
* Holds if `target` is a child of `source` in the AST, and property `key` of the edge has the
* given `value`.
*/
query predicate edges(PrintASTNode source, PrintASTNode target, string key, string value) {
exists(int childIndex |
source.shouldPrint() and
@@ -517,6 +551,7 @@ query predicate edges(PrintASTNode source, PrintASTNode target, string key, stri
)
}
/** Holds if property `key` of the graph has the given `value`. */
query predicate graphProperties(string key, string value) {
key = "semmle.graphKind" and value = "tree"
}

View File

@@ -1,3 +1,7 @@
/**
* Provides classes for modeling specifiers and attributes.
*/
import semmle.code.cpp.Element
private import semmle.code.cpp.internal.ResolveClass
@@ -12,7 +16,7 @@ class Specifier extends Element, @specifier {
result instanceof UnknownDefaultLocation
}
override string getCanonicalQLClass() { result = "Specifier" }
override string getAPrimaryQlClass() { result = "Specifier" }
/** Gets the name of this specifier. */
string getName() { specifiers(underlyingElement(this), result) }
@@ -33,7 +37,7 @@ class FunctionSpecifier extends Specifier {
this.hasName("explicit")
}
override string getCanonicalQLClass() { result = "FunctionSpecifier)" }
override string getAPrimaryQlClass() { result = "FunctionSpecifier)" }
}
/**
@@ -49,7 +53,7 @@ class StorageClassSpecifier extends Specifier {
this.hasName("mutable")
}
override string getCanonicalQLClass() { result = "StorageClassSpecifier" }
override string getAPrimaryQlClass() { result = "StorageClassSpecifier" }
}
/**
@@ -104,7 +108,7 @@ class AccessSpecifier extends Specifier {
)
}
override string getCanonicalQLClass() { result = "AccessSpecifier" }
override string getAPrimaryQlClass() { result = "AccessSpecifier" }
}
/**
@@ -234,7 +238,7 @@ class FormatAttribute extends GnuAttribute {
)
}
override string getCanonicalQLClass() { result = "FormatAttribute" }
override string getAPrimaryQlClass() { result = "FormatAttribute" }
}
/**

View File

@@ -1,3 +1,7 @@
/**
* Provides classes for modeling `struct`s.
*/
import semmle.code.cpp.Type
import semmle.code.cpp.Class
@@ -18,7 +22,7 @@ import semmle.code.cpp.Class
class Struct extends Class {
Struct() { usertypes(underlyingElement(this), _, 1) or usertypes(underlyingElement(this), _, 3) }
override string getCanonicalQLClass() { result = "Struct" }
override string getAPrimaryQlClass() { result = "Struct" }
override string explain() { result = "struct " + this.getName() }
@@ -39,9 +43,7 @@ class Struct extends Class {
class LocalStruct extends Struct {
LocalStruct() { isLocal() }
override string getCanonicalQLClass() {
not this instanceof LocalUnion and result = "LocalStruct"
}
override string getAPrimaryQlClass() { not this instanceof LocalUnion and result = "LocalStruct" }
}
/**
@@ -58,7 +60,7 @@ class LocalStruct extends Struct {
class NestedStruct extends Struct {
NestedStruct() { this.isMember() }
override string getCanonicalQLClass() {
override string getAPrimaryQlClass() {
not this instanceof NestedUnion and result = "NestedStruct"
}

View File

@@ -1,3 +1,8 @@
/**
* Provides classes for identifying files that contain test cases. It is often
* desirable to exclude these files from analysis.
*/
import semmle.code.cpp.File
/**

View File

@@ -1,5 +1,8 @@
/**
* Provides a hierarchy of classes for modeling C/C++ types.
*/
import semmle.code.cpp.Element
import semmle.code.cpp.Member
import semmle.code.cpp.Function
private import semmle.code.cpp.internal.ResolveClass
@@ -322,7 +325,7 @@ class BuiltInType extends Type, @builtintype {
class ErroneousType extends BuiltInType {
ErroneousType() { builtintypes(underlyingElement(this), _, 1, _, _, _) }
override string getCanonicalQLClass() { result = "ErroneousType" }
override string getAPrimaryQlClass() { result = "ErroneousType" }
}
/**
@@ -342,7 +345,7 @@ class ErroneousType extends BuiltInType {
class UnknownType extends BuiltInType {
UnknownType() { builtintypes(underlyingElement(this), _, 2, _, _, _) }
override string getCanonicalQLClass() { result = "UnknownType" }
override string getAPrimaryQlClass() { result = "UnknownType" }
}
private predicate isArithmeticType(@builtintype type, int kind) {
@@ -361,7 +364,7 @@ private predicate isArithmeticType(@builtintype type, int kind) {
class ArithmeticType extends BuiltInType {
ArithmeticType() { isArithmeticType(underlyingElement(this), _) }
override string getCanonicalQLClass() { result = "ArithmeticType" }
override string getAPrimaryQlClass() { result = "ArithmeticType" }
}
private predicate isIntegralType(@builtintype type, int kind) {
@@ -561,7 +564,7 @@ class IntegralType extends ArithmeticType, IntegralOrEnumType {
class BoolType extends IntegralType {
BoolType() { builtintypes(underlyingElement(this), _, 4, _, _, _) }
override string getCanonicalQLClass() { result = "BoolType" }
override string getAPrimaryQlClass() { result = "BoolType" }
}
/**
@@ -586,7 +589,7 @@ abstract class CharType extends IntegralType { }
class PlainCharType extends CharType {
PlainCharType() { builtintypes(underlyingElement(this), _, 5, _, _, _) }
override string getCanonicalQLClass() { result = "PlainCharType" }
override string getAPrimaryQlClass() { result = "PlainCharType" }
}
/**
@@ -599,7 +602,7 @@ class PlainCharType extends CharType {
class UnsignedCharType extends CharType {
UnsignedCharType() { builtintypes(underlyingElement(this), _, 6, _, _, _) }
override string getCanonicalQLClass() { result = "UnsignedCharType" }
override string getAPrimaryQlClass() { result = "UnsignedCharType" }
}
/**
@@ -612,7 +615,7 @@ class UnsignedCharType extends CharType {
class SignedCharType extends CharType {
SignedCharType() { builtintypes(underlyingElement(this), _, 7, _, _, _) }
override string getCanonicalQLClass() { result = "SignedCharType" }
override string getAPrimaryQlClass() { result = "SignedCharType" }
}
/**
@@ -629,7 +632,7 @@ class ShortType extends IntegralType {
builtintypes(underlyingElement(this), _, 10, _, _, _)
}
override string getCanonicalQLClass() { result = "ShortType" }
override string getAPrimaryQlClass() { result = "ShortType" }
}
/**
@@ -646,7 +649,7 @@ class IntType extends IntegralType {
builtintypes(underlyingElement(this), _, 13, _, _, _)
}
override string getCanonicalQLClass() { result = "IntType" }
override string getAPrimaryQlClass() { result = "IntType" }
}
/**
@@ -663,7 +666,7 @@ class LongType extends IntegralType {
builtintypes(underlyingElement(this), _, 16, _, _, _)
}
override string getCanonicalQLClass() { result = "LongType" }
override string getAPrimaryQlClass() { result = "LongType" }
}
/**
@@ -680,7 +683,7 @@ class LongLongType extends IntegralType {
builtintypes(underlyingElement(this), _, 19, _, _, _)
}
override string getCanonicalQLClass() { result = "LongLongType" }
override string getAPrimaryQlClass() { result = "LongLongType" }
}
/**
@@ -698,7 +701,7 @@ class Int128Type extends IntegralType {
builtintypes(underlyingElement(this), _, 37, _, _, _)
}
override string getCanonicalQLClass() { result = "Int128Type" }
override string getAPrimaryQlClass() { result = "Int128Type" }
}
private newtype TTypeDomain =
@@ -894,7 +897,7 @@ class DecimalFloatingPointType extends FloatingPointType {
class FloatType extends RealNumberType, BinaryFloatingPointType {
FloatType() { builtintypes(underlyingElement(this), _, 24, _, _, _) }
override string getCanonicalQLClass() { result = "FloatType" }
override string getAPrimaryQlClass() { result = "FloatType" }
}
/**
@@ -906,7 +909,7 @@ class FloatType extends RealNumberType, BinaryFloatingPointType {
class DoubleType extends RealNumberType, BinaryFloatingPointType {
DoubleType() { builtintypes(underlyingElement(this), _, 25, _, _, _) }
override string getCanonicalQLClass() { result = "DoubleType" }
override string getAPrimaryQlClass() { result = "DoubleType" }
}
/**
@@ -918,7 +921,7 @@ class DoubleType extends RealNumberType, BinaryFloatingPointType {
class LongDoubleType extends RealNumberType, BinaryFloatingPointType {
LongDoubleType() { builtintypes(underlyingElement(this), _, 26, _, _, _) }
override string getCanonicalQLClass() { result = "LongDoubleType" }
override string getAPrimaryQlClass() { result = "LongDoubleType" }
}
/**
@@ -930,7 +933,7 @@ class LongDoubleType extends RealNumberType, BinaryFloatingPointType {
class Float128Type extends RealNumberType, BinaryFloatingPointType {
Float128Type() { builtintypes(underlyingElement(this), _, 38, _, _, _) }
override string getCanonicalQLClass() { result = "Float128Type" }
override string getAPrimaryQlClass() { result = "Float128Type" }
}
/**
@@ -942,7 +945,7 @@ class Float128Type extends RealNumberType, BinaryFloatingPointType {
class Decimal32Type extends RealNumberType, DecimalFloatingPointType {
Decimal32Type() { builtintypes(underlyingElement(this), _, 40, _, _, _) }
override string getCanonicalQLClass() { result = "Decimal32Type" }
override string getAPrimaryQlClass() { result = "Decimal32Type" }
}
/**
@@ -954,7 +957,7 @@ class Decimal32Type extends RealNumberType, DecimalFloatingPointType {
class Decimal64Type extends RealNumberType, DecimalFloatingPointType {
Decimal64Type() { builtintypes(underlyingElement(this), _, 41, _, _, _) }
override string getCanonicalQLClass() { result = "Decimal64Type" }
override string getAPrimaryQlClass() { result = "Decimal64Type" }
}
/**
@@ -966,7 +969,7 @@ class Decimal64Type extends RealNumberType, DecimalFloatingPointType {
class Decimal128Type extends RealNumberType, DecimalFloatingPointType {
Decimal128Type() { builtintypes(underlyingElement(this), _, 42, _, _, _) }
override string getCanonicalQLClass() { result = "Decimal128Type" }
override string getAPrimaryQlClass() { result = "Decimal128Type" }
}
/**
@@ -978,7 +981,7 @@ class Decimal128Type extends RealNumberType, DecimalFloatingPointType {
class VoidType extends BuiltInType {
VoidType() { builtintypes(underlyingElement(this), _, 3, _, _, _) }
override string getCanonicalQLClass() { result = "VoidType" }
override string getAPrimaryQlClass() { result = "VoidType" }
}
/**
@@ -994,7 +997,7 @@ class VoidType extends BuiltInType {
class WideCharType extends IntegralType {
WideCharType() { builtintypes(underlyingElement(this), _, 33, _, _, _) }
override string getCanonicalQLClass() { result = "WideCharType" }
override string getAPrimaryQlClass() { result = "WideCharType" }
}
/**
@@ -1006,7 +1009,7 @@ class WideCharType extends IntegralType {
class Char8Type extends IntegralType {
Char8Type() { builtintypes(underlyingElement(this), _, 51, _, _, _) }
override string getCanonicalQLClass() { result = "Char8Type" }
override string getAPrimaryQlClass() { result = "Char8Type" }
}
/**
@@ -1018,7 +1021,7 @@ class Char8Type extends IntegralType {
class Char16Type extends IntegralType {
Char16Type() { builtintypes(underlyingElement(this), _, 43, _, _, _) }
override string getCanonicalQLClass() { result = "Char16Type" }
override string getAPrimaryQlClass() { result = "Char16Type" }
}
/**
@@ -1030,7 +1033,7 @@ class Char16Type extends IntegralType {
class Char32Type extends IntegralType {
Char32Type() { builtintypes(underlyingElement(this), _, 44, _, _, _) }
override string getCanonicalQLClass() { result = "Char32Type" }
override string getAPrimaryQlClass() { result = "Char32Type" }
}
/**
@@ -1045,7 +1048,7 @@ class Char32Type extends IntegralType {
class NullPointerType extends BuiltInType {
NullPointerType() { builtintypes(underlyingElement(this), _, 34, _, _, _) }
override string getCanonicalQLClass() { result = "NullPointerType" }
override string getAPrimaryQlClass() { result = "NullPointerType" }
}
/**
@@ -1080,22 +1083,46 @@ class DerivedType extends Type, @derivedtype {
override Type stripType() { result = getBaseType().stripType() }
predicate isAutoReleasing() {
/**
* Holds if this type has the `__autoreleasing` specifier or if it points to
* a type with the `__autoreleasing` specifier.
*
* DEPRECATED: use `hasSpecifier` directly instead.
*/
deprecated predicate isAutoReleasing() {
this.hasSpecifier("__autoreleasing") or
this.(PointerType).getBaseType().hasSpecifier("__autoreleasing")
}
predicate isStrong() {
/**
* Holds if this type has the `__strong` specifier or if it points to
* a type with the `__strong` specifier.
*
* DEPRECATED: use `hasSpecifier` directly instead.
*/
deprecated predicate isStrong() {
this.hasSpecifier("__strong") or
this.(PointerType).getBaseType().hasSpecifier("__strong")
}
predicate isUnsafeRetained() {
/**
* Holds if this type has the `__unsafe_unretained` specifier or if it points
* to a type with the `__unsafe_unretained` specifier.
*
* DEPRECATED: use `hasSpecifier` directly instead.
*/
deprecated predicate isUnsafeRetained() {
this.hasSpecifier("__unsafe_unretained") or
this.(PointerType).getBaseType().hasSpecifier("__unsafe_unretained")
}
predicate isWeak() {
/**
* Holds if this type has the `__weak` specifier or if it points to
* a type with the `__weak` specifier.
*
* DEPRECATED: use `hasSpecifier` directly instead.
*/
deprecated predicate isWeak() {
this.hasSpecifier("__weak") or
this.(PointerType).getBaseType().hasSpecifier("__weak")
}
@@ -1109,7 +1136,7 @@ class DerivedType extends Type, @derivedtype {
* ```
*/
class Decltype extends Type, @decltype {
override string getCanonicalQLClass() { result = "Decltype" }
override string getAPrimaryQlClass() { result = "Decltype" }
/**
* The expression whose type is being obtained by this decltype.
@@ -1182,7 +1209,7 @@ class Decltype extends Type, @decltype {
class PointerType extends DerivedType {
PointerType() { derivedtypes(underlyingElement(this), _, 1, _) }
override string getCanonicalQLClass() { result = "PointerType" }
override string getAPrimaryQlClass() { result = "PointerType" }
override int getPointerIndirectionLevel() {
result = 1 + this.getBaseType().getPointerIndirectionLevel()
@@ -1208,7 +1235,7 @@ class ReferenceType extends DerivedType {
derivedtypes(underlyingElement(this), _, 2, _) or derivedtypes(underlyingElement(this), _, 8, _)
}
override string getCanonicalQLClass() { result = "ReferenceType" }
override string getAPrimaryQlClass() { result = "ReferenceType" }
override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() }
@@ -1235,7 +1262,7 @@ class ReferenceType extends DerivedType {
class LValueReferenceType extends ReferenceType {
LValueReferenceType() { derivedtypes(underlyingElement(this), _, 2, _) }
override string getCanonicalQLClass() { result = "LValueReferenceType" }
override string getAPrimaryQlClass() { result = "LValueReferenceType" }
}
/**
@@ -1251,7 +1278,7 @@ class LValueReferenceType extends ReferenceType {
class RValueReferenceType extends ReferenceType {
RValueReferenceType() { derivedtypes(underlyingElement(this), _, 8, _) }
override string getCanonicalQLClass() { result = "RValueReferenceType" }
override string getAPrimaryQlClass() { result = "RValueReferenceType" }
override string explain() { result = "rvalue " + super.explain() }
}
@@ -1266,7 +1293,7 @@ class RValueReferenceType extends ReferenceType {
class SpecifiedType extends DerivedType {
SpecifiedType() { derivedtypes(underlyingElement(this), _, 3, _) }
override string getCanonicalQLClass() { result = "SpecifiedType" }
override string getAPrimaryQlClass() { result = "SpecifiedType" }
override int getSize() { result = this.getBaseType().getSize() }
@@ -1314,8 +1341,12 @@ class SpecifiedType extends DerivedType {
class ArrayType extends DerivedType {
ArrayType() { derivedtypes(underlyingElement(this), _, 4, _) }
override string getCanonicalQLClass() { result = "ArrayType" }
override string getAPrimaryQlClass() { result = "ArrayType" }
/**
* Holds if this array is declared to be of a constant size. See
* `getArraySize` and `getByteSize` to get the size of the array.
*/
predicate hasArraySize() { arraysizes(underlyingElement(this), _, _, _) }
/**
@@ -1381,7 +1412,7 @@ class GNUVectorType extends DerivedType {
*/
int getNumElements() { arraysizes(underlyingElement(this), result, _, _) }
override string getCanonicalQLClass() { result = "GNUVectorType" }
override string getAPrimaryQlClass() { result = "GNUVectorType" }
/**
* Gets the size, in bytes, of this vector type.
@@ -1412,7 +1443,7 @@ class GNUVectorType extends DerivedType {
class FunctionPointerType extends FunctionPointerIshType {
FunctionPointerType() { derivedtypes(underlyingElement(this), _, 6, _) }
override string getCanonicalQLClass() { result = "FunctionPointerType" }
override string getAPrimaryQlClass() { result = "FunctionPointerType" }
override int getPointerIndirectionLevel() { result = 1 }
@@ -1430,7 +1461,7 @@ class FunctionPointerType extends FunctionPointerIshType {
class FunctionReferenceType extends FunctionPointerIshType {
FunctionReferenceType() { derivedtypes(underlyingElement(this), _, 7, _) }
override string getCanonicalQLClass() { result = "FunctionReferenceType" }
override string getAPrimaryQlClass() { result = "FunctionReferenceType" }
override int getPointerIndirectionLevel() { result = getBaseType().getPointerIndirectionLevel() }
@@ -1519,7 +1550,7 @@ class PointerToMemberType extends Type, @ptrtomember {
/** a printable representation of this named element */
override string toString() { result = this.getName() }
override string getCanonicalQLClass() { result = "PointerToMemberType" }
override string getAPrimaryQlClass() { result = "PointerToMemberType" }
/** the name of this type */
override string getName() { result = "..:: *" }
@@ -1564,16 +1595,25 @@ class RoutineType extends Type, @routinetype {
/** a printable representation of this named element */
override string toString() { result = this.getName() }
override string getCanonicalQLClass() { result = "RoutineType" }
override string getAPrimaryQlClass() { result = "RoutineType" }
override string getName() { result = "..()(..)" }
/**
* Gets the type of the `n`th parameter to this routine.
*/
Type getParameterType(int n) {
routinetypeargs(underlyingElement(this), n, unresolveElement(result))
}
/**
* Gets the type of a parameter to this routine.
*/
Type getAParameterType() { routinetypeargs(underlyingElement(this), _, unresolveElement(result)) }
/**
* Gets the return type of this routine.
*/
Type getReturnType() { routinetypes(underlyingElement(this), unresolveElement(result)) }
override string explain() {
@@ -1632,7 +1672,7 @@ class TemplateParameter extends UserType {
usertypes(underlyingElement(this), _, 7) or usertypes(underlyingElement(this), _, 8)
}
override string getCanonicalQLClass() { result = "TemplateParameter" }
override string getAPrimaryQlClass() { result = "TemplateParameter" }
override predicate involvesTemplateParameter() { any() }
}
@@ -1650,7 +1690,7 @@ class TemplateParameter extends UserType {
class TemplateTemplateParameter extends TemplateParameter {
TemplateTemplateParameter() { usertypes(underlyingElement(this), _, 8) }
override string getCanonicalQLClass() { result = "TemplateTemplateParameter" }
override string getAPrimaryQlClass() { result = "TemplateTemplateParameter" }
}
/**
@@ -1662,7 +1702,7 @@ class TemplateTemplateParameter extends TemplateParameter {
class AutoType extends TemplateParameter {
AutoType() { usertypes(underlyingElement(this), "auto", 7) }
override string getCanonicalQLClass() { result = "AutoType" }
override string getAPrimaryQlClass() { result = "AutoType" }
override Location getLocation() {
suppressUnusedThis(this) and
@@ -1698,7 +1738,7 @@ private predicate suppressUnusedThis(Type t) { any() }
class TypeMention extends Locatable, @type_mention {
override string toString() { result = "type mention" }
override string getCanonicalQLClass() { result = "TypeMention" }
override string getAPrimaryQlClass() { result = "TypeMention" }
/**
* Gets the type being referenced by this type mention.

View File

@@ -1,3 +1,7 @@
/**
* Provides classes for modeling typedefs and type aliases.
*/
import semmle.code.cpp.Type
private import semmle.code.cpp.internal.ResolveClass
@@ -55,7 +59,7 @@ class TypedefType extends UserType {
class CTypedefType extends TypedefType {
CTypedefType() { usertypes(underlyingElement(this), _, 5) }
override string getCanonicalQLClass() { result = "CTypedefType" }
override string getAPrimaryQlClass() { result = "CTypedefType" }
override string explain() {
result = "typedef {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\""
@@ -71,7 +75,7 @@ class CTypedefType extends TypedefType {
class UsingAliasTypedefType extends TypedefType {
UsingAliasTypedefType() { usertypes(underlyingElement(this), _, 14) }
override string getCanonicalQLClass() { result = "UsingAliasTypedefType" }
override string getAPrimaryQlClass() { result = "UsingAliasTypedefType" }
override string explain() {
result = "using {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\""
@@ -88,7 +92,7 @@ class UsingAliasTypedefType extends TypedefType {
class LocalTypedefType extends TypedefType {
LocalTypedefType() { isLocal() }
override string getCanonicalQLClass() { result = "LocalTypedefType" }
override string getAPrimaryQlClass() { result = "LocalTypedefType" }
}
/**
@@ -101,7 +105,7 @@ class LocalTypedefType extends TypedefType {
class NestedTypedefType extends TypedefType {
NestedTypedefType() { this.isMember() }
override string getCanonicalQLClass() { result = "NestedTypedefType" }
override string getAPrimaryQlClass() { result = "NestedTypedefType" }
/**
* DEPRECATED: use `.hasSpecifier("private")` instead.

Some files were not shown because too many files have changed in this diff Show More