Compare commits

..

1 Commits

Author SHA1 Message Date
Owen Mansel-Chan
7126b95b16 Add test with MISSING alerts 2026-06-11 07:22:17 +02:00
1683 changed files with 11939 additions and 64928 deletions

View File

@@ -2,7 +2,7 @@
* @github/code-scanning-alert-coverage * @github/code-scanning-alert-coverage
# CodeQL language libraries # CodeQL language libraries
/actions/ @github/code-scanning-alert-coverage /actions/ @github/codeql-dynamic
/cpp/ @github/codeql-c-analysis /cpp/ @github/codeql-c-analysis
/csharp/ @github/codeql-csharp /csharp/ @github/codeql-csharp
/csharp/autobuilder/Semmle.Autobuild.Cpp @github/codeql-c-extractor @github/code-scanning-language-coverage /csharp/autobuilder/Semmle.Autobuild.Cpp @github/codeql-c-extractor @github/code-scanning-language-coverage
@@ -59,5 +59,9 @@ MODULE.bazel @github/codeql-ci-reviewers
/.github/workflows/rust.yml @github/codeql-rust /.github/workflows/rust.yml @github/codeql-rust
/.github/workflows/swift.yml @github/codeql-swift /.github/workflows/swift.yml @github/codeql-swift
# Misc
/misc/scripts/accept-expected-changes-from-ci.py @RasmusWL
/misc/scripts/generate-code-scanning-query-list.py @RasmusWL
# .devcontainer # .devcontainer
/.devcontainer/ @github/codeql-ci-reviewers /.devcontainer/ @github/codeql-ci-reviewers

View File

@@ -2,7 +2,7 @@
### Minor Analysis Improvements ### Minor Analysis Improvements
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a SHA-1 or SHA-256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used. * The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.
## 0.4.36 ## 0.4.36

View File

@@ -1,4 +0,0 @@
---
category: fix
---
* The query `actions/pr-on-self-hosted-runner` was updated to the latest standard runner labels reducing false positive results.

View File

@@ -2,4 +2,4 @@
### Minor Analysis Improvements ### Minor Analysis Improvements
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a SHA-1 or SHA-256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used. * The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.

View File

@@ -1920,5 +1920,3 @@ private YamlMappingLikeNode resolveMatrixAccessPath(
else result = resolveMatrixAccessPath(newRoot, rest) else result = resolveMatrixAccessPath(newRoot, rest)
) )
} }
class Comment = YamlComment;

View File

@@ -52,12 +52,6 @@ private module YamlSig implements LibYaml::InputSig {
class ParseErrorBase extends LocatableBase, @yaml_error { class ParseErrorBase extends LocatableBase, @yaml_error {
string getMessage() { yaml_errors(this, result) } string getMessage() { yaml_errors(this, result) }
} }
class CommentBase extends LocatableBase, @yaml_comment {
string getText() { yaml_comments(this, result, _) }
override string toString() { yaml_comments(this, _, result) }
}
} }
import LibYaml::Make<YamlSig> import LibYaml::Make<YamlSig>

View File

@@ -2,12 +2,10 @@ import actions
bindingset[runner] bindingset[runner]
predicate isGithubHostedRunner(string runner) { predicate isGithubHostedRunner(string runner) {
// The list of github hosted repos: // list of github hosted repos: https://github.com/actions/runner-images/blob/main/README.md#available-images
// https://github.com/actions/runner-images/blob/main/README.md#available-images runner
// https://docs.github.com/en/enterprise-cloud@latest/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job#standard-github-hosted-runners-for-public-repositories .toLowerCase()
runner.toLowerCase().regexpMatch("^ubuntu-([0-9.]+|latest|slim)(-arm)?$") or .regexpMatch("^(ubuntu-([0-9.]+|latest)|macos-([0-9]+|latest)(-x?large)?|windows-([0-9.]+|latest))$")
runner.toLowerCase().regexpMatch("^macos-([0-9]+|latest)(-x?large|-intel)?$") or
runner.toLowerCase().regexpMatch("^windows-([0-9.]+|latest)(-vs[0-9.]+)?(-arm)?$")
} }
bindingset[runner] bindingset[runner]

View File

@@ -15,7 +15,7 @@
### Bug Fixes ### Bug Fixes
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check. * Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check.
## 0.6.28 ## 0.6.28

View File

@@ -1,8 +1,8 @@
/** /**
* @name Checkout of untrusted code in a non-privileged context * @name Checkout of untrusted code in a trusted context
* @description Checking out and running the build script from a fork executes untrusted code. Even in a * @description Privileged workflows have read/write access to the base repository and access to secrets.
* non-privileged workflow, this can be abused, for example to compromise self-hosted runners * By explicitly checking out and running the build script from a fork the untrusted code is running in an environment
* or to poison caches and artifacts that are later consumed by privileged workflows. * that is able to push to the base repository and to access secrets.
* @kind problem * @kind problem
* @problem.severity warning * @problem.severity warning
* @precision medium * @precision medium
@@ -20,4 +20,4 @@ from PRHeadCheckoutStep checkout
where where
// the checkout occurs in a non-privileged context // the checkout occurs in a non-privileged context
inNonPrivilegedContext(checkout) inNonPrivilegedContext(checkout)
select checkout, "Potential unsafe checkout of untrusted pull request on non-privileged workflow." select checkout, "Potential unsafe checkout of untrusted pull request on privileged workflow."

View File

@@ -1,4 +0,0 @@
---
category: queryMetadata
---
* The name, description, and alert message of `actions/untrusted-checkout/medium` have been corrected to describe a non-privileged context.

View File

@@ -15,4 +15,4 @@
### Bug Fixes ### Bug Fixes
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check. * Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check.

View File

@@ -1,43 +0,0 @@
name: test
on:
pull_request:
jobs:
test:
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- ubuntu-24.04
- ubuntu-24.04-arm
- ubuntu-22.04
- ubuntu-22.04-arm
- ubuntu-26.04
- ubuntu-26.04-arm
- ubuntu-slim
- macos-26
- macos-26-xlarge
- macos-26-intel
- macos-26-large
- macos-latest-large
- macos-15-large
- macos-15
- macos-15-intel
- macos-latest
- macos-15
- macos-15-xlarge
- macos-14-large
- macos-14
- macos-14-xlarge
- windows-2025-vs2026
- windows-latest
- windows-2025
- windows-2022
- windows-11
- windows-11-arm
- windows-11-vs2026-arm
runs-on: ${{ matrix.os }}
steps:
- run: cmd

View File

@@ -1,10 +1,10 @@
| .github/workflows/artifactpoisoning81.yml:11:9:14:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/artifactpoisoning81.yml:11:9:14:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/dependabot2.yml:33:9:38:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/dependabot2.yml:33:9:38:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/mend.yml:22:9:29:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/mend.yml:22:9:29:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/poc3.yml:18:7:25:4 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/poc3.yml:18:7:25:4 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/poc.yml:30:9:36:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/poc.yml:30:9:36:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/priv_pull_request_checkout.yml:14:9:20:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/priv_pull_request_checkout.yml:14:9:20:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/test3.yml:28:9:33:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/test3.yml:28:9:33:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/test4.yml:18:7:25:4 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/test4.yml:18:7:25:4 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/test8.yml:20:9:26:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/test8.yml:20:9:26:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |
| .github/workflows/test9.yml:11:9:16:6 | Uses Step | Potential unsafe checkout of untrusted pull request on non-privileged workflow. | | .github/workflows/test9.yml:11:9:16:6 | Uses Step | Potential unsafe checkout of untrusted pull request on privileged workflow. |

View File

@@ -1,2 +0,0 @@
description: Fix NameQualifier inconsistency
compatibility: full

View File

@@ -1071,7 +1071,7 @@ class NullPointerType extends BuiltInType {
* const float fa[40]; * const float fa[40];
* ``` * ```
*/ */
class DerivedType extends Type, NameQualifyingElement, @derivedtype { class DerivedType extends Type, @derivedtype {
override string toString() { result = this.getName() } override string toString() { result = this.getName() }
override string getName() { derivedtypes(underlyingElement(this), result, _, _) } override string getName() { derivedtypes(underlyingElement(this), result, _, _) }

View File

@@ -1430,8 +1430,7 @@ specialnamequalifyingelements(
@namequalifyingelement = @namespace @namequalifyingelement = @namespace
| @specialnamequalifyingelement | @specialnamequalifyingelement
| @usertype | @usertype
| @decltype | @decltype;
| @derivedtype;
namequalifiers( namequalifiers(
unique int id: @namequalifier, unique int id: @namequalifier,

View File

@@ -1,2 +0,0 @@
description: Fix NameQualifier inconsistency
compatibility: full

View File

@@ -1,7 +1,3 @@
| inconsistency2.cpp:3:3:3:5 | T:: | inconsistency2.cpp:3:3:3:6 | x | inconsistency2.cpp:2:20:2:20 | T |
| inconsistency2.cpp:3:3:3:11 | const s:: | inconsistency2.cpp:3:3:3:6 | x | file://:0:0:0:0 | const s |
| inconsistency.cpp:7:20:7:22 | S:: | inconsistency.cpp:7:20:7:23 | (int)... | inconsistency.cpp:4:8:4:8 | S |
| inconsistency.cpp:7:20:7:22 | S:: | inconsistency.cpp:7:20:7:23 | A | inconsistency.cpp:4:8:4:8 | S |
| name_qualifiers.cpp:29:7:29:8 | :: | name_qualifiers.cpp:29:7:29:9 | x | file://:0:0:0:0 | (global namespace) | | name_qualifiers.cpp:29:7:29:8 | :: | name_qualifiers.cpp:29:7:29:9 | x | file://:0:0:0:0 | (global namespace) |
| name_qualifiers.cpp:31:7:31:10 | N1:: | name_qualifiers.cpp:31:7:31:12 | nx | name_qualifiers.cpp:4:11:4:12 | N1 | | name_qualifiers.cpp:31:7:31:10 | N1:: | name_qualifiers.cpp:31:7:31:12 | nx | name_qualifiers.cpp:4:11:4:12 | N1 |
| name_qualifiers.cpp:34:7:34:8 | :: | name_qualifiers.cpp:34:9:34:12 | N1:: | file://:0:0:0:0 | (global namespace) | | name_qualifiers.cpp:34:7:34:8 | :: | name_qualifiers.cpp:34:9:34:12 | N1:: | file://:0:0:0:0 | (global namespace) |

View File

@@ -1,5 +1,7 @@
import cpp import cpp
from NameQualifier nq, Location l from NameQualifier nq, Location l
where l = nq.getQualifiedElement().getLocation() where
l = nq.getQualifiedElement().getLocation() and
l.getFile().getShortName() = "name_qualifiers"
select nq, nq.getQualifiedElement(), nq.getQualifyingElement() select nq, nq.getQualifiedElement(), nq.getQualifyingElement()

View File

@@ -1,8 +1,8 @@
// This file is present to test whether name-qualifying an enum constant leads to a database inconsistency. // This file is present to test whether name-qualifying an enum constant leads to a database inconsistency.
// As such, there is no QL part of the test.
struct S { enum E { A }; }; struct S { enum E { A }; };
static void f() { static int f() {
switch(0) { case S::A: break; } switch(0) { case S::A: break; }
} }

View File

@@ -1,12 +0,0 @@
namespace {
template <typename T> T f() {
T::x;
return {};
}
struct s {
static int x;
};
struct t {
s x = f<const s>();
};
}

View File

@@ -135,7 +135,7 @@ namespace Semmle.Autobuild.CSharp.Tests
if (!EnumerateFiles.TryGetValue(dir, out var str)) if (!EnumerateFiles.TryGetValue(dir, out var str))
throw new ArgumentException("Missing EnumerateFiles " + dir); throw new ArgumentException("Missing EnumerateFiles " + dir);
return str.Split("\n").Select(p => PathJoin(dir, p)); return str.Split("\n").Select(p => PathCombine(dir, p));
} }
public IDictionary<string, string> EnumerateDirectories { get; } = new Dictionary<string, string>(); public IDictionary<string, string> EnumerateDirectories { get; } = new Dictionary<string, string>();
@@ -147,7 +147,7 @@ namespace Semmle.Autobuild.CSharp.Tests
return string.IsNullOrEmpty(str) return string.IsNullOrEmpty(str)
? Enumerable.Empty<string>() ? Enumerable.Empty<string>()
: str.Split("\n").Select(p => PathJoin(dir, p)); : str.Split("\n").Select(p => PathCombine(dir, p));
} }
public bool IsWindows { get; set; } public bool IsWindows { get; set; }
@@ -170,7 +170,7 @@ namespace Semmle.Autobuild.CSharp.Tests
bool IBuildActions.IsMonoInstalled() => IsMonoInstalled; bool IBuildActions.IsMonoInstalled() => IsMonoInstalled;
public string PathJoin(params string[] parts) public string PathCombine(params string[] parts)
{ {
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p))); return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
} }

View File

@@ -109,7 +109,7 @@ namespace Semmle.Autobuild.CSharp
=> WithDotNet(builder, ensureDotNetAvailable: false, (_, env) => f(env)); => WithDotNet(builder, ensureDotNetAvailable: false, (_, env) => f(env));
private static string DotNetCommand(IBuildActions actions, string? dotNetPath) => private static string DotNetCommand(IBuildActions actions, string? dotNetPath) =>
dotNetPath is not null ? actions.PathJoin(dotNetPath, "dotnet") : "dotnet"; dotNetPath is not null ? actions.PathCombine(dotNetPath, "dotnet") : "dotnet";
private static CommandBuilder GetCleanCommand(IBuildActions actions, string? dotNetPath, IDictionary<string, string>? environment) private static CommandBuilder GetCleanCommand(IBuildActions actions, string? dotNetPath, IDictionary<string, string>? environment)
{ {

View File

@@ -158,7 +158,7 @@ namespace Semmle.Autobuild.Cpp.Tests
bool IBuildActions.IsMonoInstalled() => IsMonoInstalled; bool IBuildActions.IsMonoInstalled() => IsMonoInstalled;
string IBuildActions.PathJoin(params string[] parts) string IBuildActions.PathCombine(params string[] parts)
{ {
return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p))); return string.Join(IsWindows ? '\\' : '/', parts.Where(p => !string.IsNullOrWhiteSpace(p)));
} }

View File

@@ -108,7 +108,7 @@ namespace Semmle.Autobuild.Shared
/// </summary> /// </summary>
/// <param name="path">The relative path.</param> /// <param name="path">The relative path.</param>
/// <returns>True iff the path was found.</returns> /// <returns>True iff the path was found.</returns>
public bool HasRelativePath(string path) => HasPath(Actions.PathJoin(RootDirectory, path)); public bool HasRelativePath(string path) => HasPath(Actions.PathCombine(RootDirectory, path));
/// <summary> /// <summary>
/// List of project/solution files to build. /// List of project/solution files to build.

View File

@@ -32,7 +32,7 @@ namespace Semmle.Autobuild.Shared
yield break; yield break;
// Attempt to use vswhere to find installations of Visual Studio // Attempt to use vswhere to find installations of Visual Studio
var vswhere = actions.PathJoin(programFilesx86, "Microsoft Visual Studio", "Installer", "vswhere.exe"); var vswhere = actions.PathCombine(programFilesx86, "Microsoft Visual Studio", "Installer", "vswhere.exe");
if (actions.FileExists(vswhere)) if (actions.FileExists(vswhere))
{ {
@@ -51,14 +51,14 @@ namespace Semmle.Autobuild.Shared
if (majorVersion < 15) if (majorVersion < 15)
{ {
// Visual Studio 2015 and below // Visual Studio 2015 and below
yield return new VcVarsBatFile(actions.PathJoin(vsInstallation.InstallationPath, @"VC\vcvarsall.bat"), majorVersion); yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\vcvarsall.bat"), majorVersion);
} }
else else
{ {
// Visual Studio 2017 and above // Visual Studio 2017 and above
yield return new VcVarsBatFile(actions.PathJoin(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars32.bat"), majorVersion); yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars32.bat"), majorVersion);
yield return new VcVarsBatFile(actions.PathJoin(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars64.bat"), majorVersion); yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars64.bat"), majorVersion);
yield return new VcVarsBatFile(actions.PathJoin(vsInstallation.InstallationPath, @"Common7\Tools\VsDevCmd.bat"), majorVersion); yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"Common7\Tools\VsDevCmd.bat"), majorVersion);
} }
} }
// else: Skip installation without a version // else: Skip installation without a version
@@ -68,10 +68,10 @@ namespace Semmle.Autobuild.Shared
} }
// vswhere not installed or didn't run correctly - return legacy Visual Studio versions // vswhere not installed or didn't run correctly - return legacy Visual Studio versions
yield return new VcVarsBatFile(actions.PathJoin(programFilesx86, @"Microsoft Visual Studio 14.0\VC\vcvarsall.bat"), 14); yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 14.0\VC\vcvarsall.bat"), 14);
yield return new VcVarsBatFile(actions.PathJoin(programFilesx86, @"Microsoft Visual Studio 12.0\VC\vcvarsall.bat"), 12); yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 12.0\VC\vcvarsall.bat"), 12);
yield return new VcVarsBatFile(actions.PathJoin(programFilesx86, @"Microsoft Visual Studio 11.0\VC\vcvarsall.bat"), 11); yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 11.0\VC\vcvarsall.bat"), 11);
yield return new VcVarsBatFile(actions.PathJoin(programFilesx86, @"Microsoft Visual Studio 10.0\VC\vcvarsall.bat"), 10); yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 10.0\VC\vcvarsall.bat"), 10);
} }
/// <summary> /// <summary>

View File

@@ -60,7 +60,7 @@ namespace Semmle.Autobuild.Shared
// Use `nuget.exe` from source code repo, if present, otherwise first attempt with global // Use `nuget.exe` from source code repo, if present, otherwise first attempt with global
// `nuget` command, and if that fails, attempt to download `nuget.exe` from nuget.org // `nuget` command, and if that fails, attempt to download `nuget.exe` from nuget.org
var nuget = builder.GetFilename("nuget.exe").Select(t => t.Item1).FirstOrDefault() ?? "nuget"; var nuget = builder.GetFilename("nuget.exe").Select(t => t.Item1).FirstOrDefault() ?? "nuget";
var nugetDownloadPath = builder.Actions.PathJoin(FileUtils.GetTemporaryWorkingDirectory(builder.Actions.GetEnvironmentVariable, builder.Options.Language.UpperCaseName, out _), ".nuget", "nuget.exe"); var nugetDownloadPath = builder.Actions.PathCombine(FileUtils.GetTemporaryWorkingDirectory(builder.Actions.GetEnvironmentVariable, builder.Options.Language.UpperCaseName, out _), ".nuget", "nuget.exe");
var nugetDownloaded = false; var nugetDownloaded = false;
var ret = BuildScript.Success; var ret = BuildScript.Success;

View File

@@ -107,9 +107,8 @@ namespace Semmle.Autobuild.Shared
continue; continue;
} }
var includePath = builder.Actions.PathJoin(include.Value.Split('\\', StringSplitOptions.RemoveEmptyEntries)); var includePath = builder.Actions.PathCombine(include.Value.Split('\\', StringSplitOptions.RemoveEmptyEntries));
var path = Path.IsPathRooted(includePath) ? includePath : builder.Actions.PathJoin(DirectoryName, includePath); ret.Add(new Project<TAutobuildOptions>(builder, builder.Actions.PathCombine(DirectoryName, includePath)));
ret.Add(new Project<TAutobuildOptions>(builder, path));
} }
return ret; return ret;
}); });

View File

@@ -79,7 +79,7 @@ namespace Semmle.Autobuild.Shared
includedProjects = solution.ProjectsInOrder includedProjects = solution.ProjectsInOrder
.Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat) .Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat)
.Select(p => builder.Actions.PathJoin(DirectoryName, builder.Actions.PathJoin(p.RelativePath.Split('\\', StringSplitOptions.RemoveEmptyEntries)))) .Select(p => builder.Actions.PathCombine(DirectoryName, builder.Actions.PathCombine(p.RelativePath.Split('\\', StringSplitOptions.RemoveEmptyEntries))))
.Select(p => new Project<TAutobuildOptions>(builder, p)) .Select(p => new Project<TAutobuildOptions>(builder, p))
.ToArray(); .ToArray();
} }

View File

@@ -1,2 +0,0 @@
description: Restructure and rename types related to operations.
compatibility: full

View File

@@ -50,7 +50,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
return; return;
} }
var path = Path.Join(p, ParseFilePath(d)); var path = Path.Combine(p, ParseFilePath(d));
Paths.Add(path); Paths.Add(path);
Packages.Add(GetPackageName(p)); Packages.Add(GetPackageName(p));
} }

View File

@@ -75,7 +75,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
} }
} }
this.diagnosticsWriter = new DiagnosticsStream(Path.Join( this.diagnosticsWriter = new DiagnosticsStream(Path.Combine(
diagDirEnv ?? "", diagDirEnv ?? "",
$"dependency-manager-{DateTime.UtcNow:yyyyMMddHHmm}-{Environment.ProcessId}.jsonc")); $"dependency-manager-{DateTime.UtcNow:yyyyMMddHHmm}-{Environment.ProcessId}.jsonc"));
this.sourceDir = new DirectoryInfo(srcDir); this.sourceDir = new DirectoryInfo(srcDir);
@@ -327,7 +327,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
private void RemoveNugetPackageReference(string packagePrefix, ISet<AssemblyLookupLocation> dllLocations) private void RemoveNugetPackageReference(string packagePrefix, ISet<AssemblyLookupLocation> dllLocations)
{ {
var packageFolder = nugetPackageRestorer.PackageDirectory.DirInfo.FullName.ToLowerInvariant(); var packageFolder = nugetPackageRestorer.PackageDirectory.DirInfo.FullName.ToLowerInvariant();
var packagePathPrefix = Path.Join(packageFolder, packagePrefix.ToLowerInvariant()); var packagePathPrefix = Path.Combine(packageFolder, packagePrefix.ToLowerInvariant());
var toRemove = dllLocations.Where(s => s.Path.StartsWith(packagePathPrefix, StringComparison.InvariantCultureIgnoreCase)); var toRemove = dllLocations.Where(s => s.Path.StartsWith(packagePathPrefix, StringComparison.InvariantCultureIgnoreCase));
foreach (var path in toRemove) foreach (var path in toRemove)
{ {

View File

@@ -31,7 +31,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
} }
} }
private DotNet(ILogger logger, string? dotNetPath, TemporaryDirectory tempWorkingDirectory, DependabotProxy? dependabotProxy) : this(new DotNetCliInvoker(logger, Path.Join(dotNetPath ?? string.Empty, "dotnet"), dependabotProxy), logger, dotNetPath is null, tempWorkingDirectory) { } private DotNet(ILogger logger, string? dotNetPath, TemporaryDirectory tempWorkingDirectory, DependabotProxy? dependabotProxy) : this(new DotNetCliInvoker(logger, Path.Combine(dotNetPath ?? string.Empty, "dotnet"), dependabotProxy), logger, dotNetPath is null, tempWorkingDirectory) { }
internal static IDotNet Make(IDotNetCliInvoker dotnetCliInvoker, ILogger logger, bool runDotnetInfo) => new DotNet(dotnetCliInvoker, logger, runDotnetInfo); internal static IDotNet Make(IDotNetCliInvoker dotnetCliInvoker, ILogger logger, bool runDotnetInfo) => new DotNet(dotnetCliInvoker, logger, runDotnetInfo);
@@ -73,7 +73,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
var path = ".empty"; var path = ".empty";
if (tempWorkingDirectory != null) if (tempWorkingDirectory != null)
{ {
path = Path.Join(tempWorkingDirectory.ToString(), "emptyFakeDotnetRoot"); path = Path.Combine(tempWorkingDirectory.ToString(), "emptyFakeDotnetRoot");
Directory.CreateDirectory(path); Directory.CreateDirectory(path);
} }
@@ -303,7 +303,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
} }
else else
{ {
var dotnetInstallPath = actions.PathJoin(tempWorkingDirectory, ".dotnet", "dotnet-install.sh"); var dotnetInstallPath = actions.PathCombine(tempWorkingDirectory, ".dotnet", "dotnet-install.sh");
var downloadDotNetInstallSh = BuildScript.DownloadFile( var downloadDotNetInstallSh = BuildScript.DownloadFile(
"https://dot.net/v1/dotnet-install.sh", "https://dot.net/v1/dotnet-install.sh",
dotnetInstallPath, dotnetInstallPath,
@@ -339,7 +339,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
}; };
} }
var dotnetInfo = InfoScript(actions, actions.PathJoin(path, "dotnet"), MinimalEnvironment.ToDictionary(), logger); var dotnetInfo = InfoScript(actions, actions.PathCombine(path, "dotnet"), MinimalEnvironment.ToDictionary(), logger);
Func<string, BuildScript> getInstallAndVerify = version => Func<string, BuildScript> getInstallAndVerify = version =>
// run `dotnet --info` after install, to check that it executes successfully // run `dotnet --info` after install, to check that it executes successfully
@@ -384,7 +384,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// </summary> /// </summary>
public static BuildScript WithDotNet(IBuildActions actions, ILogger logger, IEnumerable<string> files, string tempWorkingDirectory, bool shouldCleanUp, bool ensureDotNetAvailable, string? version, Func<string?, BuildScript> f) public static BuildScript WithDotNet(IBuildActions actions, ILogger logger, IEnumerable<string> files, string tempWorkingDirectory, bool shouldCleanUp, bool ensureDotNetAvailable, string? version, Func<string?, BuildScript> f)
{ {
var installDir = actions.PathJoin(tempWorkingDirectory, ".dotnet"); var installDir = actions.PathCombine(tempWorkingDirectory, ".dotnet");
var installScript = DownloadDotNet(actions, logger, files, tempWorkingDirectory, shouldCleanUp, installDir, version, ensureDotNetAvailable); var installScript = DownloadDotNet(actions, logger, files, tempWorkingDirectory, shouldCleanUp, installDir, version, ensureDotNetAvailable);
return BuildScript.Bind(installScript, installed => return BuildScript.Bind(installScript, installed =>
{ {

View File

@@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
private string FullVersion => private string FullVersion =>
version.ToString(); version.ToString();
public string FullPath => Path.Join(dir, FullVersion); public string FullPath => Path.Combine(dir, FullVersion);
/** /**
* The full path to the reference assemblies for this runtime. * The full path to the reference assemblies for this runtime.
@@ -33,7 +33,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
{ {
directories[^2] = "packs"; directories[^2] = "packs";
directories[^1] = $"{directories[^1]}.Ref"; directories[^1] = $"{directories[^1]}.Ref";
return Path.Join(string.Join(Path.DirectorySeparatorChar, directories), FullVersion, "ref"); return Path.Combine(string.Join(Path.DirectorySeparatorChar, directories), FullVersion, "ref");
} }
return null; return null;
} }

View File

@@ -0,0 +1,304 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Semmle.Util;
namespace Semmle.Extraction.CSharp.DependencyFetching
{
/// <summary>
/// Manage the downloading of NuGet packages with nuget.exe.
/// Locates packages in a source tree and downloads all of the
/// referenced assemblies to a temp folder.
/// </summary>
internal class NugetExeWrapper : IDisposable
{
private readonly string? nugetExe;
private readonly Semmle.Util.Logging.ILogger logger;
public int PackageCount => fileProvider.PackagesConfigs.Count;
private readonly string? backupNugetConfig;
private readonly string? nugetConfigPath;
private readonly FileProvider fileProvider;
/// <summary>
/// The packages directory.
/// This will be in the user-specified or computed Temp location
/// so as to not trample the source tree.
/// </summary>
private readonly DependencyDirectory packageDirectory;
/// <summary>
/// Create the package manager for a specified source tree.
/// </summary>
public NugetExeWrapper(FileProvider fileProvider, DependencyDirectory packageDirectory, Semmle.Util.Logging.ILogger logger, Func<bool> useDefaultFeed)
{
this.fileProvider = fileProvider;
this.packageDirectory = packageDirectory;
this.logger = logger;
if (fileProvider.PackagesConfigs.Count > 0)
{
logger.LogInfo($"Found packages.config files, trying to use nuget.exe for package restore");
nugetExe = ResolveNugetExe();
if (HasNoPackageSource() && useDefaultFeed())
{
// We only modify or add a top level nuget.config file
nugetConfigPath = Path.Combine(fileProvider.SourceDir.FullName, "nuget.config");
try
{
if (File.Exists(nugetConfigPath))
{
var tempFolderPath = FileUtils.GetTemporaryWorkingDirectory(out _);
do
{
backupNugetConfig = Path.Combine(tempFolderPath, Path.GetRandomFileName());
}
while (File.Exists(backupNugetConfig));
File.Copy(nugetConfigPath, backupNugetConfig, true);
}
else
{
File.WriteAllText(nugetConfigPath,
"""
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
</packageSources>
</configuration>
""");
}
AddDefaultPackageSource(nugetConfigPath);
}
catch (Exception e)
{
logger.LogError($"Failed to add default package source to {nugetConfigPath}: {e}");
}
}
}
}
/// <summary>
/// Tries to find the location of `nuget.exe`. It looks for
/// - the environment variable specifying a location,
/// - files in the repository,
/// - tries to resolve nuget from the PATH, or
/// - downloads it if it is not found.
/// </summary>
private string ResolveNugetExe()
{
var envVarPath = Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetExePath);
if (!string.IsNullOrEmpty(envVarPath))
{
logger.LogInfo($"Using nuget.exe from environment variable: '{envVarPath}'");
return envVarPath;
}
try
{
return DownloadNugetExe(fileProvider.SourceDir.FullName);
}
catch (Exception exc)
{
logger.LogInfo($"Download of nuget.exe failed: {exc.Message}");
}
var nugetExesInRepo = fileProvider.NugetExes;
if (nugetExesInRepo.Count > 1)
{
logger.LogInfo($"Found multiple nuget.exe files in the repository: {string.Join(", ", nugetExesInRepo.OrderBy(s => s))}");
}
if (nugetExesInRepo.Count > 0)
{
var path = nugetExesInRepo.First();
logger.LogInfo($"Using nuget.exe from path '{path}'");
return path;
}
var executableName = Win32.IsWindows() ? "nuget.exe" : "nuget";
var nugetPath = FileUtils.FindProgramOnPath(executableName);
if (nugetPath is not null)
{
nugetPath = Path.Combine(nugetPath, executableName);
logger.LogInfo($"Using nuget.exe from PATH: {nugetPath}");
return nugetPath;
}
throw new Exception("Could not find or download nuget.exe.");
}
private string DownloadNugetExe(string sourceDir)
{
var directory = Path.Combine(sourceDir, ".nuget");
var nuget = Path.Combine(directory, "nuget.exe");
// Nuget.exe already exists in the .nuget directory.
if (File.Exists(nuget))
{
logger.LogInfo($"Found nuget.exe at {nuget}");
return nuget;
}
Directory.CreateDirectory(directory);
logger.LogInfo("Attempting to download nuget.exe");
FileUtils.DownloadFile(FileUtils.NugetExeUrl, nuget, logger);
logger.LogInfo($"Downloaded nuget.exe to {nuget}");
return nuget;
}
private bool RunWithMono => !Win32.IsWindows() && !string.IsNullOrEmpty(Path.GetExtension(nugetExe));
/// <summary>
/// Restore all packages in the specified packages.config file.
/// </summary>
/// <param name="packagesConfig">The packages.config file.</param>
private bool TryRestoreNugetPackage(string packagesConfig)
{
logger.LogInfo($"Restoring file \"{packagesConfig}\"...");
/* Use nuget.exe to install a package.
* Note that there is a clutch of NuGet assemblies which could be used to
* invoke this directly, which would arguably be nicer. However they are
* really unwieldy and this solution works for now.
*/
string exe, args;
if (RunWithMono)
{
exe = "mono";
args = $"\"{nugetExe}\" install -OutputDirectory \"{packageDirectory}\" \"{packagesConfig}\"";
}
else
{
exe = nugetExe!;
args = $"install -OutputDirectory \"{packageDirectory}\" \"{packagesConfig}\"";
}
var pi = new ProcessStartInfo(exe, args)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
var threadId = Environment.CurrentManagedThreadId;
void onOut(string s) => logger.LogDebug(s, threadId);
void onError(string s) => logger.LogError(s, threadId);
var exitCode = pi.ReadOutput(out _, onOut, onError);
if (exitCode != 0)
{
logger.LogError($"Command {pi.FileName} {pi.Arguments} failed with exit code {exitCode}");
return false;
}
else
{
logger.LogInfo($"Restored file \"{packagesConfig}\"");
return true;
}
}
/// <summary>
/// Download the packages to the temp folder.
/// </summary>
public int InstallPackages()
{
return fileProvider.PackagesConfigs.Count(TryRestoreNugetPackage);
}
private bool HasNoPackageSource()
{
if (Win32.IsWindows())
{
return false;
}
try
{
logger.LogInfo("Checking if default package source is available...");
RunMonoNugetCommand("sources list -ForceEnglishOutput", out var stdout);
if (stdout.All(line => line != "No sources found."))
{
return false;
}
return true;
}
catch (Exception e)
{
logger.LogWarning($"Failed to check if default package source is added: {e}");
return false;
}
}
private void RunMonoNugetCommand(string command, out IList<string> stdout)
{
string exe, args;
if (RunWithMono)
{
exe = "mono";
args = $"\"{nugetExe}\" {command}";
}
else
{
exe = nugetExe!;
args = command;
}
var pi = new ProcessStartInfo(exe, args)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
var threadId = Environment.CurrentManagedThreadId;
void onOut(string s) => logger.LogDebug(s, threadId);
void onError(string s) => logger.LogError(s, threadId);
pi.ReadOutput(out stdout, onOut, onError);
}
private void AddDefaultPackageSource(string nugetConfig)
{
logger.LogInfo("Adding default package source...");
RunMonoNugetCommand($"sources add -Name DefaultNugetOrg -Source {NugetPackageRestorer.PublicNugetOrgFeed} -ConfigFile \"{nugetConfig}\"", out _);
}
public void Dispose()
{
if (nugetConfigPath is null)
{
return;
}
try
{
if (backupNugetConfig is null)
{
logger.LogInfo("Removing nuget.config file");
File.Delete(nugetConfigPath);
return;
}
logger.LogInfo("Reverting nuget.config file content");
// The content of the original nuget.config file is reverted without changing the file's attributes or casing:
using (var backup = File.OpenRead(backupNugetConfig))
using (var current = File.OpenWrite(nugetConfigPath))
{
current.SetLength(0); // Truncate file
backup.CopyTo(current); // Restore original content
}
logger.LogInfo("Deleting backup nuget.config file");
File.Delete(backupNugetConfig);
}
catch (Exception exc)
{
logger.LogError($"Failed to restore original nuget.config file: {exc}");
}
}
}
}

View File

@@ -161,13 +161,13 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
reachableFeeds.UnionWith(reachableInheritedFeeds); reachableFeeds.UnionWith(reachableInheritedFeeds);
} }
using (var packagesConfigRestore = PackagesConfigRestoreFactory.Create(fileProvider, legacyPackageDirectory, logger, IsDefaultFeedReachable)) using (var nuget = new NugetExeWrapper(fileProvider, legacyPackageDirectory, logger, IsDefaultFeedReachable))
{ {
var count = packagesConfigRestore.InstallPackages(); var count = nuget.InstallPackages();
if (packagesConfigRestore.PackageCount > 0) if (nuget.PackageCount > 0)
{ {
compilationInfoContainer.CompilationInfos.Add(("packages.config files", packagesConfigRestore.PackageCount.ToString())); compilationInfoContainer.CompilationInfos.Add(("packages.config files", nuget.PackageCount.ToString()));
compilationInfoContainer.CompilationInfos.Add(("Successfully restored packages.config files", count.ToString())); compilationInfoContainer.CompilationInfos.Add(("Successfully restored packages.config files", count.ToString()));
} }
} }
@@ -209,7 +209,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
var paths = dependencies var paths = dependencies
.Paths .Paths
.Select(d => Path.Join(PackageDirectory.DirInfo.FullName, d)) .Select(d => Path.Combine(PackageDirectory.DirInfo.FullName, d))
.ToList(); .ToList();
assemblyLookupLocations.UnionWith(paths.Select(p => new AssemblyLookupLocation(p))); assemblyLookupLocations.UnionWith(paths.Select(p => new AssemblyLookupLocation(p)));
@@ -527,7 +527,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
var sb = new StringBuilder(); var sb = new StringBuilder();
fallbackNugetFeeds.ForEach((feed, index) => sb.AppendLine($"<add key=\"feed{index}\" value=\"{feed}\" />")); fallbackNugetFeeds.ForEach((feed, index) => sb.AppendLine($"<add key=\"feed{index}\" value=\"{feed}\" />"));
var nugetConfigPath = Path.Join(folderPath, "nuget.config"); var nugetConfigPath = Path.Combine(folderPath, "nuget.config");
logger.LogInfo($"Creating fallback nuget.config file {nugetConfigPath}."); logger.LogInfo($"Creating fallback nuget.config file {nugetConfigPath}.");
File.WriteAllText(nugetConfigPath, File.WriteAllText(nugetConfigPath,
$""" $"""
@@ -1052,7 +1052,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// </summary> /// </summary>
private static string ComputeTempDirectoryPath(string subfolderName) private static string ComputeTempDirectoryPath(string subfolderName)
{ {
return Path.Join(FileUtils.GetTemporaryWorkingDirectory(out _), subfolderName); return Path.Combine(FileUtils.GetTemporaryWorkingDirectory(out _), subfolderName);
} }
/// <summary> /// <summary>
@@ -1060,7 +1060,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// </summary> /// </summary>
private static string ComputeTempDirectoryPath(string srcDir, string subfolderName) private static string ComputeTempDirectoryPath(string srcDir, string subfolderName)
{ {
return Path.Join(FileUtils.GetTemporaryWorkingDirectory(out _), FileUtils.ComputeHash(srcDir), subfolderName); return Path.Combine(FileUtils.GetTemporaryWorkingDirectory(out _), FileUtils.ComputeHash(srcDir), subfolderName);
} }
} }
} }

View File

@@ -1,368 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Semmle.Util;
namespace Semmle.Extraction.CSharp.DependencyFetching
{
internal interface IPackagesConfigRestore : IDisposable
{
/// <summary>
/// The number of packages.config files found in the source tree.
/// </summary>
int PackageCount { get; }
/// <summary>
/// Download the packages to the temp folder.
/// </summary>
int InstallPackages();
}
/// <summary>
/// Factory for creating a package manager to restore NuGet packages referenced in packages.config files.
/// If the environment doesn't support using nuget.exe to restore packages from packages.config files, a no-op implementation is returned.
/// It is worth noting that for macOS and Linux, nuget.exe is used with mono. However, mono is being deprecated and the last GitHub images
/// to contain mono are:
/// - Ubuntu 22.04
/// - macOS 14
///
/// If the packages from the packages.config files are not restored with the packages.config restore functionality below, there is a subsequent
/// step that still may succeed in restoring the packages without the help of nuget.exe (by attempting to restore using dotnet).
/// </summary>
internal class PackagesConfigRestoreFactory
{
public static IPackagesConfigRestore Create(FileProvider fileProvider, DependencyDirectory packageDirectory, Semmle.Util.Logging.ILogger logger, Func<bool> useDefaultFeed)
{
if (SystemBuildActions.Instance.IsWindows() || SystemBuildActions.Instance.IsMonoInstalled())
{
return new NugetExeWrapper(fileProvider, packageDirectory, logger, useDefaultFeed);
}
return new NoOpPackagesConfig(fileProvider, logger);
}
/// <summary>
/// Manage the downloading of NuGet packages with nuget.exe.
/// Locates packages in a source tree and downloads all of the
/// referenced assemblies to a temp folder.
/// </summary>
private class NugetExeWrapper : IPackagesConfigRestore
{
private readonly string? nugetExe;
private readonly Semmle.Util.Logging.ILogger logger;
public int PackageCount => fileProvider.PackagesConfigs.Count;
private readonly string? backupNugetConfig;
private readonly string? nugetConfigPath;
private readonly FileProvider fileProvider;
/// <summary>
/// The packages directory.
/// This will be in the user-specified or computed Temp location
/// so as to not trample the source tree.
/// </summary>
private readonly DependencyDirectory packageDirectory;
private bool IsWindows => SystemBuildActions.Instance.IsWindows();
/// <summary>
/// Create the package manager for a specified source tree.
/// </summary>
public NugetExeWrapper(FileProvider fileProvider, DependencyDirectory packageDirectory, Semmle.Util.Logging.ILogger logger, Func<bool> useDefaultFeed)
{
this.fileProvider = fileProvider;
this.packageDirectory = packageDirectory;
this.logger = logger;
if (fileProvider.PackagesConfigs.Count > 0)
{
logger.LogInfo($"Found packages.config files, trying to use nuget.exe for package restore");
nugetExe = ResolveNugetExe();
if (!HasPackageSource() && useDefaultFeed())
{
// We only modify or add a top level nuget.config file
nugetConfigPath = Path.Join(fileProvider.SourceDir.FullName, "nuget.config");
try
{
if (File.Exists(nugetConfigPath))
{
var tempFolderPath = FileUtils.GetTemporaryWorkingDirectory(out _);
do
{
backupNugetConfig = Path.Join(tempFolderPath, Path.GetRandomFileName());
}
while (File.Exists(backupNugetConfig));
File.Copy(nugetConfigPath, backupNugetConfig, true);
}
else
{
File.WriteAllText(nugetConfigPath,
"""
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
</packageSources>
</configuration>
""");
}
AddDefaultPackageSource(nugetConfigPath);
}
catch (Exception e)
{
logger.LogError($"Failed to add default package source to {nugetConfigPath}: {e}");
}
}
}
}
/// <summary>
/// Tries to find the location of `nuget.exe`. It looks for
/// - the environment variable specifying a location,
/// - files in the repository,
/// - tries to resolve nuget from the PATH, or
/// - downloads it if it is not found.
/// </summary>
private string ResolveNugetExe()
{
var envVarPath = Environment.GetEnvironmentVariable(EnvironmentVariableNames.NugetExePath);
if (!string.IsNullOrEmpty(envVarPath))
{
logger.LogInfo($"Using nuget.exe from environment variable: '{envVarPath}'");
return envVarPath;
}
try
{
return DownloadNugetExe(fileProvider.SourceDir.FullName);
}
catch (Exception exc)
{
logger.LogInfo($"Download of nuget.exe failed: {exc.Message}");
}
var nugetExesInRepo = fileProvider.NugetExes;
if (nugetExesInRepo.Count > 1)
{
logger.LogInfo($"Found multiple nuget.exe files in the repository: {string.Join(", ", nugetExesInRepo.OrderBy(s => s))}");
}
if (nugetExesInRepo.Count > 0)
{
var path = nugetExesInRepo.First();
logger.LogInfo($"Using nuget.exe from path '{path}'");
return path;
}
var executableName = IsWindows ? "nuget.exe" : "nuget";
var nugetPath = FileUtils.FindProgramOnPath(executableName);
if (nugetPath is not null)
{
nugetPath = Path.Join(nugetPath, executableName);
logger.LogInfo($"Using nuget.exe from PATH: {nugetPath}");
return nugetPath;
}
throw new Exception("Could not find or download nuget.exe.");
}
private string DownloadNugetExe(string sourceDir)
{
var directory = Path.Join(sourceDir, ".nuget");
var nuget = Path.Join(directory, "nuget.exe");
// Nuget.exe already exists in the .nuget directory.
if (File.Exists(nuget))
{
logger.LogInfo($"Found nuget.exe at {nuget}");
return nuget;
}
Directory.CreateDirectory(directory);
logger.LogInfo("Attempting to download nuget.exe");
FileUtils.DownloadFile(FileUtils.NugetExeUrl, nuget, logger);
logger.LogInfo($"Downloaded nuget.exe to {nuget}");
return nuget;
}
private bool RunWithMono => !IsWindows && !string.IsNullOrEmpty(Path.GetExtension(nugetExe));
/// <summary>
/// Restore all packages in the specified packages.config file.
/// </summary>
/// <param name="packagesConfig">The packages.config file.</param>
private bool TryRestoreNugetPackage(string packagesConfig)
{
logger.LogInfo($"Restoring file \"{packagesConfig}\"...");
/* Use nuget.exe to install a package.
* Note that there is a clutch of NuGet assemblies which could be used to
* invoke this directly, which would arguably be nicer. However they are
* really unwieldy and this solution works for now.
*/
string exe, args;
if (RunWithMono)
{
exe = "mono";
args = $"\"{nugetExe}\" install -OutputDirectory \"{packageDirectory}\" \"{packagesConfig}\"";
}
else
{
exe = nugetExe!;
args = $"install -OutputDirectory \"{packageDirectory}\" \"{packagesConfig}\"";
}
var pi = new ProcessStartInfo(exe, args)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
var threadId = Environment.CurrentManagedThreadId;
void onOut(string s) => logger.LogDebug(s, threadId);
void onError(string s) => logger.LogError(s, threadId);
var exitCode = pi.ReadOutput(out _, onOut, onError);
if (exitCode != 0)
{
logger.LogError($"Command {pi.FileName} {pi.Arguments} failed with exit code {exitCode}");
return false;
}
else
{
logger.LogInfo($"Restored file \"{packagesConfig}\"");
return true;
}
}
/// <summary>
/// Download the packages to the temp folder.
/// </summary>
public int InstallPackages()
{
return fileProvider.PackagesConfigs.Count(TryRestoreNugetPackage);
}
private bool HasPackageSource()
{
if (IsWindows)
{
return true;
}
try
{
logger.LogInfo("Checking if default package source is available...");
RunMonoNugetCommand("sources list -ForceEnglishOutput", out var stdout);
if (stdout.All(line => line != "No sources found."))
{
return true;
}
return false;
}
catch (Exception e)
{
logger.LogWarning($"Failed to check if default package source is added: {e}");
return true;
}
}
private void RunMonoNugetCommand(string command, out IList<string> stdout)
{
string exe, args;
if (RunWithMono)
{
exe = "mono";
args = $"\"{nugetExe}\" {command}";
}
else
{
exe = nugetExe!;
args = command;
}
var pi = new ProcessStartInfo(exe, args)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
var threadId = Environment.CurrentManagedThreadId;
void onOut(string s) => logger.LogDebug(s, threadId);
void onError(string s) => logger.LogError(s, threadId);
pi.ReadOutput(out stdout, onOut, onError);
}
private void AddDefaultPackageSource(string nugetConfig)
{
logger.LogInfo("Adding default package source...");
RunMonoNugetCommand($"sources add -Name DefaultNugetOrg -Source {NugetPackageRestorer.PublicNugetOrgFeed} -ConfigFile \"{nugetConfig}\"", out _);
}
public void Dispose()
{
if (nugetConfigPath is null)
{
return;
}
try
{
if (backupNugetConfig is null)
{
logger.LogInfo("Removing nuget.config file");
File.Delete(nugetConfigPath);
return;
}
logger.LogInfo("Reverting nuget.config file content");
// The content of the original nuget.config file is reverted without changing the file's attributes or casing:
using (var backup = File.OpenRead(backupNugetConfig))
using (var current = File.OpenWrite(nugetConfigPath))
{
current.SetLength(0); // Truncate file
backup.CopyTo(current); // Restore original content
}
logger.LogInfo("Deleting backup nuget.config file");
File.Delete(backupNugetConfig);
}
catch (Exception exc)
{
logger.LogError($"Failed to restore original nuget.config file: {exc}");
}
}
}
private class NoOpPackagesConfig : IPackagesConfigRestore
{
private readonly Semmle.Util.Logging.ILogger logger;
private readonly FileProvider fileProvider;
public NoOpPackagesConfig(FileProvider fileProvider, Semmle.Util.Logging.ILogger logger)
{
this.fileProvider = fileProvider;
this.logger = logger;
}
public int PackageCount => fileProvider.PackagesConfigs.Count;
public int InstallPackages()
{
if (PackageCount > 0)
{
logger.LogInfo("Found packages.config files, but nuget.exe cannot be used to restore packages on this platform. Skipping restore of packages.config files.");
}
return 0;
}
public void Dispose() { }
}
}
}

View File

@@ -79,7 +79,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
var monoPath = FileUtils.FindProgramOnPath(Win32.IsWindows() ? "mono.exe" : "mono"); var monoPath = FileUtils.FindProgramOnPath(Win32.IsWindows() ? "mono.exe" : "mono");
string[] monoDirs = monoPath is not null string[] monoDirs = monoPath is not null
? [Path.GetFullPath(Path.Join(monoPath, "..", "lib", "mono")), monoPath] ? [Path.GetFullPath(Path.Combine(monoPath, "..", "lib", "mono")), monoPath]
: ["/usr/lib/mono", "/usr/local/mono", "/usr/local/bin/mono", @"C:\Program Files\Mono\lib\mono"]; : ["/usr/lib/mono", "/usr/local/mono", "/usr/local/bin/mono", @"C:\Program Files\Mono\lib\mono"];
var monoDir = monoDirs.FirstOrDefault(Directory.Exists); var monoDir = monoDirs.FirstOrDefault(Directory.Exists);

View File

@@ -63,7 +63,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
return null; return null;
} }
var path = Path.Join(version.FullPath, "Roslyn", "bincore", "csc.dll"); var path = Path.Combine(version.FullPath, "Roslyn", "bincore", "csc.dll");
logger.LogDebug($"Source generator CSC: '{path}'"); logger.LogDebug($"Source generator CSC: '{path}'");
if (!File.Exists(path)) if (!File.Exists(path))
{ {

View File

@@ -41,10 +41,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
.Replace('\\', '/'); // Ensure we're generating the same hash regardless of the OS .Replace('\\', '/'); // Ensure we're generating the same hash regardless of the OS
var name = FileUtils.ComputeHash($"{relativePathToCsProj}\n{this.GetType().Name}"); var name = FileUtils.ComputeHash($"{relativePathToCsProj}\n{this.GetType().Name}");
using var tempDir = new TemporaryDirectory(Path.Join(FileUtils.GetTemporaryWorkingDirectory(out _), "source-generator"), "source generator temporary", logger); using var tempDir = new TemporaryDirectory(Path.Join(FileUtils.GetTemporaryWorkingDirectory(out _), "source-generator"), "source generator temporary", logger);
var analyzerConfigPath = Path.Join(tempDir.DirInfo.FullName, $"{name}.txt"); var analyzerConfigPath = Path.Combine(tempDir.DirInfo.FullName, $"{name}.txt");
var dllPath = Path.Join(tempDir.DirInfo.FullName, $"{name}.dll"); var dllPath = Path.Combine(tempDir.DirInfo.FullName, $"{name}.dll");
var cscArgsPath = Path.Join(tempDir.DirInfo.FullName, $"{name}.rsp"); var cscArgsPath = Path.Combine(tempDir.DirInfo.FullName, $"{name}.rsp");
var outputFolder = Path.Join(targetDir, name); var outputFolder = Path.Combine(targetDir, name);
Directory.CreateDirectory(outputFolder); Directory.CreateDirectory(outputFolder);
logger.LogInfo("Producing analyzer config content."); logger.LogInfo("Producing analyzer config content.");
GenerateAnalyzerConfig(additionalFiles, csprojFile, analyzerConfigPath); GenerateAnalyzerConfig(additionalFiles, csprojFile, analyzerConfigPath);

View File

@@ -21,7 +21,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
throw new Exception("No SDK path available."); throw new Exception("No SDK path available.");
} }
SourceGeneratorFolder = Path.Join(sdkPath, "Sdks", "Microsoft.NET.Sdk.Razor", "source-generators"); SourceGeneratorFolder = Path.Combine(sdkPath, "Sdks", "Microsoft.NET.Sdk.Razor", "source-generators");
this.logger.LogInfo($"Razor source generator folder: {SourceGeneratorFolder}"); this.logger.LogInfo($"Razor source generator folder: {SourceGeneratorFolder}");
if (!Directory.Exists(SourceGeneratorFolder)) if (!Directory.Exists(SourceGeneratorFolder))
{ {

View File

@@ -50,7 +50,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
if (usings.Count > 0) if (usings.Count > 0)
{ {
var tempDir = GetTemporaryWorkingDirectory("implicitUsings"); var tempDir = GetTemporaryWorkingDirectory("implicitUsings");
var path = Path.Join(tempDir, "GlobalUsings.g.cs"); var path = Path.Combine(tempDir, "GlobalUsings.g.cs");
using (var writer = new StreamWriter(path)) using (var writer = new StreamWriter(path))
{ {
writer.WriteLine("// <auto-generated/>"); writer.WriteLine("// <auto-generated/>");

View File

@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
var nugetFolder = nugetPackageRestorer.TryRestore("Microsoft.CodeAnalysis.ResxSourceGenerator"); var nugetFolder = nugetPackageRestorer.TryRestore("Microsoft.CodeAnalysis.ResxSourceGenerator");
if (nugetFolder is not null) if (nugetFolder is not null)
{ {
sourceGeneratorFolder = System.IO.Path.Join(nugetFolder, "analyzers", "dotnet", "cs"); sourceGeneratorFolder = System.IO.Path.Combine(nugetFolder, "analyzers", "dotnet", "cs");
} }
} }
catch (Exception e) catch (Exception e)

View File

@@ -35,7 +35,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
/// </summary> /// </summary>
protected string GetTemporaryWorkingDirectory(string subfolder) protected string GetTemporaryWorkingDirectory(string subfolder)
{ {
var temp = Path.Join(tempWorkingDirectory.ToString(), subfolder); var temp = Path.Combine(tempWorkingDirectory.ToString(), subfolder);
Directory.CreateDirectory(temp); Directory.CreateDirectory(temp);
return temp; return temp;

View File

@@ -1,6 +1,5 @@
using System.IO; using System.IO;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.Kinds; using Semmle.Extraction.Kinds;
@@ -9,7 +8,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
internal abstract class ElementAccess : Expression<ExpressionSyntax> internal abstract class ElementAccess : Expression<ExpressionSyntax>
{ {
protected ElementAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, BracketedArgumentListSyntax argumentList) protected ElementAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, BracketedArgumentListSyntax argumentList)
: base(info.SetKind(GetKind(info.Context, info.Node, qualifier))) : base(info.SetKind(GetKind(info.Context, qualifier)))
{ {
this.qualifier = qualifier; this.qualifier = qualifier;
this.argumentList = argumentList; this.argumentList = argumentList;
@@ -18,125 +17,6 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
private readonly ExpressionSyntax qualifier; private readonly ExpressionSyntax qualifier;
private readonly BracketedArgumentListSyntax argumentList; private readonly BracketedArgumentListSyntax argumentList;
private ISymbol? GetTargetSymbol()
{
return Context.GetSymbolInfo(base.Syntax).Symbol;
}
private static void SetExprArgument(TextWriter trapFile, Expression left, Expression right)
{
trapFile.expr_argument(left, 0);
trapFile.expr_argument(right, 0);
}
private Expression MakeZeroFromEndExpression(IExpressionParentEntity parent, int child)
{
var info = new ExpressionInfo(
Context,
AnnotatedTypeSymbol.CreateNotAnnotated(Context.Compilation.GetSpecialType(SpecialType.System_Int32)),
Location,
ExprKind.INDEX,
parent,
child,
isCompilerGenerated: true,
null);
var index = new Expression(info);
MakeZeroLiteral(index, 0);
return index;
}
private Expression MakeZeroLiteral(IExpressionParentEntity parent, int child)
{
return Literal.CreateGenerated(Context, parent, child, Context.Compilation.GetSpecialType(SpecialType.System_Int32), 0, Location);
}
/// <summary>
/// It is assumed that either the input is
/// 1. A normal expression that can be used as endpoint (e.g a constant like "3").
/// 2. An index expression indicating that we should read from the end (e.g "^1").
/// </summary>
/// <param name="syntax">The syntax node representing the range endpoint.</param>
/// <param name="parent">The parent expression entity.</param>
/// <param name="child">The child index within the parent.</param>
/// <returns>An expression representing the endpoint of a range to be used in conjunction with a slice operation.</returns>
private Expression MakeFromRangeEndpoint(ExpressionSyntax syntax, IExpressionParentEntity parent, int child)
{
var info = new ExpressionNodeInfo(Context, syntax, parent, child);
return syntax.Kind() == SyntaxKind.IndexExpression
? PrefixUnary.Create(info.SetKind(ExprKind.INDEX))
: Factory.Create(info);
}
/// <summary>
/// Determines whether the given method is a slice method, which is defined as a method with
/// the name "Slice" or "Substring" and two parameters.
/// </summary>
/// <param name="method">The method symbol to check.</param>
/// <returns>True if the method is a slice method; false otherwise.</returns>
private bool IsSlice(IMethodSymbol method, out RangeExpressionSyntax? range)
{
range = null;
if (argumentList.Arguments.Count == 1)
{
range = argumentList.Arguments[0].Expression as RangeExpressionSyntax;
}
return (method.Name == "Slice" || method.Name == "Substring")
&& method.Parameters.Length == 2;
}
/// <summary>
/// Populates a slice method call based on the given range.
/// Roslyn translates indexer accesses with range expressions in the following way.
/// 1. s[a..b] -> s.Slice(a, b - a)
/// 2. s[..b] -> s.Slice(0, b)
/// 3. s[a..] -> s.Slice(a, s.Length - a)
/// 4. s[..] -> s.Slice(0, s.Length)
/// However, it is possible that both the qualifier or the index endpoints may contain method calls.
/// If we want to translate this accurately, we would need to introduce synthetic statements for qualifier and
/// the endpoints, which should then be used in the slice method call.
/// To avoid this, we translate as follows.
/// 1. s[a..b] -> s.Slice(a, b)
/// 2. s[..b] -> s.Slice(0, b)
/// 3. s[a..] -> s.Slice(a, ^0)
/// 4. s[..] -> s.Slice(0, ^0)
///
/// Even though index expressions can't technically be used in this way, they signal that we
/// could perceive ^b as "length - b".
///
/// Call arguments are only populated when a range expression is directly available in
/// the list of arguments.
/// This means that cases like below are not handled.
/// System.Range x = 1..3;
/// s[x]
/// </summary>
/// <param name="trapFile">The trap file to write to.</param>
/// <param name="slice">The slice method symbol.</param>
/// <param name="range">The range expression syntax.</param>
private void PopulateSlice(TextWriter trapFile, IMethodSymbol slice, RangeExpressionSyntax? range)
{
if (range is not null)
{
// Populate the call arguments
var left = range.LeftOperand is ExpressionSyntax lsyntax
? MakeFromRangeEndpoint(lsyntax, this, 0)
: MakeZeroLiteral(this, 0);
var right = range.RightOperand is ExpressionSyntax rsyntax
? MakeFromRangeEndpoint(rsyntax, this, 1)
: MakeZeroFromEndExpression(this, 1);
SetExprArgument(trapFile, left, right);
}
trapFile.expr_call(this, Method.Create(Context, slice));
}
protected override void PopulateExpression(TextWriter trapFile) protected override void PopulateExpression(TextWriter trapFile)
{ {
if (Kind == ExprKind.POINTER_INDIRECTION) if (Kind == ExprKind.POINTER_INDIRECTION)
@@ -150,19 +30,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
else else
{ {
Create(Context, qualifier, this, -1); Create(Context, qualifier, this, -1);
var target = GetTargetSymbol();
if (target is IMethodSymbol method && IsSlice(method, out var range))
{
// When an indexer on a span or string is used in conjunction with a range expression, the compiler translates
// this into a call to the "Slice" or "Substring" method.
// In this case, we want to populate a slice/substring method call instead of an indexer access.
PopulateSlice(trapFile, method, range);
return;
}
PopulateArguments(trapFile, argumentList, 0); PopulateArguments(trapFile, argumentList, 0);
if (target is IPropertySymbol { IsIndexer: true } indexer)
var symbolInfo = Context.GetSymbolInfo(base.Syntax);
if (symbolInfo.Symbol is IPropertySymbol indexer)
{ {
trapFile.expr_access(this, Indexer.Create(Context, indexer)); trapFile.expr_access(this, Indexer.Create(Context, indexer));
} }
@@ -174,11 +46,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
private static bool IsArray(ITypeSymbol symbol) => private static bool IsArray(ITypeSymbol symbol) =>
symbol.TypeKind == Microsoft.CodeAnalysis.TypeKind.Array || symbol.IsInlineArray(); symbol.TypeKind == Microsoft.CodeAnalysis.TypeKind.Array || symbol.IsInlineArray();
private static ExprKind GetKind(Context cx, ExpressionSyntax syntax, ExpressionSyntax qualifier) private static ExprKind GetKind(Context cx, ExpressionSyntax qualifier)
{ {
if (cx.GetSymbolInfo(syntax).Symbol is IMethodSymbol)
return ExprKind.METHOD_INVOCATION;
var qualifierType = cx.GetType(qualifier); var qualifierType = cx.GetType(qualifier);
// This is a compilation error, so make a guess and continue. // This is a compilation error, so make a guess and continue.

View File

@@ -23,9 +23,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
} }
else if (isSpecificCatchClause) // A catch clause of the form 'catch(Ex) { ... }' else if (isSpecificCatchClause) // A catch clause of the form 'catch(Ex) { ... }'
{ {
var type = Type.Create(Context, Context.GetType(Stmt.Declaration!.Type)); trapFile.catch_type(this, Type.Create(Context, Context.GetType(Stmt.Declaration!.Type)).TypeRef, true);
trapFile.catch_type(this, type.TypeRef, true);
TypeMention.Create(Context, Stmt.Declaration!.Type, this, type);
} }
else // A catch clause of the form 'catch { ... }' else // A catch clause of the form 'catch { ... }'
{ {

View File

@@ -67,7 +67,7 @@ namespace Semmle.Extraction.CSharp
return; return;
} }
var mscorlibExists = File.Exists(Path.Join(compilerDir, "mscorlib.dll")); var mscorlibExists = File.Exists(Path.Combine(compilerDir, "mscorlib.dll"));
if (specifiedFramework is null && mscorlibExists) if (specifiedFramework is null && mscorlibExists)
{ {
@@ -107,7 +107,7 @@ namespace Semmle.Extraction.CSharp
/// <summary> /// <summary>
/// The file csc.rsp. /// The file csc.rsp.
/// </summary> /// </summary>
private string CscRsp => Path.Join(FrameworkPath, csc_rsp); private string CscRsp => Path.Combine(FrameworkPath, csc_rsp);
/// <summary> /// <summary>
/// Should we skip extraction? /// Should we skip extraction?

View File

@@ -680,7 +680,7 @@ namespace Semmle.Extraction.CSharp
{ {
try try
{ {
var fullPath = Path.GetFullPath(Path.Join(Path.GetDirectoryName(mappedFromPath)!, mappedToPath)); var fullPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(mappedFromPath)!, mappedToPath));
ExtractionContext.Logger.LogDebug($"Found relative path in line mapping: '{mappedToPath}', interpreting it as '{fullPath}'"); ExtractionContext.Logger.LogDebug($"Found relative path in line mapping: '{mappedToPath}', interpreting it as '{fullPath}'");
mappedToPath = fullPath; mappedToPath = fullPath;

View File

@@ -159,11 +159,7 @@ namespace Semmle.Extraction.CSharp
return null; return null;
} }
var normalized = Path.DirectorySeparatorChar == '/' ? file.Replace("\\", "/") : file; return Path.GetFullPath(Path.Combine(projDir?.FullName ?? string.Empty, Path.DirectorySeparatorChar == '/' ? file.Replace("\\", "/") : file));
var path = projDir is not null && !Path.IsPathRooted(normalized)
? Path.Join(projDir.FullName, normalized)
: normalized;
return Path.GetFullPath(path);
} }
private readonly string[] references; private readonly string[] references;

View File

@@ -210,7 +210,7 @@ namespace Semmle.Extraction.CSharp
TracingAnalyser.GetOutputName(compilation, args), TracingAnalyser.GetOutputName(compilation, args),
compilation, compilation,
generatedSyntaxTrees, generatedSyntaxTrees,
Path.Join(compilationIdentifierPath, diagnosticName), Path.Combine(compilationIdentifierPath, diagnosticName),
options), options),
() => { }); () => { });
@@ -377,7 +377,7 @@ namespace Semmle.Extraction.CSharp
else else
{ {
var composed = referencePaths.Value var composed = referencePaths.Value
.Select(path => Path.Join(path, clref.Reference)) .Select(path => Path.Combine(path, clref.Reference))
.Where(path => File.Exists(path)) .Where(path => File.Exists(path))
.Select(path => analyser.PathCache.GetCanonicalPath(path)) .Select(path => analyser.PathCache.GetCanonicalPath(path))
.FirstOrDefault(); .FirstOrDefault();
@@ -559,13 +559,13 @@ namespace Semmle.Extraction.CSharp
/// Gets the path to the `csharp.log` file written to by the C# extractor. /// Gets the path to the `csharp.log` file written to by the C# extractor.
/// </summary> /// </summary>
public static string GetCSharpLogPath() => public static string GetCSharpLogPath() =>
Path.Join(GetCSharpLogDirectory(), "csharp.log"); Path.Combine(GetCSharpLogDirectory(), "csharp.log");
/// <summary> /// <summary>
/// Gets the path to a `csharp.{hash}.txt` file written to by the C# extractor. /// Gets the path to a `csharp.{hash}.txt` file written to by the C# extractor.
/// </summary> /// </summary>
public static string GetCSharpArgsLogPath(string hash) => public static string GetCSharpArgsLogPath(string hash) =>
Path.Join(GetCSharpLogDirectory(), $"csharp.{hash}.txt"); Path.Combine(GetCSharpLogDirectory(), $"csharp.{hash}.txt");
/// <summary> /// <summary>
/// Gets a list of all `csharp.{hash}.txt` files currently written to the log directory. /// Gets a list of all `csharp.{hash}.txt` files currently written to the log directory.

View File

@@ -131,7 +131,7 @@ namespace Semmle.Extraction.CSharp
return Path.ChangeExtension(entryPointFilename, ".exe"); return Path.ChangeExtension(entryPointFilename, ".exe");
} }
return Path.Join(commandLineArguments.OutputDirectory, commandLineArguments.OutputFileName); return Path.Combine(commandLineArguments.OutputDirectory, commandLineArguments.OutputFileName);
} }
private int LogDiagnostics() private int LogDiagnostics()

View File

@@ -61,7 +61,7 @@ namespace Semmle.Extraction.CSharp
* Although GetRandomFileName() is cryptographically secure, * Although GetRandomFileName() is cryptographically secure,
* there's a tiny chance the file could already exists. * there's a tiny chance the file could already exists.
*/ */
tmpFile = Path.Join(tempPath, Path.GetRandomFileName()); tmpFile = Path.Combine(tempPath, Path.GetRandomFileName());
} }
while (File.Exists(tmpFile)); while (File.Exists(tmpFile));

View File

@@ -82,13 +82,13 @@ namespace SemmleTests.Semmle.Util
[Fact] [Fact]
public void CanonicalPathMissingFile() public void CanonicalPathMissingFile()
{ {
Assert.Equal(Path.Join(Directory.GetCurrentDirectory(), "NOSUCHFILE"), cache.GetCanonicalPath("NOSUCHFILE")); Assert.Equal(Path.Combine(Directory.GetCurrentDirectory(), "NOSUCHFILE"), cache.GetCanonicalPath("NOSUCHFILE"));
} }
[Fact] [Fact]
public void CanonicalPathMissingAbsolutePath() public void CanonicalPathMissingAbsolutePath()
{ {
Assert.Equal(Path.Join(root, "no", "such", "file"), cache.GetCanonicalPath(Path.Join(root, "no", "such", "file"))); Assert.Equal(Path.Combine(root, "no", "such", "file"), cache.GetCanonicalPath(Path.Combine(root, "no", "such", "file")));
if (Win32.IsWindows()) if (Win32.IsWindows())
Assert.Equal(@"C:\Windows\no\such\file", cache.GetCanonicalPath(@"C:\windOws\no\such\file")); Assert.Equal(@"C:\Windows\no\such\file", cache.GetCanonicalPath(@"C:\windOws\no\such\file"));
@@ -97,7 +97,7 @@ namespace SemmleTests.Semmle.Util
[Fact] [Fact]
public void CanonicalPathMissingRelativePath() public void CanonicalPathMissingRelativePath()
{ {
Assert.Equal(Path.Join(Directory.GetCurrentDirectory(), "NO", "SUCH"), cache.GetCanonicalPath(Path.Join("NO", "SUCH"))); Assert.Equal(Path.Combine(Directory.GetCurrentDirectory(), "NO", "SUCH"), cache.GetCanonicalPath(Path.Combine("NO", "SUCH")));
} }
[Fact] [Fact]
@@ -125,7 +125,7 @@ namespace SemmleTests.Semmle.Util
public void CanonicalPathDots() public void CanonicalPathDots()
{ {
var abcPath = Path.GetFullPath("abc"); var abcPath = Path.GetFullPath("abc");
Assert.Equal(abcPath, cache.GetCanonicalPath(Path.Join("foo", ".", "..", "abc"))); Assert.Equal(abcPath, cache.GetCanonicalPath(Path.Combine("foo", ".", "..", "abc")));
} }
[Fact] [Fact]

View File

@@ -14,20 +14,20 @@ namespace SemmleTests.Semmle.Util
public sealed class LongPaths public sealed class LongPaths
{ {
private static readonly string tmpDir = Environment.GetEnvironmentVariable("TEST_TMPDIR") ?? Path.GetTempPath(); private static readonly string tmpDir = Environment.GetEnvironmentVariable("TEST_TMPDIR") ?? Path.GetTempPath();
private static readonly string longPathDir = Path.Join(tmpDir, "aaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbb", private static readonly string longPathDir = Path.Combine(tmpDir, "aaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"ccccccccccccccccccccccccccccccc", "ddddddddddddddddddddddddddddddddddddd", "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "fffffffffffffffffffffffffffffffff", "ccccccccccccccccccccccccccccccc", "ddddddddddddddddddddddddddddddddddddd", "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "fffffffffffffffffffffffffffffffff",
"ggggggggggggggggggggggggggggggggggg", "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"); "ggggggggggggggggggggggggggggggggggg", "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh");
private static string MakeLongPath() private static string MakeLongPath()
{ {
var uniquePostfix = Guid.NewGuid().ToString("N"); var uniquePostfix = Guid.NewGuid().ToString("N");
return Path.Join(longPathDir, $"iiiiiiiiiiiiiiii{uniquePostfix}.txt"); return Path.Combine(longPathDir, $"iiiiiiiiiiiiiiii{uniquePostfix}.txt");
} }
private static string MakeShortPath() private static string MakeShortPath()
{ {
var uniquePostfix = Guid.NewGuid().ToString("N"); var uniquePostfix = Guid.NewGuid().ToString("N");
return Path.Join(tmpDir, $"test{uniquePostfix}.txt"); return Path.Combine(tmpDir, $"test{uniquePostfix}.txt");
} }
public LongPaths() public LongPaths()
@@ -62,7 +62,7 @@ namespace SemmleTests.Semmle.Util
[Fact] [Fact]
public void ParentDirectory() public void ParentDirectory()
{ {
Assert.Equal("abc", Path.GetDirectoryName(Path.Join("abc", "def"))); Assert.Equal("abc", Path.GetDirectoryName(Path.Combine("abc", "def")));
Assert.Equal(Win32.IsWindows() ? "\\" : "/", Path.GetDirectoryName($@"{Path.DirectorySeparatorChar}def")); Assert.Equal(Win32.IsWindows() ? "\\" : "/", Path.GetDirectoryName($@"{Path.DirectorySeparatorChar}def"));
Assert.Equal("", Path.GetDirectoryName(@"def")); Assert.Equal("", Path.GetDirectoryName(@"def"));

View File

@@ -137,11 +137,11 @@ namespace Semmle.Util
bool IsMonoInstalled(); bool IsMonoInstalled();
/// <summary> /// <summary>
/// Joins path segments, Path.Join(). /// Combine path segments, Path.Combine().
/// </summary> /// </summary>
/// <param name="parts">The parts of the path.</param> /// <param name="parts">The parts of the path.</param>
/// <returns>The combined path.</returns> /// <returns>The combined path.</returns>
string PathJoin(params string[] parts); string PathCombine(params string[] parts);
/// <summary> /// <summary>
/// Gets the full path for <paramref name="path"/>, Path.GetFullPath(). /// Gets the full path for <paramref name="path"/>, Path.GetFullPath().
@@ -293,7 +293,7 @@ namespace Semmle.Util
} }
} }
string IBuildActions.PathJoin(params string[] parts) => Path.Join(parts); string IBuildActions.PathCombine(params string[] parts) => Path.Combine(parts);
void IBuildActions.WriteAllText(string filename, string contents) => File.WriteAllText(filename, contents); void IBuildActions.WriteAllText(string filename, string contents) => File.WriteAllText(filename, contents);

View File

@@ -43,7 +43,7 @@ namespace Semmle.Util
var parent = Directory.GetParent(path); var parent = Directory.GetParent(path);
return parent is not null ? return parent is not null ?
Path.Join(cache.GetCanonicalPath(parent.FullName), Path.GetFileName(path)) : Path.Combine(cache.GetCanonicalPath(parent.FullName), Path.GetFileName(path)) :
path.ToUpperInvariant(); path.ToUpperInvariant();
} }
} }
@@ -138,12 +138,12 @@ namespace Semmle.Util
var entries = Directory.GetFileSystemEntries(parentPath, name); var entries = Directory.GetFileSystemEntries(parentPath, name);
return entries.Length == 1 return entries.Length == 1
? entries[0] ? entries[0]
: Path.Join(parentPath, name); : Path.Combine(parentPath, name);
} }
catch // lgtm[cs/catch-of-all-exceptions] catch // lgtm[cs/catch-of-all-exceptions]
{ {
// IO error or security error querying directory. // IO error or security error querying directory.
return Path.Join(parentPath, name); return Path.Combine(parentPath, name);
} }
} }
} }

View File

@@ -82,7 +82,7 @@ namespace Semmle.Util
{ {
exes = new[] { prog }; exes = new[] { prog };
} }
var candidates = paths?.Where(path => exes.Any(exe0 => File.Exists(Path.Join(path, exe0)))); var candidates = paths?.Where(path => exes.Any(exe0 => File.Exists(Path.Combine(path, exe0))));
return candidates?.FirstOrDefault(); return candidates?.FirstOrDefault();
} }
@@ -179,7 +179,7 @@ namespace Semmle.Util
{ {
innerpath = ConvertPathToSafeRelativePath(innerpath); innerpath = ConvertPathToSafeRelativePath(innerpath);
nested = Path.Join(outerpath, innerpath); nested = Path.Combine(outerpath, innerpath);
} }
try try
{ {
@@ -203,7 +203,7 @@ namespace Semmle.Util
{ {
var tempPath = Path.GetTempPath(); var tempPath = Path.GetTempPath();
var name = Guid.NewGuid().ToString("N").ToUpper(); var name = Guid.NewGuid().ToString("N").ToUpper();
var tempFolder = Path.Join(tempPath, "GitHub", name); var tempFolder = Path.Combine(tempPath, "GitHub", name);
Directory.CreateDirectory(tempFolder); Directory.CreateDirectory(tempFolder);
return tempFolder; return tempFolder;
}); });
@@ -231,7 +231,7 @@ namespace Semmle.Util
string outputPath; string outputPath;
do do
{ {
outputPath = Path.Join(tempFolder, Path.GetRandomFileName() + extension); outputPath = Path.Combine(tempFolder, Path.GetRandomFileName() + extension);
} }
while (File.Exists(outputPath)); while (File.Exists(outputPath));

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Improved extraction of range-access expressions on spans and strings (for example, `a[0..3]`). These expressions are now extracted as `Slice` (span) or `Substring` (string) calls.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Improved property and indexer call target resolution for partially overridden properties and indexers.

View File

@@ -1,4 +0,0 @@
---
category: majorAnalysis
---
* Added Razor Page handler method parameters (e.g., `OnGet`, `OnPost`, `OnPostAsync`) as remote flow sources, enabling security queries such as `cs/sql-injection` to detect vulnerabilities in `PageModel` subclasses.

View File

@@ -1,4 +0,0 @@
---
category: breaking
---
* Renamed types related to *operation* expressions. The QL classes `BinaryArithmeticOperation`, `BinaryBitwiseOperation`, and `BinaryLogicalOperation` now include compound assignments; for example, `BinaryArithmeticOperation` now includes `a += b`.

View File

@@ -50,15 +50,15 @@ private predicate maybeUsedInElfHashFunction(Variable v, Operation xor, Operatio
| |
add instanceof AddOperation and add instanceof AddOperation and
e1.getAChild*() = add.getAnOperand() and e1.getAChild*() = add.getAnOperand() and
e1 instanceof BinaryBitwiseExpr and e1 instanceof BinaryBitwiseOperation and
e2 = e1.(BinaryBitwiseExpr).getLeftOperand() and e2 = e1.(BinaryBitwiseOperation).getLeftOperand() and
v = addAssign.getTargetVariable() and v = addAssign.getTargetVariable() and
addAssign.getAChild*() = add and addAssign.getAChild*() = add and
(xor instanceof BitwiseXorExpr or xor instanceof AssignXorExpr) and (xor instanceof BitwiseXorExpr or xor instanceof AssignXorExpr) and
addAssign.getControlFlowNode().getASuccessor*() = xor.getControlFlowNode() and addAssign.getControlFlowNode().getASuccessor*() = xor.getControlFlowNode() and
xorAssign.getAChild*() = xor and xorAssign.getAChild*() = xor and
v = xorAssign.getTargetVariable() and v = xorAssign.getTargetVariable() and
(notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseExpr) and (notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseOperation) and
xor.getControlFlowNode().getASuccessor*() = notOp.getControlFlowNode() and xor.getControlFlowNode().getASuccessor*() = notOp.getControlFlowNode() and
notAssign.getAChild*() = notOp and notAssign.getAChild*() = notOp and
v = notAssign.getTargetVariable() and v = notAssign.getTargetVariable() and

View File

@@ -290,7 +290,7 @@ module AssignableInternal {
newtype TAssignableDefinition = newtype TAssignableDefinition =
TAssignmentDefinition(Assignment a) { TAssignmentDefinition(Assignment a) {
not a.getLeftOperand() instanceof TupleExpr and not a.getLeftOperand() instanceof TupleExpr and
not a instanceof AssignCallExpr and not a instanceof AssignCallOperation and
not a instanceof AssignCoalesceExpr not a instanceof AssignCoalesceExpr
} or } or
TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) { tupleAssignmentDefinition(ae, leaf) } or TTupleAssignmentDefinition(AssignExpr ae, Expr leaf) { tupleAssignmentDefinition(ae, leaf) } or
@@ -324,7 +324,7 @@ module AssignableInternal {
TAddressOfDefinition(AddressOfExpr aoe) or TAddressOfDefinition(AddressOfExpr aoe) or
TPatternDefinition(TopLevelPatternDecl tlpd) or TPatternDefinition(TopLevelPatternDecl tlpd) or
TAssignOperationDefinition(AssignOperation ao) { TAssignOperationDefinition(AssignOperation ao) {
ao instanceof AssignCallExpr and not ao instanceof CompoundAssignmentOperatorCall ao instanceof AssignCallOperation and not ao instanceof CompoundAssignmentOperatorCall
or or
ao instanceof AssignCoalesceExpr ao instanceof AssignCoalesceExpr
} }

View File

@@ -121,13 +121,6 @@ private module Cached {
result = getAChildExpr(parent) result = getAChildExpr(parent)
or or
result = parent.getAChildStmt() result = parent.getAChildStmt()
or
result =
any(TypeMention tm |
tm.getTarget() = parent
or
tm.getParent+().getTarget() = parent
)
} }
private predicate parent(ControlFlowElement child, ExprOrStmtParent parent) { private predicate parent(ControlFlowElement child, ExprOrStmtParent parent) {

View File

@@ -57,28 +57,6 @@ class DeclarationWithGetSetAccessors extends DeclarationWithAccessors, TopLevelE
/** Gets the `set` accessor of this declaration, if any. */ /** Gets the `set` accessor of this declaration, if any. */
Setter getSetter() { result = this.getAnAccessor() } Setter getSetter() { result = this.getAnAccessor() }
/** Gets the target accessor of this declaration when used in a read context, if any. */
Accessor getReadTarget() {
result = this.getGetter()
or
not exists(this.getGetter()) and
result = this.getOverridee().getReadTarget()
}
/** Gets the target accessor of this declaration when used in a write context, if any. */
Accessor getWriteTarget() {
result = this.getSetter()
or
not exists(this.getSetter()) and
result = this.getOverridee().getWriteTarget()
or
result =
any(Getter g |
g = this.getReadTarget() and
g.getAnnotatedReturnType().isRef()
)
}
override DeclarationWithGetSetAccessors getOverridee() { override DeclarationWithGetSetAccessors getOverridee() {
result = DeclarationWithAccessors.super.getOverridee() result = DeclarationWithAccessors.super.getOverridee()
} }

View File

@@ -6,7 +6,6 @@ import Generics
import Location import Location
import Namespace import Namespace
import Property import Property
import semmle.code.csharp.controlflow.ControlFlowElement
private import Conversion private import Conversion
private import semmle.code.csharp.metrics.Coupling private import semmle.code.csharp.metrics.Coupling
private import TypeRef private import TypeRef
@@ -1287,7 +1286,7 @@ class TupleType extends ValueType, @tuple_type {
* A type mention, that is, any mention of a type in a source code file. * A type mention, that is, any mention of a type in a source code file.
* For example, `int` is mentioned in `int M() { return 1; }`. * For example, `int` is mentioned in `int M() { return 1; }`.
*/ */
class TypeMention extends ControlFlowElement, @type_mention { class TypeMention extends @type_mention {
Type type; Type type;
@type_mention_parent parent; @type_mention_parent parent;
@@ -1320,13 +1319,13 @@ class TypeMention extends ControlFlowElement, @type_mention {
* } * }
* ``` * ```
*/ */
override TypeMention getParent() { result = parent } TypeMention getParent() { result = parent }
/** Gets a textual representation of this type mention. */ /** Gets a textual representation of this type mention. */
override string toString() { result = type.toString() } string toString() { result = type.toString() }
/** Gets the location of this type mention. */ /** Gets the location of this type mention. */
override Location getALocation() { type_mention_location(this, result) } Location getLocation() { type_mention_location(this, result) }
} }
/** /**

View File

@@ -20,7 +20,7 @@ class ControlFlowElementOrCallable extends ExprOrStmtParent, TControlFlowElement
*/ */
class ControlFlowElement extends ControlFlowElementOrCallable, @control_flow_element { class ControlFlowElement extends ControlFlowElementOrCallable, @control_flow_element {
/** Gets the enclosing callable of this element, if any. */ /** Gets the enclosing callable of this element, if any. */
Callable getEnclosingCallable() { enclosingCallable(this, result) } Callable getEnclosingCallable() { none() }
/** Gets the assembly that this element was compiled into. */ /** Gets the assembly that this element was compiled into. */
Assembly getAssembly() { Assembly getAssembly() {

View File

@@ -912,17 +912,18 @@ module Internal {
) )
or or
// In C#, `null + 1` has type `int?` with value `null` // In C#, `null + 1` has type `int?` with value `null`
result = exists(BinaryOperation bo, Expr o |
any(BinaryArithmeticOperation bao | bo instanceof BinaryArithmeticOperation or
exists(Expr o | bo instanceof AssignArithmeticOperation
bao.getAnOperand() = e and |
bao.getAnOperand() = o and result = bo and
// The other operand must be provably non-null in order bo.getAnOperand() = e and
// for `only if` to hold bo.getAnOperand() = o and
nonNullValueImplied(o) and // The other operand must be provably non-null in order
e != o // for `only if` to hold
) nonNullValueImplied(o) and
) e != o
)
} }
/** /**
@@ -933,10 +934,10 @@ module Internal {
any(QualifiableExpr qe | any(QualifiableExpr qe |
qe.isConditional() and qe.isConditional() and
result = qe.getQualifier() result = qe.getQualifier()
) ) or
or
// In C#, `null + 1` has type `int?` with value `null` // In C#, `null + 1` has type `int?` with value `null`
e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand()) e = any(BinaryArithmeticOperation bao | result = bao.getAnOperand()) or
e = any(AssignArithmeticOperation aao | result = aao.getAnOperand())
} }
deprecated predicate isGuard(Expr e, GuardValue val) { deprecated predicate isGuard(Expr e, GuardValue val) {

View File

@@ -145,8 +145,6 @@ module Ast implements AstSig<Location> {
final private class ParameterFinal = CS::Parameter; final private class ParameterFinal = CS::Parameter;
class Parameter extends ParameterFinal { class Parameter extends ParameterFinal {
AstNode getPattern() { result = this }
Expr getDefaultValue() { Expr getDefaultValue() {
// Avoid combinatorial explosions for callables with multiple bodies // Avoid combinatorial explosions for callables with multiple bodies
result = unique( | | super.getDefaultValue()) result = unique( | | super.getDefaultValue())
@@ -174,10 +172,6 @@ module Ast implements AstSig<Location> {
class DoStmt = CS::DoStmt; class DoStmt = CS::DoStmt;
class UntilStmt extends LoopStmt {
UntilStmt() { none() }
}
final private class FinalForStmt = CS::ForStmt; final private class FinalForStmt = CS::ForStmt;
class ForStmt extends FinalForStmt { class ForStmt extends FinalForStmt {
@@ -209,7 +203,7 @@ module Ast implements AstSig<Location> {
final private class FinalTryStmt = CS::TryStmt; final private class FinalTryStmt = CS::TryStmt;
class TryStmt extends FinalTryStmt { class TryStmt extends FinalTryStmt {
AstNode getBody(int index) { index = 0 and result = this.getBlock() } Stmt getBody() { result = this.getBlock() }
CatchClause getCatch(int index) { result = this.getCatchClause(index) } CatchClause getCatch(int index) { result = this.getCatchClause(index) }

View File

@@ -124,7 +124,9 @@ private module Internal {
TDispatchDynamicOperatorCall(DynamicOperatorCall doc) or TDispatchDynamicOperatorCall(DynamicOperatorCall doc) or
TDispatchDynamicMemberAccess(DynamicMemberAccess dma) or TDispatchDynamicMemberAccess(DynamicMemberAccess dma) or
TDispatchDynamicElementAccess(DynamicElementAccess dea) or TDispatchDynamicElementAccess(DynamicElementAccess dea) or
TDispatchDynamicEventAccess(AssignArithmeticExpr aao, DynamicMemberAccess dma, string name) { TDispatchDynamicEventAccess(
AssignArithmeticOperation aao, DynamicMemberAccess dma, string name
) {
isPotentialEventCall(aao, dma, name) isPotentialEventCall(aao, dma, name)
} or } or
TDispatchDynamicObjectCreation(DynamicObjectCreation doc) or TDispatchDynamicObjectCreation(DynamicObjectCreation doc) or
@@ -228,7 +230,7 @@ private module Internal {
* accessor. * accessor.
*/ */
private predicate isPotentialEventCall( private predicate isPotentialEventCall(
AssignArithmeticExpr aao, DynamicMemberAccess dma, string name AssignArithmeticOperation aao, DynamicMemberAccess dma, string name
) { ) {
aao instanceof DynamicOperatorCall and aao instanceof DynamicOperatorCall and
dma = aao.getLeftOperand() and dma = aao.getLeftOperand() and
@@ -1395,7 +1397,9 @@ private module Internal {
private class DispatchDynamicEventAccess extends DispatchReflectionOrDynamicCall, private class DispatchDynamicEventAccess extends DispatchReflectionOrDynamicCall,
TDispatchDynamicEventAccess TDispatchDynamicEventAccess
{ {
override AssignArithmeticExpr getCall() { this = TDispatchDynamicEventAccess(result, _, _) } override AssignArithmeticOperation getCall() {
this = TDispatchDynamicEventAccess(result, _, _)
}
override string getName() { this = TDispatchDynamicEventAccess(_, _, result) } override string getName() { this = TDispatchDynamicEventAccess(_, _, result) }

View File

@@ -11,27 +11,19 @@ import Expr
* (`UnaryArithmeticOperation`) or a binary arithmetic operation * (`UnaryArithmeticOperation`) or a binary arithmetic operation
* (`BinaryArithmeticOperation`). * (`BinaryArithmeticOperation`).
*/ */
class ArithmeticOperation extends Operation, @arith_operation { class ArithmeticOperation extends Operation, @arith_op_expr {
override string getOperator() { none() } override string getOperator() { none() }
} }
/** /**
* A binary arithmetic operation. Either a binary arithmetic expression (`BinaryArithmeticExpr`) or * A unary arithmetic operation. Either a unary minus operation
* an arithmetic assignment expression (`AssignArithmeticExpr`). * (`UnaryMinusExpr`), a unary plus operation (`UnaryPlusExpr`),
*/
class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @bin_arith_operation {
override string getOperator() { none() }
}
/**
* A unary arithmetic operation. Either a unary minus expression
* (`UnaryMinusExpr`), a unary plus expression (`UnaryPlusExpr`),
* or a mutator operation (`MutatorOperation`). * or a mutator operation (`MutatorOperation`).
*/ */
class UnaryArithmeticOperation extends ArithmeticOperation, UnaryOperation, @un_arith_operation { } class UnaryArithmeticOperation extends ArithmeticOperation, UnaryOperation, @un_arith_op_expr { }
/** /**
* A unary minus expression, for example `-x`. * A unary minus operation, for example `-x`.
*/ */
class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr { class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr {
override string getOperator() { result = "-" } override string getOperator() { result = "-" }
@@ -40,7 +32,7 @@ class UnaryMinusExpr extends UnaryArithmeticOperation, @minus_expr {
} }
/** /**
* A unary plus expression, for example `+x`. * A unary plus operation, for example `+x`.
*/ */
class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr { class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr {
override string getOperator() { result = "+" } override string getOperator() { result = "+" }
@@ -52,40 +44,40 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @plus_expr {
* A mutator operation. Either an increment operation (`IncrementOperation`) * A mutator operation. Either an increment operation (`IncrementOperation`)
* or a decrement operation (`DecrementOperation`). * or a decrement operation (`DecrementOperation`).
*/ */
class MutatorOperation extends UnaryArithmeticOperation, @mut_operation { } class MutatorOperation extends UnaryArithmeticOperation, @mut_op_expr { }
/** /**
* An increment operation. Either a postfix increment expression * An increment operation. Either a postfix increment operation
* (`PostIncrExpr`) or a prefix increment expression (`PreIncrExpr`). * (`PostIncrExpr`) or a prefix increment operation (`PreIncrExpr`).
*/ */
class IncrementOperation extends MutatorOperation, @incr_operation { class IncrementOperation extends MutatorOperation, @incr_op_expr {
override string getOperator() { result = "++" } override string getOperator() { result = "++" }
} }
/** /**
* A decrement operation. Either a postfix decrement expression * A decrement operation. Either a postfix decrement operation
* (`PostDecrExpr`) or a prefix decrement expression (`PreDecrExpr`). * (`PostDecrExpr`) or a prefix decrement operation (`PreDecrExpr`).
*/ */
class DecrementOperation extends MutatorOperation, @decr_operation { class DecrementOperation extends MutatorOperation, @decr_op_expr {
override string getOperator() { result = "--" } override string getOperator() { result = "--" }
} }
/** /**
* A prefix increment expression, for example `++x`. * A prefix increment operation, for example `++x`.
*/ */
class PreIncrExpr extends IncrementOperation, @pre_incr_expr { class PreIncrExpr extends IncrementOperation, @pre_incr_expr {
override string getAPrimaryQlClass() { result = "PreIncrExpr" } override string getAPrimaryQlClass() { result = "PreIncrExpr" }
} }
/** /**
* A prefix decrement expression, for example `--x`. * A prefix decrement operation, for example `--x`.
*/ */
class PreDecrExpr extends DecrementOperation, @pre_decr_expr { class PreDecrExpr extends DecrementOperation, @pre_decr_expr {
override string getAPrimaryQlClass() { result = "PreDecrExpr" } override string getAPrimaryQlClass() { result = "PreDecrExpr" }
} }
/** /**
* A postfix increment expression, for example `x++`. * A postfix increment operation, for example `x++`.
*/ */
class PostIncrExpr extends IncrementOperation, @post_incr_expr { class PostIncrExpr extends IncrementOperation, @post_incr_expr {
override string toString() { result = "..." + this.getOperator() } override string toString() { result = "..." + this.getOperator() }
@@ -94,7 +86,7 @@ class PostIncrExpr extends IncrementOperation, @post_incr_expr {
} }
/** /**
* A postfix decrement expression, for example `x--`. * A postfix decrement operation, for example `x--`.
*/ */
class PostDecrExpr extends DecrementOperation, @post_decr_expr { class PostDecrExpr extends DecrementOperation, @post_decr_expr {
override string toString() { result = "..." + this.getOperator() } override string toString() { result = "..." + this.getOperator() }
@@ -103,84 +95,55 @@ class PostDecrExpr extends DecrementOperation, @post_decr_expr {
} }
/** /**
* An addition operation, either `x + y` or `x += y`. * A binary arithmetic operation. Either an addition operation
* (`AddExpr`), a subtraction operation (`SubExpr`), a multiplication
* operation (`MulExpr`), a division operation (`DivExpr`), or a
* remainder operation (`RemExpr`).
*/ */
class AddOperation extends BinaryArithmeticOperation, @add_operation { } class BinaryArithmeticOperation extends ArithmeticOperation, BinaryOperation, @bin_arith_op_expr {
override string getOperator() { none() }
/**
* A subtraction operation, either `x - y` or `x -= y`.
*/
class SubOperation extends BinaryArithmeticOperation, @sub_operation { }
/**
* A multiplication operation, either `x * y` or `x *= y`.
*/
class MulOperation extends BinaryArithmeticOperation, @mul_operation { }
/**
* A division operation, either `x / y` or `x /= y`.
*/
class DivOperation extends BinaryArithmeticOperation, @div_operation {
/** Gets the numerator of this division operation. */
Expr getNumerator() { result = this.getLeftOperand() }
/** Gets the denominator of this division operation. */
Expr getDenominator() { result = this.getRightOperand() }
} }
/** /**
* A remainder operation, either `x % y` or `x %= y`. * An addition operation, for example `x + y`.
*/ */
class RemOperation extends BinaryArithmeticOperation, @rem_operation { } class AddExpr extends BinaryArithmeticOperation, AddOperation, @add_expr {
/**
* A binary arithmetic expression. Either an addition expression
* (`AddExpr`), a subtraction expression (`SubExpr`), a multiplication
* expression (`MulExpr`), a division expression (`DivExpr`), or a
* remainder expression (`RemExpr`).
*/
class BinaryArithmeticExpr extends BinaryArithmeticOperation, @bin_arith_expr { }
/**
* An addition expression, for example `x + y`.
*/
class AddExpr extends BinaryArithmeticExpr, AddOperation, @add_expr {
override string getOperator() { result = "+" } override string getOperator() { result = "+" }
override string getAPrimaryQlClass() { result = "AddExpr" } override string getAPrimaryQlClass() { result = "AddExpr" }
} }
/** /**
* A subtraction expression, for example `x - y`. * A subtraction operation, for example `x - y`.
*/ */
class SubExpr extends BinaryArithmeticExpr, SubOperation, @sub_expr { class SubExpr extends BinaryArithmeticOperation, SubOperation, @sub_expr {
override string getOperator() { result = "-" } override string getOperator() { result = "-" }
override string getAPrimaryQlClass() { result = "SubExpr" } override string getAPrimaryQlClass() { result = "SubExpr" }
} }
/** /**
* A multiplication expression, for example `x * y`. * A multiplication operation, for example `x * y`.
*/ */
class MulExpr extends BinaryArithmeticExpr, MulOperation, @mul_expr { class MulExpr extends BinaryArithmeticOperation, MulOperation, @mul_expr {
override string getOperator() { result = "*" } override string getOperator() { result = "*" }
override string getAPrimaryQlClass() { result = "MulExpr" } override string getAPrimaryQlClass() { result = "MulExpr" }
} }
/** /**
* A division expression, for example `x / y`. * A division operation, for example `x / y`.
*/ */
class DivExpr extends BinaryArithmeticExpr, DivOperation, @div_expr { class DivExpr extends BinaryArithmeticOperation, DivOperation, @div_expr {
override string getOperator() { result = "/" } override string getOperator() { result = "/" }
override string getAPrimaryQlClass() { result = "DivExpr" } override string getAPrimaryQlClass() { result = "DivExpr" }
} }
/** /**
* A remainder expression, for example `x % y`. * A remainder operation, for example `x % y`.
*/ */
class RemExpr extends BinaryArithmeticExpr, RemOperation, @rem_expr { class RemExpr extends BinaryArithmeticOperation, RemOperation, @rem_expr {
override string getOperator() { result = "%" } override string getOperator() { result = "%" }
override string getAPrimaryQlClass() { result = "RemExpr" } override string getAPrimaryQlClass() { result = "RemExpr" }

View File

@@ -72,9 +72,9 @@ class AssignExpr extends Assignment, @simple_assign_expr {
} }
/** /**
* An assignment operation. Either an arithmetic assignment expression * An assignment operation. Either an arithmetic assignment operation
* (`AssignArithmeticExpr`), a bitwise assignment expression * (`AssignArithmeticOperation`), a bitwise assignment operation
* (`AssignBitwiseExpr`), an event assignment (`AddOrRemoveEventExpr`), or * (`AssignBitwiseOperation`), an event assignment (`AddOrRemoveEventExpr`), or
* a null-coalescing assignment (`AssignCoalesceExpr`). * a null-coalescing assignment (`AssignCoalesceExpr`).
*/ */
class AssignOperation extends Assignment, @assign_op_expr { class AssignOperation extends Assignment, @assign_op_expr {
@@ -94,147 +94,134 @@ class AssignOperation extends Assignment, @assign_op_expr {
} }
/** /**
* A compound assignment expression that invokes an operator. * A compound assignment operation that invokes an operator.
* *
* (1) `x += y` invokes the compound assignment operator `+=` (if it exists). * (1) `x += y` invokes the compound assignment operator `+=` (if it exists).
* (2) `x += y` invokes the operator `+` and assigns `x + y` to `x`. * (2) `x += y` invokes the operator `+` and assigns `x + y` to `x`.
* *
* Either an arithmetic assignment expression (`AssignArithmeticExpr`) or a bitwise * Either an arithmetic assignment operation (`AssignArithmeticOperation`) or a bitwise
* assignment expression (`AssignBitwiseExpr`). * assignment operation (`AssignBitwiseOperation`).
*/ */
class AssignCallExpr extends AssignOperation, OperatorCall, QualifiableExpr, @assign_op_call_expr { class AssignCallOperation extends AssignOperation, OperatorCall, QualifiableExpr,
@assign_op_call_expr
{
override string toString() { result = AssignOperation.super.toString() } override string toString() { result = AssignOperation.super.toString() }
} }
/** /**
* DEPRECATED: Use `AssignCallExpr` instead. * An arithmetic assignment operation. Either an addition assignment operation
*/ * (`AssignAddExpr`), a subtraction assignment operation (`AssignSubExpr`), a
deprecated class AssignCallOperation = AssignCallExpr; * multiplication assignment operation (`AssignMulExpr`), a division assignment
* operation (`AssignDivExpr`), or a remainder assignment operation
/**
* An arithmetic assignment expression. Either an addition assignment expression
* (`AssignAddExpr`), a subtraction assignment expression (`AssignSubExpr`), a
* multiplication assignment expression (`AssignMulExpr`), a division assignment
* expression (`AssignDivExpr`), or a remainder assignment expression
* (`AssignRemExpr`). * (`AssignRemExpr`).
*/ */
class AssignArithmeticExpr extends AssignCallExpr, @assign_arith_expr { } class AssignArithmeticOperation extends AssignCallOperation, @assign_arith_expr { }
/** /**
* DEPRECATED: Use `AssignArithmeticExpr` instead. * An addition assignment operation, for example `x += y`.
*/ */
deprecated class AssignArithmeticOperation = AssignArithmeticExpr; class AssignAddExpr extends AssignArithmeticOperation, AddOperation, @assign_add_expr {
/**
* An addition assignment expression, for example `x += y`.
*/
class AssignAddExpr extends AssignArithmeticExpr, AddOperation, @assign_add_expr {
override string getOperator() { result = "+=" } override string getOperator() { result = "+=" }
override string getAPrimaryQlClass() { result = "AssignAddExpr" } override string getAPrimaryQlClass() { result = "AssignAddExpr" }
} }
/** /**
* A subtraction assignment expression, for example `x -= y`. * A subtraction assignment operation, for example `x -= y`.
*/ */
class AssignSubExpr extends AssignArithmeticExpr, SubOperation, @assign_sub_expr { class AssignSubExpr extends AssignArithmeticOperation, SubOperation, @assign_sub_expr {
override string getOperator() { result = "-=" } override string getOperator() { result = "-=" }
override string getAPrimaryQlClass() { result = "AssignSubExpr" } override string getAPrimaryQlClass() { result = "AssignSubExpr" }
} }
/** /**
* A multiplication assignment expression, for example `x *= y`. * An multiplication assignment operation, for example `x *= y`.
*/ */
class AssignMulExpr extends AssignArithmeticExpr, MulOperation, @assign_mul_expr { class AssignMulExpr extends AssignArithmeticOperation, MulOperation, @assign_mul_expr {
override string getOperator() { result = "*=" } override string getOperator() { result = "*=" }
override string getAPrimaryQlClass() { result = "AssignMulExpr" } override string getAPrimaryQlClass() { result = "AssignMulExpr" }
} }
/** /**
* A division assignment expression, for example `x /= y`. * An division assignment operation, for example `x /= y`.
*/ */
class AssignDivExpr extends AssignArithmeticExpr, DivOperation, @assign_div_expr { class AssignDivExpr extends AssignArithmeticOperation, DivOperation, @assign_div_expr {
override string getOperator() { result = "/=" } override string getOperator() { result = "/=" }
override string getAPrimaryQlClass() { result = "AssignDivExpr" } override string getAPrimaryQlClass() { result = "AssignDivExpr" }
} }
/** /**
* A remainder assignment expression, for example `x %= y`. * A remainder assignment operation, for example `x %= y`.
*/ */
class AssignRemExpr extends AssignArithmeticExpr, RemOperation, @assign_rem_expr { class AssignRemExpr extends AssignArithmeticOperation, RemOperation, @assign_rem_expr {
override string getOperator() { result = "%=" } override string getOperator() { result = "%=" }
override string getAPrimaryQlClass() { result = "AssignRemExpr" } override string getAPrimaryQlClass() { result = "AssignRemExpr" }
} }
/** /**
* A bitwise assignment expression. Either a bitwise-and assignment * A bitwise assignment operation. Either a bitwise-and assignment
* expression (`AssignAndExpr`), a bitwise-or assignment * operation (`AssignAndExpr`), a bitwise-or assignment
* expression (`AssignOrExpr`), a bitwise exclusive-or assignment * operation (`AssignOrExpr`), a bitwise exclusive-or assignment
* expression (`AssignXorExpr`), a left-shift assignment * operation (`AssignXorExpr`), a left-shift assignment
* expression (`AssignLeftShiftExpr`), or a right-shift assignment * operation (`AssignLeftShiftExpr`), or a right-shift assignment
* expression (`AssignRightShiftExpr`), or an unsigned right-shift assignment * operation (`AssignRightShiftExpr`), or an unsigned right-shift assignment
* expression (`AssignUnsignedRightShiftExpr`). * operation (`AssignUnsignedRightShiftExpr`).
*/ */
class AssignBitwiseExpr extends AssignCallExpr, @assign_bitwise_expr { } class AssignBitwiseOperation extends AssignCallOperation, @assign_bitwise_expr { }
/** /**
* DEPRECATED: Use `AssignBitwiseExpr` instead. * A bitwise-and assignment operation, for example `x &= y`.
*/ */
deprecated class AssignBitwiseOperation = AssignBitwiseExpr; class AssignAndExpr extends AssignBitwiseOperation, BitwiseAndOperation, @assign_and_expr {
/**
* A bitwise-and assignment expression, for example `x &= y`.
*/
class AssignAndExpr extends AssignBitwiseExpr, BitwiseAndOperation, @assign_and_expr {
override string getOperator() { result = "&=" } override string getOperator() { result = "&=" }
override string getAPrimaryQlClass() { result = "AssignAndExpr" } override string getAPrimaryQlClass() { result = "AssignAndExpr" }
} }
/** /**
* A bitwise-or assignment expression, for example `x |= y`. * A bitwise-or assignment operation, for example `x |= y`.
*/ */
class AssignOrExpr extends AssignBitwiseExpr, BitwiseOrOperation, @assign_or_expr { class AssignOrExpr extends AssignBitwiseOperation, BitwiseOrOperation, @assign_or_expr {
override string getOperator() { result = "|=" } override string getOperator() { result = "|=" }
override string getAPrimaryQlClass() { result = "AssignOrExpr" } override string getAPrimaryQlClass() { result = "AssignOrExpr" }
} }
/** /**
* A bitwise exclusive-or assignment expression, for example `x ^= y`. * A bitwise exclusive-or assignment operation, for example `x ^= y`.
*/ */
class AssignXorExpr extends AssignBitwiseExpr, BitwiseXorOperation, @assign_xor_expr { class AssignXorExpr extends AssignBitwiseOperation, BitwiseXorOperation, @assign_xor_expr {
override string getOperator() { result = "^=" } override string getOperator() { result = "^=" }
override string getAPrimaryQlClass() { result = "AssignXorExpr" } override string getAPrimaryQlClass() { result = "AssignXorExpr" }
} }
/** /**
* A left-shift assignment expression, for example `x <<= y`. * A left-shift assignment operation, for example `x <<= y`.
*/ */
class AssignLeftShiftExpr extends AssignBitwiseExpr, LeftShiftOperation, @assign_lshift_expr { class AssignLeftShiftExpr extends AssignBitwiseOperation, LeftShiftOperation, @assign_lshift_expr {
override string getOperator() { result = "<<=" } override string getOperator() { result = "<<=" }
override string getAPrimaryQlClass() { result = "AssignLeftShiftExpr" } override string getAPrimaryQlClass() { result = "AssignLeftShiftExpr" }
} }
/** /**
* A right-shift assignment expression, for example `x >>= y`. * A right-shift assignment operation, for example `x >>= y`.
*/ */
class AssignRightShiftExpr extends AssignBitwiseExpr, RightShiftOperation, @assign_rshift_expr { class AssignRightShiftExpr extends AssignBitwiseOperation, RightShiftOperation, @assign_rshift_expr {
override string getOperator() { result = ">>=" } override string getOperator() { result = ">>=" }
override string getAPrimaryQlClass() { result = "AssignRightShiftExpr" } override string getAPrimaryQlClass() { result = "AssignRightShiftExpr" }
} }
/** /**
* An unsigned right-shift assignment expression, for example `x >>>= y`. * An unsigned right-shift assignment operation, for example `x >>>= y`.
*/ */
class AssignUnsignedRightShiftExpr extends AssignBitwiseExpr, UnsignedRightShiftOperation, class AssignUnsignedRightShiftExpr extends AssignBitwiseOperation, UnsignedRightShiftOperation,
@assign_urshift_expr @assign_urshift_expr
{ {
override string getOperator() { result = ">>>=" } override string getOperator() { result = ">>>=" }
@@ -310,10 +297,10 @@ class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr {
} }
/** /**
* A null-coalescing assignment expression, for example `x ??= y`. * A null-coalescing assignment operation, for example `x ??= y`.
*/ */
class AssignCoalesceExpr extends AssignOperation, NullCoalescingOperation, @assign_coalesce_expr { class AssignCoalesceExpr extends AssignOperation, NullCoalescingOperation, @assign_coalesce_expr {
override string getOperator() { result = "??=" } override string toString() { result = "... ??= ..." }
override string getAPrimaryQlClass() { result = "AssignCoalesceExpr" } override string getAPrimaryQlClass() { result = "AssignCoalesceExpr" }
} }

View File

@@ -10,16 +10,16 @@ import Expr
* A bitwise operation. Either a unary bitwise operation (`UnaryBitwiseOperation`) * A bitwise operation. Either a unary bitwise operation (`UnaryBitwiseOperation`)
* or a binary bitwise operation (`BinaryBitwiseOperation`). * or a binary bitwise operation (`BinaryBitwiseOperation`).
*/ */
class BitwiseOperation extends Operation, @bit_operation { } class BitwiseOperation extends Operation, @bit_expr { }
/** /**
* A unary bitwise operation, that is, a bitwise complement operation * A unary bitwise operation, that is, a bitwise complement operation
* (`ComplementExpr`). * (`ComplementExpr`).
*/ */
class UnaryBitwiseOperation extends BitwiseOperation, UnaryOperation, @un_bit_operation { } class UnaryBitwiseOperation extends BitwiseOperation, UnaryOperation, @un_bit_op_expr { }
/** /**
* A bitwise complement expression, for example `~x`. * A bitwise complement operation, for example `~x`.
*/ */
class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr { class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr {
override string getOperator() { result = "~" } override string getOperator() { result = "~" }
@@ -28,101 +28,67 @@ class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr {
} }
/** /**
* A binary bitwise operation. Either a binary bitwise expression (`BinaryBitwiseExpr`) or * A binary bitwise operation. Either a bitwise-and operation
* a bitwise assignment expression (`AssignBitwiseExpr`). * (`BitwiseAndExpr`), a bitwise-or operation (`BitwiseOrExpr`),
* a bitwise exclusive-or operation (`BitwiseXorExpr`), a left-shift
* operation (`LeftShiftExpr`), a right-shift operation (`RightShiftExpr`),
* or an unsigned right-shift operation (`UnsignedRightShiftExpr`).
*/ */
class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit_operation { class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit_op_expr {
override string getOperator() { none() } override string getOperator() { none() }
} }
/** /**
* A bitwise-and operation, either `x & y` or `x &= y`. * A left-shift operation, for example `x << y`.
*/ */
class BitwiseAndOperation extends BinaryBitwiseOperation, @and_operation { } class LeftShiftExpr extends BinaryBitwiseOperation, LeftShiftOperation, @lshift_expr {
/**
* A bitwise-or operation, either `x | y` or `x |= y`.
*/
class BitwiseOrOperation extends BinaryBitwiseOperation, @or_operation { }
/**
* A bitwise exclusive-or operation, either `x ^ y` or `x ^= y`.
*/
class BitwiseXorOperation extends BinaryBitwiseOperation, @xor_operation { }
/**
* A left-shift operation, either `x << y` or `x <<= y`.
*/
class LeftShiftOperation extends BinaryBitwiseOperation, @lshift_operation { }
/**
* A right-shift operation, either `x >> y` or `x >>= y`.
*/
class RightShiftOperation extends BinaryBitwiseOperation, @rshift_operation { }
/**
* An unsigned right-shift operation, either `x >>> y` or `x >>>= y`.
*/
class UnsignedRightShiftOperation extends BinaryBitwiseOperation, @urshift_operation { }
/**
* A binary bitwise expression. Either a bitwise-and expression
* (`BitwiseAndExpr`), a bitwise-or expression (`BitwiseOrExpr`),
* a bitwise exclusive-or expression (`BitwiseXorExpr`), a left-shift
* expression (`LeftShiftExpr`), a right-shift expression (`RightShiftExpr`),
* or an unsigned right-shift expression (`UnsignedRightShiftExpr`).
*/
class BinaryBitwiseExpr extends BinaryBitwiseOperation, @bin_bit_expr { }
/**
* A left-shift expression, for example `x << y`.
*/
class LeftShiftExpr extends BinaryBitwiseExpr, LeftShiftOperation, @lshift_expr {
override string getOperator() { result = "<<" } override string getOperator() { result = "<<" }
override string getAPrimaryQlClass() { result = "LeftShiftExpr" } override string getAPrimaryQlClass() { result = "LeftShiftExpr" }
} }
/** /**
* A right-shift expression, for example `x >> y`. * A right-shift operation, for example `x >> y`.
*/ */
class RightShiftExpr extends BinaryBitwiseExpr, RightShiftOperation, @rshift_expr { class RightShiftExpr extends BinaryBitwiseOperation, RightShiftOperation, @rshift_expr {
override string getOperator() { result = ">>" } override string getOperator() { result = ">>" }
override string getAPrimaryQlClass() { result = "RightShiftExpr" } override string getAPrimaryQlClass() { result = "RightShiftExpr" }
} }
/** /**
* An unsigned right-shift expression, for example `x >>> y`. * An unsigned right-shift operation, for example `x >>> y`.
*/ */
class UnsignedRightShiftExpr extends BinaryBitwiseExpr, UnsignedRightShiftOperation, @urshift_expr { class UnsignedRightShiftExpr extends BinaryBitwiseOperation, UnsignedRightShiftOperation,
@urshift_expr
{
override string getOperator() { result = ">>>" } override string getOperator() { result = ">>>" }
override string getAPrimaryQlClass() { result = "UnsignedRightShiftExpr" } override string getAPrimaryQlClass() { result = "UnsignedRightShiftExpr" }
} }
/** /**
* A bitwise-and expression, for example `x & y`. * A bitwise-and operation, for example `x & y`.
*/ */
class BitwiseAndExpr extends BinaryBitwiseExpr, BitwiseAndOperation, @bit_and_expr { class BitwiseAndExpr extends BinaryBitwiseOperation, BitwiseAndOperation, @bit_and_expr {
override string getOperator() { result = "&" } override string getOperator() { result = "&" }
override string getAPrimaryQlClass() { result = "BitwiseAndExpr" } override string getAPrimaryQlClass() { result = "BitwiseAndExpr" }
} }
/** /**
* A bitwise-or expression, for example `x | y`. * A bitwise-or operation, for example `x | y`.
*/ */
class BitwiseOrExpr extends BinaryBitwiseExpr, BitwiseOrOperation, @bit_or_expr { class BitwiseOrExpr extends BinaryBitwiseOperation, BitwiseOrOperation, @bit_or_expr {
override string getOperator() { result = "|" } override string getOperator() { result = "|" }
override string getAPrimaryQlClass() { result = "BitwiseOrExpr" } override string getAPrimaryQlClass() { result = "BitwiseOrExpr" }
} }
/** /**
* A bitwise exclusive-or expression, for example `x ^ y`. * A bitwise exclusive-or operation, for example `x ^ y`.
*/ */
class BitwiseXorExpr extends BinaryBitwiseExpr, BitwiseXorOperation, @bit_xor_expr { class BitwiseXorExpr extends BinaryBitwiseOperation, BitwiseXorOperation, @bit_xor_expr {
override string getOperator() { result = "^" } override string getOperator() { result = "^" }
override string getAPrimaryQlClass() { result = "BitwiseXorExpr" } override string getAPrimaryQlClass() { result = "BitwiseXorExpr" }

View File

@@ -609,7 +609,7 @@ class InstanceMutatorOperatorCall extends MutatorOperatorCall {
* } * }
* ``` * ```
*/ */
class CompoundAssignmentOperatorCall extends AssignCallExpr { class CompoundAssignmentOperatorCall extends AssignCallOperation {
CompoundAssignmentOperatorCall() { this.getTarget() instanceof CompoundAssignmentOperator } CompoundAssignmentOperatorCall() { this.getTarget() instanceof CompoundAssignmentOperator }
override Expr getArgument(int i) { result = this.getChildExpr(i + 1) and i >= 0 } override Expr getArgument(int i) { result = this.getChildExpr(i + 1) and i >= 0 }
@@ -762,12 +762,20 @@ class AccessorCall extends Call, QualifiableExpr, @call_access_expr {
*/ */
class PropertyCall extends AccessorCall, PropertyAccessExpr { class PropertyCall extends AccessorCall, PropertyAccessExpr {
override Accessor getReadTarget() { override Accessor getReadTarget() {
this instanceof AssignableRead and result = this.getProperty().getReadTarget() this instanceof AssignableRead and result = this.getProperty().getGetter()
} }
override Accessor getWriteTarget() { override Accessor getWriteTarget() {
this instanceof AssignableWrite and this instanceof AssignableWrite and
result = this.getProperty().getWriteTarget() exists(Property p | p = this.getProperty() |
result = p.getSetter()
or
result =
any(Getter g |
g = p.getGetter() and
g.getAnnotatedReturnType().isRef()
)
)
} }
override Expr getArgument(int i) { override Expr getArgument(int i) {
@@ -798,12 +806,20 @@ class PropertyCall extends AccessorCall, PropertyAccessExpr {
*/ */
class IndexerCall extends AccessorCall, IndexerAccessExpr { class IndexerCall extends AccessorCall, IndexerAccessExpr {
override Accessor getReadTarget() { override Accessor getReadTarget() {
this instanceof AssignableRead and result = this.getIndexer().getReadTarget() this instanceof AssignableRead and result = this.getIndexer().getGetter()
} }
override Accessor getWriteTarget() { override Accessor getWriteTarget() {
this instanceof AssignableWrite and this instanceof AssignableWrite and
result = this.getIndexer().getWriteTarget() exists(Indexer i | i = this.getIndexer() |
result = i.getSetter()
or
result =
any(Getter g |
g = i.getGetter() and
g.getAnnotatedReturnType().isRef()
)
)
} }
override Expr getArgument(int i) { override Expr getArgument(int i) {

View File

@@ -14,6 +14,7 @@ import Creation
import Dynamic import Dynamic
import Literal import Literal
import LogicalOperation import LogicalOperation
import Operation
import semmle.code.csharp.controlflow.ControlFlowElement import semmle.code.csharp.controlflow.ControlFlowElement
import semmle.code.csharp.Location import semmle.code.csharp.Location
import semmle.code.csharp.Stmt import semmle.code.csharp.Stmt
@@ -211,7 +212,7 @@ class LocalConstantDeclExpr extends LocalVariableDeclExpr {
* (`UnaryOperation`), a binary operation (`BinaryOperation`), or a * (`UnaryOperation`), a binary operation (`BinaryOperation`), or a
* ternary operation (`TernaryOperation`). * ternary operation (`TernaryOperation`).
*/ */
class Operation extends Expr, @operation_expr { class Operation extends Expr, @op_expr {
/** Gets the name of the operator in this operation. */ /** Gets the name of the operator in this operation. */
string getOperator() { none() } string getOperator() { none() }
@@ -226,7 +227,7 @@ class Operation extends Expr, @operation_expr {
* indirection operation (`PointerIndirectionExpr`), an address-of operation * indirection operation (`PointerIndirectionExpr`), an address-of operation
* (`AddressOfExpr`), or a unary logical operation (`UnaryLogicalOperation`). * (`AddressOfExpr`), or a unary logical operation (`UnaryLogicalOperation`).
*/ */
class UnaryOperation extends Operation, @un_operation { class UnaryOperation extends Operation, @un_op {
/** Gets the operand of this unary operation. */ /** Gets the operand of this unary operation. */
Expr getOperand() { result = this.getChild(0) } Expr getOperand() { result = this.getChild(0) }
@@ -240,7 +241,7 @@ class UnaryOperation extends Operation, @un_operation {
* a binary logical operation (`BinaryLogicalOperation`), or an * a binary logical operation (`BinaryLogicalOperation`), or an
* assignment (`Assignment`). * assignment (`Assignment`).
*/ */
class BinaryOperation extends Operation, @bin_operation { class BinaryOperation extends Operation, @bin_op {
/** Gets the left operand of this binary operation. */ /** Gets the left operand of this binary operation. */
Expr getLeftOperand() { result = this.getChild(0) } Expr getLeftOperand() { result = this.getChild(0) }
@@ -263,7 +264,7 @@ class BinaryOperation extends Operation, @bin_operation {
* A ternary operation, that is, a ternary conditional operation * A ternary operation, that is, a ternary conditional operation
* (`ConditionalExpr`). * (`ConditionalExpr`).
*/ */
class TernaryOperation extends Operation, @ternary_operation { } class TernaryOperation extends Operation, @ternary_op { }
/** /**
* A parenthesized expression, for example `(2 + 3)` in * A parenthesized expression, for example `(2 + 3)` in

View File

@@ -11,14 +11,14 @@ import Expr
* a binary logical operation (`BinaryLogicalOperation`), or a ternary logical * a binary logical operation (`BinaryLogicalOperation`), or a ternary logical
* operation (`TernaryLogicalOperation`). * operation (`TernaryLogicalOperation`).
*/ */
class LogicalOperation extends Operation, @log_operation { class LogicalOperation extends Operation, @log_expr {
override string getOperator() { none() } override string getOperator() { none() }
} }
/** /**
* A unary logical operation, that is, a logical 'not' (`LogicalNotExpr`). * A unary logical operation, that is, a logical 'not' (`LogicalNotExpr`).
*/ */
class UnaryLogicalOperation extends LogicalOperation, UnaryOperation, @un_log_operation { } class UnaryLogicalOperation extends LogicalOperation, UnaryOperation, @un_log_op_expr { }
/** /**
* A logical 'not', for example `!String.IsNullOrEmpty(s)`. * A logical 'not', for example `!String.IsNullOrEmpty(s)`.
@@ -31,10 +31,10 @@ class LogicalNotExpr extends UnaryLogicalOperation, @log_not_expr {
/** /**
* A binary logical operation. Either a logical 'and' (`LogicalAndExpr`), * A binary logical operation. Either a logical 'and' (`LogicalAndExpr`),
* a logical 'or' (`LogicalOrExpr`), or a null-coalescing operation * a logical 'or' (`LogicalAndExpr`), or a null-coalescing operation
* (`NullCoalescingOperation`). * (`NullCoalescingExpr`).
*/ */
class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log_operation { class BinaryLogicalOperation extends LogicalOperation, BinaryOperation, @bin_log_op_expr {
override string getOperator() { none() } override string getOperator() { none() }
} }
@@ -57,12 +57,7 @@ class LogicalOrExpr extends BinaryLogicalOperation, @log_or_expr {
} }
/** /**
* A null-coalescing operation, either `x ?? y` or `x ??= y`. * A null-coalescing operation, for example `s ?? ""` on line 2 in
*/
class NullCoalescingOperation extends BinaryLogicalOperation, @null_coalescing_operation { }
/**
* A null-coalescing expression, for example `s ?? ""` on line 2 in
* *
* ```csharp * ```csharp
* string NonNullOrEmpty(string s) { * string NonNullOrEmpty(string s) {
@@ -70,7 +65,9 @@ class NullCoalescingOperation extends BinaryLogicalOperation, @null_coalescing_o
* } * }
* ``` * ```
*/ */
class NullCoalescingExpr extends NullCoalescingOperation, @null_coalescing_expr { class NullCoalescingExpr extends BinaryLogicalOperation, NullCoalescingOperation,
@null_coalescing_expr
{
override string getOperator() { result = "??" } override string getOperator() { result = "??" }
override string getAPrimaryQlClass() { result = "NullCoalescingExpr" } override string getAPrimaryQlClass() { result = "NullCoalescingExpr" }
@@ -80,7 +77,7 @@ class NullCoalescingExpr extends NullCoalescingOperation, @null_coalescing_expr
* A ternary logical operation, that is, a ternary conditional expression * A ternary logical operation, that is, a ternary conditional expression
* (`ConditionalExpr`). * (`ConditionalExpr`).
*/ */
class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @ternary_log_operation { } class TernaryLogicalOperation extends LogicalOperation, TernaryOperation, @ternary_log_op_expr { }
/** /**
* A conditional expression, for example `s != null ? s.Length : -1` * A conditional expression, for example `s != null ? s.Length : -1`

View File

@@ -1,6 +1,71 @@
/** /**
* Provides classes for operations that also have compound assignment forms. * Provides classes for operations that also have compound assignment forms.
*/ */
deprecated module;
import Expr import Expr
/**
* An addition operation, either `x + y` or `x += y`.
*/
class AddOperation extends BinaryOperation, @add_operation { }
/**
* A subtraction operation, either `x - y` or `x -= y`.
*/
class SubOperation extends BinaryOperation, @sub_operation { }
/**
* A multiplication operation, either `x * y` or `x *= y`.
*/
class MulOperation extends BinaryOperation, @mul_operation { }
/**
* A division operation, either `x / y` or `x /= y`.
*/
class DivOperation extends BinaryOperation, @div_operation {
/** Gets the numerator of this division operation. */
Expr getNumerator() { result = this.getLeftOperand() }
/** Gets the denominator of this division operation. */
Expr getDenominator() { result = this.getRightOperand() }
}
/**
* A remainder operation, either `x % y` or `x %= y`.
*/
class RemOperation extends BinaryOperation, @rem_operation { }
/**
* A bitwise-and operation, either `x & y` or `x &= y`.
*/
class BitwiseAndOperation extends BinaryOperation, @and_operation { }
/**
* A bitwise-or operation, either `x | y` or `x |= y`.
*/
class BitwiseOrOperation extends BinaryOperation, @or_operation { }
/**
* A bitwise exclusive-or operation, either `x ^ y` or `x ^= y`.
*/
class BitwiseXorOperation extends BinaryOperation, @xor_operation { }
/**
* A left-shift operation, either `x << y` or `x <<= y`.
*/
class LeftShiftOperation extends BinaryOperation, @lshift_operation { }
/**
* A right-shift operation, either `x >> y` or `x >>= y`.
*/
class RightShiftOperation extends BinaryOperation, @rshift_operation { }
/**
* An unsigned right-shift operation, either `x >>> y` or `x >>>= y`.
*/
class UnsignedRightShiftOperation extends BinaryOperation, @urshift_operation { }
/**
* A null-coalescing operation, either `x ?? y` or `x ??= y`.
*/
class NullCoalescingOperation extends BinaryOperation, @null_coalescing_operation { }

View File

@@ -13,7 +13,6 @@ private import semmle.code.csharp.frameworks.system.web.ui.WebControls
private import semmle.code.csharp.frameworks.WCF private import semmle.code.csharp.frameworks.WCF
private import semmle.code.csharp.frameworks.microsoft.Owin private import semmle.code.csharp.frameworks.microsoft.Owin
private import semmle.code.csharp.frameworks.microsoft.AspNetCore private import semmle.code.csharp.frameworks.microsoft.AspNetCore
private import semmle.code.csharp.frameworks.Razor
private import semmle.code.csharp.dataflow.internal.ExternalFlow private import semmle.code.csharp.dataflow.internal.ExternalFlow
private import semmle.code.csharp.security.dataflow.flowsources.FlowSources private import semmle.code.csharp.security.dataflow.flowsources.FlowSources
@@ -315,22 +314,6 @@ class AspNetCoreActionMethodParameter extends AspNetCoreRemoteFlowSource, DataFl
override string getSourceType() { result = "ASP.NET Core MVC action method parameter" } override string getSourceType() { result = "ASP.NET Core MVC action method parameter" }
} }
/** A parameter to a Razor Page handler method, viewed as a source of remote user input. */
class AspNetCorePageHandlerMethodParameter extends AspNetCoreRemoteFlowSource,
DataFlow::ParameterNode
{
AspNetCorePageHandlerMethodParameter() {
exists(Parameter p |
p = this.getParameter() and
p.fromSource()
|
p = any(PageModelClass pm).getAHandlerMethod().getAParameter()
)
}
override string getSourceType() { result = "ASP.NET Core Razor Page handler method parameter" }
}
private class ExternalRemoteFlowSource extends RemoteFlowSource { private class ExternalRemoteFlowSource extends RemoteFlowSource {
ExternalRemoteFlowSource() { sourceNode(this, "remote") } ExternalRemoteFlowSource() { sourceNode(this, "remote") }

View File

@@ -219,7 +219,7 @@ overlayChangedFiles(
/** ELEMENTS **/ /** ELEMENTS **/
@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration @element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
| @using_directive | @type_parameter_constraints | @type_mention | @externalDataElement | @using_directive | @type_parameter_constraints | @externalDataElement
| @xmllocatable | @asp_element | @namespace | @preprocessor_directive; | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
@declaration = @callable | @generic | @assignable | @namespace; @declaration = @callable | @generic | @assignable | @namespace;
@@ -1254,39 +1254,33 @@ case @expr.kind of
@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; @delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
@bin_arith_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; @bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
@bin_arith_operation = @mul_operation | @div_operation | @rem_operation | @add_operation | @sub_operation; @incr_op_expr = @pre_incr_expr | @post_incr_expr;
@decr_op_expr = @pre_decr_expr | @post_decr_expr;
@mut_op_expr = @incr_op_expr | @decr_op_expr;
@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
@incr_operation = @pre_incr_expr | @post_incr_expr; @ternary_log_op_expr = @conditional_expr;
@decr_operation = @pre_decr_expr | @post_decr_expr; @bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
@mut_operation = @incr_operation | @decr_operation; @un_log_op_expr = @log_not_expr;
@un_arith_operation = @plus_expr | @minus_expr | @mut_operation; @log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
@arith_operation = @bin_arith_operation | @un_arith_operation;
@ternary_log_operation = @conditional_expr; @bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
@bin_log_operation = @log_and_expr | @log_or_expr | @null_coalescing_operation; | @rshift_expr | @urshift_expr;
@un_log_operation = @log_not_expr; @un_bit_op_expr = @bit_not_expr;
@log_operation = @un_log_operation | @bin_log_operation | @ternary_log_operation; @bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
@bin_bit_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
| @rshift_expr | @urshift_expr;
@bin_bit_operation = @and_operation | @or_operation | @xor_operation | @lshift_operation
| @rshift_operation | @urshift_operation;
@un_bit_expr = @bit_not_expr;
@un_bit_operation = @un_bit_expr;
@bit_expr = @un_bit_expr | @bin_bit_expr;
@bit_operation = @un_bit_operation | @bin_bit_operation;
@equality_op_expr = @eq_expr | @ne_expr; @equality_op_expr = @eq_expr | @ne_expr;
@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; @rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
@comp_expr = @equality_op_expr | @rel_op_expr; @comp_expr = @equality_op_expr | @rel_op_expr;
@operation_expr = @un_operation | @bin_operation | @ternary_operation; @op_expr = @un_op | @bin_op | @ternary_op;
@ternary_operation = @ternary_log_operation; @ternary_op = @ternary_log_op_expr;
@bin_operation = @assign_expr | @bin_arith_operation | @bin_log_operation | @bin_bit_operation | @comp_expr; @bin_op = @assign_expr | @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
@un_operation = @un_arith_operation | @un_log_operation | @un_bit_operation | @sizeof_expr @un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
| @pointer_indirection_expr | @address_of_expr; | @pointer_indirection_expr | @address_of_expr;
@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; @anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
@@ -1369,7 +1363,7 @@ compiler_generated(unique int id: @element ref);
/** CONTROL/DATA FLOW **/ /** CONTROL/DATA FLOW **/
@control_flow_element = @stmt | @expr | @parameter | @type_mention; @control_flow_element = @stmt | @expr | @parameter;
/* XML Files */ /* XML Files */

View File

@@ -1,2 +0,0 @@
description: Restructure and rename types related to operations.
compatibility: full

View File

@@ -63,7 +63,7 @@ module CallTargetStats implements StatsSig {
additional predicate isNotOkCall(Call c) { additional predicate isNotOkCall(Call c) {
not exists(c.getTarget()) and not exists(c.getTarget()) and
not c instanceof DelegateLikeCall and not c instanceof DelegateCall and
not c instanceof DynamicExpr and not c instanceof DynamicExpr and
not isNoSetterPropertyCallInConstructor(c) and not isNoSetterPropertyCallInConstructor(c) and
not isNoSetterPropertyInitialization(c) and not isNoSetterPropertyInitialization(c) and

View File

@@ -1,7 +1,6 @@
binarybitwise binarybitwise
| Operators.cs:7:18:7:25 | ... >>> ... | Operators.cs:7:18:7:19 | access to local variable x1 | Operators.cs:7:25:7:25 | 2 | >>> | UnsignedRightShiftExpr | | Operators.cs:7:18:7:25 | ... >>> ... | Operators.cs:7:18:7:19 | access to local variable x1 | Operators.cs:7:25:7:25 | 2 | >>> | UnsignedRightShiftExpr |
| Operators.cs:10:18:10:25 | ... >>> ... | Operators.cs:10:18:10:19 | access to local variable y1 | Operators.cs:10:25:10:25 | 3 | >>> | UnsignedRightShiftExpr | | Operators.cs:10:18:10:25 | ... >>> ... | Operators.cs:10:18:10:19 | access to local variable y1 | Operators.cs:10:25:10:25 | 3 | >>> | UnsignedRightShiftExpr |
| Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsignedRightShiftExpr |
assignbitwise assignbitwise
| Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsignedRightShiftExpr | | Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsignedRightShiftExpr |
userdefined userdefined

View File

@@ -11,7 +11,7 @@ query predicate binarybitwise(
} }
query predicate assignbitwise( query predicate assignbitwise(
AssignBitwiseExpr op, Expr left, Expr right, string name, string qlclass AssignBitwiseOperation op, Expr left, Expr right, string name, string qlclass
) { ) {
op.getFile().getStem() = "Operators" and op.getFile().getStem() = "Operators" and
left = op.getLeftOperand() and left = op.getLeftOperand() and

View File

@@ -101,7 +101,6 @@ csharp6.cs:
# 32| 0: [IntLiteral] 2 # 32| 0: [IntLiteral] 2
# 32| 0: [IntLiteral] 1 # 32| 0: [IntLiteral] 1
# 34| 1: [SpecificCatchClause] catch (...) {...} # 34| 1: [SpecificCatchClause] catch (...) {...}
# 34| 0: [TypeMention] IndexOutOfRangeException
# 35| 1: [BlockStmt] {...} # 35| 1: [BlockStmt] {...}
# 34| 2: [EQExpr] ... == ... # 34| 2: [EQExpr] ... == ...
# 34| 0: [PropertyCall] access to property Value # 34| 0: [PropertyCall] access to property Value

View File

@@ -442,31 +442,4 @@ namespace My.Qltest
static void Sink(object o) { } static void Sink(object o) { }
} }
// Test operator overloads
public class N
{
public void operator +=(N y) => throw null;
public void operator checked +=(N y) => throw null;
public void M1(N n)
{
var n0 = new N();
n += n0;
Sink(n);
}
public void M2(N n)
{
var n0 = new N();
checked
{
n += n0;
}
Sink(n);
}
static void Sink(object o) { }
}
} }

View File

@@ -32,16 +32,14 @@ models
| 31 | Summary: My.Qltest; Library; false; GetValue; (); ; Argument[this].SyntheticField[X]; ReturnValue; value; dfc-generated | | 31 | Summary: My.Qltest; Library; false; GetValue; (); ; Argument[this].SyntheticField[X]; ReturnValue; value; dfc-generated |
| 32 | Summary: My.Qltest; Library; false; MixedFlowArgs; (System.Object,System.Object); ; Argument[1]; ReturnValue; value; manual | | 32 | Summary: My.Qltest; Library; false; MixedFlowArgs; (System.Object,System.Object); ; Argument[1]; ReturnValue; value; manual |
| 33 | Summary: My.Qltest; Library; false; SetValue; (System.Object); ; Argument[0]; Argument[this].SyntheticField[X]; value; dfc-generated | | 33 | Summary: My.Qltest; Library; false; SetValue; (System.Object); ; Argument[0]; Argument[this].SyntheticField[X]; value; dfc-generated |
| 34 | Summary: My.Qltest; N; false; op_AdditionAssignment; (My.Qltest.N); ; Argument[0]; Argument[this]; taint; manual | | 34 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; Method1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 35 | Summary: My.Qltest; N; false; op_CheckedAdditionAssignment; (My.Qltest.N); ; Argument[0]; Argument[this]; taint; manual | | 35 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; StaticMethod1; (System.Object); ; Argument[0]; ReturnValue; value; manual |
| 36 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; Method1; (System.Object); ; Argument[0]; ReturnValue; value; manual | | 36 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; get_Property1; (System.Object); ; Argument[0].SyntheticField[TestExtensions.Property1]; ReturnValue; value; manual |
| 37 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; StaticMethod1; (System.Object); ; Argument[0]; ReturnValue; value; manual | | 37 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; set_Property1; (System.Object,System.Object); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.Property1]; value; manual |
| 38 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; get_Property1; (System.Object); ; Argument[0].SyntheticField[TestExtensions.Property1]; ReturnValue; value; manual | | 38 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 39 | Summary: My.Qltest; TestExtensions+extension(System.Object); false; set_Property1; (System.Object,System.Object); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.Property1]; value; manual | | 39 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericStaticMethod1; (T); ; Argument[0]; ReturnValue; value; manual |
| 40 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericMethod1; (T); ; Argument[0]; ReturnValue; value; manual | | 40 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; get_GenericProperty1; (T); ; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; ReturnValue; value; manual |
| 41 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; GenericStaticMethod1; (T); ; Argument[0]; ReturnValue; value; manual | | 41 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; set_GenericProperty1; (T,T); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; value; manual |
| 42 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; get_GenericProperty1; (T); ; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; ReturnValue; value; manual |
| 43 | Summary: My.Qltest; TestExtensions+extension(T)<T>; false; set_GenericProperty1; (T,T); ; Argument[1]; Argument[0].SyntheticField[TestExtensions.GenericProperty1]; value; manual |
edges edges
| ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object | provenance | | | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | ExternalFlow.cs:10:29:10:32 | access to local variable arg1 : Object | provenance | |
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | provenance | | | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | provenance | |
@@ -164,77 +162,69 @@ edges
| ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:373:23:373:34 | object creation of type Object : Object | ExternalFlow.cs:373:17:373:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | ExternalFlow.cs:375:18:375:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | ExternalFlow.cs:375:18:375:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | provenance | MaD:36 | | ExternalFlow.cs:374:22:374:24 | access to local variable obj : Object | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | provenance | MaD:34 |
| ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:374:22:374:34 | call to method Method1 : Object | ExternalFlow.cs:374:17:374:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | ExternalFlow.cs:378:18:378:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | ExternalFlow.cs:378:18:378:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | provenance | | | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | ExternalFlow.cs:377:17:377:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | provenance | MaD:36 | | ExternalFlow.cs:377:45:377:47 | access to local variable obj : Object | ExternalFlow.cs:377:22:377:48 | call to method Method1 : Object | provenance | MaD:34 |
| ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:383:23:383:34 | object creation of type Object : Object | ExternalFlow.cs:383:17:383:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | ExternalFlow.cs:385:18:385:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | ExternalFlow.cs:385:18:385:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | ExternalFlow.cs:384:17:384:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | provenance | MaD:37 | | ExternalFlow.cs:384:43:384:45 | access to local variable obj : Object | ExternalFlow.cs:384:22:384:46 | call to method StaticMethod1 : Object | provenance | MaD:35 |
| ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | ExternalFlow.cs:388:18:388:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | ExternalFlow.cs:388:18:388:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | provenance | | | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | ExternalFlow.cs:387:17:387:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | provenance | MaD:37 | | ExternalFlow.cs:387:51:387:53 | access to local variable obj : Object | ExternalFlow.cs:387:22:387:54 | call to method StaticMethod1 : Object | provenance | MaD:35 |
| ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:393:23:393:34 | object creation of type Object : Object | ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:393:23:393:34 | object creation of type Object : Object | ExternalFlow.cs:393:17:393:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | | | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | |
| ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:39 | | ExternalFlow.cs:394:27:394:29 | access to local variable obj : Object | ExternalFlow.cs:394:13:394:13 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 |
| ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | ExternalFlow.cs:396:18:396:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | ExternalFlow.cs:396:18:396:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | provenance | MaD:38 | | ExternalFlow.cs:395:22:395:22 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:395:22:395:32 | access to property Property1 : Object | ExternalFlow.cs:395:17:395:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:401:23:401:34 | object creation of type Object : Object | ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:401:23:401:34 | object creation of type Object : Object | ExternalFlow.cs:401:17:401:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | | | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | |
| ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:39 | | ExternalFlow.cs:402:45:402:47 | access to local variable obj : Object | ExternalFlow.cs:402:42:402:42 | [post] access to parameter o : Object [synthetic TestExtensions.Property1] : Object | provenance | MaD:37 |
| ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | ExternalFlow.cs:404:18:404:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | ExternalFlow.cs:404:18:404:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | ExternalFlow.cs:403:17:403:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | provenance | MaD:38 | | ExternalFlow.cs:403:51:403:51 | access to parameter o : Object [synthetic TestExtensions.Property1] : Object | ExternalFlow.cs:403:22:403:52 | call to extension accessor get_Property1 : Object | provenance | MaD:36 |
| ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:409:23:409:34 | object creation of type Object : Object | ExternalFlow.cs:409:17:409:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | ExternalFlow.cs:411:18:411:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | ExternalFlow.cs:411:18:411:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | provenance | MaD:40 | | ExternalFlow.cs:410:22:410:24 | access to local variable obj : Object | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:410:22:410:41 | call to method GenericMethod1 : Object | ExternalFlow.cs:410:17:410:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | ExternalFlow.cs:414:18:414:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | ExternalFlow.cs:414:18:414:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | provenance | | | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | ExternalFlow.cs:413:17:413:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | provenance | MaD:40 | | ExternalFlow.cs:413:52:413:54 | access to local variable obj : Object | ExternalFlow.cs:413:22:413:55 | call to method GenericMethod1 : Object | provenance | MaD:38 |
| ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:419:17:419:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | ExternalFlow.cs:421:18:421:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | ExternalFlow.cs:421:18:421:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:420:17:420:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | provenance | MaD:41 | | ExternalFlow.cs:420:50:420:52 | access to local variable obj : Object | ExternalFlow.cs:420:22:420:53 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 |
| ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | provenance | | | ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | provenance | |
| ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | provenance | | | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | ExternalFlow.cs:423:17:423:18 | access to local variable o2 : Object | provenance | |
| ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | provenance | MaD:41 | | ExternalFlow.cs:423:58:423:60 | access to local variable obj : Object | ExternalFlow.cs:423:22:423:61 | call to method GenericStaticMethod1 : Object | provenance | MaD:39 |
| ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:429:17:429:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | provenance | | | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | | | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | provenance | | | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [property GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:43 | | ExternalFlow.cs:430:34:430:36 | access to local variable obj : Object | ExternalFlow.cs:430:13:430:13 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 |
| ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | | | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [property GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | |
| ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | MaD:42 | | ExternalFlow.cs:431:22:431:22 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:431:22:431:39 | access to property GenericProperty1 : Object | ExternalFlow.cs:431:17:431:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | provenance | | | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:437:17:437:19 | access to local variable obj : Object | provenance | |
| ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | | | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | |
| ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:43 | | ExternalFlow.cs:438:52:438:54 | access to local variable obj : Object | ExternalFlow.cs:438:49:438:49 | [post] access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | provenance | MaD:41 |
| ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | provenance | | | ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | provenance | |
| ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | provenance | | | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | ExternalFlow.cs:439:17:439:18 | access to local variable o1 : Object | provenance | |
| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | provenance | MaD:42 | | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | provenance | MaD:40 |
| ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:455:22:455:28 | object creation of type N : N | ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | ExternalFlow.cs:457:18:457:18 | access to parameter n | provenance | |
| ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | provenance | MaD:34 |
| ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:462:22:462:28 | object creation of type N : N | ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | provenance | |
| ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | ExternalFlow.cs:467:18:467:18 | access to parameter n | provenance | |
| ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | provenance | MaD:35 |
nodes nodes
| ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | semmle.label | access to local variable arg1 : Object | | ExternalFlow.cs:9:20:9:23 | access to local variable arg1 : Object | semmle.label | access to local variable arg1 : Object |
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
@@ -453,16 +443,6 @@ nodes
| ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | semmle.label | call to extension accessor get_GenericProperty1 : Object | | ExternalFlow.cs:439:22:439:59 | call to extension accessor get_GenericProperty1 : Object | semmle.label | call to extension accessor get_GenericProperty1 : Object |
| ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | semmle.label | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | | ExternalFlow.cs:439:58:439:58 | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object | semmle.label | access to parameter o : Object [synthetic TestExtensions.GenericProperty1] : Object |
| ExternalFlow.cs:440:18:440:19 | access to local variable o1 | semmle.label | access to local variable o1 | | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | semmle.label | access to local variable o1 |
| ExternalFlow.cs:455:17:455:18 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:455:22:455:28 | object creation of type N : N | semmle.label | object creation of type N : N |
| ExternalFlow.cs:456:13:456:13 | [post] access to parameter n : N | semmle.label | [post] access to parameter n : N |
| ExternalFlow.cs:456:18:456:19 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:457:18:457:18 | access to parameter n | semmle.label | access to parameter n |
| ExternalFlow.cs:462:17:462:18 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:462:22:462:28 | object creation of type N : N | semmle.label | object creation of type N : N |
| ExternalFlow.cs:465:17:465:17 | [post] access to parameter n : N | semmle.label | [post] access to parameter n : N |
| ExternalFlow.cs:465:22:465:23 | access to local variable n0 : N | semmle.label | access to local variable n0 : N |
| ExternalFlow.cs:467:18:467:18 | access to parameter n | semmle.label | access to parameter n |
subpaths subpaths
| ExternalFlow.cs:84:29:84:32 | access to local variable objs : null [element] : Object | ExternalFlow.cs:84:35:84:35 | o : Object | ExternalFlow.cs:84:40:84:40 | access to parameter o : Object | ExternalFlow.cs:84:25:84:41 | call to method Map<Object,Object> : T[] [element] : Object | | ExternalFlow.cs:84:29:84:32 | access to local variable objs : null [element] : Object | ExternalFlow.cs:84:35:84:35 | o : Object | ExternalFlow.cs:84:40:84:40 | access to parameter o : Object | ExternalFlow.cs:84:25:84:41 | call to method Map<Object,Object> : T[] [element] : Object |
invalidModelRow invalidModelRow
@@ -509,5 +489,3 @@ invalidModelRow
| ExternalFlow.cs:424:18:424:19 | access to local variable o2 | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | $@ | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | ExternalFlow.cs:424:18:424:19 | access to local variable o2 | $@ | ExternalFlow.cs:419:23:419:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:432:18:432:19 | access to local variable o1 | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | $@ | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | ExternalFlow.cs:432:18:432:19 | access to local variable o1 | $@ | ExternalFlow.cs:429:23:429:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:440:18:440:19 | access to local variable o1 | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | $@ | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | ExternalFlow.cs:440:18:440:19 | access to local variable o1 | $@ | ExternalFlow.cs:437:23:437:34 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:457:18:457:18 | access to parameter n | ExternalFlow.cs:455:22:455:28 | object creation of type N : N | ExternalFlow.cs:457:18:457:18 | access to parameter n | $@ | ExternalFlow.cs:455:22:455:28 | object creation of type N : N | object creation of type N : N |
| ExternalFlow.cs:467:18:467:18 | access to parameter n | ExternalFlow.cs:462:22:462:28 | object creation of type N : N | ExternalFlow.cs:467:18:467:18 | access to parameter n | $@ | ExternalFlow.cs:462:22:462:28 | object creation of type N : N | object creation of type N : N |

View File

@@ -53,8 +53,6 @@ extensions:
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "GenericStaticMethod1", "(T)", "", "Argument[0]", "ReturnValue", "value", "manual"] - ["My.Qltest", "TestExtensions+extension(T)<T>", false, "GenericStaticMethod1", "(T)", "", "Argument[0]", "ReturnValue", "value", "manual"]
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "get_GenericProperty1", "(T)", "", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "ReturnValue", "value", "manual"] - ["My.Qltest", "TestExtensions+extension(T)<T>", false, "get_GenericProperty1", "(T)", "", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "ReturnValue", "value", "manual"]
- ["My.Qltest", "TestExtensions+extension(T)<T>", false, "set_GenericProperty1", "(T,T)", "", "Argument[1]", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "value", "manual"] - ["My.Qltest", "TestExtensions+extension(T)<T>", false, "set_GenericProperty1", "(T,T)", "", "Argument[1]", "Argument[0].SyntheticField[TestExtensions.GenericProperty1]", "value", "manual"]
- ["My.Qltest", "N", false, "op_AdditionAssignment", "(My.Qltest.N)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["My.Qltest", "N", false, "op_CheckedAdditionAssignment", "(My.Qltest.N)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- addsTo: - addsTo:
pack: codeql/csharp-all pack: codeql/csharp-all

View File

@@ -63,32 +63,4 @@ namespace Testing
{ {
public void MyActionMethod(string param) { } public void MyActionMethod(string param) { }
} }
// Razor Page handler tests
public class MyPageModel : Microsoft.AspNetCore.Mvc.RazorPages.PageModel
{
// Handler method parameters are remote flow sources
public void OnGet(string id) { }
public void OnPost(string command, int count) { }
public void OnPostAsync(string data) { }
public void OnPut(string value) { }
public void OnDelete(string itemId) { }
// Not a handler method — does not start with "On", so not a flow source
public void GetUser(string userId) { }
// Excluded by [NonHandler] attribute, so not a flow source
[Microsoft.AspNetCore.Mvc.RazorPages.NonHandlerAttribute]
public void OnGetNonHandler(string param) { }
}
// Subclass of a PageModel subclass
public class DerivedPageModel : MyPageModel
{
public void OnPost(string derivedParam) { }
}
} }

View File

@@ -14,10 +14,3 @@ remoteFlowSources
| AspRemoteFlowSource.cs:54:69:54:82 | mapDeleteParam | | AspRemoteFlowSource.cs:54:69:54:82 | mapDeleteParam |
| AspRemoteFlowSource.cs:56:41:56:44 | item | | AspRemoteFlowSource.cs:56:41:56:44 | item |
| AspRemoteFlowSource.cs:64:43:64:47 | param | | AspRemoteFlowSource.cs:64:43:64:47 | param |
| AspRemoteFlowSource.cs:71:34:71:35 | id |
| AspRemoteFlowSource.cs:73:35:73:41 | command |
| AspRemoteFlowSource.cs:73:48:73:52 | count |
| AspRemoteFlowSource.cs:75:40:75:43 | data |
| AspRemoteFlowSource.cs:77:34:77:38 | value |
| AspRemoteFlowSource.cs:79:37:79:42 | itemId |
| AspRemoteFlowSource.cs:92:35:92:46 | derivedParam |

View File

@@ -293,69 +293,3 @@ properties.cs:
# 160| 0: [LocalVariableAccess] access to local variable x # 160| 0: [LocalVariableAccess] access to local variable x
# 160| 1: [PropertyCall] access to property Prop # 160| 1: [PropertyCall] access to property Prop
# 160| -1: [LocalVariableAccess] access to local variable s # 160| -1: [LocalVariableAccess] access to local variable s
# 164| 13: [Class] BaseClass
# 166| 6: [Property] Value
# 166| -1: [TypeMention] int
# 168| 3: [Getter] get_Value
# 168| 4: [BlockStmt] {...}
# 168| 0: [ReturnStmt] return ...;
# 168| 0: [FieldAccess] access to field Value.field
# 169| 4: [Setter] set_Value
#-----| 2: (Parameters)
# 169| 0: [Parameter] value
# 169| 4: [BlockStmt] {...}
# 169| 0: [ExprStmt] ...;
# 169| 0: [AssignExpr] ... = ...
# 169| 0: [FieldAccess] access to field Value.field
# 169| 1: [ParameterAccess] access to parameter value
# 166| 7: [Field] Value.field
# 173| 14: [Class] DerivedClass1
#-----| 3: (Base types)
# 173| 0: [TypeMention] BaseClass
# 175| 6: [Property] Value
# 175| -1: [TypeMention] int
# 177| 3: [Getter] get_Value
# 177| 4: [BlockStmt] {...}
# 177| 0: [ReturnStmt] return ...;
# 177| 0: [IntLiteral] 20
# 181| 15: [Class] DerivedClass2
#-----| 3: (Base types)
# 181| 0: [TypeMention] BaseClass
# 183| 16: [Class] TestPartialPropertyOverride
# 185| 6: [Method] M
# 185| -1: [TypeMention] Void
# 186| 4: [BlockStmt] {...}
# 187| 0: [LocalVariableDeclStmt] ... ...;
# 187| 0: [LocalVariableDeclAndInitExpr] DerivedClass1 d1 = ...
# 187| -1: [TypeMention] DerivedClass1
# 187| 0: [LocalVariableAccess] access to local variable d1
# 187| 1: [ObjectCreation] object creation of type DerivedClass1
# 187| 0: [TypeMention] DerivedClass1
# 188| 1: [ExprStmt] ...;
# 188| 0: [AssignExpr] ... = ...
# 188| 0: [PropertyCall] access to property Value
# 188| -1: [LocalVariableAccess] access to local variable d1
# 188| 1: [IntLiteral] 11
# 189| 2: [LocalVariableDeclStmt] ... ...;
# 189| 0: [LocalVariableDeclAndInitExpr] Int32 test1 = ...
# 189| -1: [TypeMention] int
# 189| 0: [LocalVariableAccess] access to local variable test1
# 189| 1: [PropertyCall] access to property Value
# 189| -1: [LocalVariableAccess] access to local variable d1
# 191| 3: [LocalVariableDeclStmt] ... ...;
# 191| 0: [LocalVariableDeclAndInitExpr] DerivedClass2 d2 = ...
# 191| -1: [TypeMention] DerivedClass2
# 191| 0: [LocalVariableAccess] access to local variable d2
# 191| 1: [ObjectCreation] object creation of type DerivedClass2
# 191| 0: [TypeMention] DerivedClass2
# 192| 4: [ExprStmt] ...;
# 192| 0: [AssignExpr] ... = ...
# 192| 0: [PropertyCall] access to property Value
# 192| -1: [LocalVariableAccess] access to local variable d2
# 192| 1: [IntLiteral] 12
# 193| 5: [LocalVariableDeclStmt] ... ...;
# 193| 0: [LocalVariableDeclAndInitExpr] Int32 test2 = ...
# 193| -1: [TypeMention] int
# 193| 0: [LocalVariableAccess] access to local variable test2
# 193| 1: [PropertyCall] access to property Value
# 193| -1: [LocalVariableAccess] access to local variable d2

View File

@@ -1,5 +1,4 @@
| Prop.field | | Prop.field |
| Value.field |
| caption | | caption |
| next | | next |
| x | | x |

View File

@@ -6,7 +6,3 @@
| properties.cs:71:28:71:28 | Y | properties.cs:83:39:83:44 | access to property Y | properties.cs:74:13:74:15 | set_Y | | properties.cs:71:28:71:28 | Y | properties.cs:83:39:83:44 | access to property Y | properties.cs:74:13:74:15 | set_Y |
| properties.cs:146:24:146:27 | Prop | properties.cs:159:13:159:18 | access to property Prop | properties.cs:148:13:148:15 | get_Prop | | properties.cs:146:24:146:27 | Prop | properties.cs:159:13:159:18 | access to property Prop | properties.cs:148:13:148:15 | get_Prop |
| properties.cs:146:24:146:27 | Prop | properties.cs:160:21:160:26 | access to property Prop | properties.cs:148:13:148:15 | get_Prop | | properties.cs:146:24:146:27 | Prop | properties.cs:160:21:160:26 | access to property Prop | properties.cs:148:13:148:15 | get_Prop |
| properties.cs:166:28:166:32 | Value | properties.cs:192:13:192:20 | access to property Value | properties.cs:169:13:169:15 | set_Value |
| properties.cs:166:28:166:32 | Value | properties.cs:193:25:193:32 | access to property Value | properties.cs:168:13:168:15 | get_Value |
| properties.cs:175:29:175:33 | Value | properties.cs:188:13:188:20 | access to property Value | properties.cs:169:13:169:15 | set_Value |
| properties.cs:175:29:175:33 | Value | properties.cs:189:25:189:32 | access to property Value | properties.cs:177:13:177:15 | get_Value |

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