diff --git a/.github/workflows/js-ml-tests.yml b/.github/workflows/js-ml-tests.yml index e6401a09c35..ba33779455e 100644 --- a/.github/workflows/js-ml-tests.yml +++ b/.github/workflows/js-ml-tests.yml @@ -12,6 +12,7 @@ on: paths: - "javascript/ql/experimental/adaptivethreatmodeling/**" - .github/workflows/js-ml-tests.yml + workflow_dispatch: defaults: run: diff --git a/config/identical-files.json b/config/identical-files.json index d6af2fc7e1d..192144ebb4f 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -525,7 +525,8 @@ "csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll", "java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll", "javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll", - "ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll" + "ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll", + "python/ql/lib/semmle/python/frameworks/data/internal/AccessPathSyntax.qll" ], "IncompleteUrlSubstringSanitization": [ "javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll", @@ -543,7 +544,8 @@ ], "ApiGraphModels": [ "javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll", - "ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll" + "ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll", + "python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll" ], "TaintedFormatStringQuery Ruby/JS": [ "javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringQuery.qll", diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser.ql b/cpp/ql/src/experimental/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser.ql index a6fac4a40d9..d715be46bd2 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser.ql @@ -17,6 +17,36 @@ import cpp import semmle.code.cpp.dataflow.DataFlow +/** + * A Linux system call. + */ +class SystemCallFunction extends Function { + SystemCallFunction() { + exists(MacroInvocation m | + m.getMacro().getName().matches("SYSCALL\\_DEFINE%") and + this = m.getEnclosingFunction() + ) + } +} + +/** + * A value that comes from a Linux system call (sources). + */ +class SystemCallSource extends DataFlow::Node { + SystemCallSource() { + exists(FunctionCall fc | + fc.getTarget() instanceof SystemCallFunction and + ( + this.asDefiningArgument() = fc.getAnArgument().getAChild*() or + this.asExpr() = fc + ) + ) + } +} + +/** + * Macros used to check the value (barriers). + */ class WriteAccessCheckMacro extends Macro { VariableAccess va; @@ -28,6 +58,9 @@ class WriteAccessCheckMacro extends Macro { VariableAccess getArgument() { result = va } } +/** + * The `unsafe_put_user` macro and its uses (sinks). + */ class UnSafePutUserMacro extends Macro { PointerDereferenceExpr writeUserPtr; @@ -42,15 +75,13 @@ class UnSafePutUserMacro extends Macro { } } -class ExploitableUserModePtrParam extends Parameter { +class ExploitableUserModePtrParam extends SystemCallSource { ExploitableUserModePtrParam() { - not exists(WriteAccessCheckMacro writeAccessCheck | - DataFlow::localFlow(DataFlow::parameterNode(this), - DataFlow::exprNode(writeAccessCheck.getArgument())) - ) and exists(UnSafePutUserMacro unsafePutUser | - DataFlow::localFlow(DataFlow::parameterNode(this), - DataFlow::exprNode(unsafePutUser.getUserModePtr())) + DataFlow::localFlow(this, DataFlow::exprNode(unsafePutUser.getUserModePtr())) + ) and + not exists(WriteAccessCheckMacro writeAccessCheck | + DataFlow::localFlow(this, DataFlow::exprNode(writeAccessCheck.getArgument())) ) } } diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.expected index ffb7941f1cd..c81cfd254df 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/NoCheckBeforeUnsafePutUser.expected @@ -1 +1,3 @@ -| test.cpp:14:16:14:16 | p | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:14:16:14:16 | p | p | +| test.cpp:20:21:20:22 | ref arg & ... | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:20:21:20:22 | ref arg & ... | ref arg & ... | +| test.cpp:41:21:41:22 | ref arg & ... | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:41:21:41:22 | ref arg & ... | ref arg & ... | +| test.cpp:69:21:69:27 | ref arg & ... | unsafe_put_user write user-mode pointer $@ without check. | test.cpp:69:21:69:27 | ref arg & ... | ref arg & ... | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/test.cpp index 755a73864c7..277b9a545e2 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-020/NoCheckBeforeUnsafePutUser/test.cpp @@ -1,7 +1,11 @@ typedef unsigned long size_t; -void SYSC_SOMESYSTEMCALL(void *param); +#define SYSCALL_DEFINE(name, ...) \ + void do_sys_##name(); \ + void sys_##name(...) { do_sys_##name(); } \ + void do_sys_##name() +SYSCALL_DEFINE(somesystemcall, void *param) {}; bool user_access_begin_impl(const void *where, size_t sz); void user_access_end_impl(); @@ -13,14 +17,14 @@ void unsafe_put_user_impl(int what, const void *where, size_t sz); void test1(int p) { - SYSC_SOMESYSTEMCALL(&p); + sys_somesystemcall(&p); unsafe_put_user(123, &p); // BAD } void test2(int p) { - SYSC_SOMESYSTEMCALL(&p); + sys_somesystemcall(&p); if (user_access_begin(&p, sizeof(p))) { @@ -34,16 +38,16 @@ void test3() { int v; - SYSC_SOMESYSTEMCALL(&v); + sys_somesystemcall(&v); - unsafe_put_user(123, &v); // BAD [NOT DETECTED] + unsafe_put_user(123, &v); // BAD } void test4() { int v; - SYSC_SOMESYSTEMCALL(&v); + sys_somesystemcall(&v); if (user_access_begin(&v, sizeof(v))) { @@ -62,16 +66,16 @@ void test5() { data myData; - SYSC_SOMESYSTEMCALL(&myData); + sys_somesystemcall(&myData); - unsafe_put_user(123, &(myData.x)); // BAD [NOT DETECTED] + unsafe_put_user(123, &(myData.x)); // BAD } void test6() { data myData; - SYSC_SOMESYSTEMCALL(&myData); + sys_somesystemcall(&myData); if (user_access_begin(&myData, sizeof(myData))) { diff --git a/csharp/documentation/library-coverage/coverage.csv b/csharp/documentation/library-coverage/coverage.csv index 4d9996c1446..2bc6ca863ac 100644 --- a/csharp/documentation/library-coverage/coverage.csv +++ b/csharp/documentation/library-coverage/coverage.csv @@ -1,10 +1,27 @@ package,sink,source,summary,sink:code,sink:html,sink:remote,sink:sql,sink:xss,source:local,summary:taint,summary:value Dapper,55,,,,,,55,,,, +JsonToItemsTaskFactory,,,7,,,,,,,7, Microsoft.ApplicationBlocks.Data,28,,,,,,28,,,, +Microsoft.CSharp,,,24,,,,,,,24, Microsoft.EntityFrameworkCore,6,,,,,,6,,,, -Microsoft.Extensions.Primitives,,,54,,,,,,,54, -Microsoft.VisualBasic,,,4,,,,,,,,4 +Microsoft.Extensions.Caching.Distributed,,,15,,,,,,,15, +Microsoft.Extensions.Caching.Memory,,,46,,,,,,,45,1 +Microsoft.Extensions.Configuration,,,83,,,,,,,80,3 +Microsoft.Extensions.DependencyInjection,,,62,,,,,,,62, +Microsoft.Extensions.DependencyModel,,,12,,,,,,,12, +Microsoft.Extensions.FileProviders,,,15,,,,,,,15, +Microsoft.Extensions.FileSystemGlobbing,,,15,,,,,,,13,2 +Microsoft.Extensions.Hosting,,,17,,,,,,,16,1 +Microsoft.Extensions.Http,,,10,,,,,,,10, +Microsoft.Extensions.Logging,,,37,,,,,,,37, +Microsoft.Extensions.Options,,,8,,,,,,,8, +Microsoft.Extensions.Primitives,,,63,,,,,,,63, +Microsoft.Interop,,,27,,,,,,,27, +Microsoft.NET.Build.Tasks,,,1,,,,,,,1, +Microsoft.NETCore.Platforms.BuildTasks,,,4,,,,,,,4, +Microsoft.VisualBasic,,,9,,,,,,,5,4 +Microsoft.Win32,,,8,,,,,,,8, MySql.Data.MySqlClient,48,,,,,,48,,,, Newtonsoft.Json,,,91,,,,,,,73,18 ServiceStack,194,,7,27,,75,92,,,7, -System,28,3,2336,,4,,23,1,3,611,1725 +System,28,3,12038,,4,,23,1,3,10096,1942 diff --git a/csharp/documentation/library-coverage/coverage.rst b/csharp/documentation/library-coverage/coverage.rst index 9863b503fbf..076d2078d4b 100644 --- a/csharp/documentation/library-coverage/coverage.rst +++ b/csharp/documentation/library-coverage/coverage.rst @@ -8,7 +8,7 @@ C# framework & library support Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting` `ServiceStack `_,"``ServiceStack.*``, ``ServiceStack``",,7,194, - System,"``System.*``, ``System``",3,2336,28,5 - Others,"``Dapper``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Primitives``, ``Microsoft.VisualBasic``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``",,149,137, - Totals,,3,2492,359,5 + System,"``System.*``, ``System``",3,12038,28,5 + Others,"``Dapper``, ``JsonToItemsTaskFactory``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.CSharp``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NETCore.Platforms.BuildTasks``, ``Microsoft.VisualBasic``, ``Microsoft.Win32``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``",,554,137, + Totals,,3,12599,359,5 diff --git a/docs/codeql/codeql-cli/creating-codeql-databases.rst b/docs/codeql/codeql-cli/creating-codeql-databases.rst index 50dd8fb22cc..aa60cb24e79 100644 --- a/docs/codeql/codeql-cli/creating-codeql-databases.rst +++ b/docs/codeql/codeql-cli/creating-codeql-databases.rst @@ -226,7 +226,8 @@ commands that you can specify for compiled languages. - Java project built using Gradle:: - codeql database create java-database --language=java --command='gradle clean test' + # Use `--no-daemon` because a build delegated to an existing daemon cannot be detected by CodeQL: + codeql database create java-database --language=java --command='gradle --no-daemon clean test' - Java project built using Maven:: diff --git a/docs/codeql/support/reusables/versions-compilers.rst b/docs/codeql/support/reusables/versions-compilers.rst index a5f68cb64e1..4dfadcfb276 100644 --- a/docs/codeql/support/reusables/versions-compilers.rst +++ b/docs/codeql/support/reusables/versions-compilers.rst @@ -20,10 +20,10 @@ Java,"Java 7 to 18 [4]_","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [5]_",``.java`` - JavaScript,ECMAScript 2021 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_" + JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [6]_" Python,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10",Not applicable,``.py`` Ruby [7]_,"up to 3.0.2",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``" - TypeScript [8]_,"2.6-4.6",Standard TypeScript compiler,"``.ts``, ``.tsx``" + TypeScript [8]_,"2.6-4.7",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``" .. container:: footnote-group diff --git a/java/kotlin-extractor/src/main/java/com/semmle/extractor/java/OdasaOutput.java b/java/kotlin-extractor/src/main/java/com/semmle/extractor/java/OdasaOutput.java index 01861bf5ca6..73dc090f69b 100644 --- a/java/kotlin-extractor/src/main/java/com/semmle/extractor/java/OdasaOutput.java +++ b/java/kotlin-extractor/src/main/java/com/semmle/extractor/java/OdasaOutput.java @@ -4,10 +4,14 @@ import java.lang.reflect.*; import java.io.File; import java.io.IOException; import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; import com.github.codeql.Logger; import static com.github.codeql.ClassNamesKt.getIrDeclBinaryName; @@ -547,6 +551,51 @@ public class OdasaOutput { (tcv.majorVersion == majorVersion && tcv.minorVersion == minorVersion && tcv.lastModified < lastModified); } + + private static Map> jarFileEntryTimeStamps = new HashMap<>(); + + private static Map getZipFileEntryTimeStamps(String path, Logger log) { + try { + Map result = new HashMap<>(); + ZipFile zf = new ZipFile(path); + Enumeration entries = zf.entries(); + while (entries.hasMoreElements()) { + ZipEntry ze = entries.nextElement(); + result.put(ze.getName(), ze.getLastModifiedTime().toMillis()); + } + return result; + } catch(IOException e) { + log.warn("Failed to get entry timestamps from " + path, e); + return null; + } + } + + private static long getVirtualFileTimeStamp(VirtualFile vf, Logger log) { + if (vf.getFileSystem().getProtocol().equals("jar")) { + String[] parts = vf.getPath().split("!/"); + if (parts.length == 2) { + String jarFilePath = parts[0]; + String entryPath = parts[1]; + if (!jarFileEntryTimeStamps.containsKey(jarFilePath)) { + jarFileEntryTimeStamps.put(jarFilePath, getZipFileEntryTimeStamps(jarFilePath, log)); + } + Map entryTimeStamps = jarFileEntryTimeStamps.get(jarFilePath); + if (entryTimeStamps != null) { + Long entryTimeStamp = entryTimeStamps.get(entryPath); + if (entryTimeStamp != null) + return entryTimeStamp; + else + log.warn("Couldn't find timestamp for jar file " + jarFilePath + " entry " + entryPath); + } + } else { + log.warn("Expected JAR-file path " + vf.getPath() + " to have exactly one '!/' separator"); + } + } + + // For all files except for jar files, and a fallback in case of I/O problems reading a jar file: + return vf.getTimeStamp(); + } + private static TrapClassVersion fromSymbol(IrDeclaration sym, Logger log) { VirtualFile vf = sym instanceof IrClass ? getIrClassVirtualFile((IrClass)sym) : sym.getParent() instanceof IrClass ? getIrClassVirtualFile((IrClass)sym.getParent()) : @@ -583,7 +632,7 @@ public class OdasaOutput { }; (new ClassReader(vf.contentsToByteArray())).accept(versionGetter, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - return new TrapClassVersion(versionStore[0] & 0xffff, versionStore[0] >> 16, vf.getTimeStamp(), "kotlin"); + return new TrapClassVersion(versionStore[0] & 0xffff, versionStore[0] >> 16, getVirtualFileTimeStamp(vf, log), "kotlin"); } catch(IllegalAccessException e) { log.warn("Failed to read class file version information", e); diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index ddce450a887..e32e5ef1974 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -135,7 +135,7 @@ open class KotlinFileExtractor( Unit } is IrField -> { - val parentId = useDeclarationParent(declaration.parent, false)?.cast() + val parentId = useDeclarationParent(getFieldParent(declaration), false)?.cast() if (parentId != null) { extractField(declaration, parentId) } @@ -759,7 +759,8 @@ open class KotlinFileExtractor( with("field", f) { DeclarationStackAdjuster(f).use { declarationStack.push(f) - return extractField(useField(f), f.name.asString(), f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal) + val fNameSuffix = getExtensionReceiverType(f)?.let { it.classFqName?.asString()?.replace(".", "$$") } ?: "" + return extractField(useField(f), "${f.name.asString()}$fNameSuffix", f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal) } } } @@ -829,10 +830,13 @@ open class KotlinFileExtractor( } if (bf != null && extractBackingField) { - val fieldId = extractField(bf, parentId) - tw.writeKtPropertyBackingFields(id, fieldId) - if (p.isDelegated) { - tw.writeKtPropertyDelegates(id, fieldId) + val fieldParentId = useDeclarationParent(getFieldParent(bf), false) + if (fieldParentId != null) { + val fieldId = extractField(bf, fieldParentId.cast()) + tw.writeKtPropertyBackingFields(id, fieldId) + if (p.isDelegated) { + tw.writeKtPropertyDelegates(id, fieldId) + } } } diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt index 150e355e44d..14515cb85ed 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt @@ -6,6 +6,7 @@ import com.semmle.extractor.java.OdasaOutput import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.ir.allOverridden import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf +import org.jetbrains.kotlin.backend.jvm.ir.getJvmNameFromAnnotation import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.* @@ -1269,9 +1270,34 @@ open class KotlinUsesExtractor( fun useValueParameter(vp: IrValueParameter, parent: Label?): Label = tw.getLabelFor(getValueParameterLabel(vp, parent)) + fun isDirectlyExposedCompanionObjectField(f: IrField) = + f.hasAnnotation(FqName("kotlin.jvm.JvmField")) || + f.correspondingPropertySymbol?.owner?.let { + it.isConst || it.isLateinit + } ?: false + + fun getFieldParent(f: IrField) = + f.parentClassOrNull?.let { + if (it.isCompanion && isDirectlyExposedCompanionObjectField(f)) + it.parent + else + null + } ?: f.parent + + // Gets a field's corresponding property's extension receiver type, if any + fun getExtensionReceiverType(f: IrField) = + f.correspondingPropertySymbol?.owner?.let { + (it.getter ?: it.setter)?.extensionReceiverParameter?.type + } + fun getFieldLabel(f: IrField): String { - val parentId = useDeclarationParent(f.parent, false) - return "@\"field;{$parentId};${f.name.asString()}\"" + val parentId = useDeclarationParent(getFieldParent(f), false) + // Distinguish backing fields of properties based on their extension receiver type; + // otherwise two extension properties declared in the same enclosing context will get + // clashing trap labels. These are always private, so we can just make up a label without + // worrying about their names as seen from Java. + val extensionPropertyDiscriminator = getExtensionReceiverType(f)?.let { "extension;${useType(it)}" } ?: "" + return "@\"field;{$parentId};${extensionPropertyDiscriminator}${f.name.asString()}\"" } fun useField(f: IrField): Label = diff --git a/java/ql/src/utils/model-generator/CaptureSinkModels.ql b/java/ql/src/utils/model-generator/CaptureSinkModels.ql index 8fd2e4d2a30..fb04c4ede00 100644 --- a/java/ql/src/utils/model-generator/CaptureSinkModels.ql +++ b/java/ql/src/utils/model-generator/CaptureSinkModels.ql @@ -1,7 +1,9 @@ /** * @name Capture sink models. * @description Finds public methods that act as sinks as they flow into a a known sink. + * @kind diagnostic * @id java/utils/model-generator/sink-models + * @tags model-generator */ private import internal.CaptureModels diff --git a/java/ql/src/utils/model-generator/CaptureSourceModels.ql b/java/ql/src/utils/model-generator/CaptureSourceModels.ql index 49e9cb34990..d37cf5e78fb 100644 --- a/java/ql/src/utils/model-generator/CaptureSourceModels.ql +++ b/java/ql/src/utils/model-generator/CaptureSourceModels.ql @@ -1,7 +1,9 @@ /** * @name Capture source models. * @description Finds APIs that act as sources as they expose already known sources. - * @id java/utils/model-generator/sink-models + * @kind diagnostic + * @id java/utils/model-generator/source-models + * @tags model-generator */ private import internal.CaptureModels diff --git a/java/ql/src/utils/model-generator/CaptureSummaryModels.ql b/java/ql/src/utils/model-generator/CaptureSummaryModels.ql index 8f4eab20722..253c3d4ed46 100644 --- a/java/ql/src/utils/model-generator/CaptureSummaryModels.ql +++ b/java/ql/src/utils/model-generator/CaptureSummaryModels.ql @@ -1,7 +1,9 @@ /** * @name Capture summary models. * @description Finds applicable summary models to be used by other queries. + * @kind diagnostic * @id java/utils/model-generator/summary-models + * @tags model-generator */ private import internal.CaptureModels diff --git a/java/ql/test/kotlin/library-tests/clashing-extension-fields/test.expected b/java/ql/test/kotlin/library-tests/clashing-extension-fields/test.expected new file mode 100644 index 00000000000..72fe7124394 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/clashing-extension-fields/test.expected @@ -0,0 +1,9 @@ +| | +| | +| A | +| B | +| get | +| getX | +| invoke | +| x$delegatepackagename$$subpackagename$$A | +| x$delegatepackagename$$subpackagename$$B | diff --git a/java/ql/test/kotlin/library-tests/clashing-extension-fields/test.kt b/java/ql/test/kotlin/library-tests/clashing-extension-fields/test.kt new file mode 100644 index 00000000000..9a7c5d51801 --- /dev/null +++ b/java/ql/test/kotlin/library-tests/clashing-extension-fields/test.kt @@ -0,0 +1,7 @@ +package packagename.subpackagename + +public class A { } +public class B { } + +val A.x : String by lazy { "HelloA" } +val B.x : String by lazy { "HelloB" } diff --git a/java/ql/test/kotlin/library-tests/clashing-extension-fields/test.ql b/java/ql/test/kotlin/library-tests/clashing-extension-fields/test.ql new file mode 100644 index 00000000000..4c0a8d53b1f --- /dev/null +++ b/java/ql/test/kotlin/library-tests/clashing-extension-fields/test.ql @@ -0,0 +1,5 @@ +import java + +from Class c +where c.fromSource() +select c.getAMember().toString() diff --git a/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected b/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected index 4a93ee5df3b..4fdd6b4d718 100644 --- a/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected +++ b/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected @@ -31,7 +31,7 @@ delegatedProperties.kt: # 87| 0: [MethodAccess] getValue(...) # 87| -2: [TypeAccess] Integer # 87| -1: [TypeAccess] PropertyReferenceDelegatesKt -# 87| 0: [VarAccess] DelegatedPropertiesKt.extDelegated$delegate +# 87| 0: [VarAccess] DelegatedPropertiesKt.extDelegated$delegateMyClass # 87| -1: [TypeAccess] DelegatedPropertiesKt # 1| 1: [ExtensionReceiverAccess] this # 87| 2: [PropertyRefExpr] ...::... @@ -80,7 +80,7 @@ delegatedProperties.kt: # 87| 0: [MethodAccess] setValue(...) # 87| -2: [TypeAccess] Integer # 87| -1: [TypeAccess] PropertyReferenceDelegatesKt -# 87| 0: [VarAccess] DelegatedPropertiesKt.extDelegated$delegate +# 87| 0: [VarAccess] DelegatedPropertiesKt.extDelegated$delegateMyClass # 87| -1: [TypeAccess] DelegatedPropertiesKt # 1| 1: [ExtensionReceiverAccess] this # 87| 2: [PropertyRefExpr] ...::... @@ -118,7 +118,7 @@ delegatedProperties.kt: # 87| 0: [TypeAccess] MyClass # 87| 1: [TypeAccess] Integer # 87| 3: [VarAccess] -# 87| 5: [FieldDeclaration] KMutableProperty0 extDelegated$delegate; +# 87| 5: [FieldDeclaration] KMutableProperty0 extDelegated$delegateMyClass; # 87| -1: [TypeAccess] KMutableProperty0 # 87| 0: [TypeAccess] Integer # 87| 0: [PropertyRefExpr] ...::... diff --git a/java/ql/test/kotlin/library-tests/exprs/delegatedProperties.expected b/java/ql/test/kotlin/library-tests/exprs/delegatedProperties.expected index c60b200a2eb..7141b6d1531 100644 --- a/java/ql/test/kotlin/library-tests/exprs/delegatedProperties.expected +++ b/java/ql/test/kotlin/library-tests/exprs/delegatedProperties.expected @@ -16,7 +16,7 @@ delegatedProperties | delegatedProperties.kt:77:5:77:49 | delegatedToTopLevel | delegatedToTopLevel | non-local | delegatedProperties.kt:77:34:77:49 | delegatedToTopLevel$delegate | delegatedProperties.kt:77:37:77:49 | ...::... | | delegatedProperties.kt:79:5:79:38 | max | max | non-local | delegatedProperties.kt:79:18:79:38 | max$delegate | delegatedProperties.kt:79:21:79:38 | ...::... | | delegatedProperties.kt:82:9:82:54 | delegatedToMember3 | delegatedToMember3 | local | delegatedProperties.kt:82:37:82:54 | KMutableProperty0 delegatedToMember3$delegate | delegatedProperties.kt:82:40:82:54 | ...::... | -| delegatedProperties.kt:87:1:87:46 | extDelegated | extDelegated | non-local | delegatedProperties.kt:87:31:87:46 | extDelegated$delegate | delegatedProperties.kt:87:34:87:46 | ...::... | +| delegatedProperties.kt:87:1:87:46 | extDelegated | extDelegated | non-local | delegatedProperties.kt:87:31:87:46 | extDelegated$delegateMyClass | delegatedProperties.kt:87:34:87:46 | ...::... | delegatedPropertyTypes | delegatedProperties.kt:6:9:9:9 | prop1 | file://:0:0:0:0 | int | file:///Lazy.class:0:0:0:0 | Lazy | | delegatedProperties.kt:19:9:19:51 | varResource1 | file://:0:0:0:0 | int | delegatedProperties.kt:45:1:51:1 | ResourceDelegate | diff --git a/java/ql/test/kotlin/library-tests/exprs/exprs.expected b/java/ql/test/kotlin/library-tests/exprs/exprs.expected index a2a1e3bd941..110d9e47147 100644 --- a/java/ql/test/kotlin/library-tests/exprs/exprs.expected +++ b/java/ql/test/kotlin/library-tests/exprs/exprs.expected @@ -830,9 +830,9 @@ | delegatedProperties.kt:87:31:87:46 | DelegatedPropertiesKt | delegatedProperties.kt:87:31:87:46 | set | TypeAccess | | delegatedProperties.kt:87:31:87:46 | DelegatedPropertiesKt | delegatedProperties.kt:87:31:87:46 | set | TypeAccess | | delegatedProperties.kt:87:31:87:46 | DelegatedPropertiesKt | delegatedProperties.kt:87:31:87:46 | setExtDelegated | TypeAccess | -| delegatedProperties.kt:87:31:87:46 | DelegatedPropertiesKt.extDelegated$delegate | delegatedProperties.kt:0:0:0:0 | | VarAccess | -| delegatedProperties.kt:87:31:87:46 | DelegatedPropertiesKt.extDelegated$delegate | delegatedProperties.kt:87:31:87:46 | getExtDelegated | VarAccess | -| delegatedProperties.kt:87:31:87:46 | DelegatedPropertiesKt.extDelegated$delegate | delegatedProperties.kt:87:31:87:46 | setExtDelegated | VarAccess | +| delegatedProperties.kt:87:31:87:46 | DelegatedPropertiesKt.extDelegated$delegateMyClass | delegatedProperties.kt:0:0:0:0 | | VarAccess | +| delegatedProperties.kt:87:31:87:46 | DelegatedPropertiesKt.extDelegated$delegateMyClass | delegatedProperties.kt:87:31:87:46 | getExtDelegated | VarAccess | +| delegatedProperties.kt:87:31:87:46 | DelegatedPropertiesKt.extDelegated$delegateMyClass | delegatedProperties.kt:87:31:87:46 | setExtDelegated | VarAccess | | delegatedProperties.kt:87:31:87:46 | Integer | delegatedProperties.kt:87:31:87:46 | getExtDelegated | TypeAccess | | delegatedProperties.kt:87:31:87:46 | Integer | delegatedProperties.kt:87:31:87:46 | setExtDelegated | TypeAccess | | delegatedProperties.kt:87:31:87:46 | Integer | file://:0:0:0:0 | | TypeAccess | diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index 3053bcef1bf..6898986e749 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "4.6.2" + "typescript": "4.7.2" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index f7d0c40fed8..3a10c8452f0 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -6,7 +6,7 @@ version "12.7.11" resolved node-12.7.11.tgz#be879b52031cfb5d295b047f5462d8ef1a716446 -typescript@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" - integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== +typescript@4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.2.tgz#1f9aa2ceb9af87cca227813b4310fff0b51593c4" + integrity sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A== diff --git a/javascript/extractor/src/com/semmle/js/dependencies/Fetcher.java b/javascript/extractor/src/com/semmle/js/dependencies/Fetcher.java index fa996f1b34e..d094f05653d 100644 --- a/javascript/extractor/src/com/semmle/js/dependencies/Fetcher.java +++ b/javascript/extractor/src/com/semmle/js/dependencies/Fetcher.java @@ -141,8 +141,9 @@ public class Fetcher { entryPath = entryPath.subpath(1, entryPath.getNameCount()); String filename = entryPath.getFileName().toString(); - if (!filename.endsWith(".d.ts") && !filename.equals("package.json")) { - continue; // Only extract .d.ts files and package.json + if (!filename.endsWith(".d.ts") && !filename.endsWith(".d.mts") && !filename.endsWith(".d.cts") + && !filename.equals("package.json")) { + continue; // Only extract .d.ts, .d.mts, .d.cts files, and package.json } relativePaths.add(entryPath); Path outputFile = destDir.resolve(entryPath); diff --git a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java index 1e9b7d6ad84..bc30d83690d 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java @@ -203,7 +203,7 @@ public class FileExtractor { } }, - TYPESCRIPT(".ts", ".tsx") { + TYPESCRIPT(".ts", ".tsx", ".mts", ".cts") { @Override protected boolean contains(File f, String lcExt, ExtractorConfig config) { if (config.getTypeScriptMode() == TypeScriptMode.NONE) return false; diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 5b425ab8af9..e5196ae1181 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -43,7 +43,7 @@ public class Main { * A version identifier that should be updated every time the extractor changes in such a way that * it may produce different tuples for the same file under the same {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2022-02-22"; + public static final String EXTRACTOR_VERSION = "2022-05-24"; public static final Pattern NEWLINE = Pattern.compile("\n"); diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll index ca7f12b7a33..f146f569684 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/experimental/adaptivethreatmodeling/EndpointFeatures.qll @@ -144,9 +144,9 @@ private module AccessPaths { not param = base.getReceiver() | result = param and - name = param.getAnImmediateUse().asExpr().(Parameter).getName() + name = param.asSource().asExpr().(Parameter).getName() or - param.getAnImmediateUse().asExpr() instanceof DestructuringPattern and + param.asSource().asExpr() instanceof DestructuringPattern and result = param.getMember(name) ) } diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml index 9e154c1b7d9..64406dd8eeb 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-experimental-atm-lib -version: 0.2.1 +version: 0.3.1 extractor: javascript library: true groups: diff --git a/javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml index 89ae6183055..4cf8ca1dbef 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/model/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/javascript-experimental-atm-model -version: 0.1.1 +version: 0.2.1 groups: - javascript - experimental diff --git a/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/codeql-pack.lock.yml b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/codeql-pack.lock.yml index 304d32a3b4f..9486bf8ef42 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/codeql-pack.lock.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/codeql-pack.lock.yml @@ -1,6 +1,6 @@ --- dependencies: codeql/javascript-experimental-atm-model: - version: 0.1.0 + version: 0.2.0 compiled: false lockVersion: 1.0.0 diff --git a/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml index d12e0b4ab75..bb195f22f90 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/qlpack.yml @@ -6,4 +6,4 @@ groups: - experimental dependencies: codeql/javascript-experimental-atm-lib: "*" - codeql/javascript-experimental-atm-model: "0.1.0" + codeql/javascript-experimental-atm-model: "0.2.0" diff --git a/javascript/ql/experimental/adaptivethreatmodeling/src/codeql-pack.lock.yml b/javascript/ql/experimental/adaptivethreatmodeling/src/codeql-pack.lock.yml index 304d32a3b4f..9486bf8ef42 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/src/codeql-pack.lock.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/src/codeql-pack.lock.yml @@ -1,6 +1,6 @@ --- dependencies: codeql/javascript-experimental-atm-model: - version: 0.1.0 + version: 0.2.0 compiled: false lockVersion: 1.0.0 diff --git a/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml index c3fb23e887b..e344fc6f98d 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml @@ -1,6 +1,6 @@ name: codeql/javascript-experimental-atm-queries language: javascript -version: 0.2.1 +version: 0.3.1 suites: codeql-suites defaultSuiteFile: codeql-suites/javascript-atm-code-scanning.qls groups: @@ -8,4 +8,4 @@ groups: - experimental dependencies: codeql/javascript-experimental-atm-lib: "*" - codeql/javascript-experimental-atm-model: "0.1.0" + codeql/javascript-experimental-atm-model: "0.2.0" diff --git a/javascript/ql/experimental/adaptivethreatmodeling/test/codeql-pack.lock.yml b/javascript/ql/experimental/adaptivethreatmodeling/test/codeql-pack.lock.yml index 304d32a3b4f..9486bf8ef42 100644 --- a/javascript/ql/experimental/adaptivethreatmodeling/test/codeql-pack.lock.yml +++ b/javascript/ql/experimental/adaptivethreatmodeling/test/codeql-pack.lock.yml @@ -1,6 +1,6 @@ --- dependencies: codeql/javascript-experimental-atm-model: - version: 0.1.0 + version: 0.2.0 compiled: false lockVersion: 1.0.0 diff --git a/javascript/ql/lib/change-notes/2022-05-24-ecmascript-2022.md b/javascript/ql/lib/change-notes/2022-05-24-ecmascript-2022.md new file mode 100644 index 00000000000..389b7c9044b --- /dev/null +++ b/javascript/ql/lib/change-notes/2022-05-24-ecmascript-2022.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* All new ECMAScript 2022 features are now supported. diff --git a/javascript/ql/lib/change-notes/2022-05-24-typescript-4-7.md b/javascript/ql/lib/change-notes/2022-05-24-typescript-4-7.md new file mode 100644 index 00000000000..16fe46c675f --- /dev/null +++ b/javascript/ql/lib/change-notes/2022-05-24-typescript-4-7.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* Added support for TypeScript 4.7. diff --git a/javascript/ql/lib/semmle/javascript/ApiGraphs.qll b/javascript/ql/lib/semmle/javascript/ApiGraphs.qll index 51101e3182a..205ff21d1fd 100644 --- a/javascript/ql/lib/semmle/javascript/ApiGraphs.qll +++ b/javascript/ql/lib/semmle/javascript/ApiGraphs.qll @@ -2,11 +2,7 @@ * Provides an implementation of _API graphs_, which are an abstract representation of the API * surface used and/or defined by a code base. * - * The nodes of the API graph represent definitions and uses of API components. The edges are - * directed and labeled; they specify how the components represented by nodes relate to each other. - * For example, if one of the nodes represents a definition of an API function, then there - * will be nodes corresponding to the function's parameters, which are connected to the function - * node by edges labeled `parameter `. + * See `API::Node` for more in-depth documentation. */ import javascript @@ -14,50 +10,159 @@ private import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps private import internal.CachedStages /** - * Provides classes and predicates for working with APIs defined or used in a database. + * Provides classes and predicates for working with the API boundary between the current + * codebase and external libraries. + * + * See `API::Node` for more in-depth documentation. */ module API { /** - * An abstract representation of a definition or use of an API component such as a function - * exported by an npm package, a parameter of such a function, or its result. + * A node in the API graph, representing a value that has crossed the boundary between this + * codebase and an external library (or in general, any external codebase). + * + * ### Basic usage + * + * API graphs are typically used to identify "API calls", that is, calls to an external function + * whose implementation is not necessarily part of the current codebase. + * + * The most basic use of API graphs is typically as follows: + * 1. Start with `API::moduleImport` for the relevant library. + * 2. Follow up with a chain of accessors such as `getMember` describing how to get to the relevant API function. + * 3. Map the resulting API graph nodes to data-flow nodes, using `asSource` or `asSink`. + * + * For example, a simplified way to get arguments to `underscore.extend` would be + * ```ql + * API::moduleImport("underscore").getMember("extend").getParameter(0).asSink() + * ``` + * + * The most commonly used accessors are `getMember`, `getParameter`, and `getReturn`. + * + * ### API graph nodes + * + * There are two kinds of nodes in the API graphs, distinguished by who is "holding" the value: + * - **Use-nodes** represent values held by the current codebase, which came from an external library. + * (The current codebase is "using" a value that came from the library). + * - **Def-nodes** represent values held by the external library, which came from this codebase. + * (The current codebase "defines" the value seen by the library). + * + * API graph nodes are associated with data-flow nodes in the current codebase. + * (Since external libraries are not part of the database, there is no way to associate with concrete + * data-flow nodes from the external library). + * - **Use-nodes** are associated with data-flow nodes where a value enters the current codebase, + * such as the return value of a call to an external function. + * - **Def-nodes** are associated with data-flow nodes where a value leaves the current codebase, + * such as an argument passed in a call to an external function. + * + * + * ### Access paths and edge labels + * + * Nodes in the API graph are associated with a set of access paths, describing a series of operations + * that may be performed to obtain that value. + * + * For example, the access path `API::moduleImport("lodash").getMember("extend")` represents the action of + * importing `lodash` and then accessing the member `extend` on the resulting object. + * It would be associated with an expression such as `require("lodash").extend`. + * + * Each edge in the graph is labelled by such an "operation". For an edge `A->B`, the type of the `A` node + * determines who is performing the operation, and the type of the `B` node determines who ends up holding + * the result: + * - An edge starting from a use-node describes what the current codebase is doing to a value that + * came from a library. + * - An edge starting from a def-node describes what the external library might do to a value that + * came from the current codebase. + * - An edge ending in a use-node means the result ends up in the current codebase (at its associated data-flow node). + * - An edge ending in a def-node means the result ends up in external code (its associated data-flow node is + * the place where it was "last seen" in the current codebase before flowing out) + * + * Because the implementation of the external library is not visible, it is not known exactly what operations + * it will perform on values that flow there. Instead, the edges starting from a def-node are operations that would + * lead to an observable effect within the current codebase; without knowing for certain if the library will actually perform + * those operations. (When constructing these edges, we assume the library is somewhat well-behaved). + * + * For example, given this snippet: + * ```js + * require('foo')(x => { doSomething(x) }) + * ``` + * A callback is passed to the external function `foo`. We can't know if `foo` will actually invoke this callback. + * But _if_ the library should decide to invoke the callback, then a value will flow into the current codebase via the `x` parameter. + * For that reason, an edge is generated representing the argument-passing operation that might be performed by `foo`. + * This edge is going from the def-node associated with the callback to the use-node associated with the parameter `x`. + * + * ### Thinking in operations versus code patterns + * + * Treating edges as "operations" helps avoid a pitfall in which library models become overly specific to certain code patterns. + * Consider the following two equivalent calls to `foo`: + * ```js + * const foo = require('foo'); + * + * foo({ + * myMethod(x) {...} + * }); + * + * foo({ + * get myMethod() { + * return function(x) {...} + * } + * }); + * ``` + * If `foo` calls `myMethod` on its first parameter, either of the `myMethod` implementations will be invoked. + * And indeed, the access path `API::moduleImport("foo").getParameter(0).getMember("myMethod").getParameter(0)` correctly + * identifies both `x` parameters. + * + * Observe how `getMember("myMethod")` behaves when the member is defined via a getter. When thinking in code patterns, + * it might seem obvious that `getMember` should have obtained a reference to the getter method itself. + * But when seeing it as an access to `myMethod` performed by the library, we can deduce that the relevant expression + * on the client side is actually the return-value of the getter. + * + * Although one may think of API graphs as a tool to find certain program elements in the codebase, + * it can lead to some situations where intuition does not match what works best in practice. */ class Node extends Impl::TApiNode { /** - * Gets a data-flow node corresponding to a use of the API component represented by this node. + * Get a data-flow node where this value may flow after entering the current codebase. * - * For example, `require('fs').readFileSync` is a use of the function `readFileSync` from the - * `fs` module, and `require('fs').readFileSync(file)` is a use of the return of that function. - * - * This includes indirect uses found via data flow, meaning that in - * `f(obj.foo); function f(x) {};` both `obj.foo` and `x` are uses of the `foo` member from `obj`. - * - * As another example, in the assignment `exports.plusOne = (x) => x+1` the two references to - * `x` are uses of the first parameter of `plusOne`. + * This is similar to `asSource()` but additionally includes nodes that are transitively reachable by data flow. + * See `asSource()` for examples. */ pragma[inline] - DataFlow::Node getAUse() { - exists(DataFlow::SourceNode src | Impl::use(this, src) | - Impl::trackUseNode(src).flowsTo(result) - ) + DataFlow::Node getAValueReachableFromSource() { + Impl::trackUseNode(this.asSource()).flowsTo(result) } /** - * Gets an immediate use of the API component represented by this node. + * Get a data-flow node where this value enters the current codebase. * - * For example, `require('fs').readFileSync` is a an immediate use of the `readFileSync` member - * from the `fs` module. + * For example: + * ```js + * // API::moduleImport("fs").asSource() + * require('fs'); * - * Unlike `getAUse()`, this predicate only gets the immediate references, not the indirect uses - * found via data flow. This means that in `const x = fs.readFile` only `fs.readFile` is a reference - * to the `readFile` member of `fs`, neither `x` nor any node that `x` flows to is a reference to - * this API component. + * // API::moduleImport("fs").getMember("readFile").asSource() + * require('fs').readFile; + * + * // API::moduleImport("fs").getMember("readFile").getReturn().asSource() + * require('fs').readFile(); + * + * require('fs').readFile( + * filename, + * // 'y' matched by API::moduleImport("fs").getMember("readFile").getParameter(1).getParameter(0).asSource() + * y => { + * ... + * }); + * ``` */ - DataFlow::SourceNode getAnImmediateUse() { Impl::use(this, result) } + DataFlow::SourceNode asSource() { Impl::use(this, result) } + + /** DEPRECATED. This predicate has been renamed to `asSource`. */ + deprecated DataFlow::SourceNode getAnImmediateUse() { result = this.asSource() } + + /** DEPRECATED. This predicate has been renamed to `getAValueReachableFromSource`. */ + deprecated DataFlow::Node getAUse() { result = this.getAValueReachableFromSource() } /** * Gets a call to the function represented by this API component. */ - CallNode getACall() { result = this.getReturn().getAnImmediateUse() } + CallNode getACall() { result = this.getReturn().asSource() } /** * Gets a call to the function represented by this API component, @@ -72,7 +177,7 @@ module API { /** * Gets a `new` call to the function represented by this API component. */ - NewNode getAnInstantiation() { result = this.getInstance().getAnImmediateUse() } + NewNode getAnInstantiation() { result = this.getInstance().asSource() } /** * Gets an invocation (with our without `new`) to the function represented by this API component. @@ -80,26 +185,38 @@ module API { InvokeNode getAnInvocation() { result = this.getACall() or result = this.getAnInstantiation() } /** - * Gets a data-flow node corresponding to the right-hand side of a definition of the API - * component represented by this node. + * Get a data-flow node where this value leaves the current codebase and flows into an + * external library (or in general, any external codebase). * - * For example, in the assignment `exports.plusOne = (x) => x+1`, the function expression - * `(x) => x+1` is the right-hand side of the definition of the member `plusOne` of - * the enclosing module, and the expression `x+1` is the right-had side of the definition of - * its result. + * Concretely, this is either an argument passed to a call to external code, + * or the right-hand side of a property write on an object flowing into such a call. * - * Note that for parameters, it is the arguments flowing into that parameter that count as - * right-hand sides of the definition, not the declaration of the parameter itself. - * Consequently, in `require('fs').readFileSync(file)`, `file` is the right-hand - * side of a definition of the first parameter of `readFileSync` from the `fs` module. + * For example: + * ```js + * // 'x' is matched by API::moduleImport("foo").getParameter(0).asSink() + * require('foo')(x); + * + * // 'x' is matched by API::moduleImport("foo").getParameter(0).getMember("prop").asSink() + * require('foo')({ + * prop: x + * }); + * ``` */ - DataFlow::Node getARhs() { Impl::rhs(this, result) } + DataFlow::Node asSink() { Impl::rhs(this, result) } /** - * Gets a data-flow node that may interprocedurally flow to the right-hand side of a definition - * of the API component represented by this node. + * Get a data-flow node that transitively flows to an external library (or in general, any external codebase). + * + * This is similar to `asSink()` but additionally includes nodes that transitively reach a sink by data flow. + * See `asSink()` for examples. */ - DataFlow::Node getAValueReachingRhs() { result = Impl::trackDefNode(this.getARhs()) } + DataFlow::Node getAValueReachingSink() { result = Impl::trackDefNode(this.asSink()) } + + /** DEPRECATED. This predicate has been renamed to `asSink`. */ + deprecated DataFlow::Node getARhs() { result = this.asSink() } + + /** DEPRECATED. This predicate has been renamed to `getAValueReachingSink`. */ + deprecated DataFlow::Node getAValueReachingRhs() { result = this.getAValueReachingSink() } /** * Gets a node representing member `m` of this API component. @@ -334,7 +451,7 @@ module API { * In other words, the value of a use of `that` may flow into the right-hand side of a * definition of this node. */ - predicate refersTo(Node that) { this.getARhs() = that.getAUse() } + predicate refersTo(Node that) { this.asSink() = that.getAValueReachableFromSource() } /** * Gets the data-flow node that gives rise to this node, if any. @@ -445,11 +562,17 @@ module API { bindingset[this] EntryPoint() { any() } - /** Gets a data-flow node that uses this entry point. */ - abstract DataFlow::SourceNode getAUse(); + /** DEPRECATED. This predicate has been renamed to `getASource`. */ + deprecated DataFlow::SourceNode getAUse() { none() } - /** Gets a data-flow node that defines this entry point. */ - abstract DataFlow::Node getARhs(); + /** DEPRECATED. This predicate has been renamed to `getASink`. */ + deprecated DataFlow::SourceNode getARhs() { none() } + + /** Gets a data-flow node where a value enters the current codebase through this entry-point. */ + DataFlow::SourceNode getASource() { none() } + + /** Gets a data-flow node where a value leaves the current codebase through this entry-point. */ + DataFlow::Node getASink() { none() } /** Gets an API-node for this entry point. */ API::Node getANode() { result = root().getASuccessor(Label::entryPoint(this)) } @@ -567,7 +690,7 @@ module API { base = MkRoot() and exists(EntryPoint e | lbl = Label::entryPoint(e) and - rhs = e.getARhs() + rhs = e.getASink() ) or exists(string m, string prop | @@ -744,7 +867,7 @@ module API { base = MkRoot() and exists(EntryPoint e | lbl = Label::entryPoint(e) and - ref = e.getAUse() + ref = e.getASource() ) or // property reads @@ -1178,8 +1301,8 @@ module API { API::Node callee; InvokeNode() { - this = callee.getReturn().getAnImmediateUse() or - this = callee.getInstance().getAnImmediateUse() or + this = callee.getReturn().asSource() or + this = callee.getInstance().asSource() or this = Impl::getAPromisifiedInvocation(callee, _, _) } @@ -1194,7 +1317,7 @@ module API { * Gets an API node where a RHS of the node is the `i`th argument to this call. */ pragma[noinline] - private Node getAParameterCandidate(int i) { result.getARhs() = this.getArgument(i) } + private Node getAParameterCandidate(int i) { result.asSink() = this.getArgument(i) } /** Gets the API node for a parameter of this invocation. */ Node getAParameter() { result = this.getParameter(_) } @@ -1205,13 +1328,13 @@ module API { /** Gets the API node for the return value of this call. */ Node getReturn() { result = callee.getReturn() and - result.getAnImmediateUse() = this + result.asSource() = this } /** Gets the API node for the object constructed by this invocation. */ Node getInstance() { result = callee.getInstance() and - result.getAnImmediateUse() = this + result.asSource() = this } } diff --git a/javascript/ql/lib/semmle/javascript/Arrays.qll b/javascript/ql/lib/semmle/javascript/Arrays.qll index 0433b1b5681..c129e9a31b2 100644 --- a/javascript/ql/lib/semmle/javascript/Arrays.qll +++ b/javascript/ql/lib/semmle/javascript/Arrays.qll @@ -75,7 +75,7 @@ module ArrayTaintTracking { succ.(DataFlow::SourceNode).getAMethodCall("splice") = call or // `e = array.pop()`, `e = array.shift()`, or similar: if `array` is tainted, then so is `e`. - call.(DataFlow::MethodCallNode).calls(pred, ["pop", "shift", "slice", "splice"]) and + call.(DataFlow::MethodCallNode).calls(pred, ["pop", "shift", "slice", "splice", "at"]) and succ = call or // `e = Array.from(x)`: if `x` is tainted, then so is `e`. @@ -199,13 +199,13 @@ private module ArrayDataFlow { } /** - * A step for retrieving an element from an array using `.pop()` or `.shift()`. + * A step for retrieving an element from an array using `.pop()`, `.shift()`, or `.at()`. * E.g. `array.pop()`. */ private class ArrayPopStep extends DataFlow::SharedFlowStep { override predicate loadStep(DataFlow::Node obj, DataFlow::Node element, string prop) { exists(DataFlow::MethodCallNode call | - call.getMethodName() = ["pop", "shift"] and + call.getMethodName() = ["pop", "shift", "at"] and prop = arrayElement() and obj = call.getReceiver() and element = call diff --git a/javascript/ql/lib/semmle/javascript/JsonParsers.qll b/javascript/ql/lib/semmle/javascript/JsonParsers.qll index 35a227c3ad8..e3f1f285a21 100644 --- a/javascript/ql/lib/semmle/javascript/JsonParsers.qll +++ b/javascript/ql/lib/semmle/javascript/JsonParsers.qll @@ -29,7 +29,7 @@ private class PlainJsonParserCall extends JsonParserCall { callee = DataFlow::moduleMember(["json3", "json5", "flatted", "teleport-javascript", "json-cycle"], "parse") or - callee = API::moduleImport("replicator").getInstance().getMember("decode").getAnImmediateUse() or + callee = API::moduleImport("replicator").getInstance().getMember("decode").asSource() or callee = DataFlow::moduleImport("parse-json") or callee = DataFlow::moduleImport("json-parse-better-errors") or callee = DataFlow::moduleImport("json-safe-parse") or diff --git a/javascript/ql/lib/semmle/javascript/JsonSchema.qll b/javascript/ql/lib/semmle/javascript/JsonSchema.qll index bf45bcdd7b4..a298abfd2dd 100644 --- a/javascript/ql/lib/semmle/javascript/JsonSchema.qll +++ b/javascript/ql/lib/semmle/javascript/JsonSchema.qll @@ -134,7 +134,7 @@ module JsonSchema { .ref() .getMember(["addSchema", "validate", "compile", "compileAsync"]) .getParameter(0) - .getARhs() + .asSink() } } } @@ -184,7 +184,7 @@ module JsonSchema { override boolean getPolarity() { none() } override DataFlow::Node getAValidationResultAccess(boolean polarity) { - result = this.getReturn().getMember("error").getAnImmediateUse() and + result = this.getReturn().getMember("error").asSource() and polarity = false } } diff --git a/javascript/ql/lib/semmle/javascript/JsonStringifiers.qll b/javascript/ql/lib/semmle/javascript/JsonStringifiers.qll index 03ca152471f..f4cdda89e31 100644 --- a/javascript/ql/lib/semmle/javascript/JsonStringifiers.qll +++ b/javascript/ql/lib/semmle/javascript/JsonStringifiers.qll @@ -14,7 +14,7 @@ class JsonStringifyCall extends DataFlow::CallNode { callee = DataFlow::moduleMember(["json3", "json5", "flatted", "teleport-javascript", "json-cycle"], "stringify") or - callee = API::moduleImport("replicator").getInstance().getMember("encode").getAnImmediateUse() or + callee = API::moduleImport("replicator").getInstance().getMember("encode").asSource() or callee = DataFlow::moduleImport([ "json-stringify-safe", "json-stable-stringify", "stringify-object", diff --git a/javascript/ql/lib/semmle/javascript/MembershipCandidates.qll b/javascript/ql/lib/semmle/javascript/MembershipCandidates.qll index 6c51b487f43..607c55c9d02 100644 --- a/javascript/ql/lib/semmle/javascript/MembershipCandidates.qll +++ b/javascript/ql/lib/semmle/javascript/MembershipCandidates.qll @@ -229,10 +229,10 @@ module MembershipCandidate { membersNode = inExpr.getRightOperand() ) or - exists(MethodCallExpr hasOwn | - this = hasOwn.getArgument(0).flow() and - test = hasOwn and - hasOwn.calls(membersNode, "hasOwnProperty") + exists(HasOwnPropertyCall hasOwn | + this = hasOwn.getProperty() and + test = hasOwn.asExpr() and + membersNode = hasOwn.getObject().asExpr() ) } diff --git a/javascript/ql/lib/semmle/javascript/StandardLibrary.qll b/javascript/ql/lib/semmle/javascript/StandardLibrary.qll index d99cd0e7e0d..9366c76d9cc 100644 --- a/javascript/ql/lib/semmle/javascript/StandardLibrary.qll +++ b/javascript/ql/lib/semmle/javascript/StandardLibrary.qll @@ -192,3 +192,35 @@ class StringSplitCall extends DataFlow::MethodCallNode { bindingset[i] DataFlow::Node getASubstringRead(int i) { result = this.getAPropertyRead(i.toString()) } } + +/** + * A call to `Object.prototype.hasOwnProperty`, `Object.hasOwn`, or a library that implements + * the same functionality. + */ +class HasOwnPropertyCall extends DataFlow::Node instanceof DataFlow::CallNode { + DataFlow::Node object; + DataFlow::Node property; + + HasOwnPropertyCall() { + // Make sure we handle reflective calls since libraries love to do that. + super.getCalleeNode().getALocalSource().(DataFlow::PropRead).getPropertyName() = + "hasOwnProperty" and + object = super.getReceiver() and + property = super.getArgument(0) + or + this = + [ + DataFlow::globalVarRef("Object").getAMemberCall("hasOwn"), // + DataFlow::moduleImport("has").getACall(), // + LodashUnderscore::member("has").getACall() + ] and + object = super.getArgument(0) and + property = super.getArgument(1) + } + + /** Gets the object whose property is being checked. */ + DataFlow::Node getObject() { result = object } + + /** Gets the property being checked. */ + DataFlow::Node getProperty() { result = property } +} diff --git a/javascript/ql/lib/semmle/javascript/TypeScript.qll b/javascript/ql/lib/semmle/javascript/TypeScript.qll index 70a1ed98830..2a0ce9464fb 100644 --- a/javascript/ql/lib/semmle/javascript/TypeScript.qll +++ b/javascript/ql/lib/semmle/javascript/TypeScript.qll @@ -1286,6 +1286,8 @@ class ExpressionWithTypeArguments extends @expression_with_type_arguments, Expr override ControlFlowNode getFirstControlFlowNode() { result = this.getExpression().getFirstControlFlowNode() } + + override string getAPrimaryQlClass() { result = "ExpressionWithTypeArguments" } } /** diff --git a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll index dde1c004946..0f82ec2e8e6 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll @@ -1027,18 +1027,16 @@ module TaintTracking { class WhitelistContainmentCallSanitizer extends AdditionalSanitizerGuardNode, DataFlow::MethodCallNode { WhitelistContainmentCallSanitizer() { - exists(string name | - name = "contains" or - name = "has" or - name = "hasOwnProperty" - | - this.getMethodName() = name - ) + this.getMethodName() = ["contains", "has", "hasOwnProperty", "hasOwn"] } override predicate sanitizes(boolean outcome, Expr e) { - outcome = true and - e = this.getArgument(0).asExpr() + exists(int propertyIndex | + if this.getMethodName() = "hasOwn" then propertyIndex = 1 else propertyIndex = 0 + | + outcome = true and + e = this.getArgument(propertyIndex).asExpr() + ) } override predicate appliesTo(Configuration cfg) { any() } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Babel.qll b/javascript/ql/lib/semmle/javascript/frameworks/Babel.qll index 3d061eb2aef..4280862c6e0 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Babel.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Babel.qll @@ -198,7 +198,7 @@ module Babel { .getMember(["transform", "transformSync", "transformAsync"]) .getACall() and pred = call.getArgument(0) and - succ = [call, call.getParameter(2).getParameter(0).getAnImmediateUse()] + succ = [call, call.getParameter(2).getParameter(0).asSource()] ) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Cheerio.qll b/javascript/ql/lib/semmle/javascript/frameworks/Cheerio.qll index 7c8e4a040a4..fdc820861b1 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Cheerio.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Cheerio.qll @@ -14,7 +14,7 @@ module Cheerio { } /** Gets a reference to the `cheerio` function, possibly with a loaded DOM. */ - DataFlow::SourceNode cheerioRef() { result = cheerioApi().getAUse() } + DataFlow::SourceNode cheerioRef() { result = cheerioApi().getAValueReachableFromSource() } /** * A creation of `cheerio` object, a collection of virtual DOM elements diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ClassValidator.qll b/javascript/ql/lib/semmle/javascript/frameworks/ClassValidator.qll index 381451c393c..35f966217bd 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ClassValidator.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ClassValidator.qll @@ -39,7 +39,8 @@ module ClassValidator { /** Holds if the given field has a decorator that sanitizes its value for the purpose of taint tracking. */ predicate isFieldSanitizedByDecorator(FieldDefinition field) { - field.getADecorator().getExpression().flow() = sanitizingDecorator().getReturn().getAUse() + field.getADecorator().getExpression().flow() = + sanitizingDecorator().getReturn().getAValueReachableFromSource() } pragma[noinline] diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll index e86af94463f..8e56a36b9bf 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ClientRequests.qll @@ -265,7 +265,7 @@ module ClientRequest { or responseType = this.getResponseType() and promise = false and - result = this.getReturn().getPromisedError().getMember("response").getAnImmediateUse() + result = this.getReturn().getPromisedError().getMember("response").asSource() } } @@ -463,7 +463,7 @@ module ClientRequest { */ private API::Node netSocketInstantiation(DataFlow::NewNode socket) { result = API::moduleImport("net").getMember("Socket").getInstance() and - socket = result.getAnImmediateUse() + socket = result.asSource() } /** @@ -827,7 +827,7 @@ module ClientRequest { class ApolloClientRequest extends ClientRequest::Range, API::InvokeNode { ApolloClientRequest() { this = apolloUriCallee().getAnInvocation() } - override DataFlow::Node getUrl() { result = this.getParameter(0).getMember("uri").getARhs() } + override DataFlow::Node getUrl() { result = this.getParameter(0).getMember("uri").asSink() } override DataFlow::Node getHost() { none() } @@ -848,10 +848,10 @@ module ClientRequest { override DataFlow::Node getUrl() { result = this.getArgument(0) } - override DataFlow::Node getHost() { result = this.getParameter(0).getMember("host").getARhs() } + override DataFlow::Node getHost() { result = this.getParameter(0).getMember("host").asSink() } override DataFlow::Node getADataNode() { - result = form.getMember("append").getACall().getParameter(1).getARhs() + result = form.getMember("append").getACall().getParameter(1).asSink() } } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Credentials.qll b/javascript/ql/lib/semmle/javascript/frameworks/Credentials.qll index b6892b5aa49..164bc6e8f88 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Credentials.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Credentials.qll @@ -21,7 +21,7 @@ private class CredentialsFromModel extends CredentialsExpr { string kind; CredentialsFromModel() { - this = ModelOutput::getASinkNode("credentials[" + kind + "]").getARhs().asExpr() + this = ModelOutput::getASinkNode("credentials[" + kind + "]").asSink().asExpr() } override string getCredentialsKind() { result = kind } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/D3.qll b/javascript/ql/lib/semmle/javascript/frameworks/D3.qll index 1dda09dedb8..76bdeb1324a 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/D3.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/D3.qll @@ -9,9 +9,7 @@ module D3 { private class D3GlobalEntry extends API::EntryPoint { D3GlobalEntry() { this = "D3GlobalEntry" } - override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("d3") } - - override DataFlow::Node getARhs() { none() } + override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("d3") } } /** Gets an API node referring to the `d3` module. */ @@ -71,18 +69,18 @@ module D3 { D3XssSink() { exists(API::Node htmlArg | htmlArg = d3Selection().getMember("html").getParameter(0) and - this = [htmlArg, htmlArg.getReturn()].getARhs() + this = [htmlArg, htmlArg.getReturn()].asSink() ) } } private class D3DomValueSource extends DOM::DomValueSource::Range { D3DomValueSource() { - this = d3Selection().getMember("each").getReceiver().getAnImmediateUse() + this = d3Selection().getMember("each").getReceiver().asSource() or - this = d3Selection().getMember("node").getReturn().getAnImmediateUse() + this = d3Selection().getMember("node").getReturn().asSource() or - this = d3Selection().getMember("nodes").getReturn().getUnknownMember().getAnImmediateUse() + this = d3Selection().getMember("nodes").getReturn().getUnknownMember().asSource() } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Electron.qll b/javascript/ql/lib/semmle/javascript/frameworks/Electron.qll index 1b3ee3dfea5..038f4b8afb3 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Electron.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Electron.qll @@ -56,13 +56,13 @@ module Electron { } } - private API::Node browserObject() { result.getAnImmediateUse() instanceof NewBrowserObject } + private API::Node browserObject() { result.asSource() instanceof NewBrowserObject } /** * A data flow node whose value may originate from a browser object instantiation. */ private class BrowserObjectByFlow extends BrowserObject { - BrowserObjectByFlow() { browserObject().getAUse() = this } + BrowserObjectByFlow() { browserObject().getAValueReachableFromSource() = this } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Files.qll b/javascript/ql/lib/semmle/javascript/frameworks/Files.qll index 0bad9367b7f..f03f5ee1458 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Files.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Files.qll @@ -89,7 +89,7 @@ private API::Node globbyFileNameSource() { * A file name or an array of file names from the `globby` library. */ private class GlobbyFileNameSource extends FileNameSource { - GlobbyFileNameSource() { this = globbyFileNameSource().getAnImmediateUse() } + GlobbyFileNameSource() { this = globbyFileNameSource().asSource() } } /** Gets a file name or an array of file names from the `fast-glob` library. */ @@ -116,7 +116,7 @@ private API::Node fastGlobFileName() { * A file name or an array of file names from the `fast-glob` library. */ private class FastGlobFileNameSource extends FileNameSource { - FastGlobFileNameSource() { this = fastGlobFileName().getAnImmediateUse() } + FastGlobFileNameSource() { this = fastGlobFileName().asSource() } } /** @@ -200,7 +200,7 @@ private class RecursiveReadDir extends FileSystemAccess, FileNameProducer, API:: override DataFlow::Node getAPathArgument() { result = this.getArgument(0) } - override DataFlow::Node getAFileName() { result = this.trackFileSource().getAnImmediateUse() } + override DataFlow::Node getAFileName() { result = this.trackFileSource().asSource() } private API::Node trackFileSource() { result = this.getParameter([1 .. 2]).getParameter(1) @@ -223,7 +223,7 @@ private module JsonFile { override DataFlow::Node getAPathArgument() { result = this.getArgument(0) } - override DataFlow::Node getADataNode() { result = this.trackRead().getAnImmediateUse() } + override DataFlow::Node getADataNode() { result = this.trackRead().asSource() } private API::Node trackRead() { this.getCalleeName() = "readFile" and @@ -272,7 +272,7 @@ private class LoadJsonFile extends FileSystemReadAccess, API::CallNode { override DataFlow::Node getAPathArgument() { result = this.getArgument(0) } - override DataFlow::Node getADataNode() { result = this.trackRead().getAnImmediateUse() } + override DataFlow::Node getADataNode() { result = this.trackRead().asSource() } private API::Node trackRead() { this.getCalleeName() = "sync" and result = this.getReturn() @@ -310,7 +310,7 @@ private class WalkDir extends FileNameProducer, FileSystemAccess, API::CallNode override DataFlow::Node getAPathArgument() { result = this.getArgument(0) } - override DataFlow::Node getAFileName() { result = this.trackFileSource().getAnImmediateUse() } + override DataFlow::Node getAFileName() { result = this.trackFileSource().asSource() } private API::Node trackFileSource() { not this.getCalleeName() = ["sync", "async"] and diff --git a/javascript/ql/lib/semmle/javascript/frameworks/FormParsers.qll b/javascript/ql/lib/semmle/javascript/frameworks/FormParsers.qll index c5fa208406f..26e0d4fe94f 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/FormParsers.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/FormParsers.qll @@ -15,7 +15,7 @@ private class BusBoyRemoteFlow extends RemoteFlowSource { .getMember("on") .getParameter(1) .getAParameter() - .getAnImmediateUse() + .asSource() } override string getSourceType() { result = "parsed user value from Busbuy" } @@ -49,12 +49,12 @@ private class MultipartyRemoteFlow extends RemoteFlowSource { MultipartyRemoteFlow() { exists(API::Node form | form = API::moduleImport("multiparty").getMember("Form").getInstance() | exists(API::CallNode parse | parse = form.getMember("parse").getACall() | - this = parse.getParameter(1).getAParameter().getAnImmediateUse() + this = parse.getParameter(1).getAParameter().asSource() ) or exists(API::CallNode on | on = form.getMember("on").getACall() | on.getArgument(0).mayHaveStringValue(["part", "file", "field"]) and - this = on.getParameter(1).getAParameter().getAnImmediateUse() + this = on.getParameter(1).getAParameter().asSource() ) ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/History.qll b/javascript/ql/lib/semmle/javascript/frameworks/History.qll index b4535b9bf2b..37c0057f6c1 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/History.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/History.qll @@ -8,9 +8,7 @@ module History { private class HistoryGlobalEntry extends API::EntryPoint { HistoryGlobalEntry() { this = "HistoryLibrary" } - override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("HistoryLibrary") } - - override DataFlow::Node getARhs() { none() } + override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("HistoryLibrary") } } /** @@ -40,11 +38,11 @@ module History { HistoryLibraryRemoteFlow() { exists(API::Node loc | loc = [getBrowserHistory(), getHashHistory()].getMember("location") | - this = loc.getMember("hash").getAnImmediateUse() and kind.isFragment() + this = loc.getMember("hash").asSource() and kind.isFragment() or - this = loc.getMember("pathname").getAnImmediateUse() and kind.isPath() + this = loc.getMember("pathname").asSource() and kind.isPath() or - this = loc.getMember("search").getAnImmediateUse() and kind.isQuery() + this = loc.getMember("search").asSource() and kind.isQuery() ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/HttpProxy.qll b/javascript/ql/lib/semmle/javascript/frameworks/HttpProxy.qll index 2467ca0973b..24e694ca8d9 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/HttpProxy.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/HttpProxy.qll @@ -19,10 +19,10 @@ private module HttpProxy { .getACall() } - override DataFlow::Node getUrl() { result = getParameter(0).getMember("target").getARhs() } + override DataFlow::Node getUrl() { result = getParameter(0).getMember("target").asSink() } override DataFlow::Node getHost() { - result = getParameter(0).getMember("target").getMember("host").getARhs() + result = getParameter(0).getMember("target").getMember("host").asSink() } override DataFlow::Node getADataNode() { none() } @@ -49,10 +49,10 @@ private module HttpProxy { ) } - override DataFlow::Node getUrl() { result = getOptionsObject().getMember("target").getARhs() } + override DataFlow::Node getUrl() { result = getOptionsObject().getMember("target").asSink() } override DataFlow::Node getHost() { - result = getOptionsObject().getMember("target").getMember("host").getARhs() + result = getOptionsObject().getMember("target").getMember("host").asSink() } override DataFlow::Node getADataNode() { none() } @@ -78,8 +78,8 @@ private module HttpProxy { ProxyListenerCallback() { exists(API::CallNode call | call = any(CreateServerCall server).getReturn().getMember(["on", "once"]).getACall() and - call.getParameter(0).getARhs().mayHaveStringValue(event) and - this = call.getParameter(1).getARhs().getAFunctionValue() + call.getParameter(0).asSink().mayHaveStringValue(event) and + this = call.getParameter(1).asSink().getAFunctionValue() ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Immutable.qll b/javascript/ql/lib/semmle/javascript/frameworks/Immutable.qll index 39b0ea201bb..3a5ef400801 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Immutable.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Immutable.qll @@ -16,9 +16,7 @@ private module Immutable { private class ImmutableGlobalEntry extends API::EntryPoint { ImmutableGlobalEntry() { this = "ImmutableGlobalEntry" } - override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("Immutable") } - - override DataFlow::Node getARhs() { none() } + override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("Immutable") } } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Knex.qll b/javascript/ql/lib/semmle/javascript/frameworks/Knex.qll index 6f2098f27c9..e768a9feaff 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Knex.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Knex.qll @@ -69,7 +69,7 @@ module Knex { private class KnexDatabaseAwait extends DatabaseAccess, DataFlow::ValueNode { KnexDatabaseAwait() { exists(AwaitExpr enclosingAwait | this = enclosingAwait.flow() | - enclosingAwait.getOperand() = knexObject().getAUse().asExpr() + enclosingAwait.getOperand() = knexObject().getAValueReachableFromSource().asExpr() ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/LdapJS.qll b/javascript/ql/lib/semmle/javascript/frameworks/LdapJS.qll index 853b76afdda..1118f05b506 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/LdapJS.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/LdapJS.qll @@ -61,10 +61,10 @@ module LdapJS { SearchFilter() { options = ldapClient().getMember("search").getACall().getParameter(1) and - this = options.getARhs() + this = options.asSink() } - override DataFlow::Node getInput() { result = options.getMember("filter").getARhs() } + override DataFlow::Node getInput() { result = options.getMember("filter").asSink() } override DataFlow::Node getOutput() { result = this } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll b/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll index aa365680cd2..1d7604e0b0c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/LiveServer.qll @@ -12,7 +12,7 @@ private module LiveServer { class ServerDefinition extends HTTP::Servers::StandardServerDefinition { ServerDefinition() { this = DataFlow::moduleImport("live-server").asExpr() } - API::Node getImportNode() { result.getAnImmediateUse().asExpr() = this } + API::Node getImportNode() { result.asSource().asExpr() = this } } /** @@ -41,7 +41,7 @@ private module LiveServer { override DataFlow::SourceNode getARouteHandler() { exists(DataFlow::SourceNode middleware | - middleware = call.getParameter(0).getMember("middleware").getAValueReachingRhs() + middleware = call.getParameter(0).getMember("middleware").getAValueReachingSink() | result = middleware.getAMemberCall(["push", "unshift"]).getArgument(0).getAFunctionValue() or diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Logging.qll b/javascript/ql/lib/semmle/javascript/frameworks/Logging.qll index aa79a35785b..8f5938f4865 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Logging.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Logging.qll @@ -35,9 +35,7 @@ private module Console { private class ConsoleGlobalEntry extends API::EntryPoint { ConsoleGlobalEntry() { this = "ConsoleGlobalEntry" } - override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("console") } - - override DataFlow::Node getARhs() { none() } + override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("console") } } /** @@ -352,7 +350,7 @@ private module Pino { // `pino` is installed as the "log" property on the request object in `Express` and similar libraries. // in `Hapi` the property is "logger". exists(HTTP::RequestExpr req, API::Node reqNode | - reqNode.getAnImmediateUse() = req.flow().getALocalSource() and + reqNode.asSource() = req.flow().getALocalSource() and result = reqNode.getMember(["log", "logger"]) ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll b/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll index d131c70773a..492ab0cbcec 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Markdown.qll @@ -163,14 +163,14 @@ module Markdown { or call = API::moduleImport("markdown-it").getMember("Markdown").getAnInvocation() | - call.getParameter(0).getMember("html").getARhs().mayHaveBooleanValue(true) and + call.getParameter(0).getMember("html").asSink().mayHaveBooleanValue(true) and result = call.getReturn() ) or exists(API::CallNode call | call = markdownIt().getMember(["use", "set", "configure", "enable", "disable"]).getACall() and result = call.getReturn() and - not call.getParameter(0).getAValueReachingRhs() = + not call.getParameter(0).getAValueReachingSink() = DataFlow::moduleImport("markdown-it-sanitizer") ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll index bc2bf109fdf..1799f35beb8 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Nest.qll @@ -140,11 +140,9 @@ module NestJS { private class ValidationNodeEntry extends API::EntryPoint { ValidationNodeEntry() { this = "ValidationNodeEntry" } - override DataFlow::SourceNode getAUse() { + override DataFlow::SourceNode getASource() { result.(DataFlow::ClassNode).getName() = "ValidationPipe" } - - override DataFlow::Node getARhs() { none() } } /** Gets an API node referring to the constructor of `ValidationPipe` */ @@ -181,7 +179,7 @@ module NestJS { predicate hasGlobalValidationPipe(Folder folder) { exists(DataFlow::CallNode call | call.getCalleeName() = "useGlobalPipes" and - call.getArgument(0) = validationPipe().getInstance().getAUse() and + call.getArgument(0) = validationPipe().getInstance().getAValueReachableFromSource() and folder = call.getFile().getParentContainer() ) or @@ -193,7 +191,7 @@ module NestJS { .getAMember() .getMember("useFactory") .getReturn() - .getARhs() = validationPipe().getInstance().getAUse() and + .asSink() = validationPipe().getInstance().getAValueReachableFromSource() and folder = decorator.getFile().getParentContainer() ) or @@ -204,7 +202,7 @@ module NestJS { * Holds if `param` is affected by a pipe that sanitizes inputs. */ private predicate hasSanitizingPipe(NestJSRequestInput param, boolean dependsOnType) { - param.getAPipe() = sanitizingPipe(dependsOnType).getAUse() + param.getAPipe() = sanitizingPipe(dependsOnType).getAValueReachableFromSource() or hasGlobalValidationPipe(param.getFile().getParentContainer()) and dependsOnType = true @@ -395,11 +393,11 @@ module NestJS { /** Gets a parameter with this decorator applied. */ DataFlow::ParameterNode getADecoratedParameter() { - result.getADecorator() = getReturn().getReturn().getAUse() + result.getADecorator() = getReturn().getReturn().getAValueReachableFromSource() } /** Gets a value returned by the decorator's callback, which becomes the value of the decorated parameter. */ - DataFlow::Node getResult() { result = getParameter(0).getReturn().getARhs() } + DataFlow::Node getResult() { result = getParameter(0).getReturn().asSink() } } /** @@ -427,7 +425,7 @@ module NestJS { private class ExpressRequestSource extends Express::RequestSource { ExpressRequestSource() { this.(DataFlow::ParameterNode).getADecorator() = - nestjs().getMember(["Req", "Request"]).getReturn().getAnImmediateUse() + nestjs().getMember(["Req", "Request"]).getReturn().asSource() or this = executionContext() @@ -435,7 +433,7 @@ module NestJS { .getReturn() .getMember("getRequest") .getReturn() - .getAnImmediateUse() + .asSource() } /** @@ -452,7 +450,7 @@ module NestJS { private class ExpressResponseSource extends Express::ResponseSource { ExpressResponseSource() { this.(DataFlow::ParameterNode).getADecorator() = - nestjs().getMember(["Res", "Response"]).getReturn().getAnImmediateUse() + nestjs().getMember(["Res", "Response"]).getReturn().asSource() } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Next.qll b/javascript/ql/lib/semmle/javascript/frameworks/Next.qll index 644754ce75e..091aa8ba1af 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Next.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Next.qll @@ -252,6 +252,6 @@ module NextJS { .getParameter(0) .getParameter(0) .getMember("router") - .getAnImmediateUse() + .asSource() } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll b/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll index b04467a93ec..0d2da4b10bb 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NoSQL.qll @@ -20,7 +20,7 @@ deprecated module NoSQL = NoSql; * Gets a value that has been assigned to the "$where" property of an object that flows to `queryArg`. */ private DataFlow::Node getADollarWhereProperty(API::Node queryArg) { - result = queryArg.getMember("$where").getARhs() + result = queryArg.getMember("$where").asSink() } /** @@ -418,7 +418,7 @@ private module Mongoose { param = f.getParameter(0).getParameter(1) | exists(DataFlow::MethodCallNode pred | - // limitation: look at the previous method call + // limitation: look at the previous method call Query::MethodSignatures::returnsDocumentQuery(pred.getMethodName(), asArray) and pred.getAMethodCall() = f.getACall() ) @@ -501,7 +501,7 @@ private module Mongoose { Credentials() { exists(string prop | - this = createConnection().getParameter(3).getMember(prop).getARhs().asExpr() + this = createConnection().getParameter(3).getMember(prop).asSink().asExpr() | prop = "user" and kind = "user name" or @@ -518,7 +518,7 @@ private module Mongoose { class MongoDBQueryPart extends NoSql::Query { MongooseFunction f; - MongoDBQueryPart() { this = f.getQueryArgument().getARhs().asExpr() } + MongoDBQueryPart() { this = f.getQueryArgument().asSink().asExpr() } override DataFlow::Node getACodeOperator() { result = getADollarWhereProperty(f.getQueryArgument()) @@ -540,7 +540,7 @@ private module Mongoose { override DataFlow::Node getAQueryArgument() { // NB: the complete information is not easily accessible for deeply chained calls - f.getQueryArgument().getARhs() = result + f.getQueryArgument().asSink() = result } override DataFlow::Node getAResult() { @@ -770,7 +770,7 @@ private module Redis { RedisKeyArgument() { exists(string method, int argIndex | QuerySignatures::argumentIsAmbiguousKey(method, argIndex) and - this = redis().getMember(method).getParameter(argIndex).getARhs().asExpr() + this = redis().getMember(method).getParameter(argIndex).asSink().asExpr() ) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll index 2adc68f907a..75e222730cc 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.qll @@ -739,7 +739,7 @@ module NodeJSLib { methodName = ["execFile", "execFileSync", "spawn", "spawnSync", "fork"] ) and // all of the above methods take the command as their first argument - result = this.getParameter(0).getARhs() + result = this.getParameter(0).asSink() } override DataFlow::Node getACommandArgument() { result = this.getACommandArgument(_) } @@ -751,7 +751,7 @@ module NodeJSLib { override DataFlow::Node getArgumentList() { methodName = ["execFile", "execFileSync", "fork", "spawn", "spawnSync"] and // all of the above methods take the argument list as their second argument - result = this.getParameter(1).getARhs() + result = this.getParameter(1).asSink() } override predicate isSync() { methodName.matches("%Sync") } @@ -759,7 +759,7 @@ module NodeJSLib { override DataFlow::Node getOptionsArg() { not result.getALocalSource() instanceof DataFlow::FunctionNode and // looks like callback not result.getALocalSource() instanceof DataFlow::ArrayCreationNode and // looks like argumentlist - not result = this.getParameter(0).getARhs() and + not result = this.getParameter(0).asSink() and // fork/spawn and all sync methos always has options as the last argument if methodName.matches("fork%") or @@ -768,7 +768,7 @@ module NodeJSLib { then result = this.getLastArgument() else // the rest (exec/execFile) has the options argument as their second last. - result = this.getParameter(this.getNumArgument() - 2).getARhs() + result = this.getParameter(this.getNumArgument() - 2).asSink() } } @@ -1070,7 +1070,7 @@ module NodeJSLib { */ private class EventEmitterSubClass extends DataFlow::ClassNode { EventEmitterSubClass() { - this.getASuperClassNode() = getAnEventEmitterImport().getAUse() or + this.getASuperClassNode() = getAnEventEmitterImport().getAValueReachableFromSource() or this.getADirectSuperClass() instanceof EventEmitterSubClass } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Prettier.qll b/javascript/ql/lib/semmle/javascript/frameworks/Prettier.qll index ec9e490159e..1277c1ee133 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Prettier.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Prettier.qll @@ -22,7 +22,7 @@ private module Prettier { call = API::moduleImport("prettier").getMember("formatWithCursor").getACall() | pred = call.getArgument(0) and - succ = call.getReturn().getMember("formatted").getAnImmediateUse() + succ = call.getReturn().getMember("formatted").asSource() ) } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Puppeteer.qll b/javascript/ql/lib/semmle/javascript/frameworks/Puppeteer.qll index b7bef025d23..0636b8603b9 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Puppeteer.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Puppeteer.qll @@ -86,7 +86,7 @@ module Puppeteer { this = page().getMember(["addStyleTag", "addScriptTag"]).getACall() } - override DataFlow::Node getUrl() { result = getParameter(0).getMember("url").getARhs() } + override DataFlow::Node getUrl() { result = getParameter(0).getMember("url").asSink() } override DataFlow::Node getHost() { none() } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll b/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll index fae5a1c76d7..67901528f2b 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Redux.qll @@ -58,10 +58,10 @@ module Redux { */ class StoreCreation extends DataFlow::SourceNode instanceof StoreCreation::Range { /** Gets a reference to the store. */ - DataFlow::SourceNode ref() { result = asApiNode().getAUse() } + DataFlow::SourceNode ref() { result = asApiNode().getAValueReachableFromSource() } /** Gets an API node that refers to this store creation. */ - API::Node asApiNode() { result.getAnImmediateUse() = this } + API::Node asApiNode() { result.asSource() = this } /** Gets the data flow node holding the root reducer for this store. */ DataFlow::Node getReducerArg() { result = super.getReducerArg() } @@ -94,7 +94,7 @@ module Redux { } override DataFlow::Node getReducerArg() { - result = getParameter(0).getMember("reducer").getARhs() + result = getParameter(0).getMember("reducer").asSink() } } } @@ -106,7 +106,7 @@ module Redux { private API::Node rootState() { result instanceof RootStateSource or - stateStep(rootState().getAUse(), result.getAnImmediateUse()) + stateStep(rootState().getAValueReachableFromSource(), result.asSource()) } /** @@ -120,7 +120,7 @@ module Redux { accessPath = joinAccessPaths(base, prop) ) or - stateStep(rootStateAccessPath(accessPath).getAUse(), result.getAnImmediateUse()) + stateStep(rootStateAccessPath(accessPath).getAValueReachableFromSource(), result.asSource()) } /** @@ -193,7 +193,7 @@ module Redux { CombineReducers() { this = combineReducers().getACall() } override DataFlow::Node getStateHandlerArg(string prop) { - result = getParameter(0).getMember(prop).getARhs() + result = getParameter(0).getMember(prop).asSink() } } @@ -207,7 +207,7 @@ module Redux { */ private class NestedCombineReducers extends DelegatingReducer, DataFlow::ObjectLiteralNode { NestedCombineReducers() { - this = combineReducers().getParameter(0).getAMember+().getAValueReachingRhs() + this = combineReducers().getParameter(0).getAMember+().getAValueReachingSink() } override DataFlow::Node getStateHandlerArg(string prop) { @@ -235,7 +235,7 @@ module Redux { override DataFlow::Node getActionHandlerArg(DataFlow::Node actionType) { exists(DataFlow::PropWrite write | - result = getParameter(0).getAMember().getARhs() and + result = getParameter(0).getAMember().asSink() and write.getRhs() = result and actionType = write.getPropertyNameExpr().flow() ) @@ -374,7 +374,7 @@ module Redux { CreateSliceReducer() { call = API::moduleImport("@reduxjs/toolkit").getMember("createSlice").getACall() and - this = call.getReturn().getMember("reducer").getAnImmediateUse() + this = call.getReturn().getMember("reducer").asSource() } private API::Node getABuilderRef() { @@ -385,14 +385,14 @@ module Redux { override DataFlow::Node getActionHandlerArg(DataFlow::Node actionType) { exists(string name | - result = call.getParameter(0).getMember("reducers").getMember(name).getARhs() and - actionType = call.getReturn().getMember("actions").getMember(name).getAnImmediateUse() + result = call.getParameter(0).getMember("reducers").getMember(name).asSink() and + actionType = call.getReturn().getMember("actions").getMember(name).asSource() ) or // Properties of 'extraReducers': // { extraReducers: { [action]: reducer }} exists(DataFlow::PropWrite write | - result = call.getParameter(0).getMember("extraReducers").getAMember().getARhs() and + result = call.getParameter(0).getMember("extraReducers").getAMember().asSink() and write.getRhs() = result and actionType = write.getPropertyNameExpr().flow() ) @@ -444,8 +444,8 @@ module Redux { or // x -> bindActionCreators({ x, ... }) exists(BindActionCreatorsCall bind, string prop | - ref(t.continue()).flowsTo(bind.getParameter(0).getMember(prop).getARhs()) and - result = bind.getReturn().getMember(prop).getAnImmediateUse() + ref(t.continue()).flowsTo(bind.getParameter(0).getMember(prop).asSink()) and + result = bind.getReturn().getMember(prop).asSource() ) or // x -> combineActions(x, ...) @@ -580,11 +580,11 @@ module Redux { MultiAction() { createActions = API::moduleImport("redux-actions").getMember("createActions").getACall() and - this = createActions.getReturn().getMember(name).getAnImmediateUse() + this = createActions.getReturn().getMember(name).asSource() } override DataFlow::FunctionNode getMiddlewareFunction(boolean async) { - result.flowsTo(createActions.getParameter(0).getMember(getTypeTag()).getARhs()) and + result.flowsTo(createActions.getParameter(0).getMember(getTypeTag()).asSink()) and async = false } @@ -614,12 +614,12 @@ module Redux { CreateSliceAction() { call = API::moduleImport("@reduxjs/toolkit").getMember("createSlice").getACall() and - this = call.getReturn().getMember("actions").getMember(actionName).getAnImmediateUse() + this = call.getReturn().getMember("actions").getMember(actionName).asSource() } override string getTypeTag() { exists(string prefix | - call.getParameter(0).getMember("name").getARhs().mayHaveStringValue(prefix) and + call.getParameter(0).getMember("name").asSink().mayHaveStringValue(prefix) and result = prefix + "/" + actionName ) } @@ -640,7 +640,7 @@ module Redux { override DataFlow::FunctionNode getMiddlewareFunction(boolean async) { async = true and - result = getParameter(1).getAValueReachingRhs() + result = getParameter(1).getAValueReachingSink() } override string getTypeTag() { getArgument(0).mayHaveStringValue(result) } @@ -885,12 +885,12 @@ module Redux { accessPath = getAffectedStateAccessPath(reducer) | pred = function.getReturnNode() and - succ = rootStateAccessPath(accessPath).getAnImmediateUse() + succ = rootStateAccessPath(accessPath).asSource() or exists(string suffix, DataFlow::SourceNode base | base = [function.getParameter(0), function.getReturnNode().getALocalSource()] and pred = AccessPath::getAnAssignmentTo(base, suffix) and - succ = rootStateAccessPath(accessPath + "." + suffix).getAnImmediateUse() + succ = rootStateAccessPath(accessPath + "." + suffix).asSource() ) ) or @@ -901,7 +901,7 @@ module Redux { reducer.isRootStateHandler() and base = [function.getParameter(0), function.getReturnNode().getALocalSource()] and pred = AccessPath::getAnAssignmentTo(base, suffix) and - succ = rootStateAccessPath(suffix).getAnImmediateUse() + succ = rootStateAccessPath(suffix).asSource() ) } @@ -916,7 +916,7 @@ module Redux { */ private DataFlow::ObjectLiteralNode getAManuallyDispatchedValue(string actionType) { result.getAPropertyWrite("type").getRhs().mayHaveStringValue(actionType) and - result = getADispatchedValueNode().getAValueReachingRhs() + result = getADispatchedValueNode().getAValueReachingSink() } /** @@ -994,7 +994,7 @@ module Redux { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { exists(API::CallNode call | call = useSelector().getACall() and - pred = call.getParameter(0).getReturn().getARhs() and + pred = call.getParameter(0).getReturn().asSink() and succ = call ) } @@ -1046,19 +1046,19 @@ module Redux { // // const mapDispatchToProps = { foo } // - result = getMapDispatchToProps().getMember(name).getARhs() + result = getMapDispatchToProps().getMember(name).asSink() or // // const mapDispatchToProps = dispatch => ( { foo } ) // - result = getMapDispatchToProps().getReturn().getMember(name).getARhs() + result = getMapDispatchToProps().getReturn().getMember(name).asSink() or // Explicitly bound by bindActionCreators: // // const mapDispatchToProps = dispatch => bindActionCreators({ foo }, dispatch); // exists(BindActionCreatorsCall bind | - bind.flowsTo(getMapDispatchToProps().getReturn().getARhs()) and + bind.flowsTo(getMapDispatchToProps().getReturn().asSink()) and result = bind.getOptionArgument(0, name) ) } @@ -1096,9 +1096,7 @@ module Redux { private class HeuristicConnectEntryPoint extends API::EntryPoint { HeuristicConnectEntryPoint() { this = "react-redux-connect" } - override DataFlow::Node getARhs() { none() } - - override DataFlow::SourceNode getAUse() { + override DataFlow::SourceNode getASource() { exists(DataFlow::CallNode call | call.getAnArgument().asExpr().(Identifier).getName() = ["mapStateToProps", "mapDispatchToProps"] and @@ -1115,12 +1113,12 @@ module Redux { override API::Node getMapStateToProps() { result = getAParameter() and - result.getARhs().asExpr().(Identifier).getName() = "mapStateToProps" + result.asSink().asExpr().(Identifier).getName() = "mapStateToProps" } override API::Node getMapDispatchToProps() { result = getAParameter() and - result.getARhs().asExpr().(Identifier).getName() = "mapDispatchToProps" + result.asSink().asExpr().(Identifier).getName() = "mapDispatchToProps" } } @@ -1130,7 +1128,7 @@ module Redux { private class StateToPropsStep extends StateStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { exists(ConnectCall call | - pred = call.getMapStateToProps().getReturn().getARhs() and + pred = call.getMapStateToProps().getReturn().asSink() and succ = call.getReactComponent().getADirectPropsAccess() ) } @@ -1205,7 +1203,7 @@ module Redux { // Selector functions may be given as an array exists(DataFlow::ArrayCreationNode array | array.flowsTo(getArgument(0)) and - result.getAUse() = array.getElement(i) + result.getAValueReachableFromSource() = array.getElement(i) ) } } @@ -1221,13 +1219,13 @@ module Redux { // Return value of `i`th callback flows to the `i`th parameter of the last callback. exists(CreateSelectorCall call, int index | call.getNumArgument() > 1 and - pred = call.getSelectorFunction(index).getReturn().getARhs() and - succ = call.getLastParameter().getParameter(index).getAnImmediateUse() + pred = call.getSelectorFunction(index).getReturn().asSink() and + succ = call.getLastParameter().getParameter(index).asSource() ) or // The result of the last callback is the final result exists(CreateSelectorCall call | - pred = call.getLastParameter().getReturn().getARhs() and + pred = call.getLastParameter().getReturn().asSink() and succ = call ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll b/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll index 03c78c2561f..edd92614a2c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/SQL.qll @@ -9,7 +9,7 @@ module SQL { abstract class SqlString extends Expr { } private class SqlStringFromModel extends SqlString { - SqlStringFromModel() { this = ModelOutput::getASinkNode("sql-injection").getARhs().asExpr() } + SqlStringFromModel() { this = ModelOutput::getASinkNode("sql-injection").asSink().asExpr() } } /** @@ -109,7 +109,7 @@ private module MySql { Credentials() { exists(API::Node callee, string prop | callee in [createConnection(), createPool()] and - this = callee.getParameter(0).getMember(prop).getARhs().asExpr() and + this = callee.getParameter(0).getMember(prop).asSink().asExpr() and ( prop = "user" and kind = "user name" or @@ -200,7 +200,7 @@ private module Postgres { QueryString() { this = any(QueryCall qc).getAQueryArgument().asExpr() or - this = API::moduleImport("pg-cursor").getParameter(0).getARhs().asExpr() + this = API::moduleImport("pg-cursor").getParameter(0).asSink().asExpr() } } @@ -210,9 +210,9 @@ private module Postgres { Credentials() { exists(string prop | - this = [newClient(), newPool()].getParameter(0).getMember(prop).getARhs().asExpr() + this = [newClient(), newPool()].getParameter(0).getMember(prop).asSink().asExpr() or - this = pgPromise().getParameter(0).getMember(prop).getARhs().asExpr() + this = pgPromise().getParameter(0).getMember(prop).asSink().asExpr() | prop = "user" and kind = "user name" or @@ -383,7 +383,7 @@ private module Sqlite { /** A call to a Sqlite query method. */ private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { QueryCall() { - this = getAChainingQueryCall().getAnImmediateUse() + this = getAChainingQueryCall().asSource() or this = database().getMember("prepare").getACall() } @@ -440,7 +440,8 @@ private module MsSql { override TaggedTemplateExpr astNode; QueryTemplateExpr() { - mssql().getMember("query").getAUse() = DataFlow::valueNode(astNode.getTag()) + mssql().getMember("query").getAValueReachableFromSource() = + DataFlow::valueNode(astNode.getTag()) } override DataFlow::Node getAResult() { @@ -494,7 +495,7 @@ private module MsSql { or callee = mssql().getMember("ConnectionPool") ) and - this = callee.getParameter(0).getMember(prop).getARhs().asExpr() and + this = callee.getParameter(0).getMember(prop).asSink().asExpr() and ( prop = "user" and kind = "user name" or diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Snapdragon.qll b/javascript/ql/lib/semmle/javascript/frameworks/Snapdragon.qll index d5692c3d2c2..6f460a842ff 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Snapdragon.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Snapdragon.qll @@ -27,7 +27,7 @@ private module Snapdragon { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { exists(string methodName, API::CallNode set, API::CallNode call, API::Node base | // the handler, registered with a call to `.set`. - set = getSetCall+(base.getMember(methodName + "r")).getAnImmediateUse() and + set = getSetCall+(base.getMember(methodName + "r")).asSource() and // the snapdragon instance. The API is chaining, you can also use the instance directly. base = API::moduleImport("snapdragon").getInstance() and methodName = ["parse", "compile"] and @@ -47,7 +47,7 @@ private module Snapdragon { or // for compiler handlers the input is the first parameter. methodName = "compile" and - succ = set.getParameter(1).getParameter(0).getAnImmediateUse() + succ = set.getParameter(1).getParameter(0).asSource() ) ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/SocketIO.qll b/javascript/ql/lib/semmle/javascript/frameworks/SocketIO.qll index df761420e29..e48d674fa74 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/SocketIO.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/SocketIO.qll @@ -41,7 +41,7 @@ module SocketIO { class ServerObject extends SocketIOObject { API::Node node; - ServerObject() { node = newServer() and this = node.getAnImmediateUse() } + ServerObject() { node = newServer() and this = node.asSource() } /** Gets the Api node for this server. */ API::Node asApiNode() { result = node } @@ -81,7 +81,7 @@ module SocketIO { ) } - override DataFlow::SourceNode ref() { result = this.server().getAUse() } + override DataFlow::SourceNode ref() { result = this.server().getAValueReachableFromSource() } } /** A data flow node that may produce (that is, create or return) a socket.io server. */ @@ -119,7 +119,7 @@ module SocketIO { API::Node node; NamespaceBase() { - this = node.getAnImmediateUse() and + this = node.asSource() and exists(ServerObject srv | // namespace lookup on `srv` node = srv.asApiNode().getMember("sockets") and @@ -158,7 +158,7 @@ module SocketIO { ) } - override DataFlow::SourceNode ref() { result = this.namespace().getAUse() } + override DataFlow::SourceNode ref() { result = this.namespace().getAValueReachableFromSource() } } /** A data flow node that may produce a namespace object. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Templating.qll b/javascript/ql/lib/semmle/javascript/frameworks/Templating.qll index c1e6cb342f1..90adf7d7de6 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Templating.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Templating.qll @@ -233,7 +233,7 @@ module Templating { /** Gets an API node that may flow to `succ` through a template instantiation. */ private API::Node getTemplateInput(DataFlow::SourceNode succ) { exists(TemplateInstantiation inst, API::Node base, string name | - base.getARhs() = inst.getTemplateParamsNode() and + base.asSink() = inst.getTemplateParamsNode() and result = base.getMember(name) and succ = inst.getTemplateFile() @@ -244,7 +244,7 @@ module Templating { ) or exists(TemplateInstantiation inst, string accessPath | - result.getARhs() = inst.getTemplateParamForValue(accessPath) and + result.asSink() = inst.getTemplateParamForValue(accessPath) and succ = inst.getTemplateFile() .getAnImportedFile*() @@ -261,7 +261,7 @@ module Templating { private class TemplateInputStep extends DataFlow::SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { - getTemplateInput(succ).getARhs() = pred + getTemplateInput(succ).asSink() = pred } } @@ -321,8 +321,8 @@ module Templating { result = this.getStringValue() or exists(API::Node node | - this = node.getARhs() and - result = node.getAValueReachingRhs().getStringValue() + this = node.asSink() and + result = node.getAValueReachingSink().getStringValue() ) } @@ -657,11 +657,9 @@ module Templating { private class IncludeFunctionAsEntryPoint extends API::EntryPoint { IncludeFunctionAsEntryPoint() { this = "IncludeFunctionAsEntryPoint" } - override DataFlow::SourceNode getAUse() { + override DataFlow::SourceNode getASource() { result = any(TemplatePlaceholderTag tag).getInnerTopLevel().getAVariableUse("include") } - - override DataFlow::Node getARhs() { none() } } /** @@ -718,7 +716,7 @@ module Templating { override TemplateSyntax getTemplateSyntax() { result.getAPackageName() = engine } override DataFlow::SourceNode getOutput() { - result = this.getParameter([1, 2]).getParameter(1).getAnImmediateUse() + result = this.getParameter([1, 2]).getParameter(1).asSource() or not exists(this.getParameter([1, 2]).getParameter(1)) and result = this diff --git a/javascript/ql/lib/semmle/javascript/frameworks/TorrentLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/TorrentLibraries.qll index 1724e1174aa..29c100234bf 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/TorrentLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/TorrentLibraries.qll @@ -21,7 +21,7 @@ module ParseTorrent { node = mod().getReturn() or node = mod().getMember("remote").getParameter(1).getParameter(1) ) and - this = node.getAnImmediateUse() + this = node.asSource() } /** Gets the API node for this torrent object. */ @@ -29,7 +29,9 @@ module ParseTorrent { } /** Gets a data flow node referring to a parsed torrent. */ - DataFlow::SourceNode parsedTorrentRef() { result = any(ParsedTorrent t).asApiNode().getAUse() } + DataFlow::SourceNode parsedTorrentRef() { + result = any(ParsedTorrent t).asApiNode().getAValueReachableFromSource() + } /** * An access to user-controlled torrent information. @@ -38,7 +40,7 @@ module ParseTorrent { UserControlledTorrentInfo() { exists(API::Node read | read = any(ParsedTorrent t).asApiNode().getAMember() and - this = read.getAnImmediateUse() + this = read.asSource() | exists(string prop | not ( diff --git a/javascript/ql/lib/semmle/javascript/frameworks/TrustedTypes.qll b/javascript/ql/lib/semmle/javascript/frameworks/TrustedTypes.qll index 8335600f9db..b1b2cc6cf0a 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/TrustedTypes.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/TrustedTypes.qll @@ -14,9 +14,7 @@ module TrustedTypes { private class TrustedTypesEntry extends API::EntryPoint { TrustedTypesEntry() { this = "TrustedTypesEntry" } - override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("trustedTypes") } - - override DataFlow::Node getARhs() { none() } + override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("trustedTypes") } } private API::Node trustedTypesObj() { result = any(TrustedTypesEntry entry).getANode() } @@ -38,7 +36,7 @@ module TrustedTypes { private class PolicyInputStep extends DataFlow::SharedFlowStep { override predicate step(DataFlow::Node pred, DataFlow::Node succ) { exists(PolicyCreation policy, string method | - pred = policy.getReturn().getMember(method).getParameter(0).getARhs() and + pred = policy.getReturn().getMember(method).getParameter(0).asSink() and succ = policy.getPolicyCallback(method).getParameter(0) ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/UriLibraries.qll b/javascript/ql/lib/semmle/javascript/frameworks/UriLibraries.qll index 6551ef469e0..492139b3641 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/UriLibraries.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/UriLibraries.qll @@ -190,7 +190,7 @@ module Querystringify { * Gets a data flow source node for member `name` of the querystringify library. */ DataFlow::SourceNode querystringifyMember(string name) { - result = querystringify().getMember(name).getAnImmediateUse() + result = querystringify().getMember(name).asSource() } /** Gets an API node referring to the `querystringify` module. */ diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll index d32db710fa8..95a372025e2 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Vue.qll @@ -9,9 +9,7 @@ module Vue { private class GlobalVueEntryPoint extends API::EntryPoint { GlobalVueEntryPoint() { this = "VueEntryPoint" } - override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("Vue") } - - override DataFlow::Node getARhs() { none() } + override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("Vue") } } /** @@ -22,9 +20,7 @@ module Vue { private class VueExportEntryPoint extends API::EntryPoint { VueExportEntryPoint() { this = "VueExportEntryPoint" } - override DataFlow::SourceNode getAUse() { none() } - - override DataFlow::Node getARhs() { + override DataFlow::Node getASink() { result = any(SingleFileComponent c).getModule().getDefaultOrBulkExport() } } @@ -41,7 +37,7 @@ module Vue { /** * Gets a reference to the 'Vue' object. */ - DataFlow::SourceNode vue() { result = vueLibrary().getAnImmediateUse() } + DataFlow::SourceNode vue() { result = vueLibrary().asSource() } /** Gets an API node referring to a component or `Vue`. */ private API::Node component() { @@ -176,8 +172,8 @@ module Vue { /** Gets a component which is extended by this one. */ Component getABaseComponent() { - result.getComponentRef().getAUse() = - getOwnOptions().getMember(["extends", "mixins"]).getARhs() + result.getComponentRef().getAValueReachableFromSource() = + getOwnOptions().getMember(["extends", "mixins"]).asSink() } /** @@ -195,12 +191,12 @@ module Vue { } /** - * DEPRECATED. Use `getOwnOptions().getARhs()`. + * DEPRECATED. Use `getOwnOptions().getASink()`. * * Gets the options passed to the Vue object, such as the object literal `{...}` in `new Vue{{...})` * or the default export of a single-file component. */ - deprecated DataFlow::Node getOwnOptionsObject() { result = getOwnOptions().getARhs() } + deprecated DataFlow::Node getOwnOptionsObject() { result = getOwnOptions().asSink() } /** * Gets the class implementing this Vue component, if any. @@ -208,19 +204,19 @@ module Vue { * Specifically, this is a class annotated with `@Component` which flows to the options * object of this Vue component. */ - ClassComponent getAsClassComponent() { result = getOwnOptions().getAValueReachingRhs() } + ClassComponent getAsClassComponent() { result = getOwnOptions().getAValueReachingSink() } /** * Gets the node for option `name` for this component, not including * those from extended objects and mixins. */ - DataFlow::Node getOwnOption(string name) { result = getOwnOptions().getMember(name).getARhs() } + DataFlow::Node getOwnOption(string name) { result = getOwnOptions().getMember(name).asSink() } /** * Gets the node for option `name` for this component, including those from * extended objects and mixins. */ - DataFlow::Node getOption(string name) { result = getOptions().getMember(name).getARhs() } + DataFlow::Node getOption(string name) { result = getOptions().getMember(name).asSink() } /** * Gets a source node flowing into the option `name` of this component, including those from @@ -228,7 +224,7 @@ module Vue { */ pragma[nomagic] DataFlow::SourceNode getOptionSource(string name) { - result = getOptions().getMember(name).getAValueReachingRhs() + result = getOptions().getMember(name).getAValueReachingSink() } /** @@ -289,7 +285,7 @@ module Vue { DataFlow::FunctionNode getWatchHandler(string propName) { exists(API::Node propWatch | propWatch = getOptions().getMember("watch").getMember(propName) and - result = [propWatch, propWatch.getMember("handler")].getAValueReachingRhs() + result = [propWatch, propWatch.getMember("handler")].getAValueReachingSink() ) } @@ -322,16 +318,16 @@ module Vue { * Gets a node for a function that will be invoked with `this` bound to this component. */ DataFlow::FunctionNode getABoundFunction() { - result = getOptions().getAMember+().getAValueReachingRhs() + result = getOptions().getAMember+().getAValueReachingSink() or result = getAsClassComponent().getAnInstanceMember() } /** Gets an API node referring to an instance of this component. */ - API::Node getInstance() { result.getAnImmediateUse() = getABoundFunction().getReceiver() } + API::Node getInstance() { result.asSource() = getABoundFunction().getReceiver() } /** Gets a data flow node referring to an instance of this component. */ - DataFlow::SourceNode getAnInstanceRef() { result = getInstance().getAnImmediateUse() } + DataFlow::SourceNode getAnInstanceRef() { result = getInstance().asSource() } pragma[noinline] private DataFlow::PropWrite getAPropertyValueWrite(string name) { @@ -484,14 +480,12 @@ module Vue { private class VueFileImportEntryPoint extends API::EntryPoint { VueFileImportEntryPoint() { this = "VueFileImportEntryPoint" } - override DataFlow::SourceNode getAUse() { + override DataFlow::SourceNode getASource() { exists(Import imprt | imprt.getImportedPath().resolve() instanceof VueFile and result = imprt.getImportedModuleNode() ) } - - override DataFlow::Node getARhs() { none() } } /** @@ -533,13 +527,13 @@ module Vue { // of the .vue file. exists(Import imprt | imprt.getImportedPath().resolve() = file and - result.getAnImmediateUse() = imprt.getImportedModuleNode() + result.asSource() = imprt.getImportedModuleNode() ) } override API::Node getOwnOptions() { // Use the entry point generated by `VueExportEntryPoint` - result.getARhs() = getModule().getDefaultOrBulkExport() + result.asSink() = getModule().getDefaultOrBulkExport() } override string toString() { result = file.toString() } @@ -695,7 +689,7 @@ module Vue { t.start() and ( exists(API::Node router | router = API::moduleImport("vue-router") | - result = router.getInstance().getMember("currentRoute").getAnImmediateUse() + result = router.getInstance().getMember("currentRoute").asSource() or result = router @@ -703,17 +697,12 @@ module Vue { .getMember(["beforeEach", "beforeResolve", "afterEach"]) .getParameter(0) .getParameter([0, 1]) - .getAnImmediateUse() + .asSource() or - result = - router - .getParameter(0) - .getMember("scrollBehavior") - .getParameter([0, 1]) - .getAnImmediateUse() + result = router.getParameter(0).getMember("scrollBehavior").getParameter([0, 1]).asSource() ) or - result = routeConfig().getMember("beforeEnter").getParameter([0, 1]).getAnImmediateUse() + result = routeConfig().getMember("beforeEnter").getParameter([0, 1]).asSource() or exists(Component c | result = c.getABoundFunction().getAFunctionValue().getReceiver().getAPropertyRead("$route") diff --git a/javascript/ql/lib/semmle/javascript/frameworks/Vuex.qll b/javascript/ql/lib/semmle/javascript/frameworks/Vuex.qll index 8d062a447aa..71132fb531d 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/Vuex.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/Vuex.qll @@ -75,7 +75,7 @@ module Vuex { or exists(API::CallNode call | call = vuex().getMember("createNamespacedHelpers").getACall() and - namespace = call.getParameter(0).getAValueReachingRhs().getStringValue() + "/" and + namespace = call.getParameter(0).getAValueReachingSink().getStringValue() + "/" and this = call.getReturn().getMember(helperName).getACall() ) ) @@ -88,7 +88,8 @@ module Vuex { pragma[noinline] string getNamespace() { getNumArgument() = 2 and - result = appendToNamespace(namespace, getParameter(0).getAValueReachingRhs().getStringValue()) + result = + appendToNamespace(namespace, getParameter(0).getAValueReachingSink().getStringValue()) or getNumArgument() = 1 and result = namespace @@ -99,28 +100,28 @@ module Vuex { */ predicate hasMapping(string localName, string storeName) { // mapGetters('foo') - getLastParameter().getAValueReachingRhs().getStringValue() = localName and + getLastParameter().getAValueReachingSink().getStringValue() = localName and storeName = getNamespace() + localName or // mapGetters(['foo', 'bar']) - getLastParameter().getUnknownMember().getAValueReachingRhs().getStringValue() = localName and + getLastParameter().getUnknownMember().getAValueReachingSink().getStringValue() = localName and storeName = getNamespace() + localName or // mapGetters({foo: 'bar'}) storeName = getNamespace() + - getLastParameter().getMember(localName).getAValueReachingRhs().getStringValue() and + getLastParameter().getMember(localName).getAValueReachingSink().getStringValue() and localName != "*" // ignore special API graph member named "*" } /** Gets the Vue component in which the generated functions are installed. */ Vue::Component getVueComponent() { exists(DataFlow::ObjectLiteralNode obj | - obj.getASpreadProperty() = getReturn().getAUse() and - result.getOwnOptions().getAMember().getARhs() = obj + obj.getASpreadProperty() = getReturn().getAValueReachableFromSource() and + result.getOwnOptions().getAMember().asSink() = obj ) or - result.getOwnOptions().getAMember().getARhs() = this + result.getOwnOptions().getAMember().asSink() = this } } @@ -146,7 +147,7 @@ module Vuex { /** Gets a value that is returned by a getter registered with the given name. */ private DataFlow::Node getterPred(string name) { exists(string prefix, string prop | - result = storeConfigObject(prefix).getMember("getters").getMember(prop).getReturn().getARhs() and + result = storeConfigObject(prefix).getMember("getters").getMember(prop).getReturn().asSink() and name = prefix + prop ) } @@ -154,12 +155,12 @@ module Vuex { /** Gets a property access that may receive the produced by a getter of the given name. */ private DataFlow::Node getterSucc(string name) { exists(string prefix, string prop | - result = storeRef(prefix).getMember("getters").getMember(prop).getAnImmediateUse() and + result = storeRef(prefix).getMember("getters").getMember(prop).asSource() and prop != "*" and name = prefix + prop ) or - result = getAMappedAccess("mapGetters", name).getAnImmediateUse() + result = getAMappedAccess("mapGetters", name).asSource() } /** Holds if `pred -> succ` is a step from a getter function to a relevant property access. */ @@ -212,19 +213,19 @@ module Vuex { commitCall = commitLikeFunctionRef(kind, prefix).getACall() | // commit('name', payload) - name = prefix + commitCall.getParameter(0).getAValueReachingRhs().getStringValue() and + name = prefix + commitCall.getParameter(0).getAValueReachingSink().getStringValue() and result = commitCall.getArgument(1) or // commit({type: 'name', ......}) name = prefix + - commitCall.getParameter(0).getMember("type").getAValueReachingRhs().getStringValue() and + commitCall.getParameter(0).getMember("type").getAValueReachingSink().getStringValue() and result = commitCall.getArgument(0) ) or // this.name(payload) // methods: {...mapMutations(['name'])} } - result = getAMappedAccess(getMapHelperForCommitKind(kind), name).getParameter(0).getARhs() + result = getAMappedAccess(getMapHelperForCommitKind(kind), name).getParameter(0).asSink() } /** Gets a node that refers the payload of a committed mutation with the given `name.` */ @@ -238,7 +239,7 @@ module Vuex { .getMember(getStorePropForCommitKind(kind)) .getMember(prop) .getParameter(1) - .getAnImmediateUse() and + .asSource() and prop != "*" and name = prefix + prop ) @@ -293,19 +294,17 @@ module Vuex { /** Gets a value that flows into the given access path of the state. */ DataFlow::Node stateMutationPred(string path) { - result = stateRefByAccessPath(path).getARhs() + result = stateRefByAccessPath(path).asSink() or exists(ExtendCall call, string base, string prop | - call.getDestinationOperand() = stateRefByAccessPath(base).getAUse() and + call.getDestinationOperand() = stateRefByAccessPath(base).getAValueReachableFromSource() and result = call.getASourceOperand().getALocalSource().getAPropertyWrite(prop).getRhs() and path = appendToNamespace(base, prop) ) } /** Gets a value that refers to the given access path of the state. */ - DataFlow::Node stateMutationSucc(string path) { - result = stateRefByAccessPath(path).getAnImmediateUse() - } + DataFlow::Node stateMutationSucc(string path) { result = stateRefByAccessPath(path).asSource() } /** Holds if `pred -> succ` is a step from state mutation to state access. */ predicate stateMutationStep(DataFlow::Node pred, DataFlow::Node succ) { @@ -325,7 +324,7 @@ module Vuex { exists(MapHelperCall call | call.getHelperName() = "mapState" and component = call.getVueComponent() and - result = call.getLastParameter().getMember(name).getReturn().getARhs() + result = call.getLastParameter().getMember(name).getReturn().asSink() ) } @@ -336,7 +335,7 @@ module Vuex { predicate mapStateHelperStep(DataFlow::Node pred, DataFlow::Node succ) { exists(Vue::Component component, string name | pred = mapStateHelperPred(component, name) and - succ = pragma[only_bind_out](component).getInstance().getMember(name).getAnImmediateUse() + succ = pragma[only_bind_out](component).getInstance().getMember(name).asSource() ) } @@ -378,7 +377,7 @@ module Vuex { /** Gets a package that can be considered an entry point for a Vuex app. */ private PackageJson entryPointPackage() { - result = getPackageJson(storeRef().getAnImmediateUse().getFile()) + result = getPackageJson(storeRef().asSource().getFile()) or // Any package that imports a store-creating package is considered a potential entry point. packageDependsOn(result, entryPointPackage()) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/XmlParsers.qll b/javascript/ql/lib/semmle/javascript/frameworks/XmlParsers.qll index 41cecb36941..355ee485246 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/XmlParsers.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/XmlParsers.qll @@ -100,7 +100,7 @@ module XML { } override DataFlow::Node getAResult() { - result = [doc(), element(), attr()].getAnImmediateUse() + result = [doc(), element(), attr()].asSource() or result = element().getMember(["name", "text"]).getACall() or @@ -282,11 +282,7 @@ module XML { override DataFlow::Node getAResult() { result = - parser - .getReturn() - .getMember(any(string s | s.matches("on%"))) - .getAParameter() - .getAnImmediateUse() + parser.getReturn().getMember(any(string s | s.matches("on%"))).getAParameter().asSource() } } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll index f8b2118a55f..bbed827c3e5 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/ModelsAsData.qll @@ -26,7 +26,7 @@ import Shared::ModelOutput as ModelOutput * A remote flow source originating from a CSV source row. */ private class RemoteFlowSourceFromCsv extends RemoteFlowSource { - RemoteFlowSourceFromCsv() { this = ModelOutput::getASourceNode("remote").getAnImmediateUse() } + RemoteFlowSourceFromCsv() { this = ModelOutput::getASourceNode("remote").asSource() } override string getSourceType() { result = "Remote flow" } } @@ -37,8 +37,8 @@ private class RemoteFlowSourceFromCsv extends RemoteFlowSource { private predicate summaryStepNodes(DataFlow::Node pred, DataFlow::Node succ, string kind) { exists(API::Node predNode, API::Node succNode | Specific::summaryStep(predNode, succNode, kind) and - pred = predNode.getARhs() and - succ = succNode.getAnImmediateUse() + pred = predNode.asSink() and + succ = succNode.asSource() ) } diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll index 127d9ca5122..69563a3eab4 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll @@ -299,7 +299,7 @@ private class AccessPathRange extends AccessPath::Range { bindingset[token] API::Node getSuccessorFromNode(API::Node node, AccessPathToken token) { // API graphs use the same label for arguments and parameters. An edge originating from a - // use-node represents be an argument, and an edge originating from a def-node represents a parameter. + // use-node represents an argument, and an edge originating from a def-node represents a parameter. // We just map both to the same thing. token.getName() = ["Argument", "Parameter"] and result = node.getParameter(AccessPath::parseIntUnbounded(token.getAnArgument())) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll index a5e366a671f..861a44a2cfc 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -61,9 +61,7 @@ private class GlobalApiEntryPoint extends API::EntryPoint { this = "GlobalApiEntryPoint:" + global } - override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef(global) } - - override DataFlow::Node getARhs() { none() } + override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef(global) } /** Gets the name of the global variable. */ string getGlobal() { result = global } @@ -151,7 +149,7 @@ API::Node getExtraSuccessorFromInvoke(API::InvokeNode node, AccessPathToken toke or token.getName() = "Argument" and token.getAnArgument() = "this" and - result.getARhs() = node.(DataFlow::CallNode).getReceiver() + result.asSink() = node.(DataFlow::CallNode).getReceiver() } /** diff --git a/javascript/ql/lib/semmle/javascript/heuristics/AdditionalSources.qll b/javascript/ql/lib/semmle/javascript/heuristics/AdditionalSources.qll index 35b1ac83e2d..40c86ed4855 100644 --- a/javascript/ql/lib/semmle/javascript/heuristics/AdditionalSources.qll +++ b/javascript/ql/lib/semmle/javascript/heuristics/AdditionalSources.qll @@ -58,7 +58,7 @@ class RemoteServerResponse extends HeuristicSource, RemoteFlowSource { */ private class RemoteFlowSourceFromDBAccess extends RemoteFlowSource, HeuristicSource { RemoteFlowSourceFromDBAccess() { - this = ModelOutput::getASourceNode("database-access-result").getAUse() or + this = ModelOutput::getASourceNode("database-access-result").getAValueReachableFromSource() or exists(DatabaseAccess dba | this = dba.getAResult()) } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll index 93c9fa63a59..b23f52d7c22 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll @@ -49,7 +49,7 @@ module DomBasedXss { or // A construction of a JSDOM object (server side DOM), where scripts are allowed. exists(DataFlow::NewNode instance | - instance = API::moduleImport("jsdom").getMember("JSDOM").getInstance().getAnImmediateUse() and + instance = API::moduleImport("jsdom").getMember("JSDOM").getInstance().asSource() and this = instance.getArgument(0) and instance.getOptionArgument(1, "runScripts").mayHaveStringValue("dangerously") ) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ExceptionXssCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ExceptionXssCustomizations.qll index 30ae50c2382..2418962ef65 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ExceptionXssCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ExceptionXssCustomizations.qll @@ -61,7 +61,7 @@ module ExceptionXss { */ private class JsonSchemaValidationError extends Source { JsonSchemaValidationError() { - this = any(JsonSchema::Ajv::Instance i).getAValidationError().getAnImmediateUse() + this = any(JsonSchema::Ajv::Instance i).getAValidationError().asSource() or this = any(JsonSchema::Joi::JoiValidationErrorRead r).getAValidationResultAccess(_) } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll index a061fd5bc6f..fb663a755ed 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ExternalAPIUsedWithUntrustedDataCustomizations.qll @@ -48,7 +48,7 @@ module ExternalApiUsedWithUntrustedData { } /** Holds if `node` corresponds to a deep object argument. */ - private predicate isDeepObjectSink(API::Node node) { node.getARhs() instanceof DeepObjectSink } + private predicate isDeepObjectSink(API::Node node) { node.asSink() instanceof DeepObjectSink } /** * A sanitizer for data flowing to an external API. @@ -165,9 +165,9 @@ module ExternalApiUsedWithUntrustedData { not param = base.getReceiver() | result = param and - name = param.getAnImmediateUse().asExpr().(Parameter).getName() + name = param.asSource().asExpr().(Parameter).getName() or - param.getAnImmediateUse().asExpr() instanceof DestructuringPattern and + param.asSource().asExpr() instanceof DestructuringPattern and result = param.getMember(name) ) } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll index a410bda46b5..108ce5d8e62 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/IndirectCommandInjectionCustomizations.qll @@ -74,7 +74,7 @@ module IndirectCommandInjection { ].getMember("parse").getACall() or // `require('commander').myCmdArgumentName` - this = commander().getAMember().getAnImmediateUse() + this = commander().getAMember().asSource() or // `require('commander').opt()` => `{a: ..., b: ...}` this = commander().getMember("opts").getACall() diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll index fc30c91018a..f1a27697725 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/MissingRateLimiting.qll @@ -152,9 +152,7 @@ abstract class RateLimitingMiddleware extends DataFlow::SourceNode { * A rate limiter constructed using the `express-rate-limit` package. */ class ExpressRateLimit extends RateLimitingMiddleware { - ExpressRateLimit() { - this = API::moduleImport("express-rate-limit").getReturn().getAnImmediateUse() - } + ExpressRateLimit() { this = API::moduleImport("express-rate-limit").getReturn().asSource() } } /** @@ -162,7 +160,7 @@ class ExpressRateLimit extends RateLimitingMiddleware { */ class BruteForceRateLimit extends RateLimitingMiddleware { BruteForceRateLimit() { - this = API::moduleImport("express-brute").getInstance().getMember("prevent").getAnImmediateUse() + this = API::moduleImport("express-brute").getInstance().getMember("prevent").asSource() } } @@ -174,7 +172,7 @@ class BruteForceRateLimit extends RateLimitingMiddleware { */ class RouteHandlerLimitedByExpressLimiter extends RateLimitingMiddleware { RouteHandlerLimitedByExpressLimiter() { - this = API::moduleImport("express-limiter").getReturn().getReturn().getAnImmediateUse() + this = API::moduleImport("express-limiter").getReturn().getReturn().asSource() } override Routing::Node getRoutingNode() { @@ -211,7 +209,7 @@ class RateLimiterFlexibleRateLimiter extends DataFlow::FunctionNode { rateLimiterClass = API::moduleImport("rate-limiter-flexible").getMember(rateLimiterClassName) and rateLimiterConsume = rateLimiterClass.getInstance().getMember("consume") and request.getParameter() = getRouteHandlerParameter(this.getFunction(), "request") and - request.getAPropertyRead().flowsTo(rateLimiterConsume.getAParameter().getARhs()) + request.getAPropertyRead().flowsTo(rateLimiterConsume.getAParameter().asSink()) ) } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll index ff026f3a3a4..bb60b5bc23e 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/RemoteFlowSources.qll @@ -164,9 +164,7 @@ private class ExternalRemoteFlowSourceSpecEntryPoint extends API::EntryPoint { string getName() { result = name } - override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef(name) } - - override DataFlow::Node getARhs() { none() } + override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef(name) } } /** @@ -175,7 +173,7 @@ private class ExternalRemoteFlowSourceSpecEntryPoint extends API::EntryPoint { private class ExternalRemoteFlowSource extends RemoteFlowSource { RemoteFlowSourceAccessPath ap; - ExternalRemoteFlowSource() { Stages::Taint::ref() and this = ap.resolve().getAnImmediateUse() } + ExternalRemoteFlowSource() { Stages::Taint::ref() and this = ap.resolve().asSource() } override string getSourceType() { result = ap.getSourceType() } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll index 695876ac90f..8307c1f6f93 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ResourceExhaustionCustomizations.qll @@ -78,14 +78,8 @@ module ResourceExhaustion { exists(DataFlow::SourceNode clazz, DataFlow::InvokeNode invk, int index | clazz = DataFlow::globalVarRef("Buffer") and this = invk.getArgument(index) | - exists(string name | - invk = clazz.getAMemberCall(name) and - ( - name = "from" and index = 2 // the length argument - or - name = ["alloc", "allocUnsafe", "allocUnsafeSlow"] and index = 0 // the buffer size - ) - ) + invk = clazz.getAMemberCall(["alloc", "allocUnsafe", "allocUnsafeSlow"]) and + index = 0 // the buffer size or invk = clazz.getAnInvocation() and ( diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll index e3bf02362a4..42ffe2ea3c3 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll @@ -51,7 +51,7 @@ module SqlInjection { this = any(LdapJS::ClientCall call).getArgument(0) or // A search options object, which contains a filter and a baseDN. - this = any(LdapJS::SearchOptions opt).getARhs() + this = any(LdapJS::SearchOptions opt).asSink() or // A call to "parseDN", which parses a DN from a string. this = LdapJS::ldapjs().getMember("parseDN").getACall().getArgument(0) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index c094d82163c..03b1211326a 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -681,7 +681,7 @@ module TaintedPath { .getMember(["pdf", "screenshot"]) .getParameter(0) .getMember("path") - .getARhs() + .asSink() } } @@ -702,7 +702,7 @@ module TaintedPath { .getACall() .getParameter(1) .getMember("config") - .getARhs() + .asSink() } } @@ -716,7 +716,7 @@ module TaintedPath { .getMember(["readPackageAsync", "readPackageSync"]) .getParameter(0) .getMember("cwd") - .getARhs() + .asSink() } } @@ -726,8 +726,8 @@ module TaintedPath { private class ShellCwdSink extends TaintedPath::Sink { ShellCwdSink() { exists(SystemCommandExecution sys, API::Node opts | - opts.getARhs() = sys.getOptionsArg() and // assuming that an API::Node exists here. - this = opts.getMember("cwd").getARhs() + opts.asSink() = sys.getOptionsArg() and // assuming that an API::Node exists here. + this = opts.getMember("cwd").asSink() ) } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/TypeConfusionThroughParameterTamperingQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/TypeConfusionThroughParameterTamperingQuery.qll index da6b698d97f..8e24b3e36d8 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/TypeConfusionThroughParameterTamperingQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/TypeConfusionThroughParameterTamperingQuery.qll @@ -27,4 +27,30 @@ class Configuration extends DataFlow::Configuration { } override predicate isBarrier(DataFlow::Node node) { node instanceof Barrier } + + override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) { + guard instanceof TypeOfTestBarrier or + guard instanceof IsArrayBarrier + } +} + +private class TypeOfTestBarrier extends DataFlow::BarrierGuardNode, DataFlow::ValueNode { + override EqualityTest astNode; + + TypeOfTestBarrier() { TaintTracking::isTypeofGuard(astNode, _, _) } + + override predicate blocks(boolean outcome, Expr e) { + if TaintTracking::isTypeofGuard(astNode, e, ["string", "object"]) + then outcome = [true, false] // separation between string/array removes type confusion in both branches + else outcome = astNode.getPolarity() // block flow to branch where value is neither string nor array + } +} + +private class IsArrayBarrier extends DataFlow::BarrierGuardNode, DataFlow::CallNode { + IsArrayBarrier() { this = DataFlow::globalVarRef("Array").getAMemberCall("isArray").getACall() } + + override predicate blocks(boolean outcome, Expr e) { + e = getArgument(0).asExpr() and + outcome = [true, false] // separation between string/array removes type confusion in both branches + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll index b869b028902..3f0f569eff6 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll @@ -208,8 +208,7 @@ module XssThroughDom { exists(API::Node useForm | useForm = API::moduleImport("react-hook-form").getMember("useForm").getReturn() | - this = - useForm.getMember("handleSubmit").getParameter(0).getParameter(0).getAnImmediateUse() + this = useForm.getMember("handleSubmit").getParameter(0).getParameter(0).asSource() or this = useForm.getMember("getValues").getACall() ) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll index 3c4c5f66b75..1cb58609d13 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ZipSlipCustomizations.qll @@ -103,7 +103,7 @@ module ZipSlip { class JSZipFilesSource extends Source instanceof DynamicPropertyAccess::EnumeratedPropName { JSZipFilesSource() { super.getSourceObject() = - API::moduleImport("jszip").getInstance().getMember("files").getAnImmediateUse() + API::moduleImport("jszip").getInstance().getMember("files").asSource() } } @@ -116,7 +116,7 @@ module ZipSlip { .getMember(["forEach", "filter"]) .getParameter(0) .getParameter(0) - .getAnImmediateUse() + .asSource() } } diff --git a/javascript/ql/src/Declarations/UnusedProperty.ql b/javascript/ql/src/Declarations/UnusedProperty.ql index 19d43a09db2..1a8f9ee291f 100644 --- a/javascript/ql/src/Declarations/UnusedProperty.ql +++ b/javascript/ql/src/Declarations/UnusedProperty.ql @@ -27,6 +27,8 @@ predicate hasUnknownPropertyRead(LocalObject obj) { or exists(obj.getAPropertyRead("hasOwnProperty")) or + obj.flowsTo(DataFlow::globalVarRef("Object").getAMemberCall("hasOwn").getArgument(0)) + or exists(obj.getAPropertyRead("propertyIsEnumerable")) } diff --git a/javascript/ql/src/Performance/PolynomialReDoS.qhelp b/javascript/ql/src/Performance/PolynomialReDoS.qhelp index 78746df38ad..210a4a8a84b 100644 --- a/javascript/ql/src/Performance/PolynomialReDoS.qhelp +++ b/javascript/ql/src/Performance/PolynomialReDoS.qhelp @@ -71,7 +71,7 @@

- ^0\.\d+E?\d+$ // BAD + /^0\.\d+E?\d+$/.test(str) // BAD

diff --git a/javascript/ql/src/Security/CWE-020/MissingOriginCheck.ql b/javascript/ql/src/Security/CWE-020/MissingOriginCheck.ql index 543d3996abb..107f1c9a12c 100644 --- a/javascript/ql/src/Security/CWE-020/MissingOriginCheck.ql +++ b/javascript/ql/src/Security/CWE-020/MissingOriginCheck.ql @@ -9,6 +9,7 @@ * @tags correctness * security * external/cwe/cwe-020 + * external/cwe/cwe-940 */ import javascript diff --git a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql index 42861fcb9be..7fd76a635ec 100644 --- a/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql +++ b/javascript/ql/src/Security/CWE-295/DisablingCertificateValidation.ql @@ -45,7 +45,7 @@ where or // the same thing, but with API-nodes if they happen to be available exists(API::Node tlsInvk | tlsInvk.getAnInvocation() = tlsInvocation() | - disable.getRhs() = tlsInvk.getAParameter().getMember("rejectUnauthorized").getARhs() + disable.getRhs() = tlsInvk.getAParameter().getMember("rejectUnauthorized").asSink() ) ) and disable.getRhs().(AnalyzedNode).getTheBooleanValue() = false diff --git a/javascript/ql/src/Security/CWE-352/MissingCsrfMiddleware.ql b/javascript/ql/src/Security/CWE-352/MissingCsrfMiddleware.ql index 52617ce675d..6240615a6e7 100644 --- a/javascript/ql/src/Security/CWE-352/MissingCsrfMiddleware.ql +++ b/javascript/ql/src/Security/CWE-352/MissingCsrfMiddleware.ql @@ -143,7 +143,7 @@ API::CallNode passportAuthenticateCall() { */ API::CallNode nonSessionBasedAuthMiddleware() { result = passportAuthenticateCall() and - result.getParameter(1).getMember("session").getARhs().mayHaveBooleanValue(false) + result.getParameter(1).getMember("session").asSink().mayHaveBooleanValue(false) } /** diff --git a/javascript/ql/src/Security/CWE-915/PrototypePollutingFunction.ql b/javascript/ql/src/Security/CWE-915/PrototypePollutingFunction.ql index 2fb9cece66d..9e5b873f663 100644 --- a/javascript/ql/src/Security/CWE-915/PrototypePollutingFunction.ql +++ b/javascript/ql/src/Security/CWE-915/PrototypePollutingFunction.ql @@ -339,19 +339,16 @@ class AllowListEqualityGuard extends DataFlow::LabeledBarrierGuardNode, ValueNod * but the destination object generally doesn't. It is therefore only a sanitizer when * used on the destination object. */ -class HasOwnPropertyGuard extends DataFlow::BarrierGuardNode, CallNode { +class HasOwnPropertyGuard extends DataFlow::BarrierGuardNode instanceof HasOwnPropertyCall { HasOwnPropertyGuard() { - // Make sure we handle reflective calls since libraries love to do that. - getCalleeNode().getALocalSource().(DataFlow::PropRead).getPropertyName() = "hasOwnProperty" and - exists(getReceiver()) and // Try to avoid `src.hasOwnProperty` by requiring that the receiver // does not locally have its properties enumerated. Typically there is no // reason to enumerate the properties of the destination object. - not arePropertiesEnumerated(getReceiver().getALocalSource()) + not arePropertiesEnumerated(super.getObject().getALocalSource()) } override predicate blocks(boolean outcome, Expr e) { - e = getArgument(0).asExpr() and outcome = true + e = super.getProperty().asExpr() and outcome = true } } diff --git a/javascript/ql/src/change-notes/2022-05-24-resource-exhaustion-no-buffer.from.md b/javascript/ql/src/change-notes/2022-05-24-resource-exhaustion-no-buffer.from.md new file mode 100644 index 00000000000..8dadbdb4c93 --- /dev/null +++ b/javascript/ql/src/change-notes/2022-05-24-resource-exhaustion-no-buffer.from.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- +* The `js/resource-exhaustion` query no longer treats the 3-argument version of `Buffer.from` as a sink, + since it does not allocate a new buffer. diff --git a/javascript/ql/src/meta/ApiGraphs/ApiGraphRhsNodes.ql b/javascript/ql/src/meta/ApiGraphs/ApiGraphRhsNodes.ql index fcb98dc57af..4f07f9be7fe 100644 --- a/javascript/ql/src/meta/ApiGraphs/ApiGraphRhsNodes.ql +++ b/javascript/ql/src/meta/ApiGraphs/ApiGraphRhsNodes.ql @@ -12,4 +12,4 @@ import javascript import meta.MetaMetrics -select projectRoot(), count(any(API::Node nd).getARhs()) +select projectRoot(), count(any(API::Node nd).asSink()) diff --git a/javascript/ql/src/meta/ApiGraphs/ApiGraphUseNodes.ql b/javascript/ql/src/meta/ApiGraphs/ApiGraphUseNodes.ql index 446df101364..8f6629cc624 100644 --- a/javascript/ql/src/meta/ApiGraphs/ApiGraphUseNodes.ql +++ b/javascript/ql/src/meta/ApiGraphs/ApiGraphUseNodes.ql @@ -11,4 +11,4 @@ import javascript import meta.MetaMetrics -select projectRoot(), count(any(API::Node nd).getAUse()) +select projectRoot(), count(any(API::Node nd).getAValueReachableFromSource()) diff --git a/javascript/ql/test/ApiGraphs/VerifyAssertions.qll b/javascript/ql/test/ApiGraphs/VerifyAssertions.qll index a81c0d03ae9..c65f2b7ad81 100644 --- a/javascript/ql/test/ApiGraphs/VerifyAssertions.qll +++ b/javascript/ql/test/ApiGraphs/VerifyAssertions.qll @@ -21,10 +21,10 @@ import javascript private DataFlow::Node getNode(API::Node nd, string kind) { kind = "def" and - result = nd.getARhs() + result = nd.asSink() or kind = "use" and - result = nd.getAUse() + result = nd.getAValueReachableFromSource() } private string getLoc(DataFlow::Node nd) { diff --git a/javascript/ql/test/ApiGraphs/call-nodes/test.ql b/javascript/ql/test/ApiGraphs/call-nodes/test.ql index cbea83fa4be..8f0ea4bfc8b 100644 --- a/javascript/ql/test/ApiGraphs/call-nodes/test.ql +++ b/javascript/ql/test/ApiGraphs/call-nodes/test.ql @@ -3,9 +3,9 @@ import javascript class FooCall extends API::CallNode { FooCall() { this = API::moduleImport("mylibrary").getMember("foo").getACall() } - DataFlow::Node getFirst() { result = getParameter(0).getMember("value").getARhs() } + DataFlow::Node getFirst() { result = getParameter(0).getMember("value").asSink() } - DataFlow::Node getSecond() { result = getParameter(1).getMember("value").getARhs() } + DataFlow::Node getSecond() { result = getParameter(1).getMember("value").asSink() } } query predicate values(FooCall call, int first, int second) { diff --git a/javascript/ql/test/ApiGraphs/custom-entry-point/VerifyAssertions.ql b/javascript/ql/test/ApiGraphs/custom-entry-point/VerifyAssertions.ql index fb8a943f2ca..3502c0ea556 100644 --- a/javascript/ql/test/ApiGraphs/custom-entry-point/VerifyAssertions.ql +++ b/javascript/ql/test/ApiGraphs/custom-entry-point/VerifyAssertions.ql @@ -1,9 +1,7 @@ class CustomEntryPoint extends API::EntryPoint { CustomEntryPoint() { this = "CustomEntryPoint" } - override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("CustomEntryPoint") } - - override DataFlow::Node getARhs() { none() } + override DataFlow::SourceNode getASource() { result = DataFlow::globalVarRef("CustomEntryPoint") } } import ApiGraphs.VerifyAssertions diff --git a/javascript/ql/test/ApiGraphs/typed/NodeOfType.ql b/javascript/ql/test/ApiGraphs/typed/NodeOfType.ql index 582385c802a..10c5133f9a8 100644 --- a/javascript/ql/test/ApiGraphs/typed/NodeOfType.ql +++ b/javascript/ql/test/ApiGraphs/typed/NodeOfType.ql @@ -1,4 +1,4 @@ import javascript from string mod, string tp -select mod, tp, API::Node::ofType(mod, tp).getAnImmediateUse() +select mod, tp, API::Node::ofType(mod, tp).asSource() diff --git a/javascript/ql/test/library-tests/Arrays/DataFlow.expected b/javascript/ql/test/library-tests/Arrays/DataFlow.expected index fd98b66d4db..2f5179075cf 100644 --- a/javascript/ql/test/library-tests/Arrays/DataFlow.expected +++ b/javascript/ql/test/library-tests/Arrays/DataFlow.expected @@ -11,6 +11,7 @@ | arrays.js:2:16:2:23 | "source" | arrays.js:74:8:74:29 | arr.fin ... llback) | | arrays.js:2:16:2:23 | "source" | arrays.js:77:8:77:35 | arrayFi ... llback) | | arrays.js:2:16:2:23 | "source" | arrays.js:81:10:81:10 | x | +| arrays.js:2:16:2:23 | "source" | arrays.js:84:8:84:17 | arr.at(-1) | | arrays.js:18:22:18:29 | "source" | arrays.js:18:50:18:50 | e | | arrays.js:22:15:22:22 | "source" | arrays.js:23:8:23:17 | arr2.pop() | | arrays.js:25:15:25:22 | "source" | arrays.js:26:8:26:17 | arr3.pop() | diff --git a/javascript/ql/test/library-tests/Arrays/arrays.js b/javascript/ql/test/library-tests/Arrays/arrays.js index 9b445760f47..2dfb203cd54 100644 --- a/javascript/ql/test/library-tests/Arrays/arrays.js +++ b/javascript/ql/test/library-tests/Arrays/arrays.js @@ -80,4 +80,6 @@ for (const x of uniq(arr)) { sink(x); // NOT OK } + + sink(arr.at(-1)); // NOT OK }); diff --git a/javascript/ql/test/library-tests/Arrays/printAst.expected b/javascript/ql/test/library-tests/Arrays/printAst.expected index 8364838f8bd..c6e097c770e 100644 --- a/javascript/ql/test/library-tests/Arrays/printAst.expected +++ b/javascript/ql/test/library-tests/Arrays/printAst.expected @@ -1,9 +1,9 @@ nodes -| arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | semmle.label | [ParExpr] (functi ... } }) | -| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | semmle.label | [ExprStmt] (functi ... } }); | -| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | semmle.order | 1 | -| arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | semmle.label | [FunctionExpr] functio ... K } } | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | semmle.label | [BlockStmt] { let ... K } } | +| arrays.js:1:1:85:2 | [ParExpr] (functi ... T OK }) | semmle.label | [ParExpr] (functi ... T OK }) | +| arrays.js:1:1:85:3 | [ExprStmt] (functi ... OK }); | semmle.label | [ExprStmt] (functi ... OK }); | +| arrays.js:1:1:85:3 | [ExprStmt] (functi ... OK }); | semmle.order | 1 | +| arrays.js:1:2:85:1 | [FunctionExpr] functio ... OT OK } | semmle.label | [FunctionExpr] functio ... OT OK } | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | semmle.label | [BlockStmt] { let ... OT OK } | | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | [DeclStmt] let source = ... | | arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | [VarDecl] source | | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | [VariableDeclarator] source = "source" | @@ -339,6 +339,17 @@ nodes | arrays.js:81:5:81:11 | [CallExpr] sink(x) | semmle.label | [CallExpr] sink(x) | | arrays.js:81:5:81:12 | [ExprStmt] sink(x); | semmle.label | [ExprStmt] sink(x); | | arrays.js:81:10:81:10 | [VarRef] x | semmle.label | [VarRef] x | +| arrays.js:84:3:84:6 | [VarRef] sink | semmle.label | [VarRef] sink | +| arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | semmle.label | [CallExpr] sink(arr.at(-1)) | +| arrays.js:84:3:84:19 | [ExprStmt] sink(arr.at(-1)); | semmle.label | [ExprStmt] sink(arr.at(-1)); | +| arrays.js:84:8:84:10 | [VarRef] arr | semmle.label | [VarRef] arr | +| arrays.js:84:8:84:13 | [DotExpr] arr.at | semmle.label | [DotExpr] arr.at | +| arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | semmle.label | [MethodCallExpr] arr.at(-1) | +| arrays.js:84:12:84:13 | [Label] at | semmle.label | [Label] at | +| arrays.js:84:15:84:16 | [UnaryExpr] -1 | semmle.label | [UnaryExpr] -1 | +| arrays.js:84:16:84:16 | [Literal] 1 | semmle.label | [Literal] 1 | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | @@ -386,88 +397,90 @@ nodes | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | edges -| arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | semmle.label | 1 | -| arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | semmle.order | 1 | -| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | semmle.label | 1 | -| arrays.js:1:1:83:3 | [ExprStmt] (functi ... } }); | arrays.js:1:1:83:2 | [ParExpr] (functi ... } }) | semmle.order | 1 | -| arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | semmle.label | 5 | -| arrays.js:1:2:83:1 | [FunctionExpr] functio ... K } } | arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | semmle.order | 5 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.label | 18 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.order | 18 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 19 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 19 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 20 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 20 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.label | 21 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.order | 21 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.label | 22 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.order | 22 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 23 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 23 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 24 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 24 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.label | 25 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.order | 25 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.label | 26 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.order | 26 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.label | 27 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.order | 27 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.label | 28 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.order | 28 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.label | 29 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.order | 29 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 30 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 30 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.label | 31 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.order | 31 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 32 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 32 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 34 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 34 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.label | 35 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.order | 35 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 36 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 36 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.label | 37 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.order | 37 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 | -| arrays.js:1:14:83:1 | [BlockStmt] { let ... K } } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 | +| arrays.js:1:1:85:2 | [ParExpr] (functi ... T OK }) | arrays.js:1:2:85:1 | [FunctionExpr] functio ... OT OK } | semmle.label | 1 | +| arrays.js:1:1:85:2 | [ParExpr] (functi ... T OK }) | arrays.js:1:2:85:1 | [FunctionExpr] functio ... OT OK } | semmle.order | 1 | +| arrays.js:1:1:85:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:85:2 | [ParExpr] (functi ... T OK }) | semmle.label | 1 | +| arrays.js:1:1:85:3 | [ExprStmt] (functi ... OK }); | arrays.js:1:1:85:2 | [ParExpr] (functi ... T OK }) | semmle.order | 1 | +| arrays.js:1:2:85:1 | [FunctionExpr] functio ... OT OK } | arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | semmle.label | 5 | +| arrays.js:1:2:85:1 | [FunctionExpr] functio ... OT OK } | arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | semmle.order | 5 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.label | 1 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | semmle.order | 1 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.label | 2 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:4:3:4:28 | [DeclStmt] var obj = ... | semmle.order | 2 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.label | 3 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:5:3:5:16 | [ExprStmt] sink(obj.foo); | semmle.order | 3 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.label | 4 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:7:3:7:15 | [DeclStmt] var arr = ... | semmle.order | 4 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.label | 5 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:8:3:8:19 | [ExprStmt] arr.push(source); | semmle.order | 5 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.label | 6 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:10:3:12:3 | [ForStmt] for (va ... OK } | semmle.order | 6 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.label | 7 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:15:3:15:30 | [ExprStmt] arr.for ... nk(e)); | semmle.order | 7 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.label | 8 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:16:3:16:26 | [ExprStmt] arr.map ... nk(e)); | semmle.order | 8 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.label | 9 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:18:3:18:53 | [ExprStmt] [1, 2, ... nk(e)); | semmle.order | 9 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.label | 10 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:20:3:20:18 | [ExprStmt] sink(arr.pop()); | semmle.order | 10 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.label | 11 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:22:3:22:24 | [DeclStmt] var arr2 = ... | semmle.order | 11 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.label | 12 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:23:3:23:19 | [ExprStmt] sink(arr2.pop()); | semmle.order | 12 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.label | 13 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:25:3:25:24 | [DeclStmt] var arr3 = ... | semmle.order | 13 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.label | 14 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:26:3:26:19 | [ExprStmt] sink(arr3.pop()); | semmle.order | 14 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.label | 15 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:28:3:28:16 | [DeclStmt] var arr4 = ... | semmle.order | 15 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.label | 16 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:29:3:29:30 | [ExprStmt] arr4.sp ... urce"); | semmle.order | 16 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.label | 17 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:30:3:30:19 | [ExprStmt] sink(arr4.pop()); | semmle.order | 17 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.label | 18 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:32:3:32:29 | [DeclStmt] var arr5 = ... | semmle.order | 18 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.label | 19 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:33:3:33:19 | [ExprStmt] sink(arr5.pop()); | semmle.order | 19 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.label | 20 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:35:3:35:28 | [ExprStmt] sink(ar ... pop()); | semmle.order | 20 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.label | 21 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:37:3:37:16 | [DeclStmt] var arr6 = ... | semmle.order | 21 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.label | 22 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:38:3:40:3 | [ForStmt] for (va ... i]; } | semmle.order | 22 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.label | 23 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:41:3:41:19 | [ExprStmt] sink(arr6.pop()); | semmle.order | 23 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.label | 24 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:44:3:47:5 | [ExprStmt] ["sourc ... . }); | semmle.order | 24 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.label | 25 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:49:3:49:15 | [ExprStmt] sink(arr[0]); | semmle.order | 25 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.label | 26 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:51:3:53:3 | [ForOfStmt] for (co ... OK } | semmle.order | 26 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.label | 27 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:55:3:57:3 | [ForOfStmt] for (co ... OK } | semmle.order | 27 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.label | 28 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:59:3:61:3 | [ForOfStmt] for (co ... OK } | semmle.order | 28 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.label | 29 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:63:3:63:16 | [DeclStmt] var arr7 = ... | semmle.order | 29 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.label | 30 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:64:3:64:20 | [ExprStmt] arr7.push(...arr); | semmle.order | 30 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.label | 31 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:65:3:67:3 | [ForOfStmt] for (co ... OK } | semmle.order | 31 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.label | 32 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:69:3:69:42 | [DeclStmt] const arrayFrom = ... | semmle.order | 32 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.label | 33 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:70:3:72:3 | [ForOfStmt] for (co ... OK } | semmle.order | 33 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.label | 34 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:74:3:74:31 | [ExprStmt] sink(ar ... back)); | semmle.order | 34 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.label | 35 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:76:3:76:42 | [DeclStmt] const arrayFind = ... | semmle.order | 35 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.label | 36 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:77:3:77:37 | [ExprStmt] sink(ar ... back)); | semmle.order | 36 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.label | 37 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:79:3:79:31 | [DeclStmt] const uniq = ... | semmle.order | 37 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.label | 38 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:80:3:82:3 | [ForOfStmt] for (co ... OK } | semmle.order | 38 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:84:3:84:19 | [ExprStmt] sink(arr.at(-1)); | semmle.label | 39 | +| arrays.js:1:14:85:1 | [BlockStmt] { let ... OT OK } | arrays.js:84:3:84:19 | [ExprStmt] sink(arr.at(-1)); | semmle.order | 39 | | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.label | 1 | | arrays.js:2:3:2:24 | [DeclStmt] let source = ... | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | semmle.order | 1 | | arrays.js:2:7:2:23 | [VariableDeclarator] source = "source" | arrays.js:2:7:2:12 | [VarDecl] source | semmle.label | 1 | @@ -1052,6 +1065,22 @@ edges | arrays.js:81:5:81:11 | [CallExpr] sink(x) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | | arrays.js:81:5:81:12 | [ExprStmt] sink(x); | arrays.js:81:5:81:11 | [CallExpr] sink(x) | semmle.label | 1 | | arrays.js:81:5:81:12 | [ExprStmt] sink(x); | arrays.js:81:5:81:11 | [CallExpr] sink(x) | semmle.order | 1 | +| arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | arrays.js:84:3:84:6 | [VarRef] sink | semmle.label | 0 | +| arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | arrays.js:84:3:84:6 | [VarRef] sink | semmle.order | 0 | +| arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:84:3:84:19 | [ExprStmt] sink(arr.at(-1)); | arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | semmle.label | 1 | +| arrays.js:84:3:84:19 | [ExprStmt] sink(arr.at(-1)); | arrays.js:84:3:84:18 | [CallExpr] sink(arr.at(-1)) | semmle.order | 1 | +| arrays.js:84:8:84:13 | [DotExpr] arr.at | arrays.js:84:8:84:10 | [VarRef] arr | semmle.label | 1 | +| arrays.js:84:8:84:13 | [DotExpr] arr.at | arrays.js:84:8:84:10 | [VarRef] arr | semmle.order | 1 | +| arrays.js:84:8:84:13 | [DotExpr] arr.at | arrays.js:84:12:84:13 | [Label] at | semmle.label | 2 | +| arrays.js:84:8:84:13 | [DotExpr] arr.at | arrays.js:84:12:84:13 | [Label] at | semmle.order | 2 | +| arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | arrays.js:84:8:84:13 | [DotExpr] arr.at | semmle.label | 0 | +| arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | arrays.js:84:8:84:13 | [DotExpr] arr.at | semmle.order | 0 | +| arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| arrays.js:84:15:84:16 | [UnaryExpr] -1 | arrays.js:84:16:84:16 | [Literal] 1 | semmle.label | 1 | +| arrays.js:84:15:84:16 | [UnaryExpr] -1 | arrays.js:84:16:84:16 | [Literal] 1 | semmle.order | 1 | | file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.label | 0 | | file://:0:0:0:0 | (Arguments) | arrays.js:5:8:5:14 | [DotExpr] obj.foo | semmle.order | 0 | | file://:0:0:0:0 | (Arguments) | arrays.js:8:12:8:17 | [VarRef] source | semmle.label | 0 | @@ -1140,6 +1169,10 @@ edges | file://:0:0:0:0 | (Arguments) | arrays.js:80:24:80:26 | [VarRef] arr | semmle.order | 0 | | file://:0:0:0:0 | (Arguments) | arrays.js:81:10:81:10 | [VarRef] x | semmle.label | 0 | | file://:0:0:0:0 | (Arguments) | arrays.js:81:10:81:10 | [VarRef] x | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:84:8:84:17 | [MethodCallExpr] arr.at(-1) | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:84:15:84:16 | [UnaryExpr] -1 | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | arrays.js:84:15:84:16 | [UnaryExpr] -1 | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.label | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:15:16:15:16 | [SimpleParameter] e | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | arrays.js:16:12:16:12 | [SimpleParameter] e | semmle.label | 0 | diff --git a/javascript/ql/test/library-tests/Routing/test.ql b/javascript/ql/test/library-tests/Routing/test.ql index aa89c7212d2..b427f710894 100644 --- a/javascript/ql/test/library-tests/Routing/test.ql +++ b/javascript/ql/test/library-tests/Routing/test.ql @@ -9,12 +9,12 @@ class Taint extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node node) { node.(DataFlow::CallNode).getCalleeName() = "source" or - node = testInstance().getMember("getSource").getReturn().getAnImmediateUse() + node = testInstance().getMember("getSource").getReturn().asSource() } override predicate isSink(DataFlow::Node node) { node = any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument() or - node = testInstance().getMember("getSink").getAParameter().getARhs() + node = testInstance().getMember("getSink").getAParameter().asSink() } } diff --git a/javascript/ql/test/library-tests/TaintBarriers/tests.expected b/javascript/ql/test/library-tests/TaintBarriers/tests.expected index 33f06a2ff23..3ee1223b87d 100644 --- a/javascript/ql/test/library-tests/TaintBarriers/tests.expected +++ b/javascript/ql/test/library-tests/TaintBarriers/tests.expected @@ -43,6 +43,10 @@ isLabeledBarrier | ExampleConfiguration | tst.js:361:14:361:14 | v | taint | | ExampleConfiguration | tst.js:371:14:371:16 | o.p | taint | | ExampleConfiguration | tst.js:378:14:378:17 | o[p] | taint | +| ExampleConfiguration | tst.js:392:14:392:14 | v | taint | +| ExampleConfiguration | tst.js:394:14:394:16 | v.p | taint | +| ExampleConfiguration | tst.js:396:14:396:18 | v.p.q | taint | +| ExampleConfiguration | tst.js:402:14:402:14 | v | taint | isSanitizer | ExampleConfiguration | tst.js:176:18:176:18 | v | sanitizingGuard @@ -122,6 +126,12 @@ sanitizingGuard | tst.js:370:9:370:29 | o.p == ... listed" | tst.js:370:16:370:29 | "white-listed" | true | | tst.js:377:11:377:32 | o[p] == ... listed" | tst.js:377:11:377:14 | o[p] | true | | tst.js:377:11:377:32 | o[p] == ... listed" | tst.js:377:19:377:32 | "white-listed" | true | +| tst.js:391:9:391:27 | o.hasOwnProperty(v) | tst.js:391:26:391:26 | v | true | +| tst.js:393:16:393:36 | o.hasOw ... ty(v.p) | tst.js:393:33:393:35 | v.p | true | +| tst.js:395:16:395:38 | o.hasOw ... (v.p.q) | tst.js:395:33:395:37 | v.p.q | true | +| tst.js:397:16:397:36 | o.hasOw ... ty(v.p) | tst.js:397:33:397:35 | v.p | true | +| tst.js:399:16:399:41 | o.hasOw ... "p.q"]) | tst.js:399:33:399:40 | v["p.q"] | true | +| tst.js:401:16:401:34 | Object.hasOwn(o, v) | tst.js:401:33:401:33 | v | true | taintedSink | tst.js:2:13:2:20 | SOURCE() | tst.js:3:10:3:10 | v | | tst.js:2:13:2:20 | SOURCE() | tst.js:8:14:8:14 | v | @@ -186,3 +196,6 @@ taintedSink | tst.js:367:13:367:20 | SOURCE() | tst.js:373:14:373:16 | o.p | | tst.js:367:13:367:20 | SOURCE() | tst.js:380:14:380:17 | o[p] | | tst.js:367:13:367:20 | SOURCE() | tst.js:382:14:382:17 | o[p] | +| tst.js:388:13:388:20 | SOURCE() | tst.js:389:10:389:14 | v.p.q | +| tst.js:388:13:388:20 | SOURCE() | tst.js:398:14:398:14 | v | +| tst.js:388:13:388:20 | SOURCE() | tst.js:400:14:400:18 | v.p.q | diff --git a/javascript/ql/test/library-tests/TaintBarriers/tst.js b/javascript/ql/test/library-tests/TaintBarriers/tst.js index 265c5ac6210..20102605af1 100644 --- a/javascript/ql/test/library-tests/TaintBarriers/tst.js +++ b/javascript/ql/test/library-tests/TaintBarriers/tst.js @@ -383,3 +383,22 @@ function constantComparisonSanitizer2() { } } } + +function propertySanitization(o) { + var v = SOURCE(); + SINK(v.p.q); // NOT OK + + if (o.hasOwnProperty(v)) { + SINK(v); // OK + } else if (o.hasOwnProperty(v.p)) { + SINK(v.p); // OK + } else if (o.hasOwnProperty(v.p.q)) { + SINK(v.p.q); // OK + } else if (o.hasOwnProperty(v.p)) { + SINK(v); // NOT OK + } else if (o.hasOwnProperty(v["p.q"])) { + SINK(v.p.q); // NOT OK + } else if (Object.hasOwn(o, v)) { + SINK(v); // OK + } +} diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 12fdd69e80f..cd41461e4a8 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -17,6 +17,7 @@ typeInferenceMismatch | arrays.js:2:15:2:22 | source() | arrays.js:11:10:11:28 | union(["bla"], foo) | | arrays.js:2:15:2:22 | source() | arrays.js:14:10:14:18 | flat(foo) | | arrays.js:2:15:2:22 | source() | arrays.js:19:10:19:12 | res | +| arrays.js:2:15:2:22 | source() | arrays.js:21:10:21:19 | foo.at(-1) | | booleanOps.js:2:11:2:18 | source() | booleanOps.js:4:8:4:8 | x | | booleanOps.js:2:11:2:18 | source() | booleanOps.js:13:10:13:10 | x | | booleanOps.js:2:11:2:18 | source() | booleanOps.js:19:10:19:10 | x | diff --git a/javascript/ql/test/library-tests/TaintTracking/arrays.js b/javascript/ql/test/library-tests/TaintTracking/arrays.js index b99e2058d80..b9daf4943b3 100644 --- a/javascript/ql/test/library-tests/TaintTracking/arrays.js +++ b/javascript/ql/test/library-tests/TaintTracking/arrays.js @@ -17,4 +17,6 @@ function test() { return prev + '' + current + ''; }, ''); sink(res); // NOT OK + + sink(foo.at(-1)); // NOT OK } diff --git a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected index e50154887a2..9f4f6c6aba5 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected @@ -94,6 +94,11 @@ nodes | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | +| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | @@ -120,6 +125,17 @@ nodes | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | | file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) | +| file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) | +| file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) | +| file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) | +| file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) | | file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) | | file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) | | file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) | @@ -1128,17 +1144,314 @@ nodes | tst.ts:293:7:293:23 | [MethodCallExpr] payload.toFixed() | semmle.label | [MethodCallExpr] payload.toFixed() | | tst.ts:293:7:293:24 | [ExprStmt] payload.toFixed(); | semmle.label | [ExprStmt] payload.toFixed(); | | tst.ts:293:15:293:21 | [Label] toFixed | semmle.label | [Label] toFixed | +| tst.ts:298:1:298:21 | [DeclStmt] const key = ... | semmle.label | [DeclStmt] const key = ... | +| tst.ts:298:1:298:21 | [DeclStmt] const key = ... | semmle.order | 61 | +| tst.ts:298:7:298:9 | [VarDecl] key | semmle.label | [VarDecl] key | +| tst.ts:298:7:298:20 | [VariableDeclarator] key = Symbol() | semmle.label | [VariableDeclarator] key = Symbol() | +| tst.ts:298:13:298:18 | [VarRef] Symbol | semmle.label | [VarRef] Symbol | +| tst.ts:298:13:298:20 | [CallExpr] Symbol() | semmle.label | [CallExpr] Symbol() | +| tst.ts:300:1:300:58 | [DeclStmt] const numberOrString = ... | semmle.label | [DeclStmt] const numberOrString = ... | +| tst.ts:300:1:300:58 | [DeclStmt] const numberOrString = ... | semmle.order | 62 | +| tst.ts:300:7:300:20 | [VarDecl] numberOrString | semmle.label | [VarDecl] numberOrString | +| tst.ts:300:7:300:57 | [VariableDeclarator] numberO ... "hello" | semmle.label | [VariableDeclarator] numberO ... "hello" | +| tst.ts:300:24:300:27 | [VarRef] Math | semmle.label | [VarRef] Math | +| tst.ts:300:24:300:34 | [DotExpr] Math.random | semmle.label | [DotExpr] Math.random | +| tst.ts:300:24:300:36 | [MethodCallExpr] Math.random() | semmle.label | [MethodCallExpr] Math.random() | +| tst.ts:300:24:300:42 | [BinaryExpr] Math.random() < 0.5 | semmle.label | [BinaryExpr] Math.random() < 0.5 | +| tst.ts:300:24:300:57 | [ConditionalExpr] Math.ra ... "hello" | semmle.label | [ConditionalExpr] Math.ra ... "hello" | +| tst.ts:300:29:300:34 | [Label] random | semmle.label | [Label] random | +| tst.ts:300:40:300:42 | [Literal] 0.5 | semmle.label | [Literal] 0.5 | +| tst.ts:300:46:300:47 | [Literal] 42 | semmle.label | [Literal] 42 | +| tst.ts:300:51:300:57 | [Literal] "hello" | semmle.label | [Literal] "hello" | +| tst.ts:302:1:304:2 | [DeclStmt] let obj = ... | semmle.label | [DeclStmt] let obj = ... | +| tst.ts:302:1:304:2 | [DeclStmt] let obj = ... | semmle.order | 63 | +| tst.ts:302:5:302:7 | [VarDecl] obj | semmle.label | [VarDecl] obj | +| tst.ts:302:5:304:1 | [VariableDeclarator] obj = { ... ring, } | semmle.label | [VariableDeclarator] obj = { ... ring, } | +| tst.ts:302:11:304:1 | [ObjectExpr] { [ke ... ring, } | semmle.label | [ObjectExpr] { [ke ... ring, } | +| tst.ts:303:3:303:23 | [Property] [key]: ... rString | semmle.label | [Property] [key]: ... rString | +| tst.ts:303:4:303:6 | [VarRef] key | semmle.label | [VarRef] key | +| tst.ts:303:10:303:23 | [VarRef] numberOrString | semmle.label | [VarRef] numberOrString | +| tst.ts:306:1:309:1 | [IfStmt] if (typ ... se(); } | semmle.label | [IfStmt] if (typ ... se(); } | +| tst.ts:306:1:309:1 | [IfStmt] if (typ ... se(); } | semmle.order | 64 | +| tst.ts:306:5:306:19 | [UnaryExpr] typeof obj[key] | semmle.label | [UnaryExpr] typeof obj[key] | +| tst.ts:306:5:306:32 | [BinaryExpr] typeof ... string" | semmle.label | [BinaryExpr] typeof ... string" | +| tst.ts:306:12:306:14 | [VarRef] obj | semmle.label | [VarRef] obj | +| tst.ts:306:12:306:19 | [IndexExpr] obj[key] | semmle.label | [IndexExpr] obj[key] | +| tst.ts:306:16:306:18 | [VarRef] key | semmle.label | [VarRef] key | +| tst.ts:306:25:306:32 | [Literal] "string" | semmle.label | [Literal] "string" | +| tst.ts:306:35:309:1 | [BlockStmt] { let ... se(); } | semmle.label | [BlockStmt] { let ... se(); } | +| tst.ts:307:3:307:21 | [DeclStmt] let str = ... | semmle.label | [DeclStmt] let str = ... | +| tst.ts:307:7:307:9 | [VarDecl] str | semmle.label | [VarDecl] str | +| tst.ts:307:7:307:20 | [VariableDeclarator] str = obj[key] | semmle.label | [VariableDeclarator] str = obj[key] | +| tst.ts:307:13:307:15 | [VarRef] obj | semmle.label | [VarRef] obj | +| tst.ts:307:13:307:20 | [IndexExpr] obj[key] | semmle.label | [IndexExpr] obj[key] | +| tst.ts:307:17:307:19 | [VarRef] key | semmle.label | [VarRef] key | +| tst.ts:308:3:308:5 | [VarRef] str | semmle.label | [VarRef] str | +| tst.ts:308:3:308:17 | [DotExpr] str.toUpperCase | semmle.label | [DotExpr] str.toUpperCase | +| tst.ts:308:3:308:19 | [MethodCallExpr] str.toUpperCase() | semmle.label | [MethodCallExpr] str.toUpperCase() | +| tst.ts:308:3:308:20 | [ExprStmt] str.toUpperCase(); | semmle.label | [ExprStmt] str.toUpperCase(); | +| tst.ts:308:7:308:17 | [Label] toUpperCase | semmle.label | [Label] toUpperCase | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | semmle.label | [FunctionDeclStmt] functio ... void {} | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | semmle.order | 65 | +| tst.ts:313:10:313:10 | [VarDecl] f | semmle.label | [VarDecl] f | +| tst.ts:313:12:313:12 | [Identifier] T | semmle.label | [Identifier] T | +| tst.ts:313:12:313:12 | [TypeParameter] T | semmle.label | [TypeParameter] T | +| tst.ts:313:15:313:17 | [SimpleParameter] arg | semmle.label | [SimpleParameter] arg | +| tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | semmle.label | [InterfaceTypeExpr] { pro ... void } | +| tst.ts:314:3:314:9 | [Label] produce | semmle.label | [Label] produce | +| tst.ts:314:3:314:28 | [FieldDeclaration] produce ... ) => T, | semmle.label | [FieldDeclaration] produce ... ) => T, | +| tst.ts:314:12:314:27 | [FunctionExpr] (n: string) => T | semmle.label | [FunctionExpr] (n: string) => T | +| tst.ts:314:12:314:27 | [FunctionTypeExpr] (n: string) => T | semmle.label | [FunctionTypeExpr] (n: string) => T | +| tst.ts:314:13:314:13 | [SimpleParameter] n | semmle.label | [SimpleParameter] n | +| tst.ts:314:16:314:21 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | +| tst.ts:314:27:314:27 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | +| tst.ts:315:3:315:9 | [Label] consume | semmle.label | [Label] consume | +| tst.ts:315:3:315:25 | [FieldDeclaration] consume ... => void | semmle.label | [FieldDeclaration] consume ... => void | +| tst.ts:315:12:315:25 | [FunctionExpr] (x: T) => void | semmle.label | [FunctionExpr] (x: T) => void | +| tst.ts:315:12:315:25 | [FunctionTypeExpr] (x: T) => void | semmle.label | [FunctionTypeExpr] (x: T) => void | +| tst.ts:315:13:315:13 | [SimpleParameter] x | semmle.label | [SimpleParameter] x | +| tst.ts:315:16:315:16 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | +| tst.ts:315:22:315:25 | [KeywordTypeExpr] void | semmle.label | [KeywordTypeExpr] void | +| tst.ts:316:4:316:7 | [KeywordTypeExpr] void | semmle.label | [KeywordTypeExpr] void | +| tst.ts:316:9:316:10 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | +| tst.ts:316:11:316:11 | [EmptyStmt] ; | semmle.label | [EmptyStmt] ; | +| tst.ts:316:11:316:11 | [EmptyStmt] ; | semmle.order | 66 | +| tst.ts:318:1:318:1 | [VarRef] f | semmle.label | [VarRef] f | +| tst.ts:318:1:321:2 | [CallExpr] f({ p ... se() }) | semmle.label | [CallExpr] f({ p ... se() }) | +| tst.ts:318:1:321:3 | [ExprStmt] f({ p ... e() }); | semmle.label | [ExprStmt] f({ p ... e() }); | +| tst.ts:318:1:321:3 | [ExprStmt] f({ p ... e() }); | semmle.order | 67 | +| tst.ts:318:3:321:1 | [ObjectExpr] {produce: ...} | semmle.label | [ObjectExpr] {produce: ...} | +| tst.ts:319:3:319:9 | [Label] produce | semmle.label | [Label] produce | +| tst.ts:319:3:319:17 | [Property] produce: n => n | semmle.label | [Property] produce: n => n | +| tst.ts:319:12:319:12 | [SimpleParameter] n | semmle.label | [SimpleParameter] n | +| tst.ts:319:12:319:17 | [ArrowFunctionExpr] n => n | semmle.label | [ArrowFunctionExpr] n => n | +| tst.ts:319:17:319:17 | [VarRef] n | semmle.label | [VarRef] n | +| tst.ts:320:3:320:9 | [Label] consume | semmle.label | [Label] consume | +| tst.ts:320:3:320:31 | [Property] consume ... rCase() | semmle.label | [Property] consume ... rCase() | +| tst.ts:320:12:320:12 | [SimpleParameter] x | semmle.label | [SimpleParameter] x | +| tst.ts:320:12:320:31 | [ArrowFunctionExpr] x => x.toLowerCase() | semmle.label | [ArrowFunctionExpr] x => x.toLowerCase() | +| tst.ts:320:17:320:17 | [VarRef] x | semmle.label | [VarRef] x | +| tst.ts:320:17:320:29 | [DotExpr] x.toLowerCase | semmle.label | [DotExpr] x.toLowerCase | +| tst.ts:320:17:320:31 | [MethodCallExpr] x.toLowerCase() | semmle.label | [MethodCallExpr] x.toLowerCase() | +| tst.ts:320:19:320:29 | [Label] toLowerCase | semmle.label | [Label] toLowerCase | +| tst.ts:325:1:325:36 | [DeclStmt] const ErrorMap = ... | semmle.label | [DeclStmt] const ErrorMap = ... | +| tst.ts:325:1:325:36 | [DeclStmt] const ErrorMap = ... | semmle.order | 68 | +| tst.ts:325:7:325:14 | [VarDecl] ErrorMap | semmle.label | [VarDecl] ErrorMap | +| tst.ts:325:7:325:35 | [VariableDeclarator] ErrorMa ... Error> | semmle.label | [VariableDeclarator] ErrorMa ... Error> | +| tst.ts:325:18:325:20 | [VarRef] Map | semmle.label | [VarRef] Map | +| tst.ts:325:18:325:35 | [ExpressionWithTypeArguments] Map | semmle.label | [ExpressionWithTypeArguments] Map | +| tst.ts:325:22:325:27 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | +| tst.ts:325:30:325:34 | [LocalTypeAccess] Error | semmle.label | [LocalTypeAccess] Error | +| tst.ts:327:1:327:32 | [DeclStmt] const errorMap = ... | semmle.label | [DeclStmt] const errorMap = ... | +| tst.ts:327:1:327:32 | [DeclStmt] const errorMap = ... | semmle.order | 69 | +| tst.ts:327:7:327:14 | [VarDecl] errorMap | semmle.label | [VarDecl] errorMap | +| tst.ts:327:7:327:31 | [VariableDeclarator] errorMa ... orMap() | semmle.label | [VariableDeclarator] errorMa ... orMap() | +| tst.ts:327:18:327:31 | [NewExpr] new ErrorMap() | semmle.label | [NewExpr] new ErrorMap() | +| tst.ts:327:22:327:29 | [VarRef] ErrorMap | semmle.label | [VarRef] ErrorMap | +| tst.ts:331:1:334:14 | [TypeAliasDeclaration,TypeDefinition] type Fi ... never; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Fi ... never; | +| tst.ts:331:1:334:14 | [TypeAliasDeclaration,TypeDefinition] type Fi ... never; | semmle.order | 70 | +| tst.ts:331:6:331:16 | [Identifier] FirstString | semmle.label | [Identifier] FirstString | +| tst.ts:331:18:331:18 | [Identifier] T | semmle.label | [Identifier] T | +| tst.ts:331:18:331:18 | [TypeParameter] T | semmle.label | [TypeParameter] T | +| tst.ts:332:3:332:3 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | +| tst.ts:332:3:334:13 | [ConditionalTypeExpr] T exten ... : never | semmle.label | [ConditionalTypeExpr] T exten ... : never | +| tst.ts:332:13:332:50 | [TupleTypeExpr] [infer ... nown[]] | semmle.label | [TupleTypeExpr] [infer ... nown[]] | +| tst.ts:332:14:332:35 | [InferTypeExpr] infer S ... string | semmle.label | [InferTypeExpr] infer S ... string | +| tst.ts:332:20:332:20 | [Identifier] S | semmle.label | [Identifier] S | +| tst.ts:332:20:332:35 | [TypeParameter] S extends string | semmle.label | [TypeParameter] S extends string | +| tst.ts:332:30:332:35 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | +| tst.ts:332:38:332:49 | [RestTypeExpr] ...unknown[] | semmle.label | [RestTypeExpr] ...unknown[] | +| tst.ts:332:41:332:47 | [KeywordTypeExpr] unknown | semmle.label | [KeywordTypeExpr] unknown | +| tst.ts:332:41:332:49 | [ArrayTypeExpr] unknown[] | semmle.label | [ArrayTypeExpr] unknown[] | +| tst.ts:333:9:333:9 | [LocalTypeAccess] S | semmle.label | [LocalTypeAccess] S | +| tst.ts:334:9:334:13 | [KeywordTypeExpr] never | semmle.label | [KeywordTypeExpr] never | +| tst.ts:336:1:336:51 | [TypeAliasDeclaration,TypeDefinition] type F ... lean]>; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type F ... lean]>; | +| tst.ts:336:1:336:51 | [TypeAliasDeclaration,TypeDefinition] type F ... lean]>; | semmle.order | 71 | +| tst.ts:336:6:336:6 | [Identifier] F | semmle.label | [Identifier] F | +| tst.ts:336:10:336:20 | [LocalTypeAccess] FirstString | semmle.label | [LocalTypeAccess] FirstString | +| tst.ts:336:10:336:50 | [GenericTypeExpr] FirstSt ... olean]> | semmle.label | [GenericTypeExpr] FirstSt ... olean]> | +| tst.ts:336:22:336:49 | [TupleTypeExpr] ['a' \| ... oolean] | semmle.label | [TupleTypeExpr] ['a' \| ... oolean] | +| tst.ts:336:23:336:25 | [LiteralTypeExpr] 'a' | semmle.label | [LiteralTypeExpr] 'a' | +| tst.ts:336:23:336:31 | [UnionTypeExpr] 'a' \| 'b' | semmle.label | [UnionTypeExpr] 'a' \| 'b' | +| tst.ts:336:29:336:31 | [LiteralTypeExpr] 'b' | semmle.label | [LiteralTypeExpr] 'b' | +| tst.ts:336:34:336:39 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| tst.ts:336:42:336:48 | [KeywordTypeExpr] boolean | semmle.label | [KeywordTypeExpr] boolean | +| tst.ts:338:1:338:17 | [DeclStmt] const a = ... | semmle.label | [DeclStmt] const a = ... | +| tst.ts:338:1:338:17 | [DeclStmt] const a = ... | semmle.order | 72 | +| tst.ts:338:7:338:7 | [VarDecl] a | semmle.label | [VarDecl] a | +| tst.ts:338:7:338:16 | [VariableDeclarator] a: F = 'a' | semmle.label | [VariableDeclarator] a: F = 'a' | +| tst.ts:338:10:338:10 | [LocalTypeAccess] F | semmle.label | [LocalTypeAccess] F | +| tst.ts:338:14:338:16 | [Literal] 'a' | semmle.label | [Literal] 'a' | +| tst.ts:342:1:345:1 | [InterfaceDeclaration,TypeDefinition] interfa ... void; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... void; } | +| tst.ts:342:1:345:1 | [InterfaceDeclaration,TypeDefinition] interfa ... void; } | semmle.order | 73 | +| tst.ts:342:11:342:15 | [Identifier] State | semmle.label | [Identifier] State | +| tst.ts:342:17:342:24 | [TypeParameter] in out T | semmle.label | [TypeParameter] in out T | +| tst.ts:342:24:342:24 | [Identifier] T | semmle.label | [Identifier] T | +| tst.ts:343:3:343:5 | [Label] get | semmle.label | [Label] get | +| tst.ts:343:3:343:15 | [FieldDeclaration] get: () => T; | semmle.label | [FieldDeclaration] get: () => T; | +| tst.ts:343:8:343:14 | [FunctionExpr] () => T | semmle.label | [FunctionExpr] () => T | +| tst.ts:343:8:343:14 | [FunctionTypeExpr] () => T | semmle.label | [FunctionTypeExpr] () => T | +| tst.ts:343:14:343:14 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | +| tst.ts:344:3:344:5 | [Label] set | semmle.label | [Label] set | +| tst.ts:344:3:344:26 | [FieldDeclaration] set: (v ... > void; | semmle.label | [FieldDeclaration] set: (v ... > void; | +| tst.ts:344:8:344:25 | [FunctionExpr] (value: T) => void | semmle.label | [FunctionExpr] (value: T) => void | +| tst.ts:344:8:344:25 | [FunctionTypeExpr] (value: T) => void | semmle.label | [FunctionTypeExpr] (value: T) => void | +| tst.ts:344:9:344:13 | [SimpleParameter] value | semmle.label | [SimpleParameter] value | +| tst.ts:344:16:344:16 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | +| tst.ts:344:22:344:25 | [KeywordTypeExpr] void | semmle.label | [KeywordTypeExpr] void | +| tst.ts:347:1:350:1 | [DeclStmt] const state = ... | semmle.label | [DeclStmt] const state = ... | +| tst.ts:347:1:350:1 | [DeclStmt] const state = ... | semmle.order | 74 | +| tst.ts:347:7:347:11 | [VarDecl] state | semmle.label | [VarDecl] state | +| tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | semmle.label | [VariableDeclarator] state: ... > { } } | +| tst.ts:347:14:347:18 | [LocalTypeAccess] State | semmle.label | [LocalTypeAccess] State | +| tst.ts:347:14:347:26 | [GenericTypeExpr] State | semmle.label | [GenericTypeExpr] State | +| tst.ts:347:20:347:25 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| tst.ts:347:30:350:1 | [ObjectExpr] {get: ...} | semmle.label | [ObjectExpr] {get: ...} | +| tst.ts:348:3:348:5 | [Label] get | semmle.label | [Label] get | +| tst.ts:348:3:348:15 | [Property] get: () => 42 | semmle.label | [Property] get: () => 42 | +| tst.ts:348:8:348:15 | [ArrowFunctionExpr] () => 42 | semmle.label | [ArrowFunctionExpr] () => 42 | +| tst.ts:348:14:348:15 | [Literal] 42 | semmle.label | [Literal] 42 | +| tst.ts:349:3:349:5 | [Label] set | semmle.label | [Label] set | +| tst.ts:349:3:349:21 | [Property] set: (value) => { } | semmle.label | [Property] set: (value) => { } | +| tst.ts:349:8:349:21 | [ArrowFunctionExpr] (value) => { } | semmle.label | [ArrowFunctionExpr] (value) => { } | +| tst.ts:349:9:349:13 | [SimpleParameter] value | semmle.label | [SimpleParameter] value | +| tst.ts:349:19:349:21 | [BlockStmt] { } | semmle.label | [BlockStmt] { } | +| tst.ts:352:1:352:29 | [DeclStmt] const fortyTwo = ... | semmle.label | [DeclStmt] const fortyTwo = ... | +| tst.ts:352:1:352:29 | [DeclStmt] const fortyTwo = ... | semmle.order | 75 | +| tst.ts:352:7:352:14 | [VarDecl] fortyTwo | semmle.label | [VarDecl] fortyTwo | +| tst.ts:352:7:352:28 | [VariableDeclarator] fortyTw ... e.get() | semmle.label | [VariableDeclarator] fortyTw ... e.get() | +| tst.ts:352:18:352:22 | [VarRef] state | semmle.label | [VarRef] state | +| tst.ts:352:18:352:26 | [DotExpr] state.get | semmle.label | [DotExpr] state.get | +| tst.ts:352:18:352:28 | [MethodCallExpr] state.get() | semmle.label | [MethodCallExpr] state.get() | +| tst.ts:352:24:352:26 | [Label] get | semmle.label | [Label] get | +| tst.ts:356:1:356:44 | [ImportDeclaration] import ... S.mjs'; | semmle.label | [ImportDeclaration] import ... S.mjs'; | +| tst.ts:356:1:356:44 | [ImportDeclaration] import ... S.mjs'; | semmle.order | 76 | +| tst.ts:356:8:356:18 | [ImportSpecifier] tstModuleES | semmle.label | [ImportSpecifier] tstModuleES | +| tst.ts:356:8:356:18 | [VarDecl] tstModuleES | semmle.label | [VarDecl] tstModuleES | +| tst.ts:356:25:356:43 | [Literal] './tstModuleES.mjs' | semmle.label | [Literal] './tstModuleES.mjs' | +| tst.ts:358:1:358:7 | [VarRef] console | semmle.label | [VarRef] console | +| tst.ts:358:1:358:11 | [DotExpr] console.log | semmle.label | [DotExpr] console.log | +| tst.ts:358:1:358:26 | [MethodCallExpr] console ... leES()) | semmle.label | [MethodCallExpr] console ... leES()) | +| tst.ts:358:1:358:27 | [ExprStmt] console ... eES()); | semmle.label | [ExprStmt] console ... eES()); | +| tst.ts:358:1:358:27 | [ExprStmt] console ... eES()); | semmle.order | 77 | +| tst.ts:358:9:358:11 | [Label] log | semmle.label | [Label] log | +| tst.ts:358:13:358:23 | [VarRef] tstModuleES | semmle.label | [VarRef] tstModuleES | +| tst.ts:358:13:358:25 | [CallExpr] tstModuleES() | semmle.label | [CallExpr] tstModuleES() | +| tst.ts:360:1:360:50 | [ImportDeclaration] import ... S.cjs'; | semmle.label | [ImportDeclaration] import ... S.cjs'; | +| tst.ts:360:1:360:50 | [ImportDeclaration] import ... S.cjs'; | semmle.order | 78 | +| tst.ts:360:10:360:21 | [ImportSpecifier] tstModuleCJS | semmle.label | [ImportSpecifier] tstModuleCJS | +| tst.ts:360:10:360:21 | [Label] tstModuleCJS | semmle.label | [Label] tstModuleCJS | +| tst.ts:360:10:360:21 | [VarDecl] tstModuleCJS | semmle.label | [VarDecl] tstModuleCJS | +| tst.ts:360:30:360:49 | [Literal] './tstModuleCJS.cjs' | semmle.label | [Literal] './tstModuleCJS.cjs' | +| tst.ts:362:1:362:7 | [VarRef] console | semmle.label | [VarRef] console | +| tst.ts:362:1:362:11 | [DotExpr] console.log | semmle.label | [DotExpr] console.log | +| tst.ts:362:1:362:27 | [MethodCallExpr] console ... eCJS()) | semmle.label | [MethodCallExpr] console ... eCJS()) | +| tst.ts:362:1:362:28 | [ExprStmt] console ... CJS()); | semmle.label | [ExprStmt] console ... CJS()); | +| tst.ts:362:1:362:28 | [ExprStmt] console ... CJS()); | semmle.order | 79 | +| tst.ts:362:9:362:11 | [Label] log | semmle.label | [Label] log | +| tst.ts:362:13:362:24 | [VarRef] tstModuleCJS | semmle.label | [VarRef] tstModuleCJS | +| tst.ts:362:13:362:26 | [CallExpr] tstModuleCJS() | semmle.label | [CallExpr] tstModuleCJS() | +| tst.ts:368:1:368:34 | [ImportDeclaration] import ... ffixA'; | semmle.label | [ImportDeclaration] import ... ffixA'; | +| tst.ts:368:1:368:34 | [ImportDeclaration] import ... ffixA'; | semmle.order | 80 | +| tst.ts:368:8:368:13 | [ImportSpecifier] * as A | semmle.label | [ImportSpecifier] * as A | +| tst.ts:368:13:368:13 | [VarDecl] A | semmle.label | [VarDecl] A | +| tst.ts:368:20:368:33 | [Literal] './tstSuffixA' | semmle.label | [Literal] './tstSuffixA' | +| tst.ts:370:1:370:7 | [VarRef] console | semmle.label | [VarRef] console | +| tst.ts:370:1:370:11 | [DotExpr] console.log | semmle.label | [DotExpr] console.log | +| tst.ts:370:1:370:29 | [MethodCallExpr] console ... File()) | semmle.label | [MethodCallExpr] console ... File()) | +| tst.ts:370:1:370:30 | [ExprStmt] console ... ile()); | semmle.label | [ExprStmt] console ... ile()); | +| tst.ts:370:1:370:30 | [ExprStmt] console ... ile()); | semmle.order | 81 | +| tst.ts:370:9:370:11 | [Label] log | semmle.label | [Label] log | +| tst.ts:370:13:370:13 | [VarRef] A | semmle.label | [VarRef] A | +| tst.ts:370:13:370:26 | [DotExpr] A.resolvedFile | semmle.label | [DotExpr] A.resolvedFile | +| tst.ts:370:13:370:28 | [MethodCallExpr] A.resolvedFile() | semmle.label | [MethodCallExpr] A.resolvedFile() | +| tst.ts:370:15:370:26 | [Label] resolvedFile | semmle.label | [Label] resolvedFile | +| tst.ts:372:1:372:34 | [ImportDeclaration] import ... ffixB'; | semmle.label | [ImportDeclaration] import ... ffixB'; | +| tst.ts:372:1:372:34 | [ImportDeclaration] import ... ffixB'; | semmle.order | 82 | +| tst.ts:372:8:372:13 | [ImportSpecifier] * as B | semmle.label | [ImportSpecifier] * as B | +| tst.ts:372:13:372:13 | [VarDecl] B | semmle.label | [VarDecl] B | +| tst.ts:372:20:372:33 | [Literal] './tstSuffixB' | semmle.label | [Literal] './tstSuffixB' | +| tst.ts:374:1:374:7 | [VarRef] console | semmle.label | [VarRef] console | +| tst.ts:374:1:374:11 | [DotExpr] console.log | semmle.label | [DotExpr] console.log | +| tst.ts:374:1:374:29 | [MethodCallExpr] console ... File()) | semmle.label | [MethodCallExpr] console ... File()) | +| tst.ts:374:1:374:30 | [ExprStmt] console ... ile()); | semmle.label | [ExprStmt] console ... ile()); | +| tst.ts:374:1:374:30 | [ExprStmt] console ... ile()); | semmle.order | 83 | +| tst.ts:374:9:374:11 | [Label] log | semmle.label | [Label] log | +| tst.ts:374:13:374:13 | [VarRef] B | semmle.label | [VarRef] B | +| tst.ts:374:13:374:26 | [DotExpr] B.resolvedFile | semmle.label | [DotExpr] B.resolvedFile | +| tst.ts:374:13:374:28 | [MethodCallExpr] B.resolvedFile() | semmle.label | [MethodCallExpr] B.resolvedFile() | +| tst.ts:374:15:374:26 | [Label] resolvedFile | semmle.label | [Label] resolvedFile | +| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.label | [ExportDeclaration] export ... 'b'; } | +| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 84 | +| tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | [FunctionDeclStmt] functio ... 'b'; } | +| tstModuleCJS.cts:1:17:1:28 | [VarDecl] tstModuleCJS | semmle.label | [VarDecl] tstModuleCJS | +| tstModuleCJS.cts:1:33:1:35 | [LiteralTypeExpr] 'a' | semmle.label | [LiteralTypeExpr] 'a' | +| tstModuleCJS.cts:1:33:1:41 | [UnionTypeExpr] 'a' \| 'b' | semmle.label | [UnionTypeExpr] 'a' \| 'b' | +| tstModuleCJS.cts:1:39:1:41 | [LiteralTypeExpr] 'b' | semmle.label | [LiteralTypeExpr] 'b' | +| tstModuleCJS.cts:1:43:3:1 | [BlockStmt] { r ... 'b'; } | semmle.label | [BlockStmt] { r ... 'b'; } | +| tstModuleCJS.cts:2:5:2:43 | [ReturnStmt] return ... : 'b'; | semmle.label | [ReturnStmt] return ... : 'b'; | +| tstModuleCJS.cts:2:12:2:15 | [VarRef] Math | semmle.label | [VarRef] Math | +| tstModuleCJS.cts:2:12:2:22 | [DotExpr] Math.random | semmle.label | [DotExpr] Math.random | +| tstModuleCJS.cts:2:12:2:24 | [MethodCallExpr] Math.random() | semmle.label | [MethodCallExpr] Math.random() | +| tstModuleCJS.cts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | semmle.label | [BinaryExpr] Math.random() > 0.5 | +| tstModuleCJS.cts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | semmle.label | [ConditionalExpr] Math.ra ... ' : 'b' | +| tstModuleCJS.cts:2:17:2:22 | [Label] random | semmle.label | [Label] random | +| tstModuleCJS.cts:2:28:2:30 | [Literal] 0.5 | semmle.label | [Literal] 0.5 | +| tstModuleCJS.cts:2:34:2:36 | [Literal] 'a' | semmle.label | [Literal] 'a' | +| tstModuleCJS.cts:2:40:2:42 | [Literal] 'b' | semmle.label | [Literal] 'b' | +| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.label | [ExportDeclaration] export ... 'b'; } | +| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | semmle.order | 85 | +| tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | [FunctionDeclStmt] functio ... 'b'; } | +| tstModuleES.mts:1:25:1:35 | [VarDecl] tstModuleES | semmle.label | [VarDecl] tstModuleES | +| tstModuleES.mts:1:40:1:42 | [LiteralTypeExpr] 'a' | semmle.label | [LiteralTypeExpr] 'a' | +| tstModuleES.mts:1:40:1:48 | [UnionTypeExpr] 'a' \| 'b' | semmle.label | [UnionTypeExpr] 'a' \| 'b' | +| tstModuleES.mts:1:46:1:48 | [LiteralTypeExpr] 'b' | semmle.label | [LiteralTypeExpr] 'b' | +| tstModuleES.mts:1:50:3:1 | [BlockStmt] { r ... 'b'; } | semmle.label | [BlockStmt] { r ... 'b'; } | +| tstModuleES.mts:2:5:2:43 | [ReturnStmt] return ... : 'b'; | semmle.label | [ReturnStmt] return ... : 'b'; | +| tstModuleES.mts:2:12:2:15 | [VarRef] Math | semmle.label | [VarRef] Math | +| tstModuleES.mts:2:12:2:22 | [DotExpr] Math.random | semmle.label | [DotExpr] Math.random | +| tstModuleES.mts:2:12:2:24 | [MethodCallExpr] Math.random() | semmle.label | [MethodCallExpr] Math.random() | +| tstModuleES.mts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | semmle.label | [BinaryExpr] Math.random() > 0.5 | +| tstModuleES.mts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | semmle.label | [ConditionalExpr] Math.ra ... ' : 'b' | +| tstModuleES.mts:2:17:2:22 | [Label] random | semmle.label | [Label] random | +| tstModuleES.mts:2:28:2:30 | [Literal] 0.5 | semmle.label | [Literal] 0.5 | +| tstModuleES.mts:2:34:2:36 | [Literal] 'a' | semmle.label | [Literal] 'a' | +| tstModuleES.mts:2:40:2:42 | [Literal] 'b' | semmle.label | [Literal] 'b' | +| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } | +| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 86 | +| tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } | +| tstSuffixA.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile | +| tstSuffixA.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixA.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixA.ts' | +| tstSuffixA.ts:1:49:3:1 | [BlockStmt] { r ... .ts'; } | semmle.label | [BlockStmt] { r ... .ts'; } | +| tstSuffixA.ts:2:5:2:27 | [ReturnStmt] return ... xA.ts'; | semmle.label | [ReturnStmt] return ... xA.ts'; | +| tstSuffixA.ts:2:12:2:26 | [Literal] 'tstSuffixA.ts' | semmle.label | [Literal] 'tstSuffixA.ts' | +| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } | +| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 87 | +| tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } | +| tstSuffixB.ios.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile | +| tstSuffixB.ios.ts:1:33:1:51 | [LiteralTypeExpr] 'tstSuffixB.ios.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixB.ios.ts' | +| tstSuffixB.ios.ts:1:53:3:1 | [BlockStmt] { r ... .ts'; } | semmle.label | [BlockStmt] { r ... .ts'; } | +| tstSuffixB.ios.ts:2:5:2:31 | [ReturnStmt] return ... os.ts'; | semmle.label | [ReturnStmt] return ... os.ts'; | +| tstSuffixB.ios.ts:2:12:2:30 | [Literal] 'tstSuffixB.ios.ts' | semmle.label | [Literal] 'tstSuffixB.ios.ts' | +| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.label | [ExportDeclaration] export ... .ts'; } | +| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | semmle.order | 88 | +| tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | [FunctionDeclStmt] functio ... .ts'; } | +| tstSuffixB.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | [VarDecl] resolvedFile | +| tstSuffixB.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixB.ts' | semmle.label | [LiteralTypeExpr] 'tstSuffixB.ts' | +| tstSuffixB.ts:1:49:3:1 | [BlockStmt] { r ... .ts'; } | semmle.label | [BlockStmt] { r ... .ts'; } | +| tstSuffixB.ts:2:5:2:27 | [ReturnStmt] return ... xB.ts'; | semmle.label | [ReturnStmt] return ... xB.ts'; | +| tstSuffixB.ts:2:12:2:26 | [Literal] 'tstSuffixB.ts' | semmle.label | [Literal] 'tstSuffixB.ts' | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | -| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 61 | +| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 89 | | type_alias.ts:1:6:1:6 | [Identifier] B | semmle.label | [Identifier] B | | type_alias.ts:1:10:1:16 | [KeywordTypeExpr] boolean | semmle.label | [KeywordTypeExpr] boolean | | type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.label | [DeclStmt] var b = ... | -| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 62 | +| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 90 | | type_alias.ts:3:5:3:5 | [VarDecl] b | semmle.label | [VarDecl] b | | type_alias.ts:3:5:3:8 | [VariableDeclarator] b: B | semmle.label | [VariableDeclarator] b: B | | type_alias.ts:3:8:3:8 | [LocalTypeAccess] B | semmle.label | [LocalTypeAccess] B | | type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | -| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 63 | +| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 91 | | type_alias.ts:5:6:5:17 | [Identifier] ValueOrArray | semmle.label | [Identifier] ValueOrArray | | type_alias.ts:5:19:5:19 | [Identifier] T | semmle.label | [Identifier] T | | type_alias.ts:5:19:5:19 | [TypeParameter] T | semmle.label | [TypeParameter] T | @@ -1150,14 +1463,14 @@ nodes | type_alias.ts:5:34:5:48 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray | | type_alias.ts:5:47:5:47 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.label | [DeclStmt] var c = ... | -| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 64 | +| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 92 | | type_alias.ts:7:5:7:5 | [VarDecl] c | semmle.label | [VarDecl] c | | type_alias.ts:7:5:7:27 | [VariableDeclarator] c: Valu ... number> | semmle.label | [VariableDeclarator] c: Valu ... number> | | type_alias.ts:7:8:7:19 | [LocalTypeAccess] ValueOrArray | semmle.label | [LocalTypeAccess] ValueOrArray | | type_alias.ts:7:8:7:27 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray | | type_alias.ts:7:21:7:26 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | -| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 65 | +| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 93 | | type_alias.ts:9:6:9:9 | [Identifier] Json | semmle.label | [Identifier] Json | | type_alias.ts:10:5:15:12 | [UnionTypeExpr] \| strin ... Json[] | semmle.label | [UnionTypeExpr] \| strin ... Json[] | | type_alias.ts:10:7:10:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | @@ -1173,12 +1486,12 @@ nodes | type_alias.ts:15:7:15:10 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json | | type_alias.ts:15:7:15:12 | [ArrayTypeExpr] Json[] | semmle.label | [ArrayTypeExpr] Json[] | | type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.label | [DeclStmt] var json = ... | -| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 66 | +| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 94 | | type_alias.ts:17:5:17:8 | [VarDecl] json | semmle.label | [VarDecl] json | | type_alias.ts:17:5:17:14 | [VariableDeclarator] json: Json | semmle.label | [VariableDeclarator] json: Json | | type_alias.ts:17:11:17:14 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json | | type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | -| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 67 | +| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 95 | | type_alias.ts:19:6:19:16 | [Identifier] VirtualNode | semmle.label | [Identifier] VirtualNode | | type_alias.ts:20:5:21:56 | [UnionTypeExpr] \| strin ... Node[]] | semmle.label | [UnionTypeExpr] \| strin ... Node[]] | | type_alias.ts:20:7:20:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | @@ -1194,7 +1507,7 @@ nodes | type_alias.ts:21:43:21:53 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode | | type_alias.ts:21:43:21:55 | [ArrayTypeExpr] VirtualNode[] | semmle.label | [ArrayTypeExpr] VirtualNode[] | | type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.label | [DeclStmt] const myNode = ... | -| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 68 | +| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 96 | | type_alias.ts:23:7:23:12 | [VarDecl] myNode | semmle.label | [VarDecl] myNode | | type_alias.ts:23:7:27:5 | [VariableDeclarator] myNode: ... ] ] | semmle.label | [VariableDeclarator] myNode: ... ] ] | | type_alias.ts:23:15:23:25 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode | @@ -1219,12 +1532,12 @@ nodes | type_alias.ts:26:23:26:36 | [Literal] "second-child" | semmle.label | [Literal] "second-child" | | type_alias.ts:26:41:26:62 | [Literal] "I'm the second child" | semmle.label | [Literal] "I'm the second child" | | type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; | -| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 69 | +| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 97 | | type_definition_objects.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy | | type_definition_objects.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy | | type_definition_objects.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" | | type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.label | [ExportDeclaration] export class C {} | -| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 70 | +| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 98 | | type_definition_objects.ts:3:8:3:17 | [ClassDefinition,TypeDefinition] class C {} | semmle.label | [ClassDefinition,TypeDefinition] class C {} | | type_definition_objects.ts:3:14:3:14 | [VarDecl] C | semmle.label | [VarDecl] C | | type_definition_objects.ts:3:16:3:15 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | @@ -1232,36 +1545,36 @@ nodes | type_definition_objects.ts:3:16:3:15 | [FunctionExpr] () {} | semmle.label | [FunctionExpr] () {} | | type_definition_objects.ts:3:16:3:15 | [Label] constructor | semmle.label | [Label] constructor | | type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.label | [DeclStmt] let classObj = ... | -| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 71 | +| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 99 | | type_definition_objects.ts:4:5:4:12 | [VarDecl] classObj | semmle.label | [VarDecl] classObj | | type_definition_objects.ts:4:5:4:16 | [VariableDeclarator] classObj = C | semmle.label | [VariableDeclarator] classObj = C | | type_definition_objects.ts:4:16:4:16 | [VarRef] C | semmle.label | [VarRef] C | | type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.label | [ExportDeclaration] export enum E {} | -| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 72 | +| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 100 | | type_definition_objects.ts:6:8:6:16 | [EnumDeclaration,TypeDefinition] enum E {} | semmle.label | [EnumDeclaration,TypeDefinition] enum E {} | | type_definition_objects.ts:6:13:6:13 | [VarDecl] E | semmle.label | [VarDecl] E | | type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.label | [DeclStmt] let enumObj = ... | -| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 73 | +| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 101 | | type_definition_objects.ts:7:5:7:11 | [VarDecl] enumObj | semmle.label | [VarDecl] enumObj | | type_definition_objects.ts:7:5:7:15 | [VariableDeclarator] enumObj = E | semmle.label | [VariableDeclarator] enumObj = E | | type_definition_objects.ts:7:15:7:15 | [VarRef] E | semmle.label | [VarRef] E | | type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.label | [ExportDeclaration] export ... e N {;} | -| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 74 | +| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 102 | | type_definition_objects.ts:9:8:9:22 | [NamespaceDeclaration] namespace N {;} | semmle.label | [NamespaceDeclaration] namespace N {;} | | type_definition_objects.ts:9:18:9:18 | [VarDecl] N | semmle.label | [VarDecl] N | | type_definition_objects.ts:9:21:9:21 | [EmptyStmt] ; | semmle.label | [EmptyStmt] ; | | type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.label | [DeclStmt] let namespaceObj = ... | -| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 75 | +| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 103 | | type_definition_objects.ts:10:5:10:16 | [VarDecl] namespaceObj | semmle.label | [VarDecl] namespaceObj | | type_definition_objects.ts:10:5:10:20 | [VariableDeclarator] namespaceObj = N | semmle.label | [VariableDeclarator] namespaceObj = N | | type_definition_objects.ts:10:20:10:20 | [VarRef] N | semmle.label | [VarRef] N | | type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; | -| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 76 | +| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 104 | | type_definitions.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy | | type_definitions.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy | | type_definitions.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" | | type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | -| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 77 | +| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 105 | | type_definitions.ts:3:11:3:11 | [Identifier] I | semmle.label | [Identifier] I | | type_definitions.ts:3:13:3:13 | [Identifier] S | semmle.label | [Identifier] S | | type_definitions.ts:3:13:3:13 | [TypeParameter] S | semmle.label | [TypeParameter] S | @@ -1269,14 +1582,14 @@ nodes | type_definitions.ts:4:3:4:7 | [FieldDeclaration] x: S; | semmle.label | [FieldDeclaration] x: S; | | type_definitions.ts:4:6:4:6 | [LocalTypeAccess] S | semmle.label | [LocalTypeAccess] S | | type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.label | [DeclStmt] let i = ... | -| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 78 | +| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 106 | | type_definitions.ts:6:5:6:5 | [VarDecl] i | semmle.label | [VarDecl] i | | type_definitions.ts:6:5:6:16 | [VariableDeclarator] i: I | semmle.label | [VariableDeclarator] i: I | | type_definitions.ts:6:8:6:8 | [LocalTypeAccess] I | semmle.label | [LocalTypeAccess] I | | type_definitions.ts:6:8:6:16 | [GenericTypeExpr] I | semmle.label | [GenericTypeExpr] I | | type_definitions.ts:6:10:6:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.label | [ClassDefinition,TypeDefinition] class C ... x: T } | -| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 79 | +| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 107 | | type_definitions.ts:8:7:8:7 | [VarDecl] C | semmle.label | [VarDecl] C | | type_definitions.ts:8:8:8:7 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | | type_definitions.ts:8:8:8:7 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | [ClassInitializedMember,ConstructorDefinition] constructor() {} | @@ -1288,14 +1601,14 @@ nodes | type_definitions.ts:9:3:9:6 | [FieldDeclaration] x: T | semmle.label | [FieldDeclaration] x: T | | type_definitions.ts:9:6:9:6 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.label | [DeclStmt] let c = ... | -| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 80 | +| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 108 | | type_definitions.ts:11:5:11:5 | [VarDecl] c | semmle.label | [VarDecl] c | | type_definitions.ts:11:5:11:16 | [VariableDeclarator] c: C | semmle.label | [VariableDeclarator] c: C | | type_definitions.ts:11:8:11:8 | [LocalTypeAccess] C | semmle.label | [LocalTypeAccess] C | | type_definitions.ts:11:8:11:16 | [GenericTypeExpr] C | semmle.label | [GenericTypeExpr] C | | type_definitions.ts:11:10:11:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.label | [EnumDeclaration,TypeDefinition] enum Co ... blue } | -| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 81 | +| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 109 | | type_definitions.ts:13:6:13:10 | [VarDecl] Color | semmle.label | [VarDecl] Color | | type_definitions.ts:14:3:14:5 | [EnumMember,TypeDefinition] red | semmle.label | [EnumMember,TypeDefinition] red | | type_definitions.ts:14:3:14:5 | [VarDecl] red | semmle.label | [VarDecl] red | @@ -1304,29 +1617,29 @@ nodes | type_definitions.ts:14:15:14:18 | [EnumMember,TypeDefinition] blue | semmle.label | [EnumMember,TypeDefinition] blue | | type_definitions.ts:14:15:14:18 | [VarDecl] blue | semmle.label | [VarDecl] blue | | type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.label | [DeclStmt] let color = ... | -| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 82 | +| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 110 | | type_definitions.ts:16:5:16:9 | [VarDecl] color | semmle.label | [VarDecl] color | | type_definitions.ts:16:5:16:16 | [VariableDeclarator] color: Color | semmle.label | [VariableDeclarator] color: Color | | type_definitions.ts:16:12:16:16 | [LocalTypeAccess] Color | semmle.label | [LocalTypeAccess] Color | | type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.label | [EnumDeclaration,TypeDefinition] enum En ... ember } | -| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 83 | +| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 111 | | type_definitions.ts:18:6:18:22 | [VarDecl] EnumWithOneMember | semmle.label | [VarDecl] EnumWithOneMember | | type_definitions.ts:18:26:18:31 | [EnumMember,TypeDefinition] member | semmle.label | [EnumMember,TypeDefinition] member | | type_definitions.ts:18:26:18:31 | [VarDecl] member | semmle.label | [VarDecl] member | | type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.label | [DeclStmt] let e = ... | -| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 84 | +| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 112 | | type_definitions.ts:19:5:19:5 | [VarDecl] e | semmle.label | [VarDecl] e | | type_definitions.ts:19:5:19:24 | [VariableDeclarator] e: EnumWithOneMember | semmle.label | [VariableDeclarator] e: EnumWithOneMember | | type_definitions.ts:19:8:19:24 | [LocalTypeAccess] EnumWithOneMember | semmle.label | [LocalTypeAccess] EnumWithOneMember | | type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | -| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 85 | +| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 113 | | type_definitions.ts:21:6:21:10 | [Identifier] Alias | semmle.label | [Identifier] Alias | | type_definitions.ts:21:12:21:12 | [Identifier] T | semmle.label | [Identifier] T | | type_definitions.ts:21:12:21:12 | [TypeParameter] T | semmle.label | [TypeParameter] T | | type_definitions.ts:21:17:21:17 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_definitions.ts:21:17:21:19 | [ArrayTypeExpr] T[] | semmle.label | [ArrayTypeExpr] T[] | | type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.label | [DeclStmt] let aliasForNumberArray = ... | -| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 86 | +| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 114 | | type_definitions.ts:22:5:22:23 | [VarDecl] aliasForNumberArray | semmle.label | [VarDecl] aliasForNumberArray | | type_definitions.ts:22:5:22:38 | [VariableDeclarator] aliasFo ... number> | semmle.label | [VariableDeclarator] aliasFo ... number> | | type_definitions.ts:22:26:22:30 | [LocalTypeAccess] Alias | semmle.label | [LocalTypeAccess] Alias | @@ -1471,6 +1784,16 @@ edges | file://:0:0:0:0 | (Arguments) | tst.ts:282:17:287:3 | [ObjectExpr] {kind: ...} | semmle.order | 0 | | file://:0:0:0:0 | (Arguments) | tst.ts:285:19:285:35 | [MethodCallExpr] val.toUpperCase() | semmle.label | 0 | | file://:0:0:0:0 | (Arguments) | tst.ts:285:19:285:35 | [MethodCallExpr] val.toUpperCase() | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:318:3:321:1 | [ObjectExpr] {produce: ...} | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:318:3:321:1 | [ObjectExpr] {produce: ...} | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:358:13:358:25 | [CallExpr] tstModuleES() | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:358:13:358:25 | [CallExpr] tstModuleES() | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:362:13:362:26 | [CallExpr] tstModuleCJS() | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:362:13:362:26 | [CallExpr] tstModuleCJS() | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:370:13:370:28 | [MethodCallExpr] A.resolvedFile() | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:370:13:370:28 | [MethodCallExpr] A.resolvedFile() | semmle.order | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:374:13:374:28 | [MethodCallExpr] B.resolvedFile() | semmle.label | 0 | +| file://:0:0:0:0 | (Arguments) | tst.ts:374:13:374:28 | [MethodCallExpr] B.resolvedFile() | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | tst.ts:14:17:14:17 | [SimpleParameter] x | semmle.label | 0 | | file://:0:0:0:0 | (Parameters) | tst.ts:14:17:14:17 | [SimpleParameter] x | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | tst.ts:14:28:14:28 | [SimpleParameter] y | semmle.label | 1 | @@ -1529,6 +1852,20 @@ edges | file://:0:0:0:0 | (Parameters) | tst.ts:291:21:291:24 | [SimpleParameter] kind | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | tst.ts:291:27:291:33 | [SimpleParameter] payload | semmle.label | 1 | | file://:0:0:0:0 | (Parameters) | tst.ts:291:27:291:33 | [SimpleParameter] payload | semmle.order | 1 | +| file://:0:0:0:0 | (Parameters) | tst.ts:313:15:313:17 | [SimpleParameter] arg | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:313:15:313:17 | [SimpleParameter] arg | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:314:13:314:13 | [SimpleParameter] n | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:314:13:314:13 | [SimpleParameter] n | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:315:13:315:13 | [SimpleParameter] x | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:315:13:315:13 | [SimpleParameter] x | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:319:12:319:12 | [SimpleParameter] n | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:319:12:319:12 | [SimpleParameter] n | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:320:12:320:12 | [SimpleParameter] x | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:320:12:320:12 | [SimpleParameter] x | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:344:9:344:13 | [SimpleParameter] value | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:344:9:344:13 | [SimpleParameter] value | semmle.order | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:349:9:349:13 | [SimpleParameter] value | semmle.label | 0 | +| file://:0:0:0:0 | (Parameters) | tst.ts:349:9:349:13 | [SimpleParameter] value | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | type_alias.ts:14:10:14:17 | [SimpleParameter] property | semmle.label | 0 | | file://:0:0:0:0 | (Parameters) | type_alias.ts:14:10:14:17 | [SimpleParameter] property | semmle.order | 0 | | file://:0:0:0:0 | (Parameters) | type_alias.ts:21:19:21:21 | [SimpleParameter] key | semmle.label | 0 | @@ -1539,6 +1876,14 @@ edges | file://:0:0:0:0 | (TypeParameters) | tst.ts:272:6:272:11 | [TypeParameter] K in P | semmle.order | 0 | | file://:0:0:0:0 | (TypeParameters) | tst.ts:278:26:278:48 | [TypeParameter] K exten ... TypeMap | semmle.label | 0 | | file://:0:0:0:0 | (TypeParameters) | tst.ts:278:26:278:48 | [TypeParameter] K exten ... TypeMap | semmle.order | 0 | +| file://:0:0:0:0 | (TypeParameters) | tst.ts:313:12:313:12 | [TypeParameter] T | semmle.label | 0 | +| file://:0:0:0:0 | (TypeParameters) | tst.ts:313:12:313:12 | [TypeParameter] T | semmle.order | 0 | +| file://:0:0:0:0 | (TypeParameters) | tst.ts:331:18:331:18 | [TypeParameter] T | semmle.label | 0 | +| file://:0:0:0:0 | (TypeParameters) | tst.ts:331:18:331:18 | [TypeParameter] T | semmle.order | 0 | +| file://:0:0:0:0 | (TypeParameters) | tst.ts:332:20:332:35 | [TypeParameter] S extends string | semmle.label | 0 | +| file://:0:0:0:0 | (TypeParameters) | tst.ts:332:20:332:35 | [TypeParameter] S extends string | semmle.order | 0 | +| file://:0:0:0:0 | (TypeParameters) | tst.ts:342:17:342:24 | [TypeParameter] in out T | semmle.label | 0 | +| file://:0:0:0:0 | (TypeParameters) | tst.ts:342:17:342:24 | [TypeParameter] in out T | semmle.order | 0 | | file://:0:0:0:0 | (TypeParameters) | type_alias.ts:5:19:5:19 | [TypeParameter] T | semmle.label | 0 | | file://:0:0:0:0 | (TypeParameters) | type_alias.ts:5:19:5:19 | [TypeParameter] T | semmle.order | 0 | | file://:0:0:0:0 | (TypeParameters) | type_definitions.ts:3:13:3:13 | [TypeParameter] S | semmle.label | 0 | @@ -3351,6 +3696,488 @@ edges | tst.ts:293:7:293:23 | [MethodCallExpr] payload.toFixed() | tst.ts:293:7:293:21 | [DotExpr] payload.toFixed | semmle.order | 0 | | tst.ts:293:7:293:24 | [ExprStmt] payload.toFixed(); | tst.ts:293:7:293:23 | [MethodCallExpr] payload.toFixed() | semmle.label | 1 | | tst.ts:293:7:293:24 | [ExprStmt] payload.toFixed(); | tst.ts:293:7:293:23 | [MethodCallExpr] payload.toFixed() | semmle.order | 1 | +| tst.ts:298:1:298:21 | [DeclStmt] const key = ... | tst.ts:298:7:298:20 | [VariableDeclarator] key = Symbol() | semmle.label | 1 | +| tst.ts:298:1:298:21 | [DeclStmt] const key = ... | tst.ts:298:7:298:20 | [VariableDeclarator] key = Symbol() | semmle.order | 1 | +| tst.ts:298:7:298:20 | [VariableDeclarator] key = Symbol() | tst.ts:298:7:298:9 | [VarDecl] key | semmle.label | 1 | +| tst.ts:298:7:298:20 | [VariableDeclarator] key = Symbol() | tst.ts:298:7:298:9 | [VarDecl] key | semmle.order | 1 | +| tst.ts:298:7:298:20 | [VariableDeclarator] key = Symbol() | tst.ts:298:13:298:20 | [CallExpr] Symbol() | semmle.label | 2 | +| tst.ts:298:7:298:20 | [VariableDeclarator] key = Symbol() | tst.ts:298:13:298:20 | [CallExpr] Symbol() | semmle.order | 2 | +| tst.ts:298:13:298:20 | [CallExpr] Symbol() | tst.ts:298:13:298:18 | [VarRef] Symbol | semmle.label | 0 | +| tst.ts:298:13:298:20 | [CallExpr] Symbol() | tst.ts:298:13:298:18 | [VarRef] Symbol | semmle.order | 0 | +| tst.ts:300:1:300:58 | [DeclStmt] const numberOrString = ... | tst.ts:300:7:300:57 | [VariableDeclarator] numberO ... "hello" | semmle.label | 1 | +| tst.ts:300:1:300:58 | [DeclStmt] const numberOrString = ... | tst.ts:300:7:300:57 | [VariableDeclarator] numberO ... "hello" | semmle.order | 1 | +| tst.ts:300:7:300:57 | [VariableDeclarator] numberO ... "hello" | tst.ts:300:7:300:20 | [VarDecl] numberOrString | semmle.label | 1 | +| tst.ts:300:7:300:57 | [VariableDeclarator] numberO ... "hello" | tst.ts:300:7:300:20 | [VarDecl] numberOrString | semmle.order | 1 | +| tst.ts:300:7:300:57 | [VariableDeclarator] numberO ... "hello" | tst.ts:300:24:300:57 | [ConditionalExpr] Math.ra ... "hello" | semmle.label | 2 | +| tst.ts:300:7:300:57 | [VariableDeclarator] numberO ... "hello" | tst.ts:300:24:300:57 | [ConditionalExpr] Math.ra ... "hello" | semmle.order | 2 | +| tst.ts:300:24:300:34 | [DotExpr] Math.random | tst.ts:300:24:300:27 | [VarRef] Math | semmle.label | 1 | +| tst.ts:300:24:300:34 | [DotExpr] Math.random | tst.ts:300:24:300:27 | [VarRef] Math | semmle.order | 1 | +| tst.ts:300:24:300:34 | [DotExpr] Math.random | tst.ts:300:29:300:34 | [Label] random | semmle.label | 2 | +| tst.ts:300:24:300:34 | [DotExpr] Math.random | tst.ts:300:29:300:34 | [Label] random | semmle.order | 2 | +| tst.ts:300:24:300:36 | [MethodCallExpr] Math.random() | tst.ts:300:24:300:34 | [DotExpr] Math.random | semmle.label | 0 | +| tst.ts:300:24:300:36 | [MethodCallExpr] Math.random() | tst.ts:300:24:300:34 | [DotExpr] Math.random | semmle.order | 0 | +| tst.ts:300:24:300:42 | [BinaryExpr] Math.random() < 0.5 | tst.ts:300:24:300:36 | [MethodCallExpr] Math.random() | semmle.label | 1 | +| tst.ts:300:24:300:42 | [BinaryExpr] Math.random() < 0.5 | tst.ts:300:24:300:36 | [MethodCallExpr] Math.random() | semmle.order | 1 | +| tst.ts:300:24:300:42 | [BinaryExpr] Math.random() < 0.5 | tst.ts:300:40:300:42 | [Literal] 0.5 | semmle.label | 2 | +| tst.ts:300:24:300:42 | [BinaryExpr] Math.random() < 0.5 | tst.ts:300:40:300:42 | [Literal] 0.5 | semmle.order | 2 | +| tst.ts:300:24:300:57 | [ConditionalExpr] Math.ra ... "hello" | tst.ts:300:24:300:42 | [BinaryExpr] Math.random() < 0.5 | semmle.label | 1 | +| tst.ts:300:24:300:57 | [ConditionalExpr] Math.ra ... "hello" | tst.ts:300:24:300:42 | [BinaryExpr] Math.random() < 0.5 | semmle.order | 1 | +| tst.ts:300:24:300:57 | [ConditionalExpr] Math.ra ... "hello" | tst.ts:300:46:300:47 | [Literal] 42 | semmle.label | 2 | +| tst.ts:300:24:300:57 | [ConditionalExpr] Math.ra ... "hello" | tst.ts:300:46:300:47 | [Literal] 42 | semmle.order | 2 | +| tst.ts:300:24:300:57 | [ConditionalExpr] Math.ra ... "hello" | tst.ts:300:51:300:57 | [Literal] "hello" | semmle.label | 3 | +| tst.ts:300:24:300:57 | [ConditionalExpr] Math.ra ... "hello" | tst.ts:300:51:300:57 | [Literal] "hello" | semmle.order | 3 | +| tst.ts:302:1:304:2 | [DeclStmt] let obj = ... | tst.ts:302:5:304:1 | [VariableDeclarator] obj = { ... ring, } | semmle.label | 1 | +| tst.ts:302:1:304:2 | [DeclStmt] let obj = ... | tst.ts:302:5:304:1 | [VariableDeclarator] obj = { ... ring, } | semmle.order | 1 | +| tst.ts:302:5:304:1 | [VariableDeclarator] obj = { ... ring, } | tst.ts:302:5:302:7 | [VarDecl] obj | semmle.label | 1 | +| tst.ts:302:5:304:1 | [VariableDeclarator] obj = { ... ring, } | tst.ts:302:5:302:7 | [VarDecl] obj | semmle.order | 1 | +| tst.ts:302:5:304:1 | [VariableDeclarator] obj = { ... ring, } | tst.ts:302:11:304:1 | [ObjectExpr] { [ke ... ring, } | semmle.label | 2 | +| tst.ts:302:5:304:1 | [VariableDeclarator] obj = { ... ring, } | tst.ts:302:11:304:1 | [ObjectExpr] { [ke ... ring, } | semmle.order | 2 | +| tst.ts:302:11:304:1 | [ObjectExpr] { [ke ... ring, } | tst.ts:303:3:303:23 | [Property] [key]: ... rString | semmle.label | 1 | +| tst.ts:302:11:304:1 | [ObjectExpr] { [ke ... ring, } | tst.ts:303:3:303:23 | [Property] [key]: ... rString | semmle.order | 1 | +| tst.ts:303:3:303:23 | [Property] [key]: ... rString | tst.ts:303:4:303:6 | [VarRef] key | semmle.label | 1 | +| tst.ts:303:3:303:23 | [Property] [key]: ... rString | tst.ts:303:4:303:6 | [VarRef] key | semmle.order | 1 | +| tst.ts:303:3:303:23 | [Property] [key]: ... rString | tst.ts:303:10:303:23 | [VarRef] numberOrString | semmle.label | 2 | +| tst.ts:303:3:303:23 | [Property] [key]: ... rString | tst.ts:303:10:303:23 | [VarRef] numberOrString | semmle.order | 2 | +| tst.ts:306:1:309:1 | [IfStmt] if (typ ... se(); } | tst.ts:306:5:306:32 | [BinaryExpr] typeof ... string" | semmle.label | 1 | +| tst.ts:306:1:309:1 | [IfStmt] if (typ ... se(); } | tst.ts:306:5:306:32 | [BinaryExpr] typeof ... string" | semmle.order | 1 | +| tst.ts:306:1:309:1 | [IfStmt] if (typ ... se(); } | tst.ts:306:35:309:1 | [BlockStmt] { let ... se(); } | semmle.label | 2 | +| tst.ts:306:1:309:1 | [IfStmt] if (typ ... se(); } | tst.ts:306:35:309:1 | [BlockStmt] { let ... se(); } | semmle.order | 2 | +| tst.ts:306:5:306:19 | [UnaryExpr] typeof obj[key] | tst.ts:306:12:306:19 | [IndexExpr] obj[key] | semmle.label | 1 | +| tst.ts:306:5:306:19 | [UnaryExpr] typeof obj[key] | tst.ts:306:12:306:19 | [IndexExpr] obj[key] | semmle.order | 1 | +| tst.ts:306:5:306:32 | [BinaryExpr] typeof ... string" | tst.ts:306:5:306:19 | [UnaryExpr] typeof obj[key] | semmle.label | 1 | +| tst.ts:306:5:306:32 | [BinaryExpr] typeof ... string" | tst.ts:306:5:306:19 | [UnaryExpr] typeof obj[key] | semmle.order | 1 | +| tst.ts:306:5:306:32 | [BinaryExpr] typeof ... string" | tst.ts:306:25:306:32 | [Literal] "string" | semmle.label | 2 | +| tst.ts:306:5:306:32 | [BinaryExpr] typeof ... string" | tst.ts:306:25:306:32 | [Literal] "string" | semmle.order | 2 | +| tst.ts:306:12:306:19 | [IndexExpr] obj[key] | tst.ts:306:12:306:14 | [VarRef] obj | semmle.label | 1 | +| tst.ts:306:12:306:19 | [IndexExpr] obj[key] | tst.ts:306:12:306:14 | [VarRef] obj | semmle.order | 1 | +| tst.ts:306:12:306:19 | [IndexExpr] obj[key] | tst.ts:306:16:306:18 | [VarRef] key | semmle.label | 2 | +| tst.ts:306:12:306:19 | [IndexExpr] obj[key] | tst.ts:306:16:306:18 | [VarRef] key | semmle.order | 2 | +| tst.ts:306:35:309:1 | [BlockStmt] { let ... se(); } | tst.ts:307:3:307:21 | [DeclStmt] let str = ... | semmle.label | 1 | +| tst.ts:306:35:309:1 | [BlockStmt] { let ... se(); } | tst.ts:307:3:307:21 | [DeclStmt] let str = ... | semmle.order | 1 | +| tst.ts:306:35:309:1 | [BlockStmt] { let ... se(); } | tst.ts:308:3:308:20 | [ExprStmt] str.toUpperCase(); | semmle.label | 2 | +| tst.ts:306:35:309:1 | [BlockStmt] { let ... se(); } | tst.ts:308:3:308:20 | [ExprStmt] str.toUpperCase(); | semmle.order | 2 | +| tst.ts:307:3:307:21 | [DeclStmt] let str = ... | tst.ts:307:7:307:20 | [VariableDeclarator] str = obj[key] | semmle.label | 1 | +| tst.ts:307:3:307:21 | [DeclStmt] let str = ... | tst.ts:307:7:307:20 | [VariableDeclarator] str = obj[key] | semmle.order | 1 | +| tst.ts:307:7:307:20 | [VariableDeclarator] str = obj[key] | tst.ts:307:7:307:9 | [VarDecl] str | semmle.label | 1 | +| tst.ts:307:7:307:20 | [VariableDeclarator] str = obj[key] | tst.ts:307:7:307:9 | [VarDecl] str | semmle.order | 1 | +| tst.ts:307:7:307:20 | [VariableDeclarator] str = obj[key] | tst.ts:307:13:307:20 | [IndexExpr] obj[key] | semmle.label | 2 | +| tst.ts:307:7:307:20 | [VariableDeclarator] str = obj[key] | tst.ts:307:13:307:20 | [IndexExpr] obj[key] | semmle.order | 2 | +| tst.ts:307:13:307:20 | [IndexExpr] obj[key] | tst.ts:307:13:307:15 | [VarRef] obj | semmle.label | 1 | +| tst.ts:307:13:307:20 | [IndexExpr] obj[key] | tst.ts:307:13:307:15 | [VarRef] obj | semmle.order | 1 | +| tst.ts:307:13:307:20 | [IndexExpr] obj[key] | tst.ts:307:17:307:19 | [VarRef] key | semmle.label | 2 | +| tst.ts:307:13:307:20 | [IndexExpr] obj[key] | tst.ts:307:17:307:19 | [VarRef] key | semmle.order | 2 | +| tst.ts:308:3:308:17 | [DotExpr] str.toUpperCase | tst.ts:308:3:308:5 | [VarRef] str | semmle.label | 1 | +| tst.ts:308:3:308:17 | [DotExpr] str.toUpperCase | tst.ts:308:3:308:5 | [VarRef] str | semmle.order | 1 | +| tst.ts:308:3:308:17 | [DotExpr] str.toUpperCase | tst.ts:308:7:308:17 | [Label] toUpperCase | semmle.label | 2 | +| tst.ts:308:3:308:17 | [DotExpr] str.toUpperCase | tst.ts:308:7:308:17 | [Label] toUpperCase | semmle.order | 2 | +| tst.ts:308:3:308:19 | [MethodCallExpr] str.toUpperCase() | tst.ts:308:3:308:17 | [DotExpr] str.toUpperCase | semmle.label | 0 | +| tst.ts:308:3:308:19 | [MethodCallExpr] str.toUpperCase() | tst.ts:308:3:308:17 | [DotExpr] str.toUpperCase | semmle.order | 0 | +| tst.ts:308:3:308:20 | [ExprStmt] str.toUpperCase(); | tst.ts:308:3:308:19 | [MethodCallExpr] str.toUpperCase() | semmle.label | 1 | +| tst.ts:308:3:308:20 | [ExprStmt] str.toUpperCase(); | tst.ts:308:3:308:19 | [MethodCallExpr] str.toUpperCase() | semmle.order | 1 | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | file://:0:0:0:0 | (TypeParameters) | semmle.label | 2 | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | file://:0:0:0:0 | (TypeParameters) | semmle.order | 2 | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | tst.ts:313:10:313:10 | [VarDecl] f | semmle.label | 0 | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | tst.ts:313:10:313:10 | [VarDecl] f | semmle.order | 0 | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | tst.ts:316:4:316:7 | [KeywordTypeExpr] void | semmle.label | 4 | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | tst.ts:316:4:316:7 | [KeywordTypeExpr] void | semmle.order | 4 | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | tst.ts:316:9:316:10 | [BlockStmt] {} | semmle.label | 5 | +| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | tst.ts:316:9:316:10 | [BlockStmt] {} | semmle.order | 5 | +| tst.ts:313:12:313:12 | [TypeParameter] T | tst.ts:313:12:313:12 | [Identifier] T | semmle.label | 1 | +| tst.ts:313:12:313:12 | [TypeParameter] T | tst.ts:313:12:313:12 | [Identifier] T | semmle.order | 1 | +| tst.ts:313:15:313:17 | [SimpleParameter] arg | tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | semmle.label | 0 | +| tst.ts:313:15:313:17 | [SimpleParameter] arg | tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | semmle.order | 0 | +| tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | tst.ts:314:3:314:28 | [FieldDeclaration] produce ... ) => T, | semmle.label | 1 | +| tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | tst.ts:314:3:314:28 | [FieldDeclaration] produce ... ) => T, | semmle.order | 1 | +| tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | tst.ts:315:3:315:25 | [FieldDeclaration] consume ... => void | semmle.label | 2 | +| tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | tst.ts:315:3:315:25 | [FieldDeclaration] consume ... => void | semmle.order | 2 | +| tst.ts:314:3:314:28 | [FieldDeclaration] produce ... ) => T, | tst.ts:314:3:314:9 | [Label] produce | semmle.label | 1 | +| tst.ts:314:3:314:28 | [FieldDeclaration] produce ... ) => T, | tst.ts:314:3:314:9 | [Label] produce | semmle.order | 1 | +| tst.ts:314:3:314:28 | [FieldDeclaration] produce ... ) => T, | tst.ts:314:12:314:27 | [FunctionTypeExpr] (n: string) => T | semmle.label | 2 | +| tst.ts:314:3:314:28 | [FieldDeclaration] produce ... ) => T, | tst.ts:314:12:314:27 | [FunctionTypeExpr] (n: string) => T | semmle.order | 2 | +| tst.ts:314:12:314:27 | [FunctionExpr] (n: string) => T | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:314:12:314:27 | [FunctionExpr] (n: string) => T | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:314:12:314:27 | [FunctionExpr] (n: string) => T | tst.ts:314:27:314:27 | [LocalTypeAccess] T | semmle.label | 4 | +| tst.ts:314:12:314:27 | [FunctionExpr] (n: string) => T | tst.ts:314:27:314:27 | [LocalTypeAccess] T | semmle.order | 4 | +| tst.ts:314:12:314:27 | [FunctionTypeExpr] (n: string) => T | tst.ts:314:12:314:27 | [FunctionExpr] (n: string) => T | semmle.label | 1 | +| tst.ts:314:12:314:27 | [FunctionTypeExpr] (n: string) => T | tst.ts:314:12:314:27 | [FunctionExpr] (n: string) => T | semmle.order | 1 | +| tst.ts:314:13:314:13 | [SimpleParameter] n | tst.ts:314:16:314:21 | [KeywordTypeExpr] string | semmle.label | 0 | +| tst.ts:314:13:314:13 | [SimpleParameter] n | tst.ts:314:16:314:21 | [KeywordTypeExpr] string | semmle.order | 0 | +| tst.ts:315:3:315:25 | [FieldDeclaration] consume ... => void | tst.ts:315:3:315:9 | [Label] consume | semmle.label | 1 | +| tst.ts:315:3:315:25 | [FieldDeclaration] consume ... => void | tst.ts:315:3:315:9 | [Label] consume | semmle.order | 1 | +| tst.ts:315:3:315:25 | [FieldDeclaration] consume ... => void | tst.ts:315:12:315:25 | [FunctionTypeExpr] (x: T) => void | semmle.label | 2 | +| tst.ts:315:3:315:25 | [FieldDeclaration] consume ... => void | tst.ts:315:12:315:25 | [FunctionTypeExpr] (x: T) => void | semmle.order | 2 | +| tst.ts:315:12:315:25 | [FunctionExpr] (x: T) => void | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:315:12:315:25 | [FunctionExpr] (x: T) => void | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:315:12:315:25 | [FunctionExpr] (x: T) => void | tst.ts:315:22:315:25 | [KeywordTypeExpr] void | semmle.label | 4 | +| tst.ts:315:12:315:25 | [FunctionExpr] (x: T) => void | tst.ts:315:22:315:25 | [KeywordTypeExpr] void | semmle.order | 4 | +| tst.ts:315:12:315:25 | [FunctionTypeExpr] (x: T) => void | tst.ts:315:12:315:25 | [FunctionExpr] (x: T) => void | semmle.label | 1 | +| tst.ts:315:12:315:25 | [FunctionTypeExpr] (x: T) => void | tst.ts:315:12:315:25 | [FunctionExpr] (x: T) => void | semmle.order | 1 | +| tst.ts:315:13:315:13 | [SimpleParameter] x | tst.ts:315:16:315:16 | [LocalTypeAccess] T | semmle.label | 0 | +| tst.ts:315:13:315:13 | [SimpleParameter] x | tst.ts:315:16:315:16 | [LocalTypeAccess] T | semmle.order | 0 | +| tst.ts:318:1:321:2 | [CallExpr] f({ p ... se() }) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| tst.ts:318:1:321:2 | [CallExpr] f({ p ... se() }) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| tst.ts:318:1:321:2 | [CallExpr] f({ p ... se() }) | tst.ts:318:1:318:1 | [VarRef] f | semmle.label | 0 | +| tst.ts:318:1:321:2 | [CallExpr] f({ p ... se() }) | tst.ts:318:1:318:1 | [VarRef] f | semmle.order | 0 | +| tst.ts:318:1:321:3 | [ExprStmt] f({ p ... e() }); | tst.ts:318:1:321:2 | [CallExpr] f({ p ... se() }) | semmle.label | 1 | +| tst.ts:318:1:321:3 | [ExprStmt] f({ p ... e() }); | tst.ts:318:1:321:2 | [CallExpr] f({ p ... se() }) | semmle.order | 1 | +| tst.ts:318:3:321:1 | [ObjectExpr] {produce: ...} | tst.ts:319:3:319:17 | [Property] produce: n => n | semmle.label | 1 | +| tst.ts:318:3:321:1 | [ObjectExpr] {produce: ...} | tst.ts:319:3:319:17 | [Property] produce: n => n | semmle.order | 1 | +| tst.ts:318:3:321:1 | [ObjectExpr] {produce: ...} | tst.ts:320:3:320:31 | [Property] consume ... rCase() | semmle.label | 2 | +| tst.ts:318:3:321:1 | [ObjectExpr] {produce: ...} | tst.ts:320:3:320:31 | [Property] consume ... rCase() | semmle.order | 2 | +| tst.ts:319:3:319:17 | [Property] produce: n => n | tst.ts:319:3:319:9 | [Label] produce | semmle.label | 1 | +| tst.ts:319:3:319:17 | [Property] produce: n => n | tst.ts:319:3:319:9 | [Label] produce | semmle.order | 1 | +| tst.ts:319:3:319:17 | [Property] produce: n => n | tst.ts:319:12:319:17 | [ArrowFunctionExpr] n => n | semmle.label | 2 | +| tst.ts:319:3:319:17 | [Property] produce: n => n | tst.ts:319:12:319:17 | [ArrowFunctionExpr] n => n | semmle.order | 2 | +| tst.ts:319:12:319:17 | [ArrowFunctionExpr] n => n | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:319:12:319:17 | [ArrowFunctionExpr] n => n | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:319:12:319:17 | [ArrowFunctionExpr] n => n | tst.ts:319:17:319:17 | [VarRef] n | semmle.label | 5 | +| tst.ts:319:12:319:17 | [ArrowFunctionExpr] n => n | tst.ts:319:17:319:17 | [VarRef] n | semmle.order | 5 | +| tst.ts:320:3:320:31 | [Property] consume ... rCase() | tst.ts:320:3:320:9 | [Label] consume | semmle.label | 1 | +| tst.ts:320:3:320:31 | [Property] consume ... rCase() | tst.ts:320:3:320:9 | [Label] consume | semmle.order | 1 | +| tst.ts:320:3:320:31 | [Property] consume ... rCase() | tst.ts:320:12:320:31 | [ArrowFunctionExpr] x => x.toLowerCase() | semmle.label | 2 | +| tst.ts:320:3:320:31 | [Property] consume ... rCase() | tst.ts:320:12:320:31 | [ArrowFunctionExpr] x => x.toLowerCase() | semmle.order | 2 | +| tst.ts:320:12:320:31 | [ArrowFunctionExpr] x => x.toLowerCase() | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:320:12:320:31 | [ArrowFunctionExpr] x => x.toLowerCase() | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:320:12:320:31 | [ArrowFunctionExpr] x => x.toLowerCase() | tst.ts:320:17:320:31 | [MethodCallExpr] x.toLowerCase() | semmle.label | 5 | +| tst.ts:320:12:320:31 | [ArrowFunctionExpr] x => x.toLowerCase() | tst.ts:320:17:320:31 | [MethodCallExpr] x.toLowerCase() | semmle.order | 5 | +| tst.ts:320:17:320:29 | [DotExpr] x.toLowerCase | tst.ts:320:17:320:17 | [VarRef] x | semmle.label | 1 | +| tst.ts:320:17:320:29 | [DotExpr] x.toLowerCase | tst.ts:320:17:320:17 | [VarRef] x | semmle.order | 1 | +| tst.ts:320:17:320:29 | [DotExpr] x.toLowerCase | tst.ts:320:19:320:29 | [Label] toLowerCase | semmle.label | 2 | +| tst.ts:320:17:320:29 | [DotExpr] x.toLowerCase | tst.ts:320:19:320:29 | [Label] toLowerCase | semmle.order | 2 | +| tst.ts:320:17:320:31 | [MethodCallExpr] x.toLowerCase() | tst.ts:320:17:320:29 | [DotExpr] x.toLowerCase | semmle.label | 0 | +| tst.ts:320:17:320:31 | [MethodCallExpr] x.toLowerCase() | tst.ts:320:17:320:29 | [DotExpr] x.toLowerCase | semmle.order | 0 | +| tst.ts:325:1:325:36 | [DeclStmt] const ErrorMap = ... | tst.ts:325:7:325:35 | [VariableDeclarator] ErrorMa ... Error> | semmle.label | 1 | +| tst.ts:325:1:325:36 | [DeclStmt] const ErrorMap = ... | tst.ts:325:7:325:35 | [VariableDeclarator] ErrorMa ... Error> | semmle.order | 1 | +| tst.ts:325:7:325:35 | [VariableDeclarator] ErrorMa ... Error> | tst.ts:325:7:325:14 | [VarDecl] ErrorMap | semmle.label | 1 | +| tst.ts:325:7:325:35 | [VariableDeclarator] ErrorMa ... Error> | tst.ts:325:7:325:14 | [VarDecl] ErrorMap | semmle.order | 1 | +| tst.ts:325:7:325:35 | [VariableDeclarator] ErrorMa ... Error> | tst.ts:325:18:325:35 | [ExpressionWithTypeArguments] Map | semmle.label | 2 | +| tst.ts:325:7:325:35 | [VariableDeclarator] ErrorMa ... Error> | tst.ts:325:18:325:35 | [ExpressionWithTypeArguments] Map | semmle.order | 2 | +| tst.ts:325:18:325:35 | [ExpressionWithTypeArguments] Map | tst.ts:325:18:325:20 | [VarRef] Map | semmle.label | 1 | +| tst.ts:325:18:325:35 | [ExpressionWithTypeArguments] Map | tst.ts:325:18:325:20 | [VarRef] Map | semmle.order | 1 | +| tst.ts:325:18:325:35 | [ExpressionWithTypeArguments] Map | tst.ts:325:22:325:27 | [KeywordTypeExpr] string | semmle.label | 2 | +| tst.ts:325:18:325:35 | [ExpressionWithTypeArguments] Map | tst.ts:325:22:325:27 | [KeywordTypeExpr] string | semmle.order | 2 | +| tst.ts:325:18:325:35 | [ExpressionWithTypeArguments] Map | tst.ts:325:30:325:34 | [LocalTypeAccess] Error | semmle.label | 3 | +| tst.ts:325:18:325:35 | [ExpressionWithTypeArguments] Map | tst.ts:325:30:325:34 | [LocalTypeAccess] Error | semmle.order | 3 | +| tst.ts:327:1:327:32 | [DeclStmt] const errorMap = ... | tst.ts:327:7:327:31 | [VariableDeclarator] errorMa ... orMap() | semmle.label | 1 | +| tst.ts:327:1:327:32 | [DeclStmt] const errorMap = ... | tst.ts:327:7:327:31 | [VariableDeclarator] errorMa ... orMap() | semmle.order | 1 | +| tst.ts:327:7:327:31 | [VariableDeclarator] errorMa ... orMap() | tst.ts:327:7:327:14 | [VarDecl] errorMap | semmle.label | 1 | +| tst.ts:327:7:327:31 | [VariableDeclarator] errorMa ... orMap() | tst.ts:327:7:327:14 | [VarDecl] errorMap | semmle.order | 1 | +| tst.ts:327:7:327:31 | [VariableDeclarator] errorMa ... orMap() | tst.ts:327:18:327:31 | [NewExpr] new ErrorMap() | semmle.label | 2 | +| tst.ts:327:7:327:31 | [VariableDeclarator] errorMa ... orMap() | tst.ts:327:18:327:31 | [NewExpr] new ErrorMap() | semmle.order | 2 | +| tst.ts:327:18:327:31 | [NewExpr] new ErrorMap() | tst.ts:327:22:327:29 | [VarRef] ErrorMap | semmle.label | 0 | +| tst.ts:327:18:327:31 | [NewExpr] new ErrorMap() | tst.ts:327:22:327:29 | [VarRef] ErrorMap | semmle.order | 0 | +| tst.ts:331:1:334:14 | [TypeAliasDeclaration,TypeDefinition] type Fi ... never; | file://:0:0:0:0 | (TypeParameters) | semmle.label | -100 | +| tst.ts:331:1:334:14 | [TypeAliasDeclaration,TypeDefinition] type Fi ... never; | file://:0:0:0:0 | (TypeParameters) | semmle.order | -100 | +| tst.ts:331:1:334:14 | [TypeAliasDeclaration,TypeDefinition] type Fi ... never; | tst.ts:331:6:331:16 | [Identifier] FirstString | semmle.label | 1 | +| tst.ts:331:1:334:14 | [TypeAliasDeclaration,TypeDefinition] type Fi ... never; | tst.ts:331:6:331:16 | [Identifier] FirstString | semmle.order | 1 | +| tst.ts:331:1:334:14 | [TypeAliasDeclaration,TypeDefinition] type Fi ... never; | tst.ts:332:3:334:13 | [ConditionalTypeExpr] T exten ... : never | semmle.label | 3 | +| tst.ts:331:1:334:14 | [TypeAliasDeclaration,TypeDefinition] type Fi ... never; | tst.ts:332:3:334:13 | [ConditionalTypeExpr] T exten ... : never | semmle.order | 3 | +| tst.ts:331:18:331:18 | [TypeParameter] T | tst.ts:331:18:331:18 | [Identifier] T | semmle.label | 1 | +| tst.ts:331:18:331:18 | [TypeParameter] T | tst.ts:331:18:331:18 | [Identifier] T | semmle.order | 1 | +| tst.ts:332:3:334:13 | [ConditionalTypeExpr] T exten ... : never | tst.ts:332:3:332:3 | [LocalTypeAccess] T | semmle.label | 1 | +| tst.ts:332:3:334:13 | [ConditionalTypeExpr] T exten ... : never | tst.ts:332:3:332:3 | [LocalTypeAccess] T | semmle.order | 1 | +| tst.ts:332:3:334:13 | [ConditionalTypeExpr] T exten ... : never | tst.ts:332:13:332:50 | [TupleTypeExpr] [infer ... nown[]] | semmle.label | 2 | +| tst.ts:332:3:334:13 | [ConditionalTypeExpr] T exten ... : never | tst.ts:332:13:332:50 | [TupleTypeExpr] [infer ... nown[]] | semmle.order | 2 | +| tst.ts:332:3:334:13 | [ConditionalTypeExpr] T exten ... : never | tst.ts:333:9:333:9 | [LocalTypeAccess] S | semmle.label | 3 | +| tst.ts:332:3:334:13 | [ConditionalTypeExpr] T exten ... : never | tst.ts:333:9:333:9 | [LocalTypeAccess] S | semmle.order | 3 | +| tst.ts:332:3:334:13 | [ConditionalTypeExpr] T exten ... : never | tst.ts:334:9:334:13 | [KeywordTypeExpr] never | semmle.label | 4 | +| tst.ts:332:3:334:13 | [ConditionalTypeExpr] T exten ... : never | tst.ts:334:9:334:13 | [KeywordTypeExpr] never | semmle.order | 4 | +| tst.ts:332:13:332:50 | [TupleTypeExpr] [infer ... nown[]] | tst.ts:332:14:332:35 | [InferTypeExpr] infer S ... string | semmle.label | 1 | +| tst.ts:332:13:332:50 | [TupleTypeExpr] [infer ... nown[]] | tst.ts:332:14:332:35 | [InferTypeExpr] infer S ... string | semmle.order | 1 | +| tst.ts:332:13:332:50 | [TupleTypeExpr] [infer ... nown[]] | tst.ts:332:38:332:49 | [RestTypeExpr] ...unknown[] | semmle.label | 2 | +| tst.ts:332:13:332:50 | [TupleTypeExpr] [infer ... nown[]] | tst.ts:332:38:332:49 | [RestTypeExpr] ...unknown[] | semmle.order | 2 | +| tst.ts:332:14:332:35 | [InferTypeExpr] infer S ... string | file://:0:0:0:0 | (TypeParameters) | semmle.label | -100 | +| tst.ts:332:14:332:35 | [InferTypeExpr] infer S ... string | file://:0:0:0:0 | (TypeParameters) | semmle.order | -100 | +| tst.ts:332:20:332:35 | [TypeParameter] S extends string | tst.ts:332:20:332:20 | [Identifier] S | semmle.label | 1 | +| tst.ts:332:20:332:35 | [TypeParameter] S extends string | tst.ts:332:20:332:20 | [Identifier] S | semmle.order | 1 | +| tst.ts:332:20:332:35 | [TypeParameter] S extends string | tst.ts:332:30:332:35 | [KeywordTypeExpr] string | semmle.label | 2 | +| tst.ts:332:20:332:35 | [TypeParameter] S extends string | tst.ts:332:30:332:35 | [KeywordTypeExpr] string | semmle.order | 2 | +| tst.ts:332:38:332:49 | [RestTypeExpr] ...unknown[] | tst.ts:332:41:332:49 | [ArrayTypeExpr] unknown[] | semmle.label | 1 | +| tst.ts:332:38:332:49 | [RestTypeExpr] ...unknown[] | tst.ts:332:41:332:49 | [ArrayTypeExpr] unknown[] | semmle.order | 1 | +| tst.ts:332:41:332:49 | [ArrayTypeExpr] unknown[] | tst.ts:332:41:332:47 | [KeywordTypeExpr] unknown | semmle.label | 1 | +| tst.ts:332:41:332:49 | [ArrayTypeExpr] unknown[] | tst.ts:332:41:332:47 | [KeywordTypeExpr] unknown | semmle.order | 1 | +| tst.ts:336:1:336:51 | [TypeAliasDeclaration,TypeDefinition] type F ... lean]>; | tst.ts:336:6:336:6 | [Identifier] F | semmle.label | 1 | +| tst.ts:336:1:336:51 | [TypeAliasDeclaration,TypeDefinition] type F ... lean]>; | tst.ts:336:6:336:6 | [Identifier] F | semmle.order | 1 | +| tst.ts:336:1:336:51 | [TypeAliasDeclaration,TypeDefinition] type F ... lean]>; | tst.ts:336:10:336:50 | [GenericTypeExpr] FirstSt ... olean]> | semmle.label | 2 | +| tst.ts:336:1:336:51 | [TypeAliasDeclaration,TypeDefinition] type F ... lean]>; | tst.ts:336:10:336:50 | [GenericTypeExpr] FirstSt ... olean]> | semmle.order | 2 | +| tst.ts:336:10:336:50 | [GenericTypeExpr] FirstSt ... olean]> | tst.ts:336:10:336:20 | [LocalTypeAccess] FirstString | semmle.label | 1 | +| tst.ts:336:10:336:50 | [GenericTypeExpr] FirstSt ... olean]> | tst.ts:336:10:336:20 | [LocalTypeAccess] FirstString | semmle.order | 1 | +| tst.ts:336:10:336:50 | [GenericTypeExpr] FirstSt ... olean]> | tst.ts:336:22:336:49 | [TupleTypeExpr] ['a' \| ... oolean] | semmle.label | 2 | +| tst.ts:336:10:336:50 | [GenericTypeExpr] FirstSt ... olean]> | tst.ts:336:22:336:49 | [TupleTypeExpr] ['a' \| ... oolean] | semmle.order | 2 | +| tst.ts:336:22:336:49 | [TupleTypeExpr] ['a' \| ... oolean] | tst.ts:336:23:336:31 | [UnionTypeExpr] 'a' \| 'b' | semmle.label | 1 | +| tst.ts:336:22:336:49 | [TupleTypeExpr] ['a' \| ... oolean] | tst.ts:336:23:336:31 | [UnionTypeExpr] 'a' \| 'b' | semmle.order | 1 | +| tst.ts:336:22:336:49 | [TupleTypeExpr] ['a' \| ... oolean] | tst.ts:336:34:336:39 | [KeywordTypeExpr] number | semmle.label | 2 | +| tst.ts:336:22:336:49 | [TupleTypeExpr] ['a' \| ... oolean] | tst.ts:336:34:336:39 | [KeywordTypeExpr] number | semmle.order | 2 | +| tst.ts:336:22:336:49 | [TupleTypeExpr] ['a' \| ... oolean] | tst.ts:336:42:336:48 | [KeywordTypeExpr] boolean | semmle.label | 3 | +| tst.ts:336:22:336:49 | [TupleTypeExpr] ['a' \| ... oolean] | tst.ts:336:42:336:48 | [KeywordTypeExpr] boolean | semmle.order | 3 | +| tst.ts:336:23:336:31 | [UnionTypeExpr] 'a' \| 'b' | tst.ts:336:23:336:25 | [LiteralTypeExpr] 'a' | semmle.label | 1 | +| tst.ts:336:23:336:31 | [UnionTypeExpr] 'a' \| 'b' | tst.ts:336:23:336:25 | [LiteralTypeExpr] 'a' | semmle.order | 1 | +| tst.ts:336:23:336:31 | [UnionTypeExpr] 'a' \| 'b' | tst.ts:336:29:336:31 | [LiteralTypeExpr] 'b' | semmle.label | 2 | +| tst.ts:336:23:336:31 | [UnionTypeExpr] 'a' \| 'b' | tst.ts:336:29:336:31 | [LiteralTypeExpr] 'b' | semmle.order | 2 | +| tst.ts:338:1:338:17 | [DeclStmt] const a = ... | tst.ts:338:7:338:16 | [VariableDeclarator] a: F = 'a' | semmle.label | 1 | +| tst.ts:338:1:338:17 | [DeclStmt] const a = ... | tst.ts:338:7:338:16 | [VariableDeclarator] a: F = 'a' | semmle.order | 1 | +| tst.ts:338:7:338:16 | [VariableDeclarator] a: F = 'a' | tst.ts:338:7:338:7 | [VarDecl] a | semmle.label | 1 | +| tst.ts:338:7:338:16 | [VariableDeclarator] a: F = 'a' | tst.ts:338:7:338:7 | [VarDecl] a | semmle.order | 1 | +| tst.ts:338:7:338:16 | [VariableDeclarator] a: F = 'a' | tst.ts:338:10:338:10 | [LocalTypeAccess] F | semmle.label | 2 | +| tst.ts:338:7:338:16 | [VariableDeclarator] a: F = 'a' | tst.ts:338:10:338:10 | [LocalTypeAccess] F | semmle.order | 2 | +| tst.ts:338:7:338:16 | [VariableDeclarator] a: F = 'a' | tst.ts:338:14:338:16 | [Literal] 'a' | semmle.label | 3 | +| tst.ts:338:7:338:16 | [VariableDeclarator] a: F = 'a' | tst.ts:338:14:338:16 | [Literal] 'a' | semmle.order | 3 | +| tst.ts:342:1:345:1 | [InterfaceDeclaration,TypeDefinition] interfa ... void; } | file://:0:0:0:0 | (TypeParameters) | semmle.label | -100 | +| tst.ts:342:1:345:1 | [InterfaceDeclaration,TypeDefinition] interfa ... void; } | file://:0:0:0:0 | (TypeParameters) | semmle.order | -100 | +| tst.ts:342:1:345:1 | [InterfaceDeclaration,TypeDefinition] interfa ... void; } | tst.ts:342:11:342:15 | [Identifier] State | semmle.label | 1 | +| tst.ts:342:1:345:1 | [InterfaceDeclaration,TypeDefinition] interfa ... void; } | tst.ts:342:11:342:15 | [Identifier] State | semmle.order | 1 | +| tst.ts:342:1:345:1 | [InterfaceDeclaration,TypeDefinition] interfa ... void; } | tst.ts:343:3:343:15 | [FieldDeclaration] get: () => T; | semmle.label | 3 | +| tst.ts:342:1:345:1 | [InterfaceDeclaration,TypeDefinition] interfa ... void; } | tst.ts:343:3:343:15 | [FieldDeclaration] get: () => T; | semmle.order | 3 | +| tst.ts:342:1:345:1 | [InterfaceDeclaration,TypeDefinition] interfa ... void; } | tst.ts:344:3:344:26 | [FieldDeclaration] set: (v ... > void; | semmle.label | 4 | +| tst.ts:342:1:345:1 | [InterfaceDeclaration,TypeDefinition] interfa ... void; } | tst.ts:344:3:344:26 | [FieldDeclaration] set: (v ... > void; | semmle.order | 4 | +| tst.ts:342:17:342:24 | [TypeParameter] in out T | tst.ts:342:24:342:24 | [Identifier] T | semmle.label | 1 | +| tst.ts:342:17:342:24 | [TypeParameter] in out T | tst.ts:342:24:342:24 | [Identifier] T | semmle.order | 1 | +| tst.ts:343:3:343:15 | [FieldDeclaration] get: () => T; | tst.ts:343:3:343:5 | [Label] get | semmle.label | 1 | +| tst.ts:343:3:343:15 | [FieldDeclaration] get: () => T; | tst.ts:343:3:343:5 | [Label] get | semmle.order | 1 | +| tst.ts:343:3:343:15 | [FieldDeclaration] get: () => T; | tst.ts:343:8:343:14 | [FunctionTypeExpr] () => T | semmle.label | 2 | +| tst.ts:343:3:343:15 | [FieldDeclaration] get: () => T; | tst.ts:343:8:343:14 | [FunctionTypeExpr] () => T | semmle.order | 2 | +| tst.ts:343:8:343:14 | [FunctionExpr] () => T | tst.ts:343:14:343:14 | [LocalTypeAccess] T | semmle.label | 4 | +| tst.ts:343:8:343:14 | [FunctionExpr] () => T | tst.ts:343:14:343:14 | [LocalTypeAccess] T | semmle.order | 4 | +| tst.ts:343:8:343:14 | [FunctionTypeExpr] () => T | tst.ts:343:8:343:14 | [FunctionExpr] () => T | semmle.label | 1 | +| tst.ts:343:8:343:14 | [FunctionTypeExpr] () => T | tst.ts:343:8:343:14 | [FunctionExpr] () => T | semmle.order | 1 | +| tst.ts:344:3:344:26 | [FieldDeclaration] set: (v ... > void; | tst.ts:344:3:344:5 | [Label] set | semmle.label | 1 | +| tst.ts:344:3:344:26 | [FieldDeclaration] set: (v ... > void; | tst.ts:344:3:344:5 | [Label] set | semmle.order | 1 | +| tst.ts:344:3:344:26 | [FieldDeclaration] set: (v ... > void; | tst.ts:344:8:344:25 | [FunctionTypeExpr] (value: T) => void | semmle.label | 2 | +| tst.ts:344:3:344:26 | [FieldDeclaration] set: (v ... > void; | tst.ts:344:8:344:25 | [FunctionTypeExpr] (value: T) => void | semmle.order | 2 | +| tst.ts:344:8:344:25 | [FunctionExpr] (value: T) => void | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:344:8:344:25 | [FunctionExpr] (value: T) => void | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:344:8:344:25 | [FunctionExpr] (value: T) => void | tst.ts:344:22:344:25 | [KeywordTypeExpr] void | semmle.label | 4 | +| tst.ts:344:8:344:25 | [FunctionExpr] (value: T) => void | tst.ts:344:22:344:25 | [KeywordTypeExpr] void | semmle.order | 4 | +| tst.ts:344:8:344:25 | [FunctionTypeExpr] (value: T) => void | tst.ts:344:8:344:25 | [FunctionExpr] (value: T) => void | semmle.label | 1 | +| tst.ts:344:8:344:25 | [FunctionTypeExpr] (value: T) => void | tst.ts:344:8:344:25 | [FunctionExpr] (value: T) => void | semmle.order | 1 | +| tst.ts:344:9:344:13 | [SimpleParameter] value | tst.ts:344:16:344:16 | [LocalTypeAccess] T | semmle.label | 0 | +| tst.ts:344:9:344:13 | [SimpleParameter] value | tst.ts:344:16:344:16 | [LocalTypeAccess] T | semmle.order | 0 | +| tst.ts:347:1:350:1 | [DeclStmt] const state = ... | tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | semmle.label | 1 | +| tst.ts:347:1:350:1 | [DeclStmt] const state = ... | tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | semmle.order | 1 | +| tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | tst.ts:347:7:347:11 | [VarDecl] state | semmle.label | 1 | +| tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | tst.ts:347:7:347:11 | [VarDecl] state | semmle.order | 1 | +| tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | tst.ts:347:14:347:26 | [GenericTypeExpr] State | semmle.label | 2 | +| tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | tst.ts:347:14:347:26 | [GenericTypeExpr] State | semmle.order | 2 | +| tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | tst.ts:347:30:350:1 | [ObjectExpr] {get: ...} | semmle.label | 3 | +| tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | tst.ts:347:30:350:1 | [ObjectExpr] {get: ...} | semmle.order | 3 | +| tst.ts:347:14:347:26 | [GenericTypeExpr] State | tst.ts:347:14:347:18 | [LocalTypeAccess] State | semmle.label | 1 | +| tst.ts:347:14:347:26 | [GenericTypeExpr] State | tst.ts:347:14:347:18 | [LocalTypeAccess] State | semmle.order | 1 | +| tst.ts:347:14:347:26 | [GenericTypeExpr] State | tst.ts:347:20:347:25 | [KeywordTypeExpr] number | semmle.label | 2 | +| tst.ts:347:14:347:26 | [GenericTypeExpr] State | tst.ts:347:20:347:25 | [KeywordTypeExpr] number | semmle.order | 2 | +| tst.ts:347:30:350:1 | [ObjectExpr] {get: ...} | tst.ts:348:3:348:15 | [Property] get: () => 42 | semmle.label | 1 | +| tst.ts:347:30:350:1 | [ObjectExpr] {get: ...} | tst.ts:348:3:348:15 | [Property] get: () => 42 | semmle.order | 1 | +| tst.ts:347:30:350:1 | [ObjectExpr] {get: ...} | tst.ts:349:3:349:21 | [Property] set: (value) => { } | semmle.label | 2 | +| tst.ts:347:30:350:1 | [ObjectExpr] {get: ...} | tst.ts:349:3:349:21 | [Property] set: (value) => { } | semmle.order | 2 | +| tst.ts:348:3:348:15 | [Property] get: () => 42 | tst.ts:348:3:348:5 | [Label] get | semmle.label | 1 | +| tst.ts:348:3:348:15 | [Property] get: () => 42 | tst.ts:348:3:348:5 | [Label] get | semmle.order | 1 | +| tst.ts:348:3:348:15 | [Property] get: () => 42 | tst.ts:348:8:348:15 | [ArrowFunctionExpr] () => 42 | semmle.label | 2 | +| tst.ts:348:3:348:15 | [Property] get: () => 42 | tst.ts:348:8:348:15 | [ArrowFunctionExpr] () => 42 | semmle.order | 2 | +| tst.ts:348:8:348:15 | [ArrowFunctionExpr] () => 42 | tst.ts:348:14:348:15 | [Literal] 42 | semmle.label | 5 | +| tst.ts:348:8:348:15 | [ArrowFunctionExpr] () => 42 | tst.ts:348:14:348:15 | [Literal] 42 | semmle.order | 5 | +| tst.ts:349:3:349:21 | [Property] set: (value) => { } | tst.ts:349:3:349:5 | [Label] set | semmle.label | 1 | +| tst.ts:349:3:349:21 | [Property] set: (value) => { } | tst.ts:349:3:349:5 | [Label] set | semmle.order | 1 | +| tst.ts:349:3:349:21 | [Property] set: (value) => { } | tst.ts:349:8:349:21 | [ArrowFunctionExpr] (value) => { } | semmle.label | 2 | +| tst.ts:349:3:349:21 | [Property] set: (value) => { } | tst.ts:349:8:349:21 | [ArrowFunctionExpr] (value) => { } | semmle.order | 2 | +| tst.ts:349:8:349:21 | [ArrowFunctionExpr] (value) => { } | file://:0:0:0:0 | (Parameters) | semmle.label | 1 | +| tst.ts:349:8:349:21 | [ArrowFunctionExpr] (value) => { } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 | +| tst.ts:349:8:349:21 | [ArrowFunctionExpr] (value) => { } | tst.ts:349:19:349:21 | [BlockStmt] { } | semmle.label | 5 | +| tst.ts:349:8:349:21 | [ArrowFunctionExpr] (value) => { } | tst.ts:349:19:349:21 | [BlockStmt] { } | semmle.order | 5 | +| tst.ts:352:1:352:29 | [DeclStmt] const fortyTwo = ... | tst.ts:352:7:352:28 | [VariableDeclarator] fortyTw ... e.get() | semmle.label | 1 | +| tst.ts:352:1:352:29 | [DeclStmt] const fortyTwo = ... | tst.ts:352:7:352:28 | [VariableDeclarator] fortyTw ... e.get() | semmle.order | 1 | +| tst.ts:352:7:352:28 | [VariableDeclarator] fortyTw ... e.get() | tst.ts:352:7:352:14 | [VarDecl] fortyTwo | semmle.label | 1 | +| tst.ts:352:7:352:28 | [VariableDeclarator] fortyTw ... e.get() | tst.ts:352:7:352:14 | [VarDecl] fortyTwo | semmle.order | 1 | +| tst.ts:352:7:352:28 | [VariableDeclarator] fortyTw ... e.get() | tst.ts:352:18:352:28 | [MethodCallExpr] state.get() | semmle.label | 2 | +| tst.ts:352:7:352:28 | [VariableDeclarator] fortyTw ... e.get() | tst.ts:352:18:352:28 | [MethodCallExpr] state.get() | semmle.order | 2 | +| tst.ts:352:18:352:26 | [DotExpr] state.get | tst.ts:352:18:352:22 | [VarRef] state | semmle.label | 1 | +| tst.ts:352:18:352:26 | [DotExpr] state.get | tst.ts:352:18:352:22 | [VarRef] state | semmle.order | 1 | +| tst.ts:352:18:352:26 | [DotExpr] state.get | tst.ts:352:24:352:26 | [Label] get | semmle.label | 2 | +| tst.ts:352:18:352:26 | [DotExpr] state.get | tst.ts:352:24:352:26 | [Label] get | semmle.order | 2 | +| tst.ts:352:18:352:28 | [MethodCallExpr] state.get() | tst.ts:352:18:352:26 | [DotExpr] state.get | semmle.label | 0 | +| tst.ts:352:18:352:28 | [MethodCallExpr] state.get() | tst.ts:352:18:352:26 | [DotExpr] state.get | semmle.order | 0 | +| tst.ts:356:1:356:44 | [ImportDeclaration] import ... S.mjs'; | tst.ts:356:8:356:18 | [ImportSpecifier] tstModuleES | semmle.label | 1 | +| tst.ts:356:1:356:44 | [ImportDeclaration] import ... S.mjs'; | tst.ts:356:8:356:18 | [ImportSpecifier] tstModuleES | semmle.order | 1 | +| tst.ts:356:1:356:44 | [ImportDeclaration] import ... S.mjs'; | tst.ts:356:25:356:43 | [Literal] './tstModuleES.mjs' | semmle.label | 2 | +| tst.ts:356:1:356:44 | [ImportDeclaration] import ... S.mjs'; | tst.ts:356:25:356:43 | [Literal] './tstModuleES.mjs' | semmle.order | 2 | +| tst.ts:356:8:356:18 | [ImportSpecifier] tstModuleES | tst.ts:356:8:356:18 | [VarDecl] tstModuleES | semmle.label | 1 | +| tst.ts:356:8:356:18 | [ImportSpecifier] tstModuleES | tst.ts:356:8:356:18 | [VarDecl] tstModuleES | semmle.order | 1 | +| tst.ts:358:1:358:11 | [DotExpr] console.log | tst.ts:358:1:358:7 | [VarRef] console | semmle.label | 1 | +| tst.ts:358:1:358:11 | [DotExpr] console.log | tst.ts:358:1:358:7 | [VarRef] console | semmle.order | 1 | +| tst.ts:358:1:358:11 | [DotExpr] console.log | tst.ts:358:9:358:11 | [Label] log | semmle.label | 2 | +| tst.ts:358:1:358:11 | [DotExpr] console.log | tst.ts:358:9:358:11 | [Label] log | semmle.order | 2 | +| tst.ts:358:1:358:26 | [MethodCallExpr] console ... leES()) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| tst.ts:358:1:358:26 | [MethodCallExpr] console ... leES()) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| tst.ts:358:1:358:26 | [MethodCallExpr] console ... leES()) | tst.ts:358:1:358:11 | [DotExpr] console.log | semmle.label | 0 | +| tst.ts:358:1:358:26 | [MethodCallExpr] console ... leES()) | tst.ts:358:1:358:11 | [DotExpr] console.log | semmle.order | 0 | +| tst.ts:358:1:358:27 | [ExprStmt] console ... eES()); | tst.ts:358:1:358:26 | [MethodCallExpr] console ... leES()) | semmle.label | 1 | +| tst.ts:358:1:358:27 | [ExprStmt] console ... eES()); | tst.ts:358:1:358:26 | [MethodCallExpr] console ... leES()) | semmle.order | 1 | +| tst.ts:358:13:358:25 | [CallExpr] tstModuleES() | tst.ts:358:13:358:23 | [VarRef] tstModuleES | semmle.label | 0 | +| tst.ts:358:13:358:25 | [CallExpr] tstModuleES() | tst.ts:358:13:358:23 | [VarRef] tstModuleES | semmle.order | 0 | +| tst.ts:360:1:360:50 | [ImportDeclaration] import ... S.cjs'; | tst.ts:360:10:360:21 | [ImportSpecifier] tstModuleCJS | semmle.label | 1 | +| tst.ts:360:1:360:50 | [ImportDeclaration] import ... S.cjs'; | tst.ts:360:10:360:21 | [ImportSpecifier] tstModuleCJS | semmle.order | 1 | +| tst.ts:360:1:360:50 | [ImportDeclaration] import ... S.cjs'; | tst.ts:360:30:360:49 | [Literal] './tstModuleCJS.cjs' | semmle.label | 2 | +| tst.ts:360:1:360:50 | [ImportDeclaration] import ... S.cjs'; | tst.ts:360:30:360:49 | [Literal] './tstModuleCJS.cjs' | semmle.order | 2 | +| tst.ts:360:10:360:21 | [ImportSpecifier] tstModuleCJS | tst.ts:360:10:360:21 | [Label] tstModuleCJS | semmle.label | 1 | +| tst.ts:360:10:360:21 | [ImportSpecifier] tstModuleCJS | tst.ts:360:10:360:21 | [Label] tstModuleCJS | semmle.order | 1 | +| tst.ts:360:10:360:21 | [ImportSpecifier] tstModuleCJS | tst.ts:360:10:360:21 | [VarDecl] tstModuleCJS | semmle.label | 2 | +| tst.ts:360:10:360:21 | [ImportSpecifier] tstModuleCJS | tst.ts:360:10:360:21 | [VarDecl] tstModuleCJS | semmle.order | 2 | +| tst.ts:362:1:362:11 | [DotExpr] console.log | tst.ts:362:1:362:7 | [VarRef] console | semmle.label | 1 | +| tst.ts:362:1:362:11 | [DotExpr] console.log | tst.ts:362:1:362:7 | [VarRef] console | semmle.order | 1 | +| tst.ts:362:1:362:11 | [DotExpr] console.log | tst.ts:362:9:362:11 | [Label] log | semmle.label | 2 | +| tst.ts:362:1:362:11 | [DotExpr] console.log | tst.ts:362:9:362:11 | [Label] log | semmle.order | 2 | +| tst.ts:362:1:362:27 | [MethodCallExpr] console ... eCJS()) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| tst.ts:362:1:362:27 | [MethodCallExpr] console ... eCJS()) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| tst.ts:362:1:362:27 | [MethodCallExpr] console ... eCJS()) | tst.ts:362:1:362:11 | [DotExpr] console.log | semmle.label | 0 | +| tst.ts:362:1:362:27 | [MethodCallExpr] console ... eCJS()) | tst.ts:362:1:362:11 | [DotExpr] console.log | semmle.order | 0 | +| tst.ts:362:1:362:28 | [ExprStmt] console ... CJS()); | tst.ts:362:1:362:27 | [MethodCallExpr] console ... eCJS()) | semmle.label | 1 | +| tst.ts:362:1:362:28 | [ExprStmt] console ... CJS()); | tst.ts:362:1:362:27 | [MethodCallExpr] console ... eCJS()) | semmle.order | 1 | +| tst.ts:362:13:362:26 | [CallExpr] tstModuleCJS() | tst.ts:362:13:362:24 | [VarRef] tstModuleCJS | semmle.label | 0 | +| tst.ts:362:13:362:26 | [CallExpr] tstModuleCJS() | tst.ts:362:13:362:24 | [VarRef] tstModuleCJS | semmle.order | 0 | +| tst.ts:368:1:368:34 | [ImportDeclaration] import ... ffixA'; | tst.ts:368:8:368:13 | [ImportSpecifier] * as A | semmle.label | 1 | +| tst.ts:368:1:368:34 | [ImportDeclaration] import ... ffixA'; | tst.ts:368:8:368:13 | [ImportSpecifier] * as A | semmle.order | 1 | +| tst.ts:368:1:368:34 | [ImportDeclaration] import ... ffixA'; | tst.ts:368:20:368:33 | [Literal] './tstSuffixA' | semmle.label | 2 | +| tst.ts:368:1:368:34 | [ImportDeclaration] import ... ffixA'; | tst.ts:368:20:368:33 | [Literal] './tstSuffixA' | semmle.order | 2 | +| tst.ts:368:8:368:13 | [ImportSpecifier] * as A | tst.ts:368:13:368:13 | [VarDecl] A | semmle.label | 1 | +| tst.ts:368:8:368:13 | [ImportSpecifier] * as A | tst.ts:368:13:368:13 | [VarDecl] A | semmle.order | 1 | +| tst.ts:370:1:370:11 | [DotExpr] console.log | tst.ts:370:1:370:7 | [VarRef] console | semmle.label | 1 | +| tst.ts:370:1:370:11 | [DotExpr] console.log | tst.ts:370:1:370:7 | [VarRef] console | semmle.order | 1 | +| tst.ts:370:1:370:11 | [DotExpr] console.log | tst.ts:370:9:370:11 | [Label] log | semmle.label | 2 | +| tst.ts:370:1:370:11 | [DotExpr] console.log | tst.ts:370:9:370:11 | [Label] log | semmle.order | 2 | +| tst.ts:370:1:370:29 | [MethodCallExpr] console ... File()) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| tst.ts:370:1:370:29 | [MethodCallExpr] console ... File()) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| tst.ts:370:1:370:29 | [MethodCallExpr] console ... File()) | tst.ts:370:1:370:11 | [DotExpr] console.log | semmle.label | 0 | +| tst.ts:370:1:370:29 | [MethodCallExpr] console ... File()) | tst.ts:370:1:370:11 | [DotExpr] console.log | semmle.order | 0 | +| tst.ts:370:1:370:30 | [ExprStmt] console ... ile()); | tst.ts:370:1:370:29 | [MethodCallExpr] console ... File()) | semmle.label | 1 | +| tst.ts:370:1:370:30 | [ExprStmt] console ... ile()); | tst.ts:370:1:370:29 | [MethodCallExpr] console ... File()) | semmle.order | 1 | +| tst.ts:370:13:370:26 | [DotExpr] A.resolvedFile | tst.ts:370:13:370:13 | [VarRef] A | semmle.label | 1 | +| tst.ts:370:13:370:26 | [DotExpr] A.resolvedFile | tst.ts:370:13:370:13 | [VarRef] A | semmle.order | 1 | +| tst.ts:370:13:370:26 | [DotExpr] A.resolvedFile | tst.ts:370:15:370:26 | [Label] resolvedFile | semmle.label | 2 | +| tst.ts:370:13:370:26 | [DotExpr] A.resolvedFile | tst.ts:370:15:370:26 | [Label] resolvedFile | semmle.order | 2 | +| tst.ts:370:13:370:28 | [MethodCallExpr] A.resolvedFile() | tst.ts:370:13:370:26 | [DotExpr] A.resolvedFile | semmle.label | 0 | +| tst.ts:370:13:370:28 | [MethodCallExpr] A.resolvedFile() | tst.ts:370:13:370:26 | [DotExpr] A.resolvedFile | semmle.order | 0 | +| tst.ts:372:1:372:34 | [ImportDeclaration] import ... ffixB'; | tst.ts:372:8:372:13 | [ImportSpecifier] * as B | semmle.label | 1 | +| tst.ts:372:1:372:34 | [ImportDeclaration] import ... ffixB'; | tst.ts:372:8:372:13 | [ImportSpecifier] * as B | semmle.order | 1 | +| tst.ts:372:1:372:34 | [ImportDeclaration] import ... ffixB'; | tst.ts:372:20:372:33 | [Literal] './tstSuffixB' | semmle.label | 2 | +| tst.ts:372:1:372:34 | [ImportDeclaration] import ... ffixB'; | tst.ts:372:20:372:33 | [Literal] './tstSuffixB' | semmle.order | 2 | +| tst.ts:372:8:372:13 | [ImportSpecifier] * as B | tst.ts:372:13:372:13 | [VarDecl] B | semmle.label | 1 | +| tst.ts:372:8:372:13 | [ImportSpecifier] * as B | tst.ts:372:13:372:13 | [VarDecl] B | semmle.order | 1 | +| tst.ts:374:1:374:11 | [DotExpr] console.log | tst.ts:374:1:374:7 | [VarRef] console | semmle.label | 1 | +| tst.ts:374:1:374:11 | [DotExpr] console.log | tst.ts:374:1:374:7 | [VarRef] console | semmle.order | 1 | +| tst.ts:374:1:374:11 | [DotExpr] console.log | tst.ts:374:9:374:11 | [Label] log | semmle.label | 2 | +| tst.ts:374:1:374:11 | [DotExpr] console.log | tst.ts:374:9:374:11 | [Label] log | semmle.order | 2 | +| tst.ts:374:1:374:29 | [MethodCallExpr] console ... File()) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 | +| tst.ts:374:1:374:29 | [MethodCallExpr] console ... File()) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 | +| tst.ts:374:1:374:29 | [MethodCallExpr] console ... File()) | tst.ts:374:1:374:11 | [DotExpr] console.log | semmle.label | 0 | +| tst.ts:374:1:374:29 | [MethodCallExpr] console ... File()) | tst.ts:374:1:374:11 | [DotExpr] console.log | semmle.order | 0 | +| tst.ts:374:1:374:30 | [ExprStmt] console ... ile()); | tst.ts:374:1:374:29 | [MethodCallExpr] console ... File()) | semmle.label | 1 | +| tst.ts:374:1:374:30 | [ExprStmt] console ... ile()); | tst.ts:374:1:374:29 | [MethodCallExpr] console ... File()) | semmle.order | 1 | +| tst.ts:374:13:374:26 | [DotExpr] B.resolvedFile | tst.ts:374:13:374:13 | [VarRef] B | semmle.label | 1 | +| tst.ts:374:13:374:26 | [DotExpr] B.resolvedFile | tst.ts:374:13:374:13 | [VarRef] B | semmle.order | 1 | +| tst.ts:374:13:374:26 | [DotExpr] B.resolvedFile | tst.ts:374:15:374:26 | [Label] resolvedFile | semmle.label | 2 | +| tst.ts:374:13:374:26 | [DotExpr] B.resolvedFile | tst.ts:374:15:374:26 | [Label] resolvedFile | semmle.order | 2 | +| tst.ts:374:13:374:28 | [MethodCallExpr] B.resolvedFile() | tst.ts:374:13:374:26 | [DotExpr] B.resolvedFile | semmle.label | 0 | +| tst.ts:374:13:374:28 | [MethodCallExpr] B.resolvedFile() | tst.ts:374:13:374:26 | [DotExpr] B.resolvedFile | semmle.order | 0 | +| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | 1 | +| tstModuleCJS.cts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.order | 1 | +| tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleCJS.cts:1:17:1:28 | [VarDecl] tstModuleCJS | semmle.label | 0 | +| tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleCJS.cts:1:17:1:28 | [VarDecl] tstModuleCJS | semmle.order | 0 | +| tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleCJS.cts:1:33:1:41 | [UnionTypeExpr] 'a' \| 'b' | semmle.label | 4 | +| tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleCJS.cts:1:33:1:41 | [UnionTypeExpr] 'a' \| 'b' | semmle.order | 4 | +| tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleCJS.cts:1:43:3:1 | [BlockStmt] { r ... 'b'; } | semmle.label | 5 | +| tstModuleCJS.cts:1:8:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleCJS.cts:1:43:3:1 | [BlockStmt] { r ... 'b'; } | semmle.order | 5 | +| tstModuleCJS.cts:1:33:1:41 | [UnionTypeExpr] 'a' \| 'b' | tstModuleCJS.cts:1:33:1:35 | [LiteralTypeExpr] 'a' | semmle.label | 1 | +| tstModuleCJS.cts:1:33:1:41 | [UnionTypeExpr] 'a' \| 'b' | tstModuleCJS.cts:1:33:1:35 | [LiteralTypeExpr] 'a' | semmle.order | 1 | +| tstModuleCJS.cts:1:33:1:41 | [UnionTypeExpr] 'a' \| 'b' | tstModuleCJS.cts:1:39:1:41 | [LiteralTypeExpr] 'b' | semmle.label | 2 | +| tstModuleCJS.cts:1:33:1:41 | [UnionTypeExpr] 'a' \| 'b' | tstModuleCJS.cts:1:39:1:41 | [LiteralTypeExpr] 'b' | semmle.order | 2 | +| tstModuleCJS.cts:1:43:3:1 | [BlockStmt] { r ... 'b'; } | tstModuleCJS.cts:2:5:2:43 | [ReturnStmt] return ... : 'b'; | semmle.label | 1 | +| tstModuleCJS.cts:1:43:3:1 | [BlockStmt] { r ... 'b'; } | tstModuleCJS.cts:2:5:2:43 | [ReturnStmt] return ... : 'b'; | semmle.order | 1 | +| tstModuleCJS.cts:2:5:2:43 | [ReturnStmt] return ... : 'b'; | tstModuleCJS.cts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | semmle.label | 1 | +| tstModuleCJS.cts:2:5:2:43 | [ReturnStmt] return ... : 'b'; | tstModuleCJS.cts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | semmle.order | 1 | +| tstModuleCJS.cts:2:12:2:22 | [DotExpr] Math.random | tstModuleCJS.cts:2:12:2:15 | [VarRef] Math | semmle.label | 1 | +| tstModuleCJS.cts:2:12:2:22 | [DotExpr] Math.random | tstModuleCJS.cts:2:12:2:15 | [VarRef] Math | semmle.order | 1 | +| tstModuleCJS.cts:2:12:2:22 | [DotExpr] Math.random | tstModuleCJS.cts:2:17:2:22 | [Label] random | semmle.label | 2 | +| tstModuleCJS.cts:2:12:2:22 | [DotExpr] Math.random | tstModuleCJS.cts:2:17:2:22 | [Label] random | semmle.order | 2 | +| tstModuleCJS.cts:2:12:2:24 | [MethodCallExpr] Math.random() | tstModuleCJS.cts:2:12:2:22 | [DotExpr] Math.random | semmle.label | 0 | +| tstModuleCJS.cts:2:12:2:24 | [MethodCallExpr] Math.random() | tstModuleCJS.cts:2:12:2:22 | [DotExpr] Math.random | semmle.order | 0 | +| tstModuleCJS.cts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | tstModuleCJS.cts:2:12:2:24 | [MethodCallExpr] Math.random() | semmle.label | 1 | +| tstModuleCJS.cts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | tstModuleCJS.cts:2:12:2:24 | [MethodCallExpr] Math.random() | semmle.order | 1 | +| tstModuleCJS.cts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | tstModuleCJS.cts:2:28:2:30 | [Literal] 0.5 | semmle.label | 2 | +| tstModuleCJS.cts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | tstModuleCJS.cts:2:28:2:30 | [Literal] 0.5 | semmle.order | 2 | +| tstModuleCJS.cts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleCJS.cts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | semmle.label | 1 | +| tstModuleCJS.cts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleCJS.cts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | semmle.order | 1 | +| tstModuleCJS.cts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleCJS.cts:2:34:2:36 | [Literal] 'a' | semmle.label | 2 | +| tstModuleCJS.cts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleCJS.cts:2:34:2:36 | [Literal] 'a' | semmle.order | 2 | +| tstModuleCJS.cts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleCJS.cts:2:40:2:42 | [Literal] 'b' | semmle.label | 3 | +| tstModuleCJS.cts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleCJS.cts:2:40:2:42 | [Literal] 'b' | semmle.order | 3 | +| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.label | 1 | +| tstModuleES.mts:1:1:3:1 | [ExportDeclaration] export ... 'b'; } | tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | semmle.order | 1 | +| tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleES.mts:1:25:1:35 | [VarDecl] tstModuleES | semmle.label | 0 | +| tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleES.mts:1:25:1:35 | [VarDecl] tstModuleES | semmle.order | 0 | +| tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleES.mts:1:40:1:48 | [UnionTypeExpr] 'a' \| 'b' | semmle.label | 4 | +| tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleES.mts:1:40:1:48 | [UnionTypeExpr] 'a' \| 'b' | semmle.order | 4 | +| tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleES.mts:1:50:3:1 | [BlockStmt] { r ... 'b'; } | semmle.label | 5 | +| tstModuleES.mts:1:16:3:1 | [FunctionDeclStmt] functio ... 'b'; } | tstModuleES.mts:1:50:3:1 | [BlockStmt] { r ... 'b'; } | semmle.order | 5 | +| tstModuleES.mts:1:40:1:48 | [UnionTypeExpr] 'a' \| 'b' | tstModuleES.mts:1:40:1:42 | [LiteralTypeExpr] 'a' | semmle.label | 1 | +| tstModuleES.mts:1:40:1:48 | [UnionTypeExpr] 'a' \| 'b' | tstModuleES.mts:1:40:1:42 | [LiteralTypeExpr] 'a' | semmle.order | 1 | +| tstModuleES.mts:1:40:1:48 | [UnionTypeExpr] 'a' \| 'b' | tstModuleES.mts:1:46:1:48 | [LiteralTypeExpr] 'b' | semmle.label | 2 | +| tstModuleES.mts:1:40:1:48 | [UnionTypeExpr] 'a' \| 'b' | tstModuleES.mts:1:46:1:48 | [LiteralTypeExpr] 'b' | semmle.order | 2 | +| tstModuleES.mts:1:50:3:1 | [BlockStmt] { r ... 'b'; } | tstModuleES.mts:2:5:2:43 | [ReturnStmt] return ... : 'b'; | semmle.label | 1 | +| tstModuleES.mts:1:50:3:1 | [BlockStmt] { r ... 'b'; } | tstModuleES.mts:2:5:2:43 | [ReturnStmt] return ... : 'b'; | semmle.order | 1 | +| tstModuleES.mts:2:5:2:43 | [ReturnStmt] return ... : 'b'; | tstModuleES.mts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | semmle.label | 1 | +| tstModuleES.mts:2:5:2:43 | [ReturnStmt] return ... : 'b'; | tstModuleES.mts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | semmle.order | 1 | +| tstModuleES.mts:2:12:2:22 | [DotExpr] Math.random | tstModuleES.mts:2:12:2:15 | [VarRef] Math | semmle.label | 1 | +| tstModuleES.mts:2:12:2:22 | [DotExpr] Math.random | tstModuleES.mts:2:12:2:15 | [VarRef] Math | semmle.order | 1 | +| tstModuleES.mts:2:12:2:22 | [DotExpr] Math.random | tstModuleES.mts:2:17:2:22 | [Label] random | semmle.label | 2 | +| tstModuleES.mts:2:12:2:22 | [DotExpr] Math.random | tstModuleES.mts:2:17:2:22 | [Label] random | semmle.order | 2 | +| tstModuleES.mts:2:12:2:24 | [MethodCallExpr] Math.random() | tstModuleES.mts:2:12:2:22 | [DotExpr] Math.random | semmle.label | 0 | +| tstModuleES.mts:2:12:2:24 | [MethodCallExpr] Math.random() | tstModuleES.mts:2:12:2:22 | [DotExpr] Math.random | semmle.order | 0 | +| tstModuleES.mts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | tstModuleES.mts:2:12:2:24 | [MethodCallExpr] Math.random() | semmle.label | 1 | +| tstModuleES.mts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | tstModuleES.mts:2:12:2:24 | [MethodCallExpr] Math.random() | semmle.order | 1 | +| tstModuleES.mts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | tstModuleES.mts:2:28:2:30 | [Literal] 0.5 | semmle.label | 2 | +| tstModuleES.mts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | tstModuleES.mts:2:28:2:30 | [Literal] 0.5 | semmle.order | 2 | +| tstModuleES.mts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleES.mts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | semmle.label | 1 | +| tstModuleES.mts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleES.mts:2:12:2:30 | [BinaryExpr] Math.random() > 0.5 | semmle.order | 1 | +| tstModuleES.mts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleES.mts:2:34:2:36 | [Literal] 'a' | semmle.label | 2 | +| tstModuleES.mts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleES.mts:2:34:2:36 | [Literal] 'a' | semmle.order | 2 | +| tstModuleES.mts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleES.mts:2:40:2:42 | [Literal] 'b' | semmle.label | 3 | +| tstModuleES.mts:2:12:2:42 | [ConditionalExpr] Math.ra ... ' : 'b' | tstModuleES.mts:2:40:2:42 | [Literal] 'b' | semmle.order | 3 | +| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | 1 | +| tstSuffixA.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.order | 1 | +| tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixA.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | 0 | +| tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixA.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.order | 0 | +| tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixA.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixA.ts' | semmle.label | 4 | +| tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixA.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixA.ts' | semmle.order | 4 | +| tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixA.ts:1:49:3:1 | [BlockStmt] { r ... .ts'; } | semmle.label | 5 | +| tstSuffixA.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixA.ts:1:49:3:1 | [BlockStmt] { r ... .ts'; } | semmle.order | 5 | +| tstSuffixA.ts:1:49:3:1 | [BlockStmt] { r ... .ts'; } | tstSuffixA.ts:2:5:2:27 | [ReturnStmt] return ... xA.ts'; | semmle.label | 1 | +| tstSuffixA.ts:1:49:3:1 | [BlockStmt] { r ... .ts'; } | tstSuffixA.ts:2:5:2:27 | [ReturnStmt] return ... xA.ts'; | semmle.order | 1 | +| tstSuffixA.ts:2:5:2:27 | [ReturnStmt] return ... xA.ts'; | tstSuffixA.ts:2:12:2:26 | [Literal] 'tstSuffixA.ts' | semmle.label | 1 | +| tstSuffixA.ts:2:5:2:27 | [ReturnStmt] return ... xA.ts'; | tstSuffixA.ts:2:12:2:26 | [Literal] 'tstSuffixA.ts' | semmle.order | 1 | +| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | 1 | +| tstSuffixB.ios.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.order | 1 | +| tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ios.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | 0 | +| tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ios.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.order | 0 | +| tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ios.ts:1:33:1:51 | [LiteralTypeExpr] 'tstSuffixB.ios.ts' | semmle.label | 4 | +| tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ios.ts:1:33:1:51 | [LiteralTypeExpr] 'tstSuffixB.ios.ts' | semmle.order | 4 | +| tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ios.ts:1:53:3:1 | [BlockStmt] { r ... .ts'; } | semmle.label | 5 | +| tstSuffixB.ios.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ios.ts:1:53:3:1 | [BlockStmt] { r ... .ts'; } | semmle.order | 5 | +| tstSuffixB.ios.ts:1:53:3:1 | [BlockStmt] { r ... .ts'; } | tstSuffixB.ios.ts:2:5:2:31 | [ReturnStmt] return ... os.ts'; | semmle.label | 1 | +| tstSuffixB.ios.ts:1:53:3:1 | [BlockStmt] { r ... .ts'; } | tstSuffixB.ios.ts:2:5:2:31 | [ReturnStmt] return ... os.ts'; | semmle.order | 1 | +| tstSuffixB.ios.ts:2:5:2:31 | [ReturnStmt] return ... os.ts'; | tstSuffixB.ios.ts:2:12:2:30 | [Literal] 'tstSuffixB.ios.ts' | semmle.label | 1 | +| tstSuffixB.ios.ts:2:5:2:31 | [ReturnStmt] return ... os.ts'; | tstSuffixB.ios.ts:2:12:2:30 | [Literal] 'tstSuffixB.ios.ts' | semmle.order | 1 | +| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.label | 1 | +| tstSuffixB.ts:1:1:3:1 | [ExportDeclaration] export ... .ts'; } | tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | semmle.order | 1 | +| tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.label | 0 | +| tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ts:1:17:1:28 | [VarDecl] resolvedFile | semmle.order | 0 | +| tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixB.ts' | semmle.label | 4 | +| tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ts:1:33:1:47 | [LiteralTypeExpr] 'tstSuffixB.ts' | semmle.order | 4 | +| tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ts:1:49:3:1 | [BlockStmt] { r ... .ts'; } | semmle.label | 5 | +| tstSuffixB.ts:1:8:3:1 | [FunctionDeclStmt] functio ... .ts'; } | tstSuffixB.ts:1:49:3:1 | [BlockStmt] { r ... .ts'; } | semmle.order | 5 | +| tstSuffixB.ts:1:49:3:1 | [BlockStmt] { r ... .ts'; } | tstSuffixB.ts:2:5:2:27 | [ReturnStmt] return ... xB.ts'; | semmle.label | 1 | +| tstSuffixB.ts:1:49:3:1 | [BlockStmt] { r ... .ts'; } | tstSuffixB.ts:2:5:2:27 | [ReturnStmt] return ... xB.ts'; | semmle.order | 1 | +| tstSuffixB.ts:2:5:2:27 | [ReturnStmt] return ... xB.ts'; | tstSuffixB.ts:2:12:2:26 | [Literal] 'tstSuffixB.ts' | semmle.label | 1 | +| tstSuffixB.ts:2:5:2:27 | [ReturnStmt] return ... xB.ts'; | tstSuffixB.ts:2:12:2:26 | [Literal] 'tstSuffixB.ts' | semmle.order | 1 | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | type_alias.ts:1:6:1:6 | [Identifier] B | semmle.label | 1 | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | type_alias.ts:1:6:1:6 | [Identifier] B | semmle.order | 1 | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | type_alias.ts:1:10:1:16 | [KeywordTypeExpr] boolean | semmle.label | 2 | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected index 4e85a6fe95c..ce517db8d6d 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected @@ -386,6 +386,148 @@ getExprType | tst.ts:293:7:293:21 | payload.toFixed | (fractionDigits?: number) => string | | tst.ts:293:7:293:23 | payload.toFixed() | string | | tst.ts:293:15:293:21 | toFixed | (fractionDigits?: number) => string | +| tst.ts:298:7:298:9 | key | typeof key | +| tst.ts:298:13:298:18 | Symbol | SymbolConstructor | +| tst.ts:298:13:298:20 | Symbol() | typeof key | +| tst.ts:300:7:300:20 | numberOrString | "hello" \| 42 | +| tst.ts:300:24:300:27 | Math | Math | +| tst.ts:300:24:300:34 | Math.random | () => number | +| tst.ts:300:24:300:36 | Math.random() | number | +| tst.ts:300:24:300:42 | Math.random() < 0.5 | boolean | +| tst.ts:300:24:300:57 | Math.ra ... "hello" | "hello" \| 42 | +| tst.ts:300:29:300:34 | random | () => number | +| tst.ts:300:40:300:42 | 0.5 | 0.5 | +| tst.ts:300:46:300:47 | 42 | 42 | +| tst.ts:300:51:300:57 | "hello" | "hello" | +| tst.ts:302:5:302:7 | obj | { [key]: string \| number; } | +| tst.ts:302:11:304:1 | {\\n [ke ... ring,\\n} | { [key]: string \| number; } | +| tst.ts:303:4:303:6 | key | typeof key | +| tst.ts:303:10:303:23 | numberOrString | "hello" \| 42 | +| tst.ts:306:5:306:19 | typeof obj[key] | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| tst.ts:306:5:306:32 | typeof ... string" | boolean | +| tst.ts:306:12:306:14 | obj | { [key]: string \| number; } | +| tst.ts:306:12:306:19 | obj[key] | string \| number | +| tst.ts:306:16:306:18 | key | typeof key | +| tst.ts:306:25:306:32 | "string" | "string" | +| tst.ts:307:7:307:9 | str | string | +| tst.ts:307:13:307:15 | obj | { [key]: string \| number; } | +| tst.ts:307:13:307:20 | obj[key] | string | +| tst.ts:307:17:307:19 | key | typeof key | +| tst.ts:308:3:308:5 | str | string | +| tst.ts:308:3:308:17 | str.toUpperCase | () => string | +| tst.ts:308:3:308:19 | str.toUpperCase() | string | +| tst.ts:308:7:308:17 | toUpperCase | () => string | +| tst.ts:313:10:313:10 | f | (arg: { produce: (n: string) => T; consume: ... | +| tst.ts:313:15:313:17 | arg | { produce: (n: string) => T; consume: (x: T) =>... | +| tst.ts:314:3:314:9 | produce | (n: string) => T | +| tst.ts:314:12:314:27 | (n: string) => T | (n: string) => T | +| tst.ts:314:13:314:13 | n | string | +| tst.ts:315:3:315:9 | consume | (x: T) => void | +| tst.ts:315:12:315:25 | (x: T) => void | (x: T) => void | +| tst.ts:315:13:315:13 | x | T | +| tst.ts:318:1:318:1 | f | (arg: { produce: (n: string) => T; consume: ... | +| tst.ts:318:1:321:2 | f({\\n p ... se()\\n}) | void | +| tst.ts:318:3:321:1 | {\\n pro ... ase()\\n} | { produce: (n: string) => string; consume: (x: ... | +| tst.ts:319:3:319:9 | produce | (n: string) => string | +| tst.ts:319:12:319:12 | n | string | +| tst.ts:319:12:319:17 | n => n | (n: string) => string | +| tst.ts:319:17:319:17 | n | string | +| tst.ts:320:3:320:9 | consume | (x: string) => string | +| tst.ts:320:12:320:12 | x | string | +| tst.ts:320:12:320:31 | x => x.toLowerCase() | (x: string) => string | +| tst.ts:320:17:320:17 | x | string | +| tst.ts:320:17:320:29 | x.toLowerCase | () => string | +| tst.ts:320:17:320:31 | x.toLowerCase() | string | +| tst.ts:320:19:320:29 | toLowerCase | () => string | +| tst.ts:325:7:325:14 | ErrorMap | { new (entries?: readonly (readonly [string, Er... | +| tst.ts:325:18:325:20 | Map | MapConstructor | +| tst.ts:325:18:325:35 | Map | any | +| tst.ts:327:7:327:14 | errorMap | Map | +| tst.ts:327:18:327:31 | new ErrorMap() | Map | +| tst.ts:327:22:327:29 | ErrorMap | { new (entries?: readonly (readonly [string, Er... | +| tst.ts:338:7:338:7 | a | "a" \| "b" | +| tst.ts:338:14:338:16 | 'a' | "a" | +| tst.ts:343:3:343:5 | get | () => T | +| tst.ts:343:8:343:14 | () => T | () => T | +| tst.ts:344:3:344:5 | set | (value: T) => void | +| tst.ts:344:8:344:25 | (value: T) => void | (value: T) => void | +| tst.ts:344:9:344:13 | value | T | +| tst.ts:347:7:347:11 | state | State | +| tst.ts:347:30:350:1 | {\\n get ... > { }\\n} | State | +| tst.ts:348:3:348:5 | get | () => number | +| tst.ts:348:8:348:15 | () => 42 | () => number | +| tst.ts:348:14:348:15 | 42 | 42 | +| tst.ts:349:3:349:5 | set | (value: number) => void | +| tst.ts:349:8:349:21 | (value) => { } | (value: number) => void | +| tst.ts:349:9:349:13 | value | number | +| tst.ts:352:7:352:14 | fortyTwo | number | +| tst.ts:352:18:352:22 | state | State | +| tst.ts:352:18:352:26 | state.get | () => number | +| tst.ts:352:18:352:28 | state.get() | number | +| tst.ts:352:24:352:26 | get | () => number | +| tst.ts:356:8:356:18 | tstModuleES | () => "a" \| "b" | +| tst.ts:356:25:356:43 | './tstModuleES.mjs' | any | +| tst.ts:358:1:358:7 | console | Console | +| tst.ts:358:1:358:11 | console.log | (...data: any[]) => void | +| tst.ts:358:1:358:26 | console ... leES()) | void | +| tst.ts:358:9:358:11 | log | (...data: any[]) => void | +| tst.ts:358:13:358:23 | tstModuleES | () => "a" \| "b" | +| tst.ts:358:13:358:25 | tstModuleES() | "a" \| "b" | +| tst.ts:360:10:360:21 | tstModuleCJS | () => "a" \| "b" | +| tst.ts:360:10:360:21 | tstModuleCJS | () => "a" \| "b" | +| tst.ts:360:30:360:49 | './tstModuleCJS.cjs' | any | +| tst.ts:362:1:362:7 | console | Console | +| tst.ts:362:1:362:11 | console.log | (...data: any[]) => void | +| tst.ts:362:1:362:27 | console ... eCJS()) | void | +| tst.ts:362:9:362:11 | log | (...data: any[]) => void | +| tst.ts:362:13:362:24 | tstModuleCJS | () => "a" \| "b" | +| tst.ts:362:13:362:26 | tstModuleCJS() | "a" \| "b" | +| tst.ts:368:13:368:13 | A | typeof library-tests/TypeScript/Types/tstSuffixA.ts | +| tst.ts:368:20:368:33 | './tstSuffixA' | any | +| tst.ts:370:1:370:7 | console | Console | +| tst.ts:370:1:370:11 | console.log | (...data: any[]) => void | +| tst.ts:370:1:370:29 | console ... File()) | void | +| tst.ts:370:9:370:11 | log | (...data: any[]) => void | +| tst.ts:370:13:370:13 | A | typeof library-tests/TypeScript/Types/tstSuffixA.ts | +| tst.ts:370:13:370:26 | A.resolvedFile | () => "tstSuffixA.ts" | +| tst.ts:370:13:370:28 | A.resolvedFile() | "tstSuffixA.ts" | +| tst.ts:370:15:370:26 | resolvedFile | () => "tstSuffixA.ts" | +| tst.ts:372:13:372:13 | B | typeof library-tests/TypeScript/Types/tstSuffixB.ios.ts | +| tst.ts:372:20:372:33 | './tstSuffixB' | any | +| tst.ts:374:1:374:7 | console | Console | +| tst.ts:374:1:374:11 | console.log | (...data: any[]) => void | +| tst.ts:374:1:374:29 | console ... File()) | void | +| tst.ts:374:9:374:11 | log | (...data: any[]) => void | +| tst.ts:374:13:374:13 | B | typeof library-tests/TypeScript/Types/tstSuffixB.ios.ts | +| tst.ts:374:13:374:26 | B.resolvedFile | () => "tstSuffixB.ios.ts" | +| tst.ts:374:13:374:28 | B.resolvedFile() | "tstSuffixB.ios.ts" | +| tst.ts:374:15:374:26 | resolvedFile | () => "tstSuffixB.ios.ts" | +| tstModuleCJS.cts:1:17:1:28 | tstModuleCJS | () => "a" \| "b" | +| tstModuleCJS.cts:2:12:2:15 | Math | Math | +| tstModuleCJS.cts:2:12:2:22 | Math.random | () => number | +| tstModuleCJS.cts:2:12:2:24 | Math.random() | number | +| tstModuleCJS.cts:2:12:2:30 | Math.random() > 0.5 | boolean | +| tstModuleCJS.cts:2:12:2:42 | Math.ra ... ' : 'b' | "a" \| "b" | +| tstModuleCJS.cts:2:17:2:22 | random | () => number | +| tstModuleCJS.cts:2:28:2:30 | 0.5 | 0.5 | +| tstModuleCJS.cts:2:34:2:36 | 'a' | "a" | +| tstModuleCJS.cts:2:40:2:42 | 'b' | "b" | +| tstModuleES.mts:1:25:1:35 | tstModuleES | () => "a" \| "b" | +| tstModuleES.mts:2:12:2:15 | Math | Math | +| tstModuleES.mts:2:12:2:22 | Math.random | () => number | +| tstModuleES.mts:2:12:2:24 | Math.random() | number | +| tstModuleES.mts:2:12:2:30 | Math.random() > 0.5 | boolean | +| tstModuleES.mts:2:12:2:42 | Math.ra ... ' : 'b' | "a" \| "b" | +| tstModuleES.mts:2:17:2:22 | random | () => number | +| tstModuleES.mts:2:28:2:30 | 0.5 | 0.5 | +| tstModuleES.mts:2:34:2:36 | 'a' | "a" | +| tstModuleES.mts:2:40:2:42 | 'b' | "b" | +| tstSuffixA.ts:1:17:1:28 | resolvedFile | () => "tstSuffixA.ts" | +| tstSuffixA.ts:2:12:2:26 | 'tstSuffixA.ts' | "tstSuffixA.ts" | +| tstSuffixB.ios.ts:1:17:1:28 | resolvedFile | () => "tstSuffixB.ios.ts" | +| tstSuffixB.ios.ts:2:12:2:30 | 'tstSuffixB.ios.ts' | "tstSuffixB.ios.ts" | +| tstSuffixB.ts:1:17:1:28 | resolvedFile | () => "tstSuffixB.ts" | +| tstSuffixB.ts:2:12:2:26 | 'tstSuffixB.ts' | "tstSuffixB.ts" | | type_alias.ts:3:5:3:5 | b | boolean | | type_alias.ts:7:5:7:5 | c | ValueOrArray | | type_alias.ts:14:9:14:32 | [proper ... ]: Json | any | @@ -461,6 +603,9 @@ getTypeDefinitionType | tst.ts:265:3:269:3 | interfa ... an;\\n } | TypeMap | | tst.ts:271:3:276:7 | type Un ... }[P]; | UnionRecord

| | tst.ts:289:3:289:63 | type Fu ... > void; | Func | +| tst.ts:331:1:334:14 | type Fi ... never; | FirstString | +| tst.ts:336:1:336:51 | type F ... lean]>; | "a" \| "b" | +| tst.ts:342:1:345:1 | interfa ... void;\\n} | State | | type_alias.ts:1:1:1:17 | type B = boolean; | boolean | | type_alias.ts:5:1:5:50 | type Va ... ay>; | ValueOrArray | | type_alias.ts:9:1:15:13 | type Js ... Json[]; | Json | @@ -703,6 +848,48 @@ getTypeExprType | tst.ts:289:47:289:52 | string | string | | tst.ts:289:59:289:62 | void | void | | tst.ts:291:13:291:16 | Func | Func | +| tst.ts:313:12:313:12 | T | T | +| tst.ts:313:20:315:27 | {\\n pro ... void } | { produce: (n: string) => T; consume: (x: T) =>... | +| tst.ts:314:12:314:27 | (n: string) => T | (n: string) => T | +| tst.ts:314:16:314:21 | string | string | +| tst.ts:314:27:314:27 | T | T | +| tst.ts:315:12:315:25 | (x: T) => void | (x: T) => void | +| tst.ts:315:16:315:16 | T | T | +| tst.ts:315:22:315:25 | void | void | +| tst.ts:316:4:316:7 | void | void | +| tst.ts:325:22:325:27 | string | string | +| tst.ts:325:30:325:34 | Error | Error | +| tst.ts:331:6:331:16 | FirstString | FirstString | +| tst.ts:331:18:331:18 | T | T | +| tst.ts:336:6:336:6 | F | "a" \| "b" | +| tst.ts:336:10:336:20 | FirstString | FirstString | +| tst.ts:336:10:336:50 | FirstSt ... olean]> | "a" \| "b" | +| tst.ts:336:22:336:49 | ['a' \| ... oolean] | ["a" \| "b", number, boolean] | +| tst.ts:336:23:336:25 | 'a' | "a" | +| tst.ts:336:23:336:31 | 'a' \| 'b' | "a" \| "b" | +| tst.ts:336:29:336:31 | 'b' | "b" | +| tst.ts:336:34:336:39 | number | number | +| tst.ts:336:42:336:48 | boolean | boolean | +| tst.ts:338:10:338:10 | F | "a" \| "b" | +| tst.ts:342:11:342:15 | State | State | +| tst.ts:342:24:342:24 | T | T | +| tst.ts:343:8:343:14 | () => T | () => T | +| tst.ts:343:14:343:14 | T | T | +| tst.ts:344:8:344:25 | (value: T) => void | (value: T) => void | +| tst.ts:344:16:344:16 | T | T | +| tst.ts:344:22:344:25 | void | void | +| tst.ts:347:14:347:18 | State | State | +| tst.ts:347:14:347:26 | State | State | +| tst.ts:347:20:347:25 | number | number | +| tstModuleCJS.cts:1:33:1:35 | 'a' | "a" | +| tstModuleCJS.cts:1:33:1:41 | 'a' \| 'b' | "a" \| "b" | +| tstModuleCJS.cts:1:39:1:41 | 'b' | "b" | +| tstModuleES.mts:1:40:1:42 | 'a' | "a" | +| tstModuleES.mts:1:40:1:48 | 'a' \| 'b' | "a" \| "b" | +| tstModuleES.mts:1:46:1:48 | 'b' | "b" | +| tstSuffixA.ts:1:33:1:47 | 'tstSuffixA.ts' | "tstSuffixA.ts" | +| tstSuffixB.ios.ts:1:33:1:51 | 'tstSuffixB.ios.ts' | "tstSuffixB.ios.ts" | +| tstSuffixB.ts:1:33:1:47 | 'tstSuffixB.ts' | "tstSuffixB.ts" | | type_alias.ts:1:6:1:6 | B | boolean | | type_alias.ts:1:10:1:16 | boolean | boolean | | type_alias.ts:3:8:3:8 | B | boolean | @@ -783,6 +970,7 @@ referenceDefinition | E | type_definition_objects.ts:6:8:6:16 | enum E {} | | EnumWithOneMember | type_definitions.ts:18:26:18:31 | member | | Error | tst.ts:210:10:213:3 | interfa ... ng;\\n } | +| FirstString | tst.ts:331:1:334:14 | type Fi ... never; | | Foo | tst.ts:116:3:129:3 | class F ... }\\n } | | Foo | tst.ts:165:5:167:5 | interfa ... ;\\n } | | Foo | tst.ts:179:3:192:3 | class F ... \\n } | @@ -796,6 +984,8 @@ referenceDefinition | NonAbstractDummy | tst.ts:54:1:56:1 | interfa ... mber;\\n} | | Person | tst.ts:222:3:234:3 | class P ... }\\n } | | Shape | tst.ts:140:3:142:47 | type Sh ... mber }; | +| State | tst.ts:342:1:345:1 | interfa ... void;\\n} | +| State | tst.ts:342:1:345:1 | interfa ... void;\\n} | | Sub | tst.ts:97:3:101:3 | class S ... }\\n } | | Success | tst.ts:205:10:208:3 | interfa ... ng;\\n } | | Super | tst.ts:91:3:95:3 | class S ... }\\n } | @@ -852,16 +1042,20 @@ abstractSignature unionIndex | 1 | 0 | 1 \| 2 | | 2 | 1 | 1 \| 2 | +| 42 | 1 | "hello" \| 42 | | "NumberContents" | 0 | "NumberContents" \| "StringContents" | | "StringContents" | 1 | "NumberContents" \| "StringContents" | | "a" | 0 | "a" \| "b" | | "a" | 1 | number \| "a" | +| "a" | 3 | number \| boolean \| "a" \| "b" | | "b" | 1 | "a" \| "b" | +| "b" | 4 | number \| boolean \| "a" \| "b" | | "bigint" | 2 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | | "boolean" | 2 | keyof TypeMap | | "boolean" | 3 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | | "circle" | 0 | "circle" \| "square" | | "function" | 7 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| "hello" | 0 | "hello" \| 42 | | "number" | 1 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | | "number" | 1 | keyof TypeMap | | "object" | 6 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | @@ -871,6 +1065,7 @@ unionIndex | "symbol" | 4 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | | "undefined" | 5 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | | Error | 1 | Success \| Error | +| Error | 1 | string \| Error | | Json[] | 5 | string \| number \| boolean \| { [property: string... | | Promise | 2 | boolean \| Promise | | PromiseLike | 1 | TResult1 \| PromiseLike | @@ -890,16 +1085,19 @@ unionIndex | false | 0 | boolean | | false | 0 | boolean \| Promise | | false | 1 | number \| boolean | +| false | 1 | number \| boolean \| "a" \| "b" | | false | 2 | string \| number \| boolean | | false | 2 | string \| number \| boolean \| { [property: string... | | number | 0 | number \| "a" | | number | 0 | number \| ValueOrArray[] | | number | 0 | number \| boolean | +| number | 0 | number \| boolean \| "a" \| "b" | | number | 1 | string \| number | | number | 1 | string \| number \| boolean | | number | 1 | string \| number \| boolean \| { [property: string... | | number | 1 | string \| number \| true | | string | 0 | VirtualNode \| { [key: string]: any; } | +| string | 0 | string \| Error | | string | 0 | string \| [string, { [key: string]: any; }, ...V... | | string | 0 | string \| number | | string | 0 | string \| number \| boolean | @@ -911,6 +1109,7 @@ unionIndex | true | 1 | boolean | | true | 1 | boolean \| Promise | | true | 2 | number \| boolean | +| true | 2 | number \| boolean \| "a" \| "b" | | true | 2 | string \| number \| true | | true | 3 | string \| number \| boolean | | true | 3 | string \| number \| boolean \| { [property: string... | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tsconfig.json b/javascript/ql/test/library-tests/TypeScript/Types/tsconfig.json index f6aa3a1e752..2235cec7f7d 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tsconfig.json +++ b/javascript/ql/test/library-tests/TypeScript/Types/tsconfig.json @@ -3,6 +3,7 @@ "module": "esnext", "target": "esnext", "lib": ["dom", "esnext"], - "resolveJsonModule": true + "resolveJsonModule": true, + "moduleSuffixes": [".ios", ""] } } diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts index 9fdb0d950c4..ed8787112d3 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts @@ -293,4 +293,83 @@ module TS46 { payload.toFixed(); // <- number } }; -} \ No newline at end of file +} + +const key = Symbol(); + +const numberOrString = Math.random() < 0.5 ? 42 : "hello"; + +let obj = { + [key]: numberOrString, +}; + +if (typeof obj[key] === "string") { + let str = obj[key]; // <- string + str.toUpperCase(); +} + +////////// + +function f(arg: { + produce: (n: string) => T, + consume: (x: T) => void } +): void {}; + +f({ + produce: n => n, // <- (n: string) => string + consume: x => x.toLowerCase() +}); + +/////////// + +const ErrorMap = Map; + +const errorMap = new ErrorMap(); // <- Map + +//////////// + +type FirstString = + T extends [infer S extends string, ...unknown[]] + ? S + : never; + +type F = FirstString<['a' | 'b', number, boolean]>; + +const a: F = 'a'; // <- 'a' | 'b' + +//////////// + +interface State { + get: () => T; + set: (value: T) => void; +} + +const state: State = { + get: () => 42, + set: (value) => { } +} + +const fortyTwo = state.get(); // <- number + +///////////////// + +import tstModuleES from './tstModuleES.mjs'; + +console.log(tstModuleES()); + +import { tstModuleCJS } from './tstModuleCJS.cjs'; + +console.log(tstModuleCJS()); + +///////////////// + +// test file resolution order (see tsconfig: moduleSuffixes setting) + +import * as A from './tstSuffixA'; + +console.log(A.resolvedFile()); // <- 'tstSuffixA.ts' + +import * as B from './tstSuffixB'; + +console.log(B.resolvedFile()); // <- 'tstSuffixB.ios.ts' + diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tstModuleCJS.cts b/javascript/ql/test/library-tests/TypeScript/Types/tstModuleCJS.cts new file mode 100644 index 00000000000..c764c1e1243 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Types/tstModuleCJS.cts @@ -0,0 +1,3 @@ +export function tstModuleCJS(): 'a' | 'b' { + return Math.random() > 0.5 ? 'a' : 'b'; +} diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tstModuleES.mts b/javascript/ql/test/library-tests/TypeScript/Types/tstModuleES.mts new file mode 100644 index 00000000000..cf735d1bb49 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Types/tstModuleES.mts @@ -0,0 +1,3 @@ +export default function tstModuleES(): 'a' | 'b' { + return Math.random() > 0.5 ? 'a' : 'b'; +} diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tstSuffixA.ts b/javascript/ql/test/library-tests/TypeScript/Types/tstSuffixA.ts new file mode 100644 index 00000000000..ffe0b811492 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Types/tstSuffixA.ts @@ -0,0 +1,3 @@ +export function resolvedFile(): 'tstSuffixA.ts' { + return 'tstSuffixA.ts'; +} diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tstSuffixB.ios.ts b/javascript/ql/test/library-tests/TypeScript/Types/tstSuffixB.ios.ts new file mode 100644 index 00000000000..04463fc7699 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Types/tstSuffixB.ios.ts @@ -0,0 +1,3 @@ +export function resolvedFile(): 'tstSuffixB.ios.ts' { + return 'tstSuffixB.ios.ts'; +} diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tstSuffixB.ts b/javascript/ql/test/library-tests/TypeScript/Types/tstSuffixB.ts new file mode 100644 index 00000000000..cdb26f8f614 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Types/tstSuffixB.ts @@ -0,0 +1,3 @@ +export function resolvedFile(): 'tstSuffixB.ts' { + return 'tstSuffixB.ts'; +} diff --git a/javascript/ql/test/library-tests/frameworks/Express/MiddlewareFlow.qll b/javascript/ql/test/library-tests/frameworks/Express/MiddlewareFlow.qll index 76a21469f6b..9578d5139b5 100644 --- a/javascript/ql/test/library-tests/frameworks/Express/MiddlewareFlow.qll +++ b/javascript/ql/test/library-tests/frameworks/Express/MiddlewareFlow.qll @@ -1,3 +1,5 @@ import javascript -query DataFlow::Node dbUse() { result = API::moduleImport("@example/db").getInstance().getAUse() } +query DataFlow::Node dbUse() { + result = API::moduleImport("@example/db").getInstance().getAValueReachableFromSource() +} diff --git a/javascript/ql/test/library-tests/frameworks/data/test.ql b/javascript/ql/test/library-tests/frameworks/data/test.ql index bdc08e3706f..ff385f3afff 100644 --- a/javascript/ql/test/library-tests/frameworks/data/test.ql +++ b/javascript/ql/test/library-tests/frameworks/data/test.ql @@ -62,13 +62,13 @@ class BasicTaintTracking extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { source.(DataFlow::CallNode).getCalleeName() = "source" or - source = ModelOutput::getASourceNode("test-source").getAnImmediateUse() + source = ModelOutput::getASourceNode("test-source").asSource() } override predicate isSink(DataFlow::Node sink) { sink = any(DataFlow::CallNode call | call.getCalleeName() = "sink").getAnArgument() or - sink = ModelOutput::getASinkNode("test-sink").getARhs() + sink = ModelOutput::getASinkNode("test-sink").asSink() } } @@ -77,7 +77,7 @@ query predicate taintFlow(DataFlow::Node source, DataFlow::Node sink) { } query predicate isSink(DataFlow::Node node, string kind) { - node = ModelOutput::getASinkNode(kind).getARhs() + node = ModelOutput::getASinkNode(kind).asSink() } class SyntaxErrorTest extends ModelInput::SinkModelCsv { diff --git a/javascript/ql/test/query-tests/Declarations/UnusedProperty/tst.js b/javascript/ql/test/query-tests/Declarations/UnusedProperty/tst.js index 26cd1a110bb..847f30bd944 100644 --- a/javascript/ql/test/query-tests/Declarations/UnusedProperty/tst.js +++ b/javascript/ql/test/query-tests/Declarations/UnusedProperty/tst.js @@ -81,3 +81,11 @@ (function(){ ({ unusedProp: 42 }, 42); }); + +(function(){ + var foo = { + unused: 42 + }; + foo.unused = 42; + Object.hasOwn(foo, blab); +}); diff --git a/javascript/ql/test/query-tests/Declarations/UnusedVariable/UnusedVariable.expected b/javascript/ql/test/query-tests/Declarations/UnusedVariable/UnusedVariable.expected index 9db0d903c2d..73be1f62b89 100644 --- a/javascript/ql/test/query-tests/Declarations/UnusedVariable/UnusedVariable.expected +++ b/javascript/ql/test/query-tests/Declarations/UnusedVariable/UnusedVariable.expected @@ -5,6 +5,7 @@ | eval.js:19:9:19:24 | not_used_by_eval | Unused variable not_used_by_eval. | | externs.js:6:5:6:13 | iAmUnused | Unused variable iAmUnused. | | importWithoutPragma.jsx:1:1:1:27 | import ... react'; | Unused import h. | +| interTypes.ts:1:1:1:37 | import ... where"; | Unused import Bar. | | multi-imports.js:1:1:1:29 | import ... om 'x'; | Unused imports a, b, d. | | multi-imports.js:2:1:2:42 | import ... om 'x'; | Unused imports alphabetically, ordered. | | namespaceImportAsType.ts:3:1:3:23 | import ... om "z"; | Unused import Z. | diff --git a/javascript/ql/test/query-tests/Declarations/UnusedVariable/interTypes.ts b/javascript/ql/test/query-tests/Declarations/UnusedVariable/interTypes.ts new file mode 100644 index 00000000000..bdcd767fae8 --- /dev/null +++ b/javascript/ql/test/query-tests/Declarations/UnusedVariable/interTypes.ts @@ -0,0 +1,6 @@ +import { Foo, Bar } from "somewhere"; // OK + +type FooBar = + T extends [infer S extends Foo, ...unknown[]] + ? S + : never; diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected index a4654b29c27..5fa8a043558 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected +++ b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected @@ -50,6 +50,13 @@ nodes | express.js:146:16:146:24 | query.foo | | express.js:146:16:146:24 | query.foo | | express.js:146:16:146:24 | query.foo | +| express.js:150:7:150:34 | target | +| express.js:150:16:150:34 | req.param("target") | +| express.js:150:16:150:34 | req.param("target") | +| express.js:155:18:155:23 | target | +| express.js:155:18:155:23 | target | +| express.js:160:18:160:23 | target | +| express.js:160:18:160:23 | target | | koa.js:6:6:6:27 | url | | koa.js:6:12:6:27 | ctx.query.target | | koa.js:6:12:6:27 | ctx.query.target | @@ -140,6 +147,12 @@ edges | express.js:136:22:136:36 | req.params.user | express.js:136:16:136:36 | 'u' + r ... ms.user | | express.js:143:16:143:28 | req.query.foo | express.js:143:16:143:28 | req.query.foo | | express.js:146:16:146:24 | query.foo | express.js:146:16:146:24 | query.foo | +| express.js:150:7:150:34 | target | express.js:155:18:155:23 | target | +| express.js:150:7:150:34 | target | express.js:155:18:155:23 | target | +| express.js:150:7:150:34 | target | express.js:160:18:160:23 | target | +| express.js:150:7:150:34 | target | express.js:160:18:160:23 | target | +| express.js:150:16:150:34 | req.param("target") | express.js:150:7:150:34 | target | +| express.js:150:16:150:34 | req.param("target") | express.js:150:7:150:34 | target | | koa.js:6:6:6:27 | url | koa.js:7:15:7:17 | url | | koa.js:6:6:6:27 | url | koa.js:7:15:7:17 | url | | koa.js:6:6:6:27 | url | koa.js:8:18:8:20 | url | @@ -199,6 +212,8 @@ edges | express.js:136:16:136:36 | 'u' + r ... ms.user | express.js:136:22:136:36 | req.params.user | express.js:136:16:136:36 | 'u' + r ... ms.user | Untrusted URL redirection due to $@. | express.js:136:22:136:36 | req.params.user | user-provided value | | express.js:143:16:143:28 | req.query.foo | express.js:143:16:143:28 | req.query.foo | express.js:143:16:143:28 | req.query.foo | Untrusted URL redirection due to $@. | express.js:143:16:143:28 | req.query.foo | user-provided value | | express.js:146:16:146:24 | query.foo | express.js:146:16:146:24 | query.foo | express.js:146:16:146:24 | query.foo | Untrusted URL redirection due to $@. | express.js:146:16:146:24 | query.foo | user-provided value | +| express.js:155:18:155:23 | target | express.js:150:16:150:34 | req.param("target") | express.js:155:18:155:23 | target | Untrusted URL redirection due to $@. | express.js:150:16:150:34 | req.param("target") | user-provided value | +| express.js:160:18:160:23 | target | express.js:150:16:150:34 | req.param("target") | express.js:160:18:160:23 | target | Untrusted URL redirection due to $@. | express.js:150:16:150:34 | req.param("target") | user-provided value | | koa.js:7:15:7:17 | url | koa.js:6:12:6:27 | ctx.query.target | koa.js:7:15:7:17 | url | Untrusted URL redirection due to $@. | koa.js:6:12:6:27 | ctx.query.target | user-provided value | | koa.js:8:15:8:26 | `${url}${x}` | koa.js:6:12:6:27 | ctx.query.target | koa.js:8:15:8:26 | `${url}${x}` | Untrusted URL redirection due to $@. | koa.js:6:12:6:27 | ctx.query.target | user-provided value | | koa.js:14:16:14:18 | url | koa.js:6:12:6:27 | ctx.query.target | koa.js:14:16:14:18 | url | Untrusted URL redirection due to $@. | koa.js:6:12:6:27 | ctx.query.target | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/express.js b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/express.js index b319315b985..667d6f89f05 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/express.js +++ b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/express.js @@ -144,4 +144,18 @@ app.get("foo", (req, res) => { }); app.get("bar", ({query}, res) => { res.redirect(query.foo); // NOT OK -}) \ No newline at end of file +}) + +app.get('/some/path', function(req, res) { + let target = req.param("target"); + + if (SAFE_TARGETS.hasOwnProperty(target)) + res.redirect(target); // OK: request parameter is checked against whitelist + else + res.redirect(target); // NOT OK + + if (Object.hasOwn(SAFE_TARGETS, target)) + res.redirect(target); // OK: request parameter is checked against whitelist + else + res.redirect(target); // NOT OK +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion/ResourceExhaustion.expected b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion/ResourceExhaustion.expected index ffbdfd3d5e8..19adec40d24 100644 --- a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion/ResourceExhaustion.expected +++ b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion/ResourceExhaustion.expected @@ -17,12 +17,6 @@ nodes | resource-exhaustion.js:6:7:6:21 | n | | resource-exhaustion.js:6:11:6:21 | parseInt(s) | | resource-exhaustion.js:6:20:6:20 | s | -| resource-exhaustion.js:11:21:11:21 | s | -| resource-exhaustion.js:11:21:11:21 | s | -| resource-exhaustion.js:12:21:12:21 | n | -| resource-exhaustion.js:12:21:12:21 | n | -| resource-exhaustion.js:13:21:13:21 | n | -| resource-exhaustion.js:13:21:13:21 | n | | resource-exhaustion.js:14:16:14:16 | n | | resource-exhaustion.js:14:16:14:16 | n | | resource-exhaustion.js:15:22:15:22 | n | @@ -71,8 +65,6 @@ edges | documentaion-examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentaion-examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | | documentaion-examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentaion-examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | | resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:6:20:6:20 | s | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:11:21:11:21 | s | -| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:11:21:11:21 | s | | resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:35:12:35:12 | s | | resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:35:12:35:12 | s | | resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:82:17:82:17 | s | @@ -84,10 +76,6 @@ edges | resource-exhaustion.js:5:11:5:42 | url.par ... query.s | resource-exhaustion.js:5:7:5:42 | s | | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:5:11:5:34 | url.par ... , true) | | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:5:11:5:34 | url.par ... , true) | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:12:21:12:21 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:12:21:12:21 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:13:21:13:21 | n | -| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:13:21:13:21 | n | | resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:14:16:14:16 | n | | resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:14:16:14:16 | n | | resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:15:22:15:22 | n | @@ -124,9 +112,6 @@ edges | resource-exhaustion.js:6:20:6:20 | s | resource-exhaustion.js:6:11:6:21 | parseInt(s) | #select | documentaion-examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | documentaion-examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentaion-examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | This creates a timer with a user-controlled duration from $@. | documentaion-examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | here | -| resource-exhaustion.js:11:21:11:21 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:11:21:11:21 | s | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:12:21:12:21 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:12:21:12:21 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | -| resource-exhaustion.js:13:21:13:21 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:13:21:13:21 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | | resource-exhaustion.js:14:16:14:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:14:16:14:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | | resource-exhaustion.js:15:22:15:22 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:15:22:15:22 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | | resource-exhaustion.js:16:26:16:26 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:16:26:16:26 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here | diff --git a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion/resource-exhaustion.js b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion/resource-exhaustion.js index e4b8f2ff9e3..ddda361db3a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion/resource-exhaustion.js +++ b/javascript/ql/test/query-tests/Security/CWE-770/ResourceExhaustion/resource-exhaustion.js @@ -8,9 +8,9 @@ var server = http.createServer(function(req, res) { Buffer.from(s); // OK Buffer.from(n); // OK Buffer.from(x, n); // OK - Buffer.from(x, y, s); // NOT OK - Buffer.from(x, y, n); // NOT OK - Buffer.from(x, y, n); // NOT OK + Buffer.from(x, y, s); // OK - does not allocate memory + Buffer.from(x, y, n); // OK - does not allocate memory + Buffer.from(x, y, n); // OK - does not allocate memory Buffer.alloc(n); // NOT OK Buffer.allocUnsafe(n); // NOT OK Buffer.allocUnsafeSlow(n); // NOT OK diff --git a/javascript/ql/test/query-tests/Security/CWE-843/TypeConfusionThroughParameterTampering.expected b/javascript/ql/test/query-tests/Security/CWE-843/TypeConfusionThroughParameterTampering.expected index 5c560d8c4ca..997d8968fcc 100644 --- a/javascript/ql/test/query-tests/Security/CWE-843/TypeConfusionThroughParameterTampering.expected +++ b/javascript/ql/test/query-tests/Security/CWE-843/TypeConfusionThroughParameterTampering.expected @@ -32,6 +32,18 @@ nodes | tst.js:81:9:81:9 | p | | tst.js:82:9:82:9 | p | | tst.js:82:9:82:9 | p | +| tst.js:90:5:90:12 | data.foo | +| tst.js:90:5:90:12 | data.foo | +| tst.js:90:5:90:12 | data.foo | +| tst.js:92:9:92:16 | data.foo | +| tst.js:92:9:92:16 | data.foo | +| tst.js:92:9:92:16 | data.foo | +| tst.js:95:9:95:16 | data.foo | +| tst.js:95:9:95:16 | data.foo | +| tst.js:95:9:95:16 | data.foo | +| tst.js:98:9:98:16 | data.foo | +| tst.js:98:9:98:16 | data.foo | +| tst.js:98:9:98:16 | data.foo | edges | tst.js:5:9:5:27 | foo | tst.js:6:5:6:7 | foo | | tst.js:5:9:5:27 | foo | tst.js:6:5:6:7 | foo | @@ -63,6 +75,10 @@ edges | tst.js:80:23:80:23 | p | tst.js:81:9:81:9 | p | | tst.js:80:23:80:23 | p | tst.js:82:9:82:9 | p | | tst.js:80:23:80:23 | p | tst.js:82:9:82:9 | p | +| tst.js:90:5:90:12 | data.foo | tst.js:90:5:90:12 | data.foo | +| tst.js:92:9:92:16 | data.foo | tst.js:92:9:92:16 | data.foo | +| tst.js:95:9:95:16 | data.foo | tst.js:95:9:95:16 | data.foo | +| tst.js:98:9:98:16 | data.foo | tst.js:98:9:98:16 | data.foo | #select | tst.js:6:5:6:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:6:5:6:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter | | tst.js:8:5:8:7 | foo | tst.js:5:15:5:27 | req.query.foo | tst.js:8:5:8:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:5:15:5:27 | req.query.foo | this HTTP request parameter | @@ -75,3 +91,7 @@ edges | tst.js:46:5:46:7 | foo | tst.js:45:15:45:35 | ctx.req ... ery.foo | tst.js:46:5:46:7 | foo | Potential type confusion as $@ may be either an array or a string. | tst.js:45:15:45:35 | ctx.req ... ery.foo | this HTTP request parameter | | tst.js:81:9:81:9 | p | tst.js:77:25:77:38 | req.query.path | tst.js:81:9:81:9 | p | Potential type confusion as $@ may be either an array or a string. | tst.js:77:25:77:38 | req.query.path | this HTTP request parameter | | tst.js:82:9:82:9 | p | tst.js:77:25:77:38 | req.query.path | tst.js:82:9:82:9 | p | Potential type confusion as $@ may be either an array or a string. | tst.js:77:25:77:38 | req.query.path | this HTTP request parameter | +| tst.js:90:5:90:12 | data.foo | tst.js:90:5:90:12 | data.foo | tst.js:90:5:90:12 | data.foo | Potential type confusion as $@ may be either an array or a string. | tst.js:90:5:90:12 | data.foo | this HTTP request parameter | +| tst.js:92:9:92:16 | data.foo | tst.js:92:9:92:16 | data.foo | tst.js:92:9:92:16 | data.foo | Potential type confusion as $@ may be either an array or a string. | tst.js:92:9:92:16 | data.foo | this HTTP request parameter | +| tst.js:95:9:95:16 | data.foo | tst.js:95:9:95:16 | data.foo | tst.js:95:9:95:16 | data.foo | Potential type confusion as $@ may be either an array or a string. | tst.js:95:9:95:16 | data.foo | this HTTP request parameter | +| tst.js:98:9:98:16 | data.foo | tst.js:98:9:98:16 | data.foo | tst.js:98:9:98:16 | data.foo | Potential type confusion as $@ may be either an array or a string. | tst.js:98:9:98:16 | data.foo | this HTTP request parameter | diff --git a/javascript/ql/test/query-tests/Security/CWE-843/tst.js b/javascript/ql/test/query-tests/Security/CWE-843/tst.js index 82650bcf054..d49f7ce53d2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-843/tst.js +++ b/javascript/ql/test/query-tests/Security/CWE-843/tst.js @@ -1,7 +1,7 @@ var express = require('express'); var Koa = require('koa'); -express().get('/some/path', function(req, res) { +express().get('/some/path', function (req, res) { var foo = req.query.foo; foo.indexOf(); // NOT OK @@ -41,38 +41,38 @@ express().get('/some/path', function(req, res) { foo.length; // NOT OK }); -new Koa().use(function handler(ctx){ +new Koa().use(function handler(ctx) { var foo = ctx.request.query.foo; foo.indexOf(); // NOT OK }); -express().get('/some/path/:foo', function(req, res) { +express().get('/some/path/:foo', function (req, res) { var foo = req.params.foo; foo.indexOf(); // OK }); -express().get('/some/path/:foo', function(req, res) { - if (req.query.path.length) {} // OK +express().get('/some/path/:foo', function (req, res) { + if (req.query.path.length) { } // OK req.query.path.length == 0; // OK !req.query.path.length; // OK req.query.path.length > 0; // OK }); -express().get('/some/path/:foo', function(req, res) { +express().get('/some/path/:foo', function (req, res) { let p = req.query.path; if (typeof p !== 'string') { - return; + return; } while (p.length) { // OK - p = p.substr(1); + p = p.substr(1); } p.length < 1; // OK }); -express().get('/some/path/:foo', function(req, res) { +express().get('/some/path/:foo', function (req, res) { let someObject = {}; safeGet(someObject, req.query.path).bar = 'baz'; // prototype pollution here - but flagged in `safeGet` }); @@ -84,3 +84,26 @@ function safeGet(obj, p) { } return obj[p]; } + +express().get('/foo', function (req, res) { + let data = req.query; + data.foo.indexOf(); // NOT OK + if (typeof data.foo !== 'undefined') { + data.foo.indexOf(); // NOT OK + } + if (typeof data.foo !== 'string') { + data.foo.indexOf(); // OK + } + if (typeof data.foo !== 'undefined') { + data.foo.indexOf(); // NOT OK + } +}); + +express().get('/foo', function (req, res) { + let data = req.query; + if (Array.isArray(data)) { + data.indexOf(); // OK + } else { + data.indexOf(); // OK + } +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected index 23b21f12460..f16f3e4ef55 100644 --- a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/PrototypePollutingFunction.expected @@ -1478,6 +1478,56 @@ nodes | tests.js:547:24:547:28 | value | | tests.js:547:24:547:28 | value | | tests.js:547:24:547:28 | value | +| tests.js:552:35:552:37 | src | +| tests.js:552:35:552:37 | src | +| tests.js:553:14:553:16 | key | +| tests.js:553:14:553:16 | key | +| tests.js:553:14:553:16 | key | +| tests.js:557:43:557:45 | src | +| tests.js:557:43:557:45 | src | +| tests.js:557:43:557:50 | src[key] | +| tests.js:557:43:557:50 | src[key] | +| tests.js:557:43:557:50 | src[key] | +| tests.js:557:43:557:50 | src[key] | +| tests.js:557:43:557:50 | src[key] | +| tests.js:559:17:559:19 | key | +| tests.js:559:17:559:19 | key | +| tests.js:559:17:559:19 | key | +| tests.js:559:24:559:26 | src | +| tests.js:559:24:559:26 | src | +| tests.js:559:24:559:31 | src[key] | +| tests.js:559:24:559:31 | src[key] | +| tests.js:559:24:559:31 | src[key] | +| tests.js:559:24:559:31 | src[key] | +| tests.js:559:24:559:31 | src[key] | +| tests.js:559:24:559:31 | src[key] | +| tests.js:559:28:559:30 | key | +| tests.js:559:28:559:30 | key | +| tests.js:564:35:564:37 | src | +| tests.js:564:35:564:37 | src | +| tests.js:565:14:565:16 | key | +| tests.js:565:14:565:16 | key | +| tests.js:565:14:565:16 | key | +| tests.js:569:43:569:45 | src | +| tests.js:569:43:569:45 | src | +| tests.js:569:43:569:50 | src[key] | +| tests.js:569:43:569:50 | src[key] | +| tests.js:569:43:569:50 | src[key] | +| tests.js:569:43:569:50 | src[key] | +| tests.js:569:43:569:50 | src[key] | +| tests.js:571:17:571:19 | key | +| tests.js:571:17:571:19 | key | +| tests.js:571:17:571:19 | key | +| tests.js:571:24:571:26 | src | +| tests.js:571:24:571:26 | src | +| tests.js:571:24:571:31 | src[key] | +| tests.js:571:24:571:31 | src[key] | +| tests.js:571:24:571:31 | src[key] | +| tests.js:571:24:571:31 | src[key] | +| tests.js:571:24:571:31 | src[key] | +| tests.js:571:24:571:31 | src[key] | +| tests.js:571:28:571:30 | key | +| tests.js:571:28:571:30 | key | edges | examples/PrototypePollutingFunction.js:1:16:1:18 | dst | examples/PrototypePollutingFunction.js:5:19:5:21 | dst | | examples/PrototypePollutingFunction.js:1:16:1:18 | dst | examples/PrototypePollutingFunction.js:5:19:5:21 | dst | @@ -3347,6 +3397,70 @@ edges | tests.js:545:43:545:47 | value | tests.js:542:35:542:37 | src | | tests.js:545:43:545:47 | value | tests.js:542:35:542:37 | src | | tests.js:545:43:545:47 | value | tests.js:542:35:542:37 | src | +| tests.js:552:35:552:37 | src | tests.js:557:43:557:45 | src | +| tests.js:552:35:552:37 | src | tests.js:557:43:557:45 | src | +| tests.js:552:35:552:37 | src | tests.js:559:24:559:26 | src | +| tests.js:552:35:552:37 | src | tests.js:559:24:559:26 | src | +| tests.js:553:14:553:16 | key | tests.js:559:17:559:19 | key | +| tests.js:553:14:553:16 | key | tests.js:559:17:559:19 | key | +| tests.js:553:14:553:16 | key | tests.js:559:17:559:19 | key | +| tests.js:553:14:553:16 | key | tests.js:559:17:559:19 | key | +| tests.js:553:14:553:16 | key | tests.js:559:17:559:19 | key | +| tests.js:553:14:553:16 | key | tests.js:559:17:559:19 | key | +| tests.js:553:14:553:16 | key | tests.js:559:17:559:19 | key | +| tests.js:553:14:553:16 | key | tests.js:559:28:559:30 | key | +| tests.js:553:14:553:16 | key | tests.js:559:28:559:30 | key | +| tests.js:553:14:553:16 | key | tests.js:559:28:559:30 | key | +| tests.js:553:14:553:16 | key | tests.js:559:28:559:30 | key | +| tests.js:557:43:557:45 | src | tests.js:557:43:557:50 | src[key] | +| tests.js:557:43:557:45 | src | tests.js:557:43:557:50 | src[key] | +| tests.js:557:43:557:50 | src[key] | tests.js:552:35:552:37 | src | +| tests.js:557:43:557:50 | src[key] | tests.js:552:35:552:37 | src | +| tests.js:557:43:557:50 | src[key] | tests.js:552:35:552:37 | src | +| tests.js:557:43:557:50 | src[key] | tests.js:552:35:552:37 | src | +| tests.js:557:43:557:50 | src[key] | tests.js:552:35:552:37 | src | +| tests.js:557:43:557:50 | src[key] | tests.js:552:35:552:37 | src | +| tests.js:559:24:559:26 | src | tests.js:559:24:559:31 | src[key] | +| tests.js:559:24:559:26 | src | tests.js:559:24:559:31 | src[key] | +| tests.js:559:24:559:26 | src | tests.js:559:24:559:31 | src[key] | +| tests.js:559:24:559:26 | src | tests.js:559:24:559:31 | src[key] | +| tests.js:559:24:559:31 | src[key] | tests.js:559:24:559:31 | src[key] | +| tests.js:559:28:559:30 | key | tests.js:559:24:559:31 | src[key] | +| tests.js:559:28:559:30 | key | tests.js:559:24:559:31 | src[key] | +| tests.js:559:28:559:30 | key | tests.js:559:24:559:31 | src[key] | +| tests.js:559:28:559:30 | key | tests.js:559:24:559:31 | src[key] | +| tests.js:564:35:564:37 | src | tests.js:569:43:569:45 | src | +| tests.js:564:35:564:37 | src | tests.js:569:43:569:45 | src | +| tests.js:564:35:564:37 | src | tests.js:571:24:571:26 | src | +| tests.js:564:35:564:37 | src | tests.js:571:24:571:26 | src | +| tests.js:565:14:565:16 | key | tests.js:571:17:571:19 | key | +| tests.js:565:14:565:16 | key | tests.js:571:17:571:19 | key | +| tests.js:565:14:565:16 | key | tests.js:571:17:571:19 | key | +| tests.js:565:14:565:16 | key | tests.js:571:17:571:19 | key | +| tests.js:565:14:565:16 | key | tests.js:571:17:571:19 | key | +| tests.js:565:14:565:16 | key | tests.js:571:17:571:19 | key | +| tests.js:565:14:565:16 | key | tests.js:571:17:571:19 | key | +| tests.js:565:14:565:16 | key | tests.js:571:28:571:30 | key | +| tests.js:565:14:565:16 | key | tests.js:571:28:571:30 | key | +| tests.js:565:14:565:16 | key | tests.js:571:28:571:30 | key | +| tests.js:565:14:565:16 | key | tests.js:571:28:571:30 | key | +| tests.js:569:43:569:45 | src | tests.js:569:43:569:50 | src[key] | +| tests.js:569:43:569:45 | src | tests.js:569:43:569:50 | src[key] | +| tests.js:569:43:569:50 | src[key] | tests.js:564:35:564:37 | src | +| tests.js:569:43:569:50 | src[key] | tests.js:564:35:564:37 | src | +| tests.js:569:43:569:50 | src[key] | tests.js:564:35:564:37 | src | +| tests.js:569:43:569:50 | src[key] | tests.js:564:35:564:37 | src | +| tests.js:569:43:569:50 | src[key] | tests.js:564:35:564:37 | src | +| tests.js:569:43:569:50 | src[key] | tests.js:564:35:564:37 | src | +| tests.js:571:24:571:26 | src | tests.js:571:24:571:31 | src[key] | +| tests.js:571:24:571:26 | src | tests.js:571:24:571:31 | src[key] | +| tests.js:571:24:571:26 | src | tests.js:571:24:571:31 | src[key] | +| tests.js:571:24:571:26 | src | tests.js:571:24:571:31 | src[key] | +| tests.js:571:24:571:31 | src[key] | tests.js:571:24:571:31 | src[key] | +| tests.js:571:28:571:30 | key | tests.js:571:24:571:31 | src[key] | +| tests.js:571:28:571:30 | key | tests.js:571:24:571:31 | src[key] | +| tests.js:571:28:571:30 | key | tests.js:571:24:571:31 | src[key] | +| tests.js:571:28:571:30 | key | tests.js:571:24:571:31 | src[key] | #select | examples/PrototypePollutingFunction.js:7:13:7:15 | dst | examples/PrototypePollutingFunction.js:2:14:2:16 | key | examples/PrototypePollutingFunction.js:7:13:7:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | examples/PrototypePollutingFunction.js:2:21:2:23 | src | src | examples/PrototypePollutingFunction.js:7:13:7:15 | dst | dst | | path-assignment.js:15:13:15:18 | target | path-assignment.js:8:19:8:25 | keys[i] | path-assignment.js:15:13:15:18 | target | The property chain $@ is recursively assigned to $@ without guarding against prototype pollution. | path-assignment.js:8:19:8:25 | keys[i] | here | path-assignment.js:15:13:15:18 | target | target | diff --git a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js index d54081d6e7d..a1fc92a5776 100644 --- a/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js +++ b/javascript/ql/test/query-tests/Security/CWE-915/PrototypePollutingFunction/tests.js @@ -548,3 +548,27 @@ function mergeUsingCallback3(dst, src) { } }); } + +function copyHasOwnProperty2(dst, src) { + for (let key in src) { + // Guarding the recursive case by dst.hasOwnProperty (or Object.hasOwn) is safe, + // since '__proto__' and 'constructor' are not own properties of the destination object. + if (Object.hasOwn(dst, key)) { + copyHasOwnProperty2(dst[key], src[key]); + } else { + dst[key] = src[key]; // OK + } + } +} + +function copyHasOwnProperty3(dst, src) { + for (let key in src) { + // Guarding the recursive case by dst.hasOwnProperty (or Object.hasOwn) is safe, + // since '__proto__' and 'constructor' are not own properties of the destination object. + if (_.has(dst, key)) { + copyHasOwnProperty3(dst[key], src[key]); + } else { + dst[key] = src[key]; // OK + } + } +} diff --git a/python/ql/lib/semmle/python/ApiGraphs.qll b/python/ql/lib/semmle/python/ApiGraphs.qll index 973e1ea85fa..fcb89e5f866 100644 --- a/python/ql/lib/semmle/python/ApiGraphs.qll +++ b/python/ql/lib/semmle/python/ApiGraphs.qll @@ -136,6 +136,9 @@ module API { result = this.getASuccessor(Label::keywordParameter(name)) } + /** Gets the node representing the self parameter */ + Node getSelfParameter() { result = this.getASuccessor(Label::selfParameter()) } + /** * Gets the number of parameters of the function represented by this node. */ @@ -321,6 +324,12 @@ module API { /** Gets the API node for a parameter of this invocation. */ Node getAParameter() { result = this.getParameter(_) } + /** Gets the object that this method-call is being called on, if this is a method-call */ + Node getSelfParameter() { + result.getARhs() = this.(DataFlow::MethodCallNode).getObject() and + result = callee.getSelfParameter() + } + /** Gets the API node for the keyword parameter `name` of this invocation. */ Node getKeywordParameter(string name) { result = callee.getKeywordParameter(name) and @@ -345,6 +354,14 @@ module API { result = callee.getReturn() and result.getAnImmediateUse() = this } + + /** + * Gets the number of positional arguments of this call. + * + * Note: This is used for `WithArity[]` in modeling-as-data, where we thought + * including keyword arguments didn't make much sense. + */ + int getNumArgument() { result = count(this.getArg(_)) } } /** @@ -589,15 +606,24 @@ module API { exists(DataFlow::Node def, PY::CallableExpr fn | rhs(base, def) and fn = trackDefNode(def).asExpr() | - exists(int i | - lbl = Label::parameter(i) and + exists(int i, int offset | + if exists(PY::Parameter p | p = fn.getInnerScope().getAnArg() and p.isSelf()) + then offset = 1 + else offset = 0 + | + lbl = Label::parameter(i - offset) and ref.asExpr() = fn.getInnerScope().getArg(i) ) or - exists(string name | + exists(string name, PY::Parameter param | lbl = Label::keywordParameter(name) and - ref.asExpr() = fn.getInnerScope().getArgByName(name) + param = fn.getInnerScope().getArgByName(name) and + not param.isSelf() and + ref.asExpr() = param ) + or + lbl = Label::selfParameter() and + ref.asExpr() = any(PY::Parameter p | p = fn.getInnerScope().getAnArg() and p.isSelf()) ) or // Built-ins, treated as members of the module `builtins` @@ -664,6 +690,9 @@ module API { exists(string name | lbl = Label::keywordParameter(name) | arg = pred.getACall().getArgByName(name) ) + or + lbl = Label::selfParameter() and + arg = pred.getACall().(DataFlow::MethodCallNode).getObject() ) } @@ -780,6 +809,7 @@ module API { or exists(any(PY::Function f).getArgByName(name)) } or + MkLabelSelfParameter() or MkLabelReturn() or MkLabelSubclass() or MkLabelAwait() @@ -837,6 +867,11 @@ module API { string getName() { result = name } } + /** A label for the self parameter. */ + class LabelSelfParameter extends ApiLabel, MkLabelSelfParameter { + override string toString() { result = "getSelfParameter()" } + } + /** A label that gets the return value of a function. */ class LabelReturn extends ApiLabel, MkLabelReturn { override string toString() { result = "getReturn()" } @@ -876,6 +911,9 @@ module API { /** Gets the `parameter` edge label for the keyword parameter `name`. */ LabelKeywordParameter keywordParameter(string name) { result.getName() = name } + /** Gets the edge label for the self parameter. */ + LabelSelfParameter selfParameter() { any() } + /** Gets the `return` edge label. */ LabelReturn return() { any() } diff --git a/python/ql/lib/semmle/python/Frameworks.qll b/python/ql/lib/semmle/python/Frameworks.qll index 4812628d262..daa67ee4231 100644 --- a/python/ql/lib/semmle/python/Frameworks.qll +++ b/python/ql/lib/semmle/python/Frameworks.qll @@ -12,6 +12,7 @@ private import semmle.python.frameworks.Asyncpg private import semmle.python.frameworks.ClickhouseDriver private import semmle.python.frameworks.Cryptodome private import semmle.python.frameworks.Cryptography +private import semmle.python.frameworks.data.ModelsAsData private import semmle.python.frameworks.Dill private import semmle.python.frameworks.Django private import semmle.python.frameworks.Fabric diff --git a/python/ql/lib/semmle/python/frameworks/Asyncpg.qll b/python/ql/lib/semmle/python/frameworks/Asyncpg.qll index 5f867fe28ff..81da12a015c 100644 --- a/python/ql/lib/semmle/python/frameworks/Asyncpg.qll +++ b/python/ql/lib/semmle/python/frameworks/Asyncpg.qll @@ -7,91 +7,42 @@ private import python private import semmle.python.dataflow.new.DataFlow private import semmle.python.Concepts private import semmle.python.ApiGraphs +private import semmle.python.frameworks.data.ModelsAsData /** Provides models for the `asyncpg` PyPI package. */ private module Asyncpg { - private import semmle.python.internal.Awaited - - /** Gets a `ConnectionPool` that is created when the result of `asyncpg.create_pool()` is awaited. */ - API::Node connectionPool() { - result = API::moduleImport("asyncpg").getMember("create_pool").getReturn().getAwaited() - } - - /** - * Gets a `Connection` that is created when - * - the result of `asyncpg.connect()` is awaited. - * - the result of calling `acquire` on a `ConnectionPool` is awaited. - */ - API::Node connection() { - result = API::moduleImport("asyncpg").getMember("connect").getReturn().getAwaited() - or - result = connectionPool().getMember("acquire").getReturn().getAwaited() - } - - /** `Connection`s and `ConnectionPool`s provide some methods that execute SQL. */ - class SqlExecutionOnConnection extends SqlExecution::Range, DataFlow::MethodCallNode { - string methodName; - - SqlExecutionOnConnection() { - this = [connectionPool(), connection()].getMember(methodName).getACall() and - methodName in ["copy_from_query", "execute", "fetch", "fetchrow", "fetchval", "executemany"] - } - - override DataFlow::Node getSql() { - methodName in ["copy_from_query", "execute", "fetch", "fetchrow", "fetchval"] and - result in [this.getArg(0), this.getArgByName("query")] - or - methodName = "executemany" and - result in [this.getArg(0), this.getArgByName("command")] + class AsyncpgModel extends ModelInput::TypeModelCsv { + override predicate row(string row) { + // package1;type1;package2;type2;path + row = + [ + // a `ConnectionPool` that is created when the result of `asyncpg.create_pool()` is awaited. + "asyncpg;ConnectionPool;asyncpg;;Member[create_pool].ReturnValue.Awaited", + // a `Connection` that is created when + // * - the result of `asyncpg.connect()` is awaited. + // * - the result of calling `acquire` on a `ConnectionPool` is awaited. + "asyncpg;Connection;asyncpg;;Member[connect].ReturnValue.Awaited", + "asyncpg;Connection;asyncpg;ConnectionPool;Member[acquire].ReturnValue.Awaited", + // Creating an internal `~Connection` type that contains both `Connection` and `ConnectionPool`. + "asyncpg;~Connection;asyncpg;Connection;", "asyncpg;~Connection;asyncpg;ConnectionPool;" + ] } } - /** A model of `Connection` and `ConnectionPool`, which provide some methods that access the file system. */ - class FileAccessOnConnection extends FileSystemAccess::Range, DataFlow::MethodCallNode { - string methodName; - - FileAccessOnConnection() { - this = [connectionPool(), connection()].getMember(methodName).getACall() and - methodName in ["copy_from_query", "copy_from_table", "copy_to_table"] - } - - // The path argument is keyword only. - override DataFlow::Node getAPathArgument() { - methodName in ["copy_from_query", "copy_from_table"] and - result = this.getArgByName("output") - or - methodName = "copy_to_table" and - result = this.getArgByName("source") - } - } - - /** - * Provides models of the `PreparedStatement` class in `asyncpg`. - * `PreparedStatement`s are created when the result of calling `prepare(query)` on a connection is awaited. - * The result of calling `prepare(query)` is a `PreparedStatementFactory` and the argument, `query` needs to - * be tracked to the place where a `PreparedStatement` is created and then further to any executing methods. - * Hence the two type trackers. - */ - module PreparedStatement { - class PreparedStatementConstruction extends SqlConstruction::Range, API::CallNode { - PreparedStatementConstruction() { this = connection().getMember("prepare").getACall() } - - override DataFlow::Node getSql() { result = this.getParameter(0, "query").getARhs() } - } - - class PreparedStatementExecution extends SqlExecution::Range, API::CallNode { - PreparedStatementConstruction prepareCall; - - PreparedStatementExecution() { - this = - prepareCall - .getReturn() - .getAwaited() - .getMember(["executemany", "fetch", "fetchrow", "fetchval"]) - .getACall() - } - - override DataFlow::Node getSql() { result = prepareCall.getSql() } + class AsyncpgSink extends ModelInput::SinkModelCsv { + // package;type;path;kind + override predicate row(string row) { + row = + [ + // `Connection`s and `ConnectionPool`s provide some methods that execute SQL. + "asyncpg;~Connection;Member[copy_from_query,execute,fetch,fetchrow,fetchval].Argument[0,query:];sql-injection", + "asyncpg;~Connection;Member[executemany].Argument[0,command:];sql-injection", + // A model of `Connection` and `ConnectionPool`, which provide some methods that access the file system. + "asyncpg;~Connection;Member[copy_from_query,copy_from_table].Argument[output:];path-injection", + "asyncpg;~Connection;Member[copy_to_table].Argument[source:];path-injection", + // the `PreparedStatement` class in `asyncpg`. + "asyncpg;Connection;Member[prepare].Argument[0,query:];sql-injection", + ] } } @@ -106,7 +57,9 @@ private module Asyncpg { */ module Cursor { class CursorConstruction extends SqlConstruction::Range, API::CallNode { - CursorConstruction() { this = connection().getMember("cursor").getACall() } + CursorConstruction() { + this = ModelOutput::getATypeNode("asyncpg", "Connection").getMember("cursor").getACall() + } override DataFlow::Node getSql() { result = this.getParameter(0, "query").getARhs() } } @@ -121,8 +74,11 @@ private module Asyncpg { this = c.getReturn().getAwaited().getAnImmediateUse() ) or - exists(PreparedStatement::PreparedStatementConstruction prepareCall | - sql = prepareCall.getSql() and + exists(API::CallNode prepareCall | + prepareCall = + ModelOutput::getATypeNode("asyncpg", "Connection").getMember("prepare").getACall() + | + sql = prepareCall.getParameter(0, "query").getARhs() and this = prepareCall .getReturn() diff --git a/python/ql/lib/semmle/python/frameworks/data/ModelsAsData.qll b/python/ql/lib/semmle/python/frameworks/data/ModelsAsData.qll new file mode 100644 index 00000000000..2af91a69432 --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/data/ModelsAsData.qll @@ -0,0 +1,47 @@ +/** + * Provides classes for contributing a model, or using the interpreted results + * of a model represented as data. + * + * - Use the `ModelInput` module to contribute new models. + * - Use the `ModelOutput` module to access the model results in terms of API nodes. + * + * The package name refers to the top-level module the import comes from, and not a PyPI package. + * So for `from foo.bar import baz`, the package will be `foo`. + */ + +private import python +private import internal.ApiGraphModels as Shared +private import internal.ApiGraphModelsSpecific as Specific +import Shared::ModelInput as ModelInput +import Shared::ModelOutput as ModelOutput +private import semmle.python.dataflow.new.RemoteFlowSources +private import semmle.python.dataflow.new.DataFlow +private import semmle.python.ApiGraphs +private import semmle.python.dataflow.new.TaintTracking + +/** + * A remote flow source originating from a CSV source row. + */ +private class RemoteFlowSourceFromCsv extends RemoteFlowSource { + RemoteFlowSourceFromCsv() { this = ModelOutput::getASourceNode("remote").getAnImmediateUse() } + + override string getSourceType() { result = "Remote flow (from model)" } +} + +/** + * Like `ModelOutput::summaryStep` but with API nodes mapped to data-flow nodes. + */ +private predicate summaryStepNodes(DataFlow::Node pred, DataFlow::Node succ, string kind) { + exists(API::Node predNode, API::Node succNode | + Specific::summaryStep(predNode, succNode, kind) and + pred = predNode.getARhs() and + succ = succNode.getAnImmediateUse() + ) +} + +/** Taint steps induced by summary models of kind `taint`. */ +private class TaintStepFromSummary extends TaintTracking::AdditionalTaintStep { + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + summaryStepNodes(pred, succ, "taint") + } +} diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/AccessPathSyntax.qll b/python/ql/lib/semmle/python/frameworks/data/internal/AccessPathSyntax.qll new file mode 100644 index 00000000000..076e12f2671 --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/data/internal/AccessPathSyntax.qll @@ -0,0 +1,182 @@ +/** + * Module for parsing access paths from CSV models, both the identifying access path used + * by dynamic languages, and the input/output specifications for summary steps. + * + * This file is used by the shared data flow library and by the JavaScript libraries + * (which does not use the shared data flow libraries). + */ + +/** + * Convenience-predicate for extracting two capture groups at once. + */ +bindingset[input, regexp] +private predicate regexpCaptureTwo(string input, string regexp, string capture1, string capture2) { + capture1 = input.regexpCapture(regexp, 1) and + capture2 = input.regexpCapture(regexp, 2) +} + +/** Companion module to the `AccessPath` class. */ +module AccessPath { + /** A string that should be parsed as an access path. */ + abstract class Range extends string { + bindingset[this] + Range() { any() } + } + + /** + * Parses an integer constant `n` or interval `n1..n2` (inclusive) and gets the value + * of the constant or any value contained in the interval. + */ + bindingset[arg] + int parseInt(string arg) { + result = arg.toInt() + or + // Match "n1..n2" + exists(string lo, string hi | + regexpCaptureTwo(arg, "(-?\\d+)\\.\\.(-?\\d+)", lo, hi) and + result = [lo.toInt() .. hi.toInt()] + ) + } + + /** + * Parses a lower-bounded interval `n..` and gets the lower bound. + */ + bindingset[arg] + int parseLowerBound(string arg) { result = arg.regexpCapture("(-?\\d+)\\.\\.", 1).toInt() } + + /** + * Parses an integer constant or interval (bounded or unbounded) that explicitly + * references the arity, such as `N-1` or `N-3..N-1`. + * + * Note that expressions of form `N-x` will never resolve to a negative index, + * even if `N` is zero (it will have no result in that case). + */ + bindingset[arg, arity] + private int parseIntWithExplicitArity(string arg, int arity) { + result >= 0 and // do not allow N-1 to resolve to a negative index + exists(string lo | + // N-x + lo = arg.regexpCapture("N-(\\d+)", 1) and + result = arity - lo.toInt() + or + // N-x.. + lo = arg.regexpCapture("N-(\\d+)\\.\\.", 1) and + result = [arity - lo.toInt(), arity - 1] + ) + or + exists(string lo, string hi | + // x..N-y + regexpCaptureTwo(arg, "(-?\\d+)\\.\\.N-(\\d+)", lo, hi) and + result = [lo.toInt() .. arity - hi.toInt()] + or + // N-x..N-y + regexpCaptureTwo(arg, "N-(\\d+)\\.\\.N-(\\d+)", lo, hi) and + result = [arity - lo.toInt() .. arity - hi.toInt()] and + result >= 0 + or + // N-x..y + regexpCaptureTwo(arg, "N-(\\d+)\\.\\.(\\d+)", lo, hi) and + result = [arity - lo.toInt() .. hi.toInt()] and + result >= 0 + ) + } + + /** + * Parses an integer constant or interval (bounded or unbounded) and gets any + * of the integers contained within (of which there may be infinitely many). + * + * Has no result for arguments involving an explicit arity, such as `N-1`. + */ + bindingset[arg, result] + int parseIntUnbounded(string arg) { + result = parseInt(arg) + or + result >= parseLowerBound(arg) + } + + /** + * Parses an integer constant or interval (bounded or unbounded) that + * may reference the arity of a call, such as `N-1` or `N-3..N-1`. + * + * Note that expressions of form `N-x` will never resolve to a negative index, + * even if `N` is zero (it will have no result in that case). + */ + bindingset[arg, arity] + int parseIntWithArity(string arg, int arity) { + result = parseInt(arg) + or + result in [parseLowerBound(arg) .. arity - 1] + or + result = parseIntWithExplicitArity(arg, arity) + } +} + +/** Gets the `n`th token on the access path as a string. */ +private string getRawToken(AccessPath path, int n) { + // Avoid splitting by '.' since tokens may contain dots, e.g. `Field[foo.Bar.x]`. + // Instead use regexpFind to match valid tokens, and supplement with a final length + // check (in `AccessPath.hasSyntaxError`) to ensure all characters were included in a token. + result = path.regexpFind("\\w+(?:\\[[^\\]]*\\])?(?=\\.|$)", n, _) +} + +/** + * A string that occurs as an access path (either identifying or input/output spec) + * which might be relevant for this database. + */ +class AccessPath extends string instanceof AccessPath::Range { + /** Holds if this string is not a syntactically valid access path. */ + predicate hasSyntaxError() { + // If the lengths match, all characters must haven been included in a token + // or seen by the `.` lookahead pattern. + this != "" and + not this.length() = sum(int n | | getRawToken(this, n).length() + 1) - 1 + } + + /** Gets the `n`th token on the access path (if there are no syntax errors). */ + AccessPathToken getToken(int n) { + result = getRawToken(this, n) and + not this.hasSyntaxError() + } + + /** Gets the number of tokens on the path (if there are no syntax errors). */ + int getNumToken() { + result = count(int n | exists(getRawToken(this, n))) and + not this.hasSyntaxError() + } +} + +/** + * An access part token such as `Argument[1]` or `ReturnValue`, appearing in one or more access paths. + */ +class AccessPathToken extends string { + AccessPathToken() { this = getRawToken(_, _) } + + private string getPart(int part) { + result = this.regexpCapture("([^\\[]+)(?:\\[([^\\]]*)\\])?", part) + } + + /** Gets the name of the token, such as `Member` from `Member[x]` */ + string getName() { result = this.getPart(1) } + + /** + * Gets the argument list, such as `1,2` from `Member[1,2]`, + * or has no result if there are no arguments. + */ + string getArgumentList() { result = this.getPart(2) } + + /** Gets the `n`th argument to this token, such as `x` or `y` from `Member[x,y]`. */ + string getArgument(int n) { result = this.getArgumentList().splitAt(",", n).trim() } + + /** Gets the `n`th argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */ + pragma[nomagic] + string getArgument(string name, int n) { name = this.getName() and result = this.getArgument(n) } + + /** Gets an argument to this token, such as `x` or `y` from `Member[x,y]`. */ + string getAnArgument() { result = this.getArgument(_) } + + /** Gets an argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */ + string getAnArgument(string name) { result = this.getArgument(name, _) } + + /** Gets the number of arguments to this token, such as 2 for `Member[x,y]` or zero for `ReturnValue`. */ + int getNumArgument() { result = count(int n | exists(this.getArgument(n))) } +} diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll new file mode 100644 index 00000000000..69563a3eab4 --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModels.qll @@ -0,0 +1,522 @@ +/** + * INTERNAL use only. This is an experimental API subject to change without notice. + * + * Provides classes and predicates for dealing with flow models specified in CSV format. + * + * The CSV specification has the following columns: + * - Sources: + * `package; type; path; kind` + * - Sinks: + * `package; type; path; kind` + * - Summaries: + * `package; type; path; input; output; kind` + * - Types: + * `package1; type1; package2; type2; path` + * + * The interpretation of a row is similar to API-graphs with a left-to-right + * reading. + * 1. The `package` column selects a package name, as it would be referenced in the source code, + * such as an NPM package, PIP package, or Ruby gem. (See `ModelsAsData.qll` for language-specific details). + * It may also be a synthetic package used for a type definition (see type definitions below). + * 2. The `type` column selects all instances of a named type originating from that package, + * or the empty string if referring to the package itself. + * It can also be a synthetic type name defined by a type definition (see type definitions below). + * 3. The `path` column is a `.`-separated list of "access path tokens" to resolve, starting at the node selected by `package` and `type`. + * + * Every language supports the following tokens: + * - Argument[n]: the n-th argument to a call. May be a range of form `x..y` (inclusive) and/or a comma-separated list. + * Additionally, `N-1` refers to the last argument, `N-2` refers to the second-last, and so on. + * - Parameter[n]: the n-th parameter of a callback. May be a range of form `x..y` (inclusive) and/or a comma-separated list. + * - ReturnValue: the value returned by a function call + * - WithArity[n]: match a call with the given arity. May be a range of form `x..y` (inclusive) and/or a comma-separated list. + * + * The following tokens are common and should be implemented for languages where it makes sense: + * - Member[x]: a member named `x`; exactly what a "member" is depends on the language. May be a comma-separated list of names. + * - Instance: an instance of a class + * - Subclass: a subclass of a class + * - ArrayElement: an element of array + * - Element: an element of a collection-like object + * - MapKey: a key in map-like object + * - MapValue: a value in a map-like object + * - Awaited: the value from a resolved promise/future-like object + * + * For the time being, please consult `ApiGraphModelsSpecific.qll` to see which language-specific tokens are currently supported. + * + * 4. The `input` and `output` columns specify how data enters and leaves the element selected by the + * first `(package, type, path)` tuple. Both strings are `.`-separated access paths + * of the same syntax as the `path` column. + * 5. The `kind` column is a tag that can be referenced from QL to determine to + * which classes the interpreted elements should be added. For example, for + * sources `"remote"` indicates a default remote flow source, and for summaries + * `"taint"` indicates a default additional taint step and `"value"` indicates a + * globally applicable value-preserving step. + * + * ### Types + * + * A type row of form `package1; type1; package2; type2; path` indicates that `package2; type2; path` + * should be seen as an instance of the type `package1; type1`. + * + * A `(package,type)` pair may refer to a static type or a synthetic type name used internally in the model. + * Synthetic type names can be used to reuse intermediate sub-paths, when there are multiple ways to access the same + * element. + * See `ModelsAsData.qll` for the language-specific interpretation of packages and static type names. + * + * By convention, if one wants to avoid clashes with static types from the package, the type name + * should be prefixed with a tilde character (`~`). For example, `(foo, ~Bar)` can be used to indicate that + * the type is related to the `foo` package but is not intended to match a static type. + */ + +private import ApiGraphModelsSpecific as Specific + +private class Unit = Specific::Unit; + +private module API = Specific::API; + +private import Specific::AccessPathSyntax + +/** Module containing hooks for providing input data to be interpreted as a model. */ +module ModelInput { + /** + * A unit class for adding additional source model rows. + * + * Extend this class to add additional source definitions. + */ + class SourceModelCsv extends Unit { + /** + * Holds if `row` specifies a source definition. + * + * A row of form + * ``` + * package;type;path;kind + * ``` + * indicates that the value at `(package, type, path)` should be seen as a flow + * source of the given `kind`. + * + * The kind `remote` represents a general remote flow source. + */ + abstract predicate row(string row); + } + + /** + * A unit class for adding additional sink model rows. + * + * Extend this class to add additional sink definitions. + */ + class SinkModelCsv extends Unit { + /** + * Holds if `row` specifies a sink definition. + * + * A row of form + * ``` + * package;type;path;kind + * ``` + * indicates that the value at `(package, type, path)` should be seen as a sink + * of the given `kind`. + */ + abstract predicate row(string row); + } + + /** + * A unit class for adding additional summary model rows. + * + * Extend this class to add additional flow summary definitions. + */ + class SummaryModelCsv extends Unit { + /** + * Holds if `row` specifies a summary definition. + * + * A row of form + * ``` + * package;type;path;input;output;kind + * ``` + * indicates that for each call to `(package, type, path)`, the value referred to by `input` + * can flow to the value referred to by `output`. + * + * `kind` should be either `value` or `taint`, for value-preserving or taint-preserving steps, + * respectively. + */ + abstract predicate row(string row); + } + + /** + * A unit class for adding additional type model rows. + * + * Extend this class to add additional type definitions. + */ + class TypeModelCsv extends Unit { + /** + * Holds if `row` specifies a type definition. + * + * A row of form, + * ``` + * package1;type1;package2;type2;path + * ``` + * indicates that `(package2, type2, path)` should be seen as an instance of `(package1, type1)`. + */ + abstract predicate row(string row); + } +} + +private import ModelInput + +/** + * An empty class, except in specific tests. + * + * If this is non-empty, all models are parsed even if the package is not + * considered relevant for the current database. + */ +abstract class TestAllModels extends Unit { } + +/** + * Append `;dummy` to the value of `s` to work around the fact that `string.split(delim,n)` + * does not preserve empty trailing substrings. + */ +bindingset[result] +private string inversePad(string s) { s = result + ";dummy" } + +private predicate sourceModel(string row) { any(SourceModelCsv s).row(inversePad(row)) } + +private predicate sinkModel(string row) { any(SinkModelCsv s).row(inversePad(row)) } + +private predicate summaryModel(string row) { any(SummaryModelCsv s).row(inversePad(row)) } + +private predicate typeModel(string row) { any(TypeModelCsv s).row(inversePad(row)) } + +/** Holds if a source model exists for the given parameters. */ +predicate sourceModel(string package, string type, string path, string kind) { + exists(string row | + sourceModel(row) and + row.splitAt(";", 0) = package and + row.splitAt(";", 1) = type and + row.splitAt(";", 2) = path and + row.splitAt(";", 3) = kind + ) +} + +/** Holds if a sink model exists for the given parameters. */ +private predicate sinkModel(string package, string type, string path, string kind) { + exists(string row | + sinkModel(row) and + row.splitAt(";", 0) = package and + row.splitAt(";", 1) = type and + row.splitAt(";", 2) = path and + row.splitAt(";", 3) = kind + ) +} + +/** Holds if a summary model `row` exists for the given parameters. */ +private predicate summaryModel( + string package, string type, string path, string input, string output, string kind +) { + exists(string row | + summaryModel(row) and + row.splitAt(";", 0) = package and + row.splitAt(";", 1) = type and + row.splitAt(";", 2) = path and + row.splitAt(";", 3) = input and + row.splitAt(";", 4) = output and + row.splitAt(";", 5) = kind + ) +} + +/** Holds if an type model exists for the given parameters. */ +private predicate typeModel( + string package1, string type1, string package2, string type2, string path +) { + exists(string row | + typeModel(row) and + row.splitAt(";", 0) = package1 and + row.splitAt(";", 1) = type1 and + row.splitAt(";", 2) = package2 and + row.splitAt(";", 3) = type2 and + row.splitAt(";", 4) = path + ) +} + +/** + * Gets a package that should be seen as an alias for the given other `package`, + * or the `package` itself. + */ +bindingset[package] +bindingset[result] +string getAPackageAlias(string package) { + typeModel(package, "", result, "", "") + or + result = package +} + +/** + * Holds if CSV rows involving `package` might be relevant for the analysis of this database. + */ +private predicate isRelevantPackage(string package) { + ( + sourceModel(package, _, _, _) or + sinkModel(package, _, _, _) or + summaryModel(package, _, _, _, _, _) or + typeModel(package, _, _, _, _) + ) and + ( + Specific::isPackageUsed(package) + or + exists(TestAllModels t) + ) + or + exists(string other | + isRelevantPackage(other) and + typeModel(package, _, other, _, _) + ) +} + +/** + * Holds if `package,type,path` is used in some CSV row. + */ +pragma[nomagic] +predicate isRelevantFullPath(string package, string type, string path) { + isRelevantPackage(package) and + ( + sourceModel(package, type, path, _) or + sinkModel(package, type, path, _) or + summaryModel(package, type, path, _, _, _) or + typeModel(_, _, package, type, path) + ) +} + +/** A string from a CSV row that should be parsed as an access path. */ +private class AccessPathRange extends AccessPath::Range { + AccessPathRange() { + isRelevantFullPath(_, _, this) + or + exists(string package | isRelevantPackage(package) | + summaryModel(package, _, _, this, _, _) or + summaryModel(package, _, _, _, this, _) + ) + } +} + +/** + * Gets a successor of `node` in the API graph. + */ +bindingset[token] +API::Node getSuccessorFromNode(API::Node node, AccessPathToken token) { + // API graphs use the same label for arguments and parameters. An edge originating from a + // use-node represents an argument, and an edge originating from a def-node represents a parameter. + // We just map both to the same thing. + token.getName() = ["Argument", "Parameter"] and + result = node.getParameter(AccessPath::parseIntUnbounded(token.getAnArgument())) + or + token.getName() = "ReturnValue" and + result = node.getReturn() + or + // Language-specific tokens + result = Specific::getExtraSuccessorFromNode(node, token) +} + +/** + * Gets an API-graph successor for the given invocation. + */ +bindingset[token] +API::Node getSuccessorFromInvoke(Specific::InvokeNode invoke, AccessPathToken token) { + token.getName() = "Argument" and + result = + invoke + .getParameter(AccessPath::parseIntWithArity(token.getAnArgument(), invoke.getNumArgument())) + or + token.getName() = "ReturnValue" and + result = invoke.getReturn() + or + // Language-specific tokens + result = Specific::getExtraSuccessorFromInvoke(invoke, token) +} + +/** + * Holds if `invoke` invokes a call-site filter given by `token`. + */ +pragma[inline] +private predicate invocationMatchesCallSiteFilter(Specific::InvokeNode invoke, AccessPathToken token) { + token.getName() = "WithArity" and + invoke.getNumArgument() = AccessPath::parseIntUnbounded(token.getAnArgument()) + or + Specific::invocationMatchesExtraCallSiteFilter(invoke, token) +} + +/** + * Gets the API node identified by the first `n` tokens of `path` in the given `(package, type, path)` tuple. + */ +pragma[nomagic] +private API::Node getNodeFromPath(string package, string type, AccessPath path, int n) { + isRelevantFullPath(package, type, path) and + ( + n = 0 and + exists(string package2, string type2, AccessPath path2 | + typeModel(package, type, package2, type2, path2) and + result = getNodeFromPath(package2, type2, path2, path2.getNumToken()) + ) + or + // Language-specific cases, such as handling of global variables + result = Specific::getExtraNodeFromPath(package, type, path, n) + ) + or + result = getSuccessorFromNode(getNodeFromPath(package, type, path, n - 1), path.getToken(n - 1)) + or + // Similar to the other recursive case, but where the path may have stepped through one or more call-site filters + result = + getSuccessorFromInvoke(getInvocationFromPath(package, type, path, n - 1), path.getToken(n - 1)) +} + +/** Gets the node identified by the given `(package, type, path)` tuple. */ +API::Node getNodeFromPath(string package, string type, AccessPath path) { + result = getNodeFromPath(package, type, path, path.getNumToken()) +} + +/** + * Gets an invocation identified by the given `(package, type, path)` tuple. + * + * Unlike `getNodeFromPath`, the `path` may end with one or more call-site filters. + */ +Specific::InvokeNode getInvocationFromPath(string package, string type, AccessPath path, int n) { + result = Specific::getAnInvocationOf(getNodeFromPath(package, type, path, n)) + or + result = getInvocationFromPath(package, type, path, n - 1) and + invocationMatchesCallSiteFilter(result, path.getToken(n - 1)) +} + +/** Gets an invocation identified by the given `(package, type, path)` tuple. */ +Specific::InvokeNode getInvocationFromPath(string package, string type, AccessPath path) { + result = getInvocationFromPath(package, type, path, path.getNumToken()) +} + +/** + * Holds if `name` is a valid name for an access path token in the identifying access path. + */ +bindingset[name] +predicate isValidTokenNameInIdentifyingAccessPath(string name) { + name = ["Argument", "Parameter", "ReturnValue", "WithArity"] + or + Specific::isExtraValidTokenNameInIdentifyingAccessPath(name) +} + +/** + * Holds if `name` is a valid name for an access path token with no arguments, occurring + * in an identifying access path. + */ +bindingset[name] +predicate isValidNoArgumentTokenInIdentifyingAccessPath(string name) { + name = "ReturnValue" + or + Specific::isExtraValidNoArgumentTokenInIdentifyingAccessPath(name) +} + +/** + * Holds if `argument` is a valid argument to an access path token with the given `name`, occurring + * in an identifying access path. + */ +bindingset[name, argument] +predicate isValidTokenArgumentInIdentifyingAccessPath(string name, string argument) { + name = ["Argument", "Parameter"] and + argument.regexpMatch("(N-|-)?\\d+(\\.\\.((N-|-)?\\d+)?)?") + or + name = "WithArity" and + argument.regexpMatch("\\d+(\\.\\.(\\d+)?)?") + or + Specific::isExtraValidTokenArgumentInIdentifyingAccessPath(name, argument) +} + +/** + * Module providing access to the imported models in terms of API graph nodes. + */ +module ModelOutput { + /** + * Holds if a CSV source model contributed `source` with the given `kind`. + */ + API::Node getASourceNode(string kind) { + exists(string package, string type, string path | + sourceModel(package, type, path, kind) and + result = getNodeFromPath(package, type, path) + ) + } + + /** + * Holds if a CSV sink model contributed `sink` with the given `kind`. + */ + API::Node getASinkNode(string kind) { + exists(string package, string type, string path | + sinkModel(package, type, path, kind) and + result = getNodeFromPath(package, type, path) + ) + } + + /** + * Holds if a relevant CSV summary exists for these parameters. + */ + predicate relevantSummaryModel( + string package, string type, string path, string input, string output, string kind + ) { + isRelevantPackage(package) and + summaryModel(package, type, path, input, output, kind) + } + + /** + * Holds if a `baseNode` is an invocation identified by the `package,type,path` part of a summary row. + */ + predicate resolvedSummaryBase( + string package, string type, string path, Specific::InvokeNode baseNode + ) { + summaryModel(package, type, path, _, _, _) and + baseNode = getInvocationFromPath(package, type, path) + } + + /** + * Holds if `node` is seen as an instance of `(package,type)` due to a type definition + * contributed by a CSV model. + */ + API::Node getATypeNode(string package, string type) { + exists(string package2, string type2, AccessPath path | + typeModel(package, type, package2, type2, path) and + result = getNodeFromPath(package2, type2, path) + ) + } + + /** + * Gets an error message relating to an invalid CSV row in a model. + */ + string getAWarning() { + // Check number of columns + exists(string row, string kind, int expectedArity, int actualArity | + any(SourceModelCsv csv).row(row) and kind = "source" and expectedArity = 4 + or + any(SinkModelCsv csv).row(row) and kind = "sink" and expectedArity = 4 + or + any(SummaryModelCsv csv).row(row) and kind = "summary" and expectedArity = 6 + or + any(TypeModelCsv csv).row(row) and kind = "type" and expectedArity = 5 + | + actualArity = count(row.indexOf(";")) + 1 and + actualArity != expectedArity and + result = + "CSV " + kind + " row should have " + expectedArity + " columns but has " + actualArity + + ": " + row + ) + or + // Check names and arguments of access path tokens + exists(AccessPath path, AccessPathToken token | + isRelevantFullPath(_, _, path) and + token = path.getToken(_) + | + not isValidTokenNameInIdentifyingAccessPath(token.getName()) and + result = "Invalid token name '" + token.getName() + "' in access path: " + path + or + isValidTokenNameInIdentifyingAccessPath(token.getName()) and + exists(string argument | + argument = token.getAnArgument() and + not isValidTokenArgumentInIdentifyingAccessPath(token.getName(), argument) and + result = + "Invalid argument '" + argument + "' in token '" + token + "' in access path: " + path + ) + or + isValidTokenNameInIdentifyingAccessPath(token.getName()) and + token.getNumArgument() = 0 and + not isValidNoArgumentTokenInIdentifyingAccessPath(token.getName()) and + result = "Invalid token '" + token + "' is missing its arguments, in access path: " + path + ) + } +} diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsSpecific.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsSpecific.qll new file mode 100644 index 00000000000..92f7dcbd50b --- /dev/null +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -0,0 +1,202 @@ +/** + * Contains the language-specific part of the models-as-data implementation found in `ApiGraphModels.qll`. + * + * It must export the following members: + * ```ql + * class Unit // a unit type + * module AccessPathSyntax // a re-export of the AccessPathSyntax module + * class InvokeNode // a type representing an invocation connected to the API graph + * module API // the API graph module + * predicate isPackageUsed(string package) + * API::Node getExtraNodeFromPath(string package, string type, string path, int n) + * API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token) + * API::Node getExtraSuccessorFromInvoke(API::InvokeNode node, AccessPathToken token) + * predicate invocationMatchesExtraCallSiteFilter(API::InvokeNode invoke, AccessPathToken token) + * InvokeNode getAnInvocationOf(API::Node node) + * predicate isExtraValidTokenNameInIdentifyingAccessPath(string name) + * predicate isExtraValidNoArgumentTokenInIdentifyingAccessPath(string name) + * predicate isExtraValidTokenArgumentInIdentifyingAccessPath(string name, string argument) + * ``` + */ + +private import python as PY +private import semmle.python.dataflow.new.DataFlow +private import ApiGraphModels +import semmle.python.ApiGraphs::API as API + +class Unit = PY::Unit; + +// Re-export libraries needed by ApiGraphModels.qll +import semmle.python.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax +private import AccessPathSyntax + +/** + * Holds if models describing `package` may be relevant for the analysis of this database. + */ +predicate isPackageUsed(string package) { exists(API::moduleImport(package)) } + +/** Gets a Python-specific interpretation of the `(package, type, path)` tuple after resolving the first `n` access path tokens. */ +bindingset[package, type, path] +API::Node getExtraNodeFromPath(string package, string type, AccessPath path, int n) { + type = "" and + n = 0 and + result = API::moduleImport(package) and + exists(path) +} + +/** + * Gets a Python-specific API graph successor of `node` reachable by resolving `token`. + */ +bindingset[token] +API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token) { + token.getName() = "Member" and + result = node.getMember(token.getAnArgument()) + or + token.getName() = "Instance" and + result = node.getReturn() // In Python `Instance` is just an alias for `ReturnValue` + or + token.getName() = "Awaited" and + result = node.getAwaited() + or + token.getName() = "Subclass" and + result = node.getASubclass*() + or + token.getName() = "Method" and + result = node.getMember(token.getAnArgument()).getReturn() + or + token.getName() = ["Argument", "Parameter"] and + ( + token.getAnArgument() = "self" and + result = node.getSelfParameter() + or + exists(string name | token.getAnArgument() = name + ":" | + result = node.getKeywordParameter(name) + ) + or + token.getAnArgument() = "any" and + result = [node.getParameter(_), node.getKeywordParameter(_)] + or + token.getAnArgument() = "any-named" and + result = node.getKeywordParameter(_) + ) + // Some features don't have MaD tokens yet, they would need to be added to API-graphs first. + // - decorators ("DecoratedClass", "DecoratedMember", "DecoratedParameter") + // - Array/Map elements ("ArrayElement", "Element", "MapKey", "MapValue") +} + +/** + * Gets a Python-specific API graph successor of `node` reachable by resolving `token`. + */ +bindingset[token] +API::Node getExtraSuccessorFromInvoke(API::CallNode node, AccessPathToken token) { + token.getName() = "Instance" and + result = node.getReturn() + or + token.getName() = ["Argument", "Parameter"] and + ( + token.getAnArgument() = "self" and + result = node.getSelfParameter() + or + token.getAnArgument() = "any" and + result = [node.getParameter(_), node.getKeywordParameter(_)] + or + token.getAnArgument() = "any-named" and + result = node.getKeywordParameter(_) + or + exists(string arg | arg + ":" = token.getAnArgument() | result = node.getKeywordParameter(arg)) + ) +} + +/** + * Holds if `invoke` matches the PY-specific call site filter in `token`. + */ +bindingset[token] +predicate invocationMatchesExtraCallSiteFilter(API::CallNode invoke, AccessPathToken token) { + token.getName() = "Call" and exists(invoke) // there is only one kind of call in Python. +} + +/** + * Holds if `path` is an input or output spec for a summary with the given `base` node. + */ +pragma[nomagic] +private predicate relevantInputOutputPath(API::CallNode base, AccessPath inputOrOutput) { + exists(string package, string type, string input, string output, string path | + ModelOutput::relevantSummaryModel(package, type, path, input, output, _) and + ModelOutput::resolvedSummaryBase(package, type, path, base) and + inputOrOutput = [input, output] + ) +} + +/** + * Gets the API node for the first `n` tokens of the given input/output path, evaluated relative to `baseNode`. + */ +private API::Node getNodeFromInputOutputPath(API::CallNode baseNode, AccessPath path, int n) { + relevantInputOutputPath(baseNode, path) and + ( + n = 1 and + result = getSuccessorFromInvoke(baseNode, path.getToken(0)) + or + result = + getSuccessorFromNode(getNodeFromInputOutputPath(baseNode, path, n - 1), path.getToken(n - 1)) + ) +} + +/** + * Gets the API node for the given input/output path, evaluated relative to `baseNode`. + */ +private API::Node getNodeFromInputOutputPath(API::CallNode baseNode, AccessPath path) { + result = getNodeFromInputOutputPath(baseNode, path, path.getNumToken()) +} + +/** + * Holds if a CSV summary contributed the step `pred -> succ` of the given `kind`. + */ +predicate summaryStep(API::Node pred, API::Node succ, string kind) { + exists( + string package, string type, string path, API::CallNode base, AccessPath input, + AccessPath output + | + ModelOutput::relevantSummaryModel(package, type, path, input, output, kind) and + ModelOutput::resolvedSummaryBase(package, type, path, base) and + pred = getNodeFromInputOutputPath(base, input) and + succ = getNodeFromInputOutputPath(base, output) + ) +} + +class InvokeNode = API::CallNode; + +/** Gets an `InvokeNode` corresponding to an invocation of `node`. */ +InvokeNode getAnInvocationOf(API::Node node) { result = node.getACall() } + +/** + * Holds if `name` is a valid name for an access path token in the identifying access path. + */ +bindingset[name] +predicate isExtraValidTokenNameInIdentifyingAccessPath(string name) { + name = ["Member", "Instance", "Awaited", "Call", "Method", "Subclass"] +} + +/** + * Holds if `name` is a valid name for an access path token with no arguments, occurring + * in an identifying access path. + */ +predicate isExtraValidNoArgumentTokenInIdentifyingAccessPath(string name) { + name = ["Instance", "Awaited", "Call", "Subclass"] +} + +/** + * Holds if `argument` is a valid argument to an access path token with the given `name`, occurring + * in an identifying access path. + */ +bindingset[name, argument] +predicate isExtraValidTokenArgumentInIdentifyingAccessPath(string name, string argument) { + name = ["Member", "Method"] and + exists(argument) + or + name = ["Argument", "Parameter"] and + ( + argument = ["self", "any", "any-named"] + or + argument.regexpMatch("\\w+:") // keyword argument + ) +} diff --git a/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll index 410eee50b29..5a033664823 100644 --- a/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/PathInjectionCustomizations.qll @@ -59,6 +59,12 @@ module PathInjection { FileSystemAccessAsSink() { this = any(FileSystemAccess e).getAPathArgument() } } + private import semmle.python.frameworks.data.ModelsAsData + + private class DataAsFileSink extends Sink { + DataAsFileSink() { this = ModelOutput::getASinkNode("path-injection").getARhs() } + } + /** * A comparison with a constant string, considered as a sanitizer-guard. */ diff --git a/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll b/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll index 756a1f6b773..cf21a5c0e94 100644 --- a/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll +++ b/python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll @@ -60,4 +60,11 @@ module SqlInjection { * A comparison with a constant string, considered as a sanitizer-guard. */ class StringConstCompareAsSanitizerGuard extends SanitizerGuard, StringConstCompare { } + + private import semmle.python.frameworks.data.ModelsAsData + + /** A sink for sql-injection from model data. */ + private class DataAsSqlSink extends Sink { + DataAsSqlSink() { this = ModelOutput::getASinkNode("sql-injection").getARhs() } + } } diff --git a/python/ql/test/experimental/meta/MaDTest.qll b/python/ql/test/experimental/meta/MaDTest.qll new file mode 100644 index 00000000000..345fc973284 --- /dev/null +++ b/python/ql/test/experimental/meta/MaDTest.qll @@ -0,0 +1,46 @@ +import python +private import semmle.python.dataflow.new.DataFlow +private import semmle.python.dataflow.new.internal.PrintNode +private import semmle.python.frameworks.data.ModelsAsData +// need to import Frameworks to get the actual modeling imported +private import semmle.python.Frameworks +// this import needs to be public to get the query predicates propagated to the actual test files +import TestUtilities.InlineExpectationsTest + +class MadSinkTest extends InlineExpectationsTest { + MadSinkTest() { this = "MadSinkTest" } + + override string getARelevantTag() { + exists(string kind | exists(ModelOutput::getASinkNode(kind)) | result = "mad-sink__" + kind) + } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(DataFlow::Node sink, string kind | + sink = ModelOutput::getASinkNode(kind).getARhs() and + location = sink.getLocation() and + element = sink.toString() and + value = prettyNodeForInlineTest(sink) and + tag = "mad-sink__" + kind + ) + } +} + +class MadSourceTest extends InlineExpectationsTest { + MadSourceTest() { this = "MadSourceTest" } + + override string getARelevantTag() { + exists(string kind | exists(ModelOutput::getASourceNode(kind)) | result = "mad-source__" + kind) + } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + exists(DataFlow::Node source, string kind | + source = ModelOutput::getASourceNode(kind).getAnImmediateUse() and + location = source.getLocation() and + element = source.toString() and + value = prettyNodeForInlineTest(source) and + tag = "mad-source__" + kind + ) + } +} diff --git a/python/ql/test/library-tests/frameworks/asyncpg/MaDTest.expected b/python/ql/test/library-tests/frameworks/asyncpg/MaDTest.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/python/ql/test/library-tests/frameworks/asyncpg/MaDTest.ql b/python/ql/test/library-tests/frameworks/asyncpg/MaDTest.ql new file mode 100644 index 00000000000..fef4356ab35 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/asyncpg/MaDTest.ql @@ -0,0 +1,2 @@ +import python +import experimental.meta.MaDTest diff --git a/python/ql/test/library-tests/frameworks/asyncpg/test.py b/python/ql/test/library-tests/frameworks/asyncpg/test.py index e4b3c895ece..e2e5e1c5826 100644 --- a/python/ql/test/library-tests/frameworks/asyncpg/test.py +++ b/python/ql/test/library-tests/frameworks/asyncpg/test.py @@ -7,17 +7,17 @@ async def test_connection(): try: # The file-like object is passed in as a keyword-only argument. # See https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.connection.Connection.copy_from_query - await conn.copy_from_query("sql", output="filepath") # $ getSql="sql" getAPathArgument="filepath" - await conn.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ getSql="sql" getAPathArgument="filepath" + await conn.copy_from_query("sql", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__path-injection="filepath" + await conn.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__path-injection="filepath" - await conn.copy_from_table("table", output="filepath") # $ getAPathArgument="filepath" - await conn.copy_to_table("table", source="filepath") # $ getAPathArgument="filepath" + await conn.copy_from_table("table", output="filepath") # $ mad-sink__path-injection="filepath" + await conn.copy_to_table("table", source="filepath") # $ mad-sink__path-injection="filepath" - await conn.execute("sql") # $ getSql="sql" - await conn.executemany("sql") # $ getSql="sql" - await conn.fetch("sql") # $ getSql="sql" - await conn.fetchrow("sql") # $ getSql="sql" - await conn.fetchval("sql") # $ getSql="sql" + await conn.execute("sql") # $ mad-sink__sql-injection="sql" + await conn.executemany("sql") # $ mad-sink__sql-injection="sql" + await conn.fetch("sql") # $ mad-sink__sql-injection="sql" + await conn.fetchrow("sql") # $ mad-sink__sql-injection="sql" + await conn.fetchval("sql") # $ mad-sink__sql-injection="sql" finally: await conn.close() @@ -27,11 +27,11 @@ async def test_prepared_statement(): conn = await asyncpg.connect() try: - pstmt = await conn.prepare("psql") # $ constructedSql="psql" - pstmt.executemany() # $ getSql="psql" - pstmt.fetch() # $ getSql="psql" - pstmt.fetchrow() # $ getSql="psql" - pstmt.fetchval() # $ getSql="psql" + pstmt = await conn.prepare("psql") # $ mad-sink__sql-injection="psql" + pstmt.executemany() + pstmt.fetch() + pstmt.fetchrow() + pstmt.fetchval() finally: await conn.close() @@ -46,7 +46,7 @@ async def test_cursor(): cursor = await conn.cursor("sql") # $ getSql="sql" constructedSql="sql" await cursor.fetch() - pstmt = await conn.prepare("psql") # $ constructedSql="psql" + pstmt = await conn.prepare("psql") # $ mad-sink__sql-injection="psql" pcursor = await pstmt.cursor() # $ getSql="psql" await pcursor.fetch() @@ -69,23 +69,23 @@ async def test_connection_pool(): pool = await asyncpg.create_pool() try: - await pool.copy_from_query("sql", output="filepath") # $ getSql="sql" getAPathArgument="filepath" - await pool.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ getSql="sql" getAPathArgument="filepath" - await pool.copy_from_table("table", output="filepath") # $ getAPathArgument="filepath" - await pool.copy_to_table("table", source="filepath") # $ getAPathArgument="filepath" + await pool.copy_from_query("sql", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__path-injection="filepath" + await pool.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__path-injection="filepath" + await pool.copy_from_table("table", output="filepath") # $ mad-sink__path-injection="filepath" + await pool.copy_to_table("table", source="filepath") # $ mad-sink__path-injection="filepath" - await pool.execute("sql") # $ getSql="sql" - await pool.executemany("sql") # $ getSql="sql" - await pool.fetch("sql") # $ getSql="sql" - await pool.fetchrow("sql") # $ getSql="sql" - await pool.fetchval("sql") # $ getSql="sql" + await pool.execute("sql") # $ mad-sink__sql-injection="sql" + await pool.executemany("sql") # $ mad-sink__sql-injection="sql" + await pool.fetch("sql") # $ mad-sink__sql-injection="sql" + await pool.fetchrow("sql") # $ mad-sink__sql-injection="sql" + await pool.fetchval("sql") # $ mad-sink__sql-injection="sql" async with pool.acquire() as conn: - await conn.execute("sql") # $ getSql="sql" + await conn.execute("sql") # $ mad-sink__sql-injection="sql" conn = await pool.acquire() try: - await conn.fetch("sql") # $ getSql="sql" + await conn.fetch("sql") # $ mad-sink__sql-injection="sql" finally: await pool.release(conn) @@ -93,13 +93,13 @@ async def test_connection_pool(): await pool.close() async with asyncpg.create_pool() as pool: - await pool.execute("sql") # $ getSql="sql" + await pool.execute("sql") # $ mad-sink__sql-injection="sql" async with pool.acquire() as conn: - await conn.execute("sql") # $ getSql="sql" + await conn.execute("sql") # $ mad-sink__sql-injection="sql" conn = await pool.acquire() try: - await conn.fetch("sql") # $ getSql="sql" + await conn.fetch("sql") # $ mad-sink__sql-injection="sql" finally: await pool.release(conn) diff --git a/python/ql/test/library-tests/frameworks/data/test.expected b/python/ql/test/library-tests/frameworks/data/test.expected new file mode 100644 index 00000000000..68de6ecd878 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/data/test.expected @@ -0,0 +1,103 @@ +taintFlow +| test.py:3:5:3:15 | ControlFlowNode for getSource() | test.py:4:8:4:8 | ControlFlowNode for x | +| test.py:3:5:3:15 | ControlFlowNode for getSource() | test.py:7:17:7:17 | ControlFlowNode for x | +| test.py:9:8:9:14 | ControlFlowNode for alias() | test.py:9:8:9:14 | ControlFlowNode for alias() | +| test.py:10:8:10:22 | ControlFlowNode for Attribute() | test.py:10:8:10:22 | ControlFlowNode for Attribute() | +| test.py:11:8:11:30 | ControlFlowNode for Attribute() | test.py:11:8:11:30 | ControlFlowNode for Attribute() | +| test.py:71:28:71:38 | ControlFlowNode for getSource() | test.py:71:8:71:39 | ControlFlowNode for Attribute() | +| test.py:75:5:75:15 | ControlFlowNode for getSource() | test.py:76:22:76:22 | ControlFlowNode for x | +| test.py:75:5:75:15 | ControlFlowNode for getSource() | test.py:77:22:77:22 | ControlFlowNode for y | +| test.py:81:36:81:46 | ControlFlowNode for getSource() | test.py:81:8:81:47 | ControlFlowNode for Attribute() | +| test.py:83:50:83:60 | ControlFlowNode for getSource() | test.py:83:8:83:61 | ControlFlowNode for Attribute() | +| test.py:86:49:86:59 | ControlFlowNode for getSource() | test.py:86:8:86:60 | ControlFlowNode for Attribute() | +| test.py:87:56:87:66 | ControlFlowNode for getSource() | test.py:87:8:87:67 | ControlFlowNode for Attribute() | +isSink +| test.py:4:8:4:8 | ControlFlowNode for x | test-sink | +| test.py:7:17:7:17 | ControlFlowNode for x | test-sink | +| test.py:9:8:9:14 | ControlFlowNode for alias() | test-sink | +| test.py:10:8:10:22 | ControlFlowNode for Attribute() | test-sink | +| test.py:11:8:11:30 | ControlFlowNode for Attribute() | test-sink | +| test.py:12:8:12:34 | ControlFlowNode for Attribute() | test-sink | +| test.py:16:11:16:13 | ControlFlowNode for one | test-sink | +| test.py:17:19:17:21 | ControlFlowNode for two | test-sink | +| test.py:17:24:17:28 | ControlFlowNode for three | test-sink | +| test.py:17:31:17:34 | ControlFlowNode for four | test-sink | +| test.py:18:37:18:40 | ControlFlowNode for five | test-sink | +| test.py:19:21:19:26 | ControlFlowNode for second | test-sink | +| test.py:30:21:30:23 | ControlFlowNode for one | test-sink | +| test.py:32:22:32:24 | ControlFlowNode for one | test-sink | +| test.py:32:27:32:29 | ControlFlowNode for two | test-sink | +| test.py:33:22:33:24 | ControlFlowNode for one | test-sink | +| test.py:33:27:33:29 | ControlFlowNode for two | test-sink | +| test.py:33:32:33:36 | ControlFlowNode for three | test-sink | +| test.py:57:27:57:33 | ControlFlowNode for arg_pos | test-sink | +| test.py:66:17:66:20 | ControlFlowNode for arg1 | test-sink | +| test.py:66:23:66:26 | ControlFlowNode for arg2 | test-sink | +| test.py:66:34:66:43 | ControlFlowNode for namedThing | test-sink | +| test.py:67:34:67:44 | ControlFlowNode for secondNamed | test-sink | +| test.py:71:8:71:39 | ControlFlowNode for Attribute() | test-sink | +| test.py:72:8:72:47 | ControlFlowNode for Attribute() | test-sink | +| test.py:76:22:76:22 | ControlFlowNode for x | test-sink | +| test.py:77:22:77:22 | ControlFlowNode for y | test-sink | +| test.py:78:22:78:22 | ControlFlowNode for z | test-sink | +| test.py:81:8:81:47 | ControlFlowNode for Attribute() | test-sink | +| test.py:82:8:82:54 | ControlFlowNode for Attribute() | test-sink | +| test.py:83:8:83:61 | ControlFlowNode for Attribute() | test-sink | +| test.py:85:8:85:53 | ControlFlowNode for Attribute() | test-sink | +| test.py:86:8:86:60 | ControlFlowNode for Attribute() | test-sink | +| test.py:87:8:87:67 | ControlFlowNode for Attribute() | test-sink | +| test.py:89:21:89:23 | ControlFlowNode for one | test-sink | +| test.py:91:21:91:23 | ControlFlowNode for one | test-sink | +| test.py:91:30:91:32 | ControlFlowNode for two | test-sink | +| test.py:98:6:98:9 | ControlFlowNode for baz2 | test-sink | +isSource +| test.py:3:5:3:15 | ControlFlowNode for getSource() | test-source | +| test.py:9:8:9:14 | ControlFlowNode for alias() | test-source | +| test.py:10:8:10:14 | ControlFlowNode for alias() | test-source | +| test.py:10:8:10:22 | ControlFlowNode for Attribute() | test-source | +| test.py:11:8:11:14 | ControlFlowNode for alias() | test-source | +| test.py:11:8:11:22 | ControlFlowNode for Attribute() | test-source | +| test.py:11:8:11:30 | ControlFlowNode for Attribute() | test-source | +| test.py:12:8:12:14 | ControlFlowNode for alias() | test-source | +| test.py:12:8:12:22 | ControlFlowNode for Attribute() | test-source | +| test.py:23:24:23:26 | ControlFlowNode for one | test-source | +| test.py:24:33:24:35 | ControlFlowNode for two | test-source | +| test.py:24:38:24:42 | ControlFlowNode for three | test-source | +| test.py:24:45:24:48 | ControlFlowNode for four | test-source | +| test.py:25:34:25:39 | ControlFlowNode for second | test-source | +| test.py:39:11:39:20 | ControlFlowNode for Await | test-source | +| test.py:41:8:41:27 | ControlFlowNode for Attribute() | test-source | +| test.py:46:7:46:16 | ControlFlowNode for SubClass() | test-source | +| test.py:53:7:53:16 | ControlFlowNode for Attribute() | test-source | +| test.py:60:13:60:16 | ControlFlowNode for self | test-source | +| test.py:60:24:60:28 | ControlFlowNode for named | test-source | +| test.py:63:36:63:39 | ControlFlowNode for arg2 | test-source | +| test.py:63:42:63:45 | ControlFlowNode for arg3 | test-source | +| test.py:63:48:63:51 | ControlFlowNode for arg4 | test-source | +| test.py:63:54:63:57 | ControlFlowNode for arg5 | test-source | +| test.py:71:28:71:38 | ControlFlowNode for getSource() | test-source | +| test.py:72:36:72:46 | ControlFlowNode for getSource() | test-source | +| test.py:75:5:75:15 | ControlFlowNode for getSource() | test-source | +| test.py:81:36:81:46 | ControlFlowNode for getSource() | test-source | +| test.py:82:43:82:53 | ControlFlowNode for getSource() | test-source | +| test.py:83:50:83:60 | ControlFlowNode for getSource() | test-source | +| test.py:85:42:85:52 | ControlFlowNode for getSource() | test-source | +| test.py:86:49:86:59 | ControlFlowNode for getSource() | test-source | +| test.py:87:56:87:66 | ControlFlowNode for getSource() | test-source | +| test.py:101:29:101:31 | ControlFlowNode for arg | test-source | +| test.py:104:24:104:29 | ControlFlowNode for param1 | test-source | +| test.py:104:32:104:37 | ControlFlowNode for param2 | test-source | +| test.py:107:24:107:28 | ControlFlowNode for name1 | test-source | +| test.py:107:31:107:35 | ControlFlowNode for name2 | test-source | +syntaxErrors +| Member[foo | +| Member[foo] .Member[bar] | +| Member[foo] Member[bar] | +| Member[foo], Member[bar] | +| Member[foo],Member[bar] | +| Member[foo]. Member[bar] | +| Member[foo]..Member[bar] | +| Member[foo]Member[bar] | +| Member[foo]] | +| Member[foo]].Member[bar] | +warning diff --git a/python/ql/test/library-tests/frameworks/data/test.py b/python/ql/test/library-tests/frameworks/data/test.py new file mode 100644 index 00000000000..ea1a6e0d4d4 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/data/test.py @@ -0,0 +1,108 @@ +from testlib import getSource, mySink, alias + +x = getSource() +mySink(x) + +mySink(foo=x) # OK +mySink(sinkName=x) # NOT OK + +mySink(alias()) # NOT OK +mySink(alias().chain()) # NOT OK +mySink(alias().chain().chain()) # NOT OK +mySink(alias().chain().safeThing()) # OK + +from testlib import Args + +Args.arg0(one, two, three, four, five) +Args.arg1to3(one, two, three, four, five) +Args.lastarg(one, two, three, four, five) +Args.nonFist(first, second) + +from testlib import Callbacks + +Callbacks.first(lambda one, two, three, four, five: 0) +Callbacks.param1to3(lambda one, two, three, four, five: 0) +Callbacks.nonFirst(lambda first, second: 0) + +from testlib import CallFilter + +CallFilter.arityOne(one, two) # NO match +CallFilter.arityOne(one) # Match +CallFilter.twoOrMore(one) # NO match +CallFilter.twoOrMore(one, two) # Match +CallFilter.twoOrMore(one, two, three) # Match + +from testlib import CommonTokens + +async def async_func(): + prom = CommonTokens.makePromise(1); + val = await prom + +inst = CommonTokens.Class() + +class SubClass (CommonTokens.Super): + pass + +sub = SubClass() + +class Sub2Class (CommonTokens.Class): + pass + +sub2 = Sub2Class() # TODO: Currently not recognized as an instance of CommonTokens.Class + +val = inst.foo() + +from testlib import ArgPos + +arg_pos = ArgPos(); val = arg_pos.self_thing(arg, named=2); + +class SubClass (ArgPos.MyClass): + def foo(self, arg, named=2, otherName=3): + pass + + def secondAndAfter(self, arg1, arg2, arg3, arg4, arg5): + pass + +ArgPos.anyParam(arg1, arg2, name=namedThing) +ArgPos.anyNamed(arg4, arg5, name=secondNamed) + +from testlib import Steps + +mySink(Steps.preserveTaint(getSource())) # FLOW +mySink(Steps.preserveTaint("safe", getSource())) # NO FLOW + +Steps.taintIntoCallback( + getSource(), + lambda x: mySink(x), # FLOW + lambda y: mySink(y), # FLOW + lambda z: mySink(z) # NO FLOW +) + +mySink(Steps.preserveArgZeroAndTwo(getSource())) # FLOW +mySink(Steps.preserveArgZeroAndTwo("foo", getSource())) # NO FLOW +mySink(Steps.preserveArgZeroAndTwo("foo", "bar", getSource())) # FLOW + +mySink(Steps.preserveAllButFirstArgument(getSource())) # NO FLOW +mySink(Steps.preserveAllButFirstArgument("foo", getSource())) # FLOW +mySink(Steps.preserveAllButFirstArgument("foo", "bar", getSource())) # FLOW + +CallFilter.arityOne(one) # match +CallFilter.arityOne(one=one) # NO match +CallFilter.arityOne(one, two=two) # match - on both the named and positional arguments +CallFilter.arityOne(one=one, two=two) # NO match + +from foo1.bar import baz1 +baz1(baz1) # no match, and that's the point. + +from foo2.bar import baz2 +baz2(baz2) # match + +class OtherSubClass (ArgPos.MyClass): + def otherSelfTest(self, arg, named=2, otherName=3): # test that Parameter[0] hits `arg`. + pass + + def anyParam(self, param1, param2): # Parameter[any] matches all non-self parameters + pass + + def anyNamed(self, name1, name2=2): # Parameter[any-named] matches all non-self named parameters + pass diff --git a/python/ql/test/library-tests/frameworks/data/test.ql b/python/ql/test/library-tests/frameworks/data/test.ql new file mode 100644 index 00000000000..86f960b1adf --- /dev/null +++ b/python/ql/test/library-tests/frameworks/data/test.ql @@ -0,0 +1,127 @@ +import python +import semmle.python.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax +import semmle.python.frameworks.data.ModelsAsData +import semmle.python.dataflow.new.TaintTracking +import semmle.python.dataflow.new.DataFlow +private import semmle.python.ApiGraphs + +class Steps extends ModelInput::SummaryModelCsv { + override predicate row(string row) { + // package;type;path;input;output;kind + row = + [ + "testlib;;Member[Steps].Member[preserveTaint].Call;Argument[0];ReturnValue;taint", + "testlib;;Member[Steps].Member[taintIntoCallback];Argument[0];Argument[1..2].Parameter[0];taint", + "testlib;;Member[Steps].Member[preserveArgZeroAndTwo];Argument[0,2];ReturnValue;taint", + "testlib;;Member[Steps].Member[preserveAllButFirstArgument].Call;Argument[1..];ReturnValue;taint", + ] + } +} + +class Types extends ModelInput::TypeModelCsv { + override predicate row(string row) { + // package1;type1;package2;type2;path + row = + [ + "testlib;Alias;testlib;;Member[alias].ReturnValue", + "testlib;Alias;testlib;Alias;Member[chain].ReturnValue", + ] + } +} + +class Sinks extends ModelInput::SinkModelCsv { + override predicate row(string row) { + // package;type;path;kind + row = + [ + "testlib;;Member[mySink].Argument[0,sinkName:];test-sink", + // testing argument syntax + "testlib;;Member[Args].Member[arg0].Argument[0];test-sink", // + "testlib;;Member[Args].Member[arg1to3].Argument[1..3];test-sink", // + "testlib;;Member[Args].Member[lastarg].Argument[N-1];test-sink", // + "testlib;;Member[Args].Member[nonFist].Argument[1..];test-sink", // + // callsite filter. + "testlib;;Member[CallFilter].Member[arityOne].WithArity[1].Argument[any];test-sink", // + "testlib;;Member[CallFilter].Member[twoOrMore].WithArity[2..].Argument[0..];test-sink", // + // testing non-positional arguments + "testlib;;Member[ArgPos].Instance.Member[self_thing].Argument[self];test-sink", // + // any argument + "testlib;;Member[ArgPos].Member[anyParam].Argument[any];test-sink", // + "testlib;;Member[ArgPos].Member[anyNamed].Argument[any-named];test-sink", // + // testing package syntax + "foo1.bar;;Member[baz1].Argument[any];test-sink", // + "foo2;;Member[bar].Member[baz2].Argument[any];test-sink", // + ] + } +} + +class Sources extends ModelInput::SourceModelCsv { + // package;type;path;kind + override predicate row(string row) { + row = + [ + "testlib;;Member[getSource].ReturnValue;test-source", // + "testlib;Alias;;test-source", + // testing parameter syntax + "testlib;;Member[Callbacks].Member[first].Argument[0].Parameter[0];test-source", // + "testlib;;Member[Callbacks].Member[param1to3].Argument[0].Parameter[1..3];test-source", // + "testlib;;Member[Callbacks].Member[nonFirst].Argument[0].Parameter[1..];test-source", // + // Common tokens. + "testlib;;Member[CommonTokens].Member[makePromise].ReturnValue.Awaited;test-source", // + "testlib;;Member[CommonTokens].Member[Class].Instance;test-source", // + "testlib;;Member[CommonTokens].Member[Super].Subclass.Instance;test-source", // + // method + "testlib;;Member[CommonTokens].Member[Class].Instance.Method[foo];test-source", // + // testing non-positional arguments + "testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[foo].Parameter[self];test-source", // + "testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[foo].Parameter[named:];test-source", // + "testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[secondAndAfter].Parameter[1..];test-source", // + "testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[otherSelfTest].Parameter[0];test-source", // + "testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[anyParam].Parameter[any];test-source", // + "testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[anyNamed].Parameter[any-named];test-source", // + ] + } +} + +class BasicTaintTracking extends TaintTracking::Configuration { + BasicTaintTracking() { this = "BasicTaintTracking" } + + override predicate isSource(DataFlow::Node source) { + source = ModelOutput::getASourceNode("test-source").getAnImmediateUse() + } + + override predicate isSink(DataFlow::Node sink) { + sink = ModelOutput::getASinkNode("test-sink").getARhs() + } +} + +query predicate taintFlow(DataFlow::Node source, DataFlow::Node sink) { + any(BasicTaintTracking tr).hasFlow(source, sink) +} + +query predicate isSink(DataFlow::Node node, string kind) { + node = ModelOutput::getASinkNode(kind).getARhs() +} + +query predicate isSource(DataFlow::Node node, string kind) { + node = ModelOutput::getASourceNode(kind).getAnImmediateUse() +} + +class SyntaxErrorTest extends ModelInput::SinkModelCsv { + override predicate row(string row) { + row = + [ + "testlib;;Member[foo],Member[bar];test-sink", "testlib;;Member[foo] Member[bar];test-sink", + "testlib;;Member[foo]. Member[bar];test-sink", + "testlib;;Member[foo], Member[bar];test-sink", + "testlib;;Member[foo]..Member[bar];test-sink", + "testlib;;Member[foo] .Member[bar];test-sink", "testlib;;Member[foo]Member[bar];test-sink", + "testlib;;Member[foo;test-sink", "testlib;;Member[foo]];test-sink", + "testlib;;Member[foo]].Member[bar];test-sink" + ] + } +} + +query predicate syntaxErrors(AccessPathSyntax::AccessPath path) { path.hasSyntaxError() } + +query predicate warning = ModelOutput::getAWarning/0; diff --git a/python/ql/test/library-tests/frameworks/data/warnings.expected b/python/ql/test/library-tests/frameworks/data/warnings.expected new file mode 100644 index 00000000000..5cebb548358 --- /dev/null +++ b/python/ql/test/library-tests/frameworks/data/warnings.expected @@ -0,0 +1,7 @@ +| CSV type row should have 5 columns but has 2: test;TooFewColumns | +| CSV type row should have 5 columns but has 8: test;TooManyColumns;;;Member[Foo].Instance;too;many;columns | +| Invalid argument '0-1' in token 'Argument[0-1]' in access path: Method[foo].Argument[0-1] | +| Invalid argument '*' in token 'Argument[*]' in access path: Method[foo].Argument[*] | +| Invalid token 'Argument' is missing its arguments, in access path: Method[foo].Argument | +| Invalid token 'Member' is missing its arguments, in access path: Method[foo].Member | +| Invalid token name 'Arg' in access path: Method[foo].Arg[0] | diff --git a/python/ql/test/library-tests/frameworks/data/warnings.ql b/python/ql/test/library-tests/frameworks/data/warnings.ql new file mode 100644 index 00000000000..3443233179e --- /dev/null +++ b/python/ql/test/library-tests/frameworks/data/warnings.ql @@ -0,0 +1,25 @@ +import python +import semmle.python.frameworks.data.internal.AccessPathSyntax as AccessPathSyntax +import semmle.python.frameworks.data.internal.ApiGraphModels as ApiGraphModels +import semmle.python.frameworks.data.ModelsAsData + +private class InvalidTypeModel extends ModelInput::TypeModelCsv { + override predicate row(string row) { + row = + [ + "test;TooManyColumns;;;Member[Foo].Instance;too;many;columns", // + "test;TooFewColumns", // + "test;X;test;Y;Method[foo].Arg[0]", // + "test;X;test;Y;Method[foo].Argument[0-1]", // + "test;X;test;Y;Method[foo].Argument[*]", // + "test;X;test;Y;Method[foo].Argument", // + "test;X;test;Y;Method[foo].Member", // + ] + } +} + +class IsTesting extends ApiGraphModels::TestAllModels { + IsTesting() { this = this } +} + +query predicate warning = ModelOutput::getAWarning/0; diff --git a/ruby/ql/consistency-queries/DataFlowConsistency.ql b/ruby/ql/consistency-queries/DataFlowConsistency.ql index fdc64a8781c..000bbc57899 100644 --- a/ruby/ql/consistency-queries/DataFlowConsistency.ql +++ b/ruby/ql/consistency-queries/DataFlowConsistency.ql @@ -9,5 +9,7 @@ private class MyConsistencyConfiguration extends ConsistencyConfiguration { n instanceof BlockArgumentNode or n instanceof SummaryNode + or + n instanceof HashSplatArgumentsNode } } diff --git a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll index 6b4e11317e6..8f0673c8d99 100644 --- a/ruby/ql/lib/codeql/ruby/ApiGraphs.qll +++ b/ruby/ql/lib/codeql/ruby/ApiGraphs.qll @@ -576,7 +576,7 @@ module API { use(pred, a) and use(succ, b) and resolveConstant(b.asExpr().getExpr()) = resolveConstantWriteAccess(c) and - c.getSuperclassExpr() = a.asExpr().getExpr() and + pragma[only_bind_into](c).getSuperclassExpr() = a.asExpr().getExpr() and lbl = Label::subclass() ) or diff --git a/ruby/ql/lib/codeql/ruby/ast/Call.qll b/ruby/ql/lib/codeql/ruby/ast/Call.qll index 5339f080564..df9e1fa8403 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Call.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Call.qll @@ -145,6 +145,21 @@ class SetterMethodCall extends MethodCall, TMethodCallSynth { SetterMethodCall() { this = TMethodCallSynth(_, _, _, true, _) } final override string getAPrimaryQlClass() { result = "SetterMethodCall" } + + /** + * Gets the name of the method being called without the trailing `=`. For example, in the following + * two statements the target name is `value`: + * ```rb + * foo.value=(1) + * foo.value = 1 + * ``` + */ + final string getTargetName() { + exists(string methodName | + methodName = this.getMethodName() and + result = methodName.prefix(methodName.length() - 1) + ) + } } /** diff --git a/ruby/ql/lib/codeql/ruby/ast/Parameter.qll b/ruby/ql/lib/codeql/ruby/ast/Parameter.qll index 3b5ed80ff7f..549a7df9216 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Parameter.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Parameter.qll @@ -109,7 +109,7 @@ class NamedParameter extends Parameter, TNamedParameter { final VariableAccess getDefiningAccess() { result = this.getVariable().getDefiningAccess() or - result = this.(SimpleParameterSynthImpl).getDefininingAccess() + result = this.(SimpleParameterSynthImpl).getDefiningAccess() } override AstNode getAChild(string pred) { diff --git a/ruby/ql/lib/codeql/ruby/ast/Variable.qll b/ruby/ql/lib/codeql/ruby/ast/Variable.qll index 9952b70b2d1..714c98fa994 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Variable.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Variable.qll @@ -116,7 +116,7 @@ class VariableAccess extends Expr instanceof VariableAccessImpl { predicate isImplicitWrite() { implicitWriteAccess(toGenerated(this)) or - this = any(SimpleParameterSynthImpl p).getDefininingAccess() + this = any(SimpleParameterSynthImpl p).getDefiningAccess() or this = any(HashPattern p).getValue(_) or diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Parameter.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Parameter.qll index 0a0a7ddb708..dc7fb8c7695 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Parameter.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Parameter.qll @@ -38,7 +38,7 @@ class SimpleParameterRealImpl extends SimpleParameterImpl, TSimpleParameterReal class SimpleParameterSynthImpl extends SimpleParameterImpl, TSimpleParameterSynth { SimpleParameterSynthImpl() { this = TSimpleParameterSynth(_, _) } - LocalVariableAccessSynth getDefininingAccess() { synthChild(this, 0, result) } + LocalVariableAccessSynth getDefiningAccess() { synthChild(this, 0, result) } override LocalVariable getVariableImpl() { result = TLocalVariableSynth(this, _) } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll index 7adffd04ae3..e586d09be06 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll @@ -259,7 +259,8 @@ private module Cached { exists(any(Call c).getKeywordArgument(name)) or FlowSummaryImplSpecific::ParsePositions::isParsedKeywordParameterPosition(_, name) - } + } or + THashSplatArgumentPosition() cached newtype TParameterPosition = @@ -278,6 +279,7 @@ private module Cached { or FlowSummaryImplSpecific::ParsePositions::isParsedKeywordArgumentPosition(_, name) } or + THashSplatParameterPosition() or TAnyParameterPosition() } @@ -476,6 +478,9 @@ class ParameterPosition extends TParameterPosition { /** Holds if this position represents a keyword parameter named `name`. */ predicate isKeyword(string name) { this = TKeywordParameterPosition(name) } + /** Holds if this position represents a hash-splat parameter. */ + predicate isHashSplat() { this = THashSplatParameterPosition() } + /** * Holds if this position represents any parameter. This includes both positional * and named parameters. @@ -494,6 +499,8 @@ class ParameterPosition extends TParameterPosition { or exists(string name | this.isKeyword(name) and result = "keyword " + name) or + this.isHashSplat() and result = "**" + or this.isAny() and result = "any" } } @@ -512,6 +519,12 @@ class ArgumentPosition extends TArgumentPosition { /** Holds if this position represents a keyword argument named `name`. */ predicate isKeyword(string name) { this = TKeywordArgumentPosition(name) } + /** + * Holds if this position represents a synthesized argument containing all keyword + * arguments wrapped in a hash. + */ + predicate isHashSplat() { this = THashSplatArgumentPosition() } + /** Gets a textual representation of this position. */ string toString() { this.isSelf() and result = "self" @@ -521,6 +534,8 @@ class ArgumentPosition extends TArgumentPosition { exists(int pos | this.isPositional(pos) and result = "position " + pos) or exists(string name | this.isKeyword(name) and result = "keyword " + name) + or + this.isHashSplat() and result = "**" } } @@ -539,5 +554,7 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { or exists(string name | ppos.isKeyword(name) and apos.isKeyword(name)) or + ppos.isHashSplat() and apos.isHashSplat() + or ppos.isAny() and exists(apos) } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index 00068f46735..a6c73b1d893 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -7,6 +7,7 @@ private import DataFlowDispatch private import SsaImpl as SsaImpl private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImplSpecific as FlowSummaryImplSpecific +private import codeql.ruby.frameworks.data.ModelsAsData /** Gets the callable in which this node occurs. */ DataFlowCallable nodeGetEnclosingCallable(NodeImpl n) { result = n.getEnclosingCallable() } @@ -179,6 +180,7 @@ private class Argument extends CfgNodes::ExprCfgNode { this = call.getArgument(i) and not this.getExpr() instanceof BlockArgument and not this.getExpr().(Pair).getKey().getConstantValue().isSymbol(_) and + not this.getExpr() instanceof HashSplatExpr and arg.isPositional(i) ) or @@ -189,6 +191,10 @@ private class Argument extends CfgNodes::ExprCfgNode { ) or this = call.getReceiver() and arg.isSelf() + or + this = call.getAnArgument() and + this.getExpr() instanceof HashSplatExpr and + arg.isHashSplat() } /** Holds if this expression is the `i`th argument of `c`. */ @@ -216,7 +222,8 @@ private module Cached { TNormalParameterNode(Parameter p) { p instanceof SimpleParameter or p instanceof OptionalParameter or - p instanceof KeywordParameter + p instanceof KeywordParameter or + p instanceof HashSplatParameter } or TSelfParameterNode(MethodBase m) or TBlockParameterNode(MethodBase m) or @@ -232,6 +239,9 @@ private module Cached { } or TSummaryParameterNode(FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition pos) { FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos) + } or + THashSplatArgumentsNode(CfgNodes::ExprNodes::CallCfgNode c) { + exists(Argument arg | arg.isArgumentOf(c, any(ArgumentPosition pos | pos.isKeyword(_)))) } class TParameterNode = @@ -349,7 +359,22 @@ private module Cached { TUnknownElementContent() or TKnownPairValueContent(ConstantValue cv) or TUnknownPairValueContent() or - TFieldContent(string name) { name = any(InstanceVariable v).getName() } + TFieldContent(string name) { + name = any(InstanceVariable v).getName() + or + name = "@" + any(SetterMethodCall c).getTargetName() + or + // The following equation unfortunately leads to a non-monotonic recursion error: + // name = any(AccessPathToken a).getAnArgument("Field") + // Therefore, we use the following instead to extract the field names from the + // external model data. This, unfortunately, does not included any field names used + // in models defined in QL code. + exists(string input, string output | + ModelOutput::relevantSummaryModel(_, _, _, input, output, _) + | + name = [input, output].regexpFind("(?<=(^|\\.)Field\\[)[^\\]]+(?=\\])", _, _).trim() + ) + } /** * Holds if `e` is an `ExprNode` that may be returned by a call to `c`. @@ -389,6 +414,8 @@ predicate nodeIsHidden(Node n) { n instanceof SummaryParameterNode or n instanceof SynthReturnNode + or + n instanceof HashSplatArgumentsNode } /** An SSA definition, viewed as a node in a data flow graph. */ @@ -473,6 +500,9 @@ private module ParameterNodes { c.getAParameter() = kp and pos.isKeyword(kp.getName()) ) + or + parameter = c.getAParameter().(HashSplatParameter) and + pos.isHashSplat() } override CfgScope getCfgScope() { result = parameter.getCallable() } @@ -651,6 +681,40 @@ private module ArgumentNodes { FlowSummaryImpl::Private::summaryArgumentNode(call, this, pos) } } + + /** + * A data-flow node that represents all keyword arguments wrapped in a hash. + * + * The callee is responsible for filtering out the keyword arguments that are + * part of the method signature, such that those cannot end up in the hash-splat + * parameter. + */ + class HashSplatArgumentsNode extends ArgumentNode, THashSplatArgumentsNode { + CfgNodes::ExprNodes::CallCfgNode c; + + HashSplatArgumentsNode() { this = THashSplatArgumentsNode(c) } + + override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { + this.sourceArgumentOf(call.asCall(), pos) + } + + override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) { + call = c and + pos.isHashSplat() + } + } + + private class HashSplatArgumentsNodeImpl extends NodeImpl, THashSplatArgumentsNode { + CfgNodes::ExprNodes::CallCfgNode c; + + HashSplatArgumentsNodeImpl() { this = THashSplatArgumentsNode(c) } + + override CfgScope getCfgScope() { result = c.getExpr().getCfgScope() } + + override Location getLocationImpl() { result = c.getLocation() } + + override string toStringImpl() { result = "**" } + } } import ArgumentNodes @@ -807,6 +871,13 @@ predicate jumpStep(Node pred, Node succ) { succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr() } +private ContentSet getKeywordContent(string name) { + exists(ConstantValue::ConstantSymbolValue key | + result.isSingleton(TKnownElementContent(key)) and + key.isSymbol(name) + ) +} + /** * Holds if data can flow from `node1` to `node2` via an assignment to * content `c`. @@ -825,6 +896,16 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { ) ).getReceiver() or + // Attribute assignment, `receiver.property = value` + node2.(PostUpdateNode).getPreUpdateNode().asExpr() = + any(CfgNodes::ExprNodes::MethodCallCfgNode call | + node1.asExpr() = call.getArgument(0) and + call.getNumberOfArguments() = 1 and + c.isSingleton(any(Content::FieldContent ct | + ct.getName() = "@" + call.getExpr().(SetterMethodCall).getTargetName() + )) + ).getReceiver() + or FlowSummaryImpl::Private::Steps::summaryStoreStep(node1, c, node2) or // Needed for pairs passed into method calls where the key is not a symbol, @@ -845,6 +926,14 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { c.isSingleton(TUnknownPairValueContent()) ) ) + or + // Wrap all keyword arguments in a synthesized hash-splat argument node + exists(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition keywordPos, string name | + node2 = THashSplatArgumentsNode(call) and + node1.asExpr().(Argument).isArgumentOf(call, keywordPos) and + keywordPos.isKeyword(name) and + c = getKeywordContent(name) + ) } /** @@ -860,6 +949,19 @@ predicate readStep(Node node1, ContentSet c, Node node2) { )) ) or + // Attribute read, `receiver.field`. Note that we do not check whether + // the `field` method is really an attribute reader. This is probably fine + // because the read step has only effect if there exists a matching store step + // (instance variable assignment or setter method call). + node2.asExpr() = + any(CfgNodes::ExprNodes::MethodCallCfgNode call | + node1.asExpr() = call.getReceiver() and + call.getNumberOfArguments() = 0 and + c.isSingleton(any(Content::FieldContent ct | + ct.getName() = "@" + call.getExpr().getMethodName() + )) + ) + or FlowSummaryImpl::Private::Steps::summaryReadStep(node1, c, node2) } @@ -870,6 +972,19 @@ predicate readStep(Node node1, ContentSet c, Node node2) { */ predicate clearsContent(Node n, ContentSet c) { FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c) + or + // Filter out keyword arguments that are part of the method signature from + // the hash-splat parameter + exists( + DataFlowCallable callable, ParameterPosition hashSplatPos, ParameterNodeImpl keywordParam, + ParameterPosition keywordPos, string name + | + n.(ParameterNodes::NormalParameterNode).isParameterOf(callable, hashSplatPos) and + hashSplatPos.isHashSplat() and + keywordParam.isParameterOf(callable, keywordPos) and + keywordPos.isKeyword(name) and + c = getKeywordContent(name) + ) } /** diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImplSpecific.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImplSpecific.qll index 949f63fe1e9..4b1d3d8f5db 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImplSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImplSpecific.qll @@ -94,10 +94,16 @@ SummaryComponent interpretComponentSpecific(AccessPathToken c) { ppos.isAny() or ppos.isPositionalLowerBound(AccessPath::parseLowerBound(arg)) + or + arg = "hash-splat" and + ppos.isHashSplat() ) or result = interpretElementArg(c.getAnArgument("Element")) or + result = + FlowSummary::SummaryComponent::content(TSingletonContent(TFieldContent(c.getAnArgument("Field")))) + or exists(ContentSet cs | FlowSummary::SummaryComponent::content(cs) = interpretElementArg(c.getAnArgument("WithElement")) and result = FlowSummary::SummaryComponent::withContent(cs) diff --git a/ruby/ql/lib/codeql/ruby/experimental/Rbi.qll b/ruby/ql/lib/codeql/ruby/experimental/Rbi.qll new file mode 100644 index 00000000000..d4e620db343 --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/experimental/Rbi.qll @@ -0,0 +1,432 @@ +/** + * Provides classes and predicates for working with Ruby Interface (RBI) files + * and concepts. RBI files are valid Ruby files that can contain type + * information used by Sorbet for typechecking. + */ + +private import codeql.ruby.ApiGraphs +private import codeql.ruby.AST +private import codeql.ruby.CFG +private import codeql.ruby.controlflow.CfgNodes + +/** + * Provides classes and predicates for working with Ruby Interface (RBI) files + * and concepts. RBI files are valid Ruby files that can contain type + * information used by Sorbet for typechecking. + */ +module Rbi { + /** + * Contains classes representing RBI types. + */ + private module RbiTypes { + /** + * A node representing a Ruby Interface (RBI) type. + */ + abstract class RbiType extends Expr { } + + /** + * A `ConstantReadAccess` as an RBI type. This is typically a reference to a + * class or a constant representing a type alias - for example, the read + * accesses to `MyList1`, `Integer` and `MyList2` in: + * ```rb + * class MyList1; end + * MyList2 = T.type_alias(MyList1) + * sig { params(l: MyList2).returns(Integer) } + * def len(l); end + * ``` + */ + class ConstantReadAccessAsRbiType extends RbiType, ConstantReadAccess { } + + /** A method call where the receiver is `T`. */ + private class MethodCallAgainstT extends MethodCall { + MethodCallAgainstT() { this.getReceiver().(ConstantReadAccess).getName() = "T" } + } + + /** + * A call to `T.any` - a method that takes `RbiType` parameters, and returns + * a type representing the union of those types. + */ + class RbiUnionType extends RbiType, MethodCallAgainstT { + RbiUnionType() { this.getMethodName() = "any" } + + /** + * Gets a constituent type of this type union. + */ + RbiType getAType() { result = this.getArgument(_) } + } + + /** + * A call to `T.untyped`. + */ + class RbiUntypedType extends RbiType, MethodCallAgainstT { + RbiUntypedType() { this.getMethodName() = "untyped" } + } + + /** + * A call to `T.nilable`, creating a nilable version of the type provided as + * an argument. + */ + class RbiNilableType extends RbiType, MethodCallAgainstT { + RbiNilableType() { this.getMethodName() = "nilable" } + + /** Gets the type that this may represent if not nil. */ + RbiType getUnderlyingType() { result = this.getArgument(0) } + } + + /** + * A call to `T.type_alias`. The return value of this call can be assigned to + * create a type alias. + */ + class RbiTypeAlias extends RbiType, MethodCallAgainstT { + RbiTypeAlias() { this.getMethodName() = "type_alias" } + + /** + * Gets the type aliased by this call. + */ + RbiType getAliasedType() { + exists(ExprNodes::MethodCallCfgNode n | n.getExpr() = this | + result = n.getBlock().(ExprNodes::StmtSequenceCfgNode).getLastStmt().getExpr() + ) + } + } + + /** + * A call to `T.self_type`. + */ + class RbiSelfType extends RbiType, MethodCallAgainstT { + RbiSelfType() { this.getMethodName() = "self_type" } + } + + /** + * A call to `T.noreturn`. + */ + class RbiNoreturnType extends RbiType, MethodCallAgainstT { + RbiNoreturnType() { this.getMethodName() = "noreturn" } + } + + /** + * A `ConstantReadAccess` where the constant is from the `T` module. + */ + private class ConstantReadAccessFromT extends ConstantReadAccess { + ConstantReadAccessFromT() { this.getScopeExpr().(ConstantReadAccess).getName() = "T" } + } + + /** + * A use of `T::Boolean`. + */ + class RbiBooleanType extends RbiType, ConstantReadAccessFromT { + RbiBooleanType() { this.getName() = "Boolean" } + } + + /** + * A use of `T::Array`. + */ + class RbiArrayType extends RbiType, ConstantReadAccessFromT { + RbiArrayType() { this.getName() = "Array" } + + /** Gets the type of elements of this array. */ + RbiType getElementType() { + exists(ElementReference refNode | refNode.getReceiver() = this | + result = refNode.getArgument(0) + ) + } + } + + class RbiHashType extends RbiType, ConstantReadAccessFromT { + RbiHashType() { this.getName() = "Hash" } + + private ElementReference getRefNode() { result.getReceiver() = this } + + /** Gets the type of keys of this hash type. */ + Expr getKeyType() { result = this.getRefNode().getArgument(0) } + + /** Gets the type of values of this hash type. */ + Expr getValueType() { result = this.getRefNode().getArgument(1) } + } + + /** + * A call to `T.proc`. This defines a type signature for a proc or block + */ + class ProcCall extends RbiType, SignatureCall, MethodCallAgainstT { + ProcCall() { this.getMethodName() = "proc" } + + private ProcReturnsTypeCall getReturnsTypeCall() { result.getProcCall() = this } + + private ProcParamsCall getParamsCall() { result.getProcCall() = this } + + /** + * Gets the return type of this type signature. + */ + override ReturnType getReturnType() { result = this.getReturnsTypeCall().getReturnType() } + + /** + * Gets the type of a parameter of this type signature. + */ + override ParameterType getAParameterType() { + result = this.getParamsCall().getAParameterType() + } + // TODO: get associated method to which this can be passed + } + } + + import RbiTypes + + /** + * A Ruby Interface (RBI) File. These are valid Ruby files that can contain + * type information used by Sorbet for typechecking. + * + * RBI files can contain project source code, or act as external type + * definition files for existing Ruby code, which may include code in gems. + */ + class RbiFile extends File { + RbiFile() { this.getExtension() = "rbi" } + } + + private newtype TReturnType = + TRbiType(RbiType t) { exists(ReturnsCall r | r.getRbiType() = t) } or + TVoidType() + + /** A return type of a method. */ + class ReturnType extends TReturnType { + /** Gets a textual representation of this node. */ + cached + string toString() { + result = this.getRbiType().toString() + or + this.isVoidType() and result = "(void)" + } + + /** Gets the underlying RbiType, if any. */ + RbiType getRbiType() { exists(RbiType t | this = TRbiType(t) | result = t) } + + /** Holds if this is the void type. */ + predicate isVoidType() { this = TVoidType() } + } + + /** + * A call that defines a type signature for a method or proc. + */ + abstract class SignatureCall extends MethodCall { + /** + * Gets the return type of this type signature. + */ + abstract ReturnType getReturnType(); + + /** + * Gets the type of a parameter of this type signature. + */ + abstract ParameterType getAParameterType(); + } + + private predicate isMethodSignatureCallNode(CfgNode n) { + n.(ExprCfgNode).getExpr() instanceof MethodSignatureCall + } + + /** + * Holds if `n` is the `i`th transitive successor node of `sigNode` where there + * are no intervening nodes corresponding to `MethodSignatureCall`s. + */ + private predicate methodSignatureSuccessorNodeRanked(CfgNode sigNode, CfgNode n, int i) { + // direct successor + i = 1 and + n = sigNode.getASuccessor() and + not isMethodSignatureCallNode(n) + or + // transitive successor + i > 1 and + exists(CfgNode np | n = np.getASuccessor() | + methodSignatureSuccessorNodeRanked(sigNode, np, i - 1) and + not isMethodSignatureCallNode(np) + ) + } + + /** A call to `sig` to define the type signature of a method. */ + class MethodSignatureCall extends SignatureCall { + MethodSignatureCall() { this.getMethodName() = "sig" } + + private MethodReturnsTypeCall getReturnsTypeCall() { result.getMethodSignatureCall() = this } + + private MethodParamsCall getParamsCall() { result.getMethodSignatureCall() = this } + + private ExprCfgNode getCfgNode() { result.getExpr() = this } + + /** + * Gets the method whose type signature is defined by this call. + */ + MethodBase getAssociatedMethod() { + result = + min(ExprCfgNode methodCfgNode, int i | + methodSignatureSuccessorNodeRanked(this.getCfgNode(), methodCfgNode, i) and + methodCfgNode.getExpr() instanceof MethodBase + | + methodCfgNode order by i + ).getExpr() + } + + /** + * Gets a call to `attr_reader` or `attr_accessor` where the return type of + * the generated method is described by this call. + */ + MethodCall getAssociatedAttrReaderCall() { + result = + min(ExprNodes::MethodCallCfgNode c, int i | + c.getExpr().getMethodName() = ["attr_reader", "attr_accessor"] and + methodSignatureSuccessorNodeRanked(this.getCfgNode(), c, i) + | + c order by i + ).getExpr() + } + + /** + * Gets the return type of this type signature. + */ + override ReturnType getReturnType() { result = this.getReturnsTypeCall().getReturnType() } + + /** + * Gets the type of a parameter of this type signature. + */ + override ParameterType getAParameterType() { result = this.getParamsCall().getAParameterType() } + } + + /** + * A method call that defines either: + * - the parameters to, or + * - the return type of + * a method. + */ + class MethodSignatureDefiningCall extends MethodCall { + private MethodSignatureCall sigCall; + + MethodSignatureDefiningCall() { + exists(MethodCall c | c = sigCall.getBlock().getAChild() | + // The typical pattern for the contents of a `sig` block is something + // like `params().returns()` - we want to + // pick up both of these calls. + this = c.getReceiver*() + ) + } + + /** + * Gets the enclosing `sig` call that defines the overall type signature + * for the method associated with this call. + */ + MethodSignatureCall getMethodSignatureCall() { result = sigCall } + } + + /** + * A call to `params`. This defines the types of parameters to a method or proc. + */ + class ParamsCall extends MethodCall { + ParamsCall() { this.getMethodName() = "params" } + + /** + * Gets the type of a parameter defined by this call. + */ + ParameterType getAParameterType() { result = this.getArgument(_) } + } + + abstract class ReturnsTypeCall extends MethodCall { + abstract ReturnType getReturnType(); + } + + /** + * A call to `returns`. Defines the return type of a method or proc. + */ + class ReturnsCall extends MethodCall { + ReturnsCall() { this.getMethodName() = "returns" } + + /** + * Gets the `RbiType` return type of this call. + */ + RbiType getRbiType() { result = this.getArgument(0) } + + /** + * Gets the wrapped `ReturnType` of this call. + */ + ReturnType getReturnType() { result.getRbiType() = this.getRbiType() } + } + + /** + * A call to `void`. Essentially a "don't-care" for the return type of a method or proc. + */ + class VoidCall extends MethodCall { + VoidCall() { this.getMethodName() = "void" } + + /** + * Gets the wrapped `ReturnType` of this call. + */ + ReturnType getReturnType() { result.isVoidType() } + } + + /** A call that defines the return type of a method. */ + abstract class MethodReturnsTypeCall extends ReturnsTypeCall, MethodSignatureDefiningCall { } + + /** A call to `params` that defines the parameter types of a method */ + class MethodParamsCall extends ParamsCall, MethodSignatureDefiningCall { } + + /** A call to `returns` that defines the return type of a method. */ + class MethodReturnsCall extends MethodReturnsTypeCall instanceof ReturnsCall { + override ReturnType getReturnType() { result = ReturnsCall.super.getReturnType() } + } + + /** A call to `void` that spcifies that a given method does not return a useful value. */ + class MethodVoidCall extends MethodReturnsTypeCall instanceof VoidCall { + override ReturnType getReturnType() { result = VoidCall.super.getReturnType() } + } + + /** A call that defines part of the type signature of a proc or block argument. */ + class ProcSignatureDefiningCall extends MethodCall, RbiType { + private ProcCall procCall; + + ProcSignatureDefiningCall() { this.getReceiver+() = procCall } + + /** + * Gets the `proc` call that defines the complete type signature for the + * associated proc or block argument. + */ + ProcCall getProcCall() { result = procCall } + } + + /** A call that defines the return type of a proc or block */ + abstract class ProcReturnsTypeCall extends ReturnsTypeCall, ProcSignatureDefiningCall { } + + /** A call that defines the parameter types of a proc or block. */ + class ProcParamsCall extends ParamsCall, ProcSignatureDefiningCall { } + + /** A call that defines the return type of a non-void proc or block. */ + class ProcReturnsCall extends ProcReturnsTypeCall instanceof ReturnsCall { + override ReturnType getReturnType() { result = ReturnsCall.super.getReturnType() } + } + + /** + * A call to `void` that spcifies that a given proc or block does not return + * a useful value. + */ + class ProcVoidCall extends ProcReturnsTypeCall instanceof VoidCall { + override ReturnType getReturnType() { result = VoidCall.super.getReturnType() } + } + + /** + * A pair defining the type of a parameter to a method. + */ + class ParameterType extends Pair { + private RbiType t; + + ParameterType() { t = this.getValue() } + + /** Gets the `RbiType` of this parameter. */ + RbiType getType() { result = t } + + private SignatureCall getOuterMethodSignatureCall() { this = result.getAParameterType() } + + private MethodBase getAssociatedMethod() { + result = this.getOuterMethodSignatureCall().(MethodSignatureCall).getAssociatedMethod() + } + + /** Gets the parameter to which this type applies. */ + NamedParameter getParameter() { + result = this.getAssociatedMethod().getAParameter() and + result.getName() = this.getKey().getConstantValue().getStringlikeValue() + } + } +} diff --git a/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll b/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll index 6f0d43fb2aa..f9e97276681 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll @@ -275,7 +275,18 @@ private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation exists(MethodCall call, Expr recv | call = this.asExpr().getExpr() and recv = getUltimateReceiver(call) and - resolveConstant(recv) = cls.getAQualifiedName() and + ( + // The receiver refers to an `ActiveRecordModelClass` by name + resolveConstant(recv) = cls.getAQualifiedName() + or + // The receiver is self, and the call is within a singleton method of + // the `ActiveRecordModelClass` + recv instanceof SelfVariableAccess and + exists(SingletonMethod callScope | + callScope = call.getCfgScope() and + callScope = cls.getAMethod() + ) + ) and call.getMethodName() = finderMethodName() ) } @@ -293,18 +304,24 @@ private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInsta m = this.getCfgScope() and m.getEnclosingModule() = cls and m = cls.getAMethod() - ) + ) and + // In a singleton method, `self` refers to the class itself rather than an + // instance of that class + not this.getSelfScope() instanceof SingletonMethod } final override ActiveRecordModelClass getClass() { result = cls } } -// A (locally tracked) active record model object -private class ActiveRecordInstance extends DataFlow::Node { +/** + * An instance of an `ActiveRecord` model object. + */ +class ActiveRecordInstance extends DataFlow::Node { private ActiveRecordModelInstantiation instantiation; ActiveRecordInstance() { this = instantiation or instantiation.flowsTo(this) } + /** Gets the `ActiveRecordModelClass` that this is an instance of. */ ActiveRecordModelClass getClass() { result = instantiation.getClass() } } diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Core.qll b/ruby/ql/lib/codeql/ruby/frameworks/Core.qll index 54c8207b7a4..1ef6d8d65e5 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Core.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Core.qll @@ -73,3 +73,15 @@ private class SplatSummary extends SummarizedCallable { preservesValue = true } } + +private class HashSplatSummary extends SummarizedCallable { + HashSplatSummary() { this = "**(hash-splat)" } + + override HashSplatExpr getACall() { any() } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + input = "Argument[self].WithElement[any]" and + output = "ReturnValue" and + preservesValue = true + } +} diff --git a/ruby/ql/lib/codeql/ruby/frameworks/core/Hash.qll b/ruby/ql/lib/codeql/ruby/frameworks/core/Hash.qll index 0d4be60e9fb..2cce0b78957 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/core/Hash.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/core/Hash.qll @@ -65,6 +65,22 @@ module Hash { } } + private class HashLiteralHashSplatSummary extends SummarizedCallable { + HashLiteralHashSplatSummary() { this = "Hash.[**]" } + + final override MethodCall getACall() { + result = API::getTopLevelMember("Hash").getAMethodCall("[]").getExprNode().getExpr() and + result.getAnArgument() instanceof HashSplatExpr + } + + override predicate propagatesFlowExt(string input, string output, boolean preservesValue) { + // { **hash } + input = "Argument[hash-splat].WithElement[any]" and + output = "ReturnValue" and + preservesValue = true + } + } + /** * `Hash[]` called on an existing hash, e.g. * diff --git a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll index 127d9ca5122..69563a3eab4 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll @@ -299,7 +299,7 @@ private class AccessPathRange extends AccessPath::Range { bindingset[token] API::Node getSuccessorFromNode(API::Node node, AccessPathToken token) { // API graphs use the same label for arguments and parameters. An edge originating from a - // use-node represents be an argument, and an edge originating from a def-node represents a parameter. + // use-node represents an argument, and an edge originating from a def-node represents a parameter. // We just map both to the same thing. token.getName() = ["Argument", "Parameter"] and result = node.getParameter(AccessPath::parseIntUnbounded(token.getAnArgument())) diff --git a/ruby/ql/src/queries/security/cwe-116/IncompleteSanitization.qhelp b/ruby/ql/src/queries/security/cwe-116/IncompleteSanitization.qhelp index 4b1c31cb5d7..70fb90666f1 100644 --- a/ruby/ql/src/queries/security/cwe-116/IncompleteSanitization.qhelp +++ b/ruby/ql/src/queries/security/cwe-116/IncompleteSanitization.qhelp @@ -44,7 +44,7 @@ replace further instances of the string that result from earlier replacements.

For example, consider the code snippet s.gsub /\/\.\.\//, "", which attempts to strip -out all occurences of /../ from s. This will not work as expected: for the +out all occurrences of /../ from s. This will not work as expected: for the string /./.././, for example, it will remove the single occurrence of /../ in the middle, but the remainder of the string then becomes /../, which is another instance of the substring we were trying to remove. diff --git a/ruby/ql/src/queries/security/cwe-116/IncompleteSanitization.ql b/ruby/ql/src/queries/security/cwe-116/IncompleteSanitization.ql index 0c80e8847c9..f6090387261 100644 --- a/ruby/ql/src/queries/security/cwe-116/IncompleteSanitization.ql +++ b/ruby/ql/src/queries/security/cwe-116/IncompleteSanitization.ql @@ -116,7 +116,7 @@ predicate allBackslashesEscaped(DataFlow::Node node) { * Holds if `sub` looks like a string substitution call that deliberately * removes the first occurrence of `str`. */ -predicate removesFirstOccurence(StringSubstitutionCall sub, string str) { +predicate removesFirstOccurrence(StringSubstitutionCall sub, string str) { not sub.isGlobal() and sub.replaces(str, "") } @@ -158,8 +158,8 @@ predicate isDelimiterUnwrapper(StringSubstitutionCall leftUnwrap, StringSubstitu or left = "'" and right = "'" | - removesFirstOccurence(leftUnwrap, left) and - removesFirstOccurence(rightUnwrap, right) and + removesFirstOccurrence(leftUnwrap, left) and + removesFirstOccurrence(rightUnwrap, right) and rightUnwrap = getAMethodCall(leftUnwrap) ) } diff --git a/ruby/ql/test/library-tests/dataflow/global/Flow.expected b/ruby/ql/test/library-tests/dataflow/global/Flow.expected index 7975d3d5eb1..9ee03271537 100644 --- a/ruby/ql/test/library-tests/dataflow/global/Flow.expected +++ b/ruby/ql/test/library-tests/dataflow/global/Flow.expected @@ -33,6 +33,34 @@ edges | instance_variables.rb:20:15:20:23 | call to source : | instance_variables.rb:20:1:20:3 | [post] bar [@field] : | | instance_variables.rb:21:6:21:8 | bar [@field] : | instance_variables.rb:8:5:10:7 | self in inc_field [@field] : | | instance_variables.rb:21:6:21:8 | bar [@field] : | instance_variables.rb:21:6:21:18 | call to inc_field | +| instance_variables.rb:24:1:24:4 | [post] foo1 [@field] : | instance_variables.rb:25:6:25:9 | foo1 [@field] : | +| instance_variables.rb:24:1:24:4 | [post] foo1 [@field] : | instance_variables.rb:25:6:25:9 | foo1 [@field] : | +| instance_variables.rb:24:14:24:23 | call to source : | instance_variables.rb:24:1:24:4 | [post] foo1 [@field] : | +| instance_variables.rb:24:14:24:23 | call to source : | instance_variables.rb:24:1:24:4 | [post] foo1 [@field] : | +| instance_variables.rb:25:6:25:9 | foo1 [@field] : | instance_variables.rb:25:6:25:15 | call to field | +| instance_variables.rb:25:6:25:9 | foo1 [@field] : | instance_variables.rb:25:6:25:15 | call to field | +| instance_variables.rb:28:1:28:4 | [post] foo2 [@field] : | instance_variables.rb:29:6:29:9 | foo2 [@field] : | +| instance_variables.rb:28:1:28:4 | [post] foo2 [@field] : | instance_variables.rb:29:6:29:9 | foo2 [@field] : | +| instance_variables.rb:28:14:28:23 | call to source : | instance_variables.rb:28:1:28:4 | [post] foo2 [@field] : | +| instance_variables.rb:28:14:28:23 | call to source : | instance_variables.rb:28:1:28:4 | [post] foo2 [@field] : | +| instance_variables.rb:29:6:29:9 | foo2 [@field] : | instance_variables.rb:5:5:7:7 | self in get_field [@field] : | +| instance_variables.rb:29:6:29:9 | foo2 [@field] : | instance_variables.rb:5:5:7:7 | self in get_field [@field] : | +| instance_variables.rb:29:6:29:9 | foo2 [@field] : | instance_variables.rb:29:6:29:19 | call to get_field | +| instance_variables.rb:29:6:29:9 | foo2 [@field] : | instance_variables.rb:29:6:29:19 | call to get_field | +| instance_variables.rb:32:1:32:4 | [post] foo3 [@field] : | instance_variables.rb:33:6:33:9 | foo3 [@field] : | +| instance_variables.rb:32:1:32:4 | [post] foo3 [@field] : | instance_variables.rb:33:6:33:9 | foo3 [@field] : | +| instance_variables.rb:32:16:32:25 | call to source : | instance_variables.rb:2:19:2:19 | x : | +| instance_variables.rb:32:16:32:25 | call to source : | instance_variables.rb:2:19:2:19 | x : | +| instance_variables.rb:32:16:32:25 | call to source : | instance_variables.rb:32:1:32:4 | [post] foo3 [@field] : | +| instance_variables.rb:32:16:32:25 | call to source : | instance_variables.rb:32:1:32:4 | [post] foo3 [@field] : | +| instance_variables.rb:33:6:33:9 | foo3 [@field] : | instance_variables.rb:33:6:33:15 | call to field | +| instance_variables.rb:33:6:33:9 | foo3 [@field] : | instance_variables.rb:33:6:33:15 | call to field | +| instance_variables.rb:36:1:36:4 | [post] foo4 [@other] : | instance_variables.rb:37:6:37:9 | foo4 [@other] : | +| instance_variables.rb:36:1:36:4 | [post] foo4 [@other] : | instance_variables.rb:37:6:37:9 | foo4 [@other] : | +| instance_variables.rb:36:14:36:23 | call to source : | instance_variables.rb:36:1:36:4 | [post] foo4 [@other] : | +| instance_variables.rb:36:14:36:23 | call to source : | instance_variables.rb:36:1:36:4 | [post] foo4 [@other] : | +| instance_variables.rb:37:6:37:9 | foo4 [@other] : | instance_variables.rb:37:6:37:15 | call to other | +| instance_variables.rb:37:6:37:9 | foo4 [@other] : | instance_variables.rb:37:6:37:15 | call to other | nodes | instance_variables.rb:2:19:2:19 | x : | semmle.label | x : | | instance_variables.rb:2:19:2:19 | x : | semmle.label | x : | @@ -70,6 +98,38 @@ nodes | instance_variables.rb:20:15:20:23 | call to source : | semmle.label | call to source : | | instance_variables.rb:21:6:21:8 | bar [@field] : | semmle.label | bar [@field] : | | instance_variables.rb:21:6:21:18 | call to inc_field | semmle.label | call to inc_field | +| instance_variables.rb:24:1:24:4 | [post] foo1 [@field] : | semmle.label | [post] foo1 [@field] : | +| instance_variables.rb:24:1:24:4 | [post] foo1 [@field] : | semmle.label | [post] foo1 [@field] : | +| instance_variables.rb:24:14:24:23 | call to source : | semmle.label | call to source : | +| instance_variables.rb:24:14:24:23 | call to source : | semmle.label | call to source : | +| instance_variables.rb:25:6:25:9 | foo1 [@field] : | semmle.label | foo1 [@field] : | +| instance_variables.rb:25:6:25:9 | foo1 [@field] : | semmle.label | foo1 [@field] : | +| instance_variables.rb:25:6:25:15 | call to field | semmle.label | call to field | +| instance_variables.rb:25:6:25:15 | call to field | semmle.label | call to field | +| instance_variables.rb:28:1:28:4 | [post] foo2 [@field] : | semmle.label | [post] foo2 [@field] : | +| instance_variables.rb:28:1:28:4 | [post] foo2 [@field] : | semmle.label | [post] foo2 [@field] : | +| instance_variables.rb:28:14:28:23 | call to source : | semmle.label | call to source : | +| instance_variables.rb:28:14:28:23 | call to source : | semmle.label | call to source : | +| instance_variables.rb:29:6:29:9 | foo2 [@field] : | semmle.label | foo2 [@field] : | +| instance_variables.rb:29:6:29:9 | foo2 [@field] : | semmle.label | foo2 [@field] : | +| instance_variables.rb:29:6:29:19 | call to get_field | semmle.label | call to get_field | +| instance_variables.rb:29:6:29:19 | call to get_field | semmle.label | call to get_field | +| instance_variables.rb:32:1:32:4 | [post] foo3 [@field] : | semmle.label | [post] foo3 [@field] : | +| instance_variables.rb:32:1:32:4 | [post] foo3 [@field] : | semmle.label | [post] foo3 [@field] : | +| instance_variables.rb:32:16:32:25 | call to source : | semmle.label | call to source : | +| instance_variables.rb:32:16:32:25 | call to source : | semmle.label | call to source : | +| instance_variables.rb:33:6:33:9 | foo3 [@field] : | semmle.label | foo3 [@field] : | +| instance_variables.rb:33:6:33:9 | foo3 [@field] : | semmle.label | foo3 [@field] : | +| instance_variables.rb:33:6:33:15 | call to field | semmle.label | call to field | +| instance_variables.rb:33:6:33:15 | call to field | semmle.label | call to field | +| instance_variables.rb:36:1:36:4 | [post] foo4 [@other] : | semmle.label | [post] foo4 [@other] : | +| instance_variables.rb:36:1:36:4 | [post] foo4 [@other] : | semmle.label | [post] foo4 [@other] : | +| instance_variables.rb:36:14:36:23 | call to source : | semmle.label | call to source : | +| instance_variables.rb:36:14:36:23 | call to source : | semmle.label | call to source : | +| instance_variables.rb:37:6:37:9 | foo4 [@other] : | semmle.label | foo4 [@other] : | +| instance_variables.rb:37:6:37:9 | foo4 [@other] : | semmle.label | foo4 [@other] : | +| instance_variables.rb:37:6:37:15 | call to other | semmle.label | call to other | +| instance_variables.rb:37:6:37:15 | call to other | semmle.label | call to other | subpaths | instance_variables.rb:16:15:16:24 | call to source : | instance_variables.rb:2:19:2:19 | x : | instance_variables.rb:3:9:3:14 | [post] self [@field] : | instance_variables.rb:16:1:16:3 | [post] foo [@field] : | | instance_variables.rb:16:15:16:24 | call to source : | instance_variables.rb:2:19:2:19 | x : | instance_variables.rb:3:9:3:14 | [post] self [@field] : | instance_variables.rb:16:1:16:3 | [post] foo [@field] : | @@ -78,7 +138,15 @@ subpaths | instance_variables.rb:20:15:20:23 | call to source : | instance_variables.rb:2:19:2:19 | x : | instance_variables.rb:3:9:3:14 | [post] self [@field] : | instance_variables.rb:20:1:20:3 | [post] bar [@field] : | | instance_variables.rb:21:6:21:8 | bar [@field] : | instance_variables.rb:8:5:10:7 | self in inc_field [@field] : | instance_variables.rb:8:5:10:7 | self in inc_field [@field] : | instance_variables.rb:21:6:21:18 | call to inc_field | | instance_variables.rb:21:6:21:8 | bar [@field] : | instance_variables.rb:8:5:10:7 | self in inc_field [@field] : | instance_variables.rb:9:9:9:14 | [post] self [@field] : | instance_variables.rb:21:6:21:18 | call to inc_field | +| instance_variables.rb:29:6:29:9 | foo2 [@field] : | instance_variables.rb:5:5:7:7 | self in get_field [@field] : | instance_variables.rb:6:9:6:21 | return : | instance_variables.rb:29:6:29:19 | call to get_field | +| instance_variables.rb:29:6:29:9 | foo2 [@field] : | instance_variables.rb:5:5:7:7 | self in get_field [@field] : | instance_variables.rb:6:9:6:21 | return : | instance_variables.rb:29:6:29:19 | call to get_field | +| instance_variables.rb:32:16:32:25 | call to source : | instance_variables.rb:2:19:2:19 | x : | instance_variables.rb:3:9:3:14 | [post] self [@field] : | instance_variables.rb:32:1:32:4 | [post] foo3 [@field] : | +| instance_variables.rb:32:16:32:25 | call to source : | instance_variables.rb:2:19:2:19 | x : | instance_variables.rb:3:9:3:14 | [post] self [@field] : | instance_variables.rb:32:1:32:4 | [post] foo3 [@field] : | #select | instance_variables.rb:12:10:12:13 | @foo | instance_variables.rb:11:12:11:22 | call to source : | instance_variables.rb:12:10:12:13 | @foo | $@ | instance_variables.rb:11:12:11:22 | call to source : | call to source : | | instance_variables.rb:17:6:17:18 | call to get_field | instance_variables.rb:16:15:16:24 | call to source : | instance_variables.rb:17:6:17:18 | call to get_field | $@ | instance_variables.rb:16:15:16:24 | call to source : | call to source : | | instance_variables.rb:21:6:21:18 | call to inc_field | instance_variables.rb:20:15:20:23 | call to source : | instance_variables.rb:21:6:21:18 | call to inc_field | $@ | instance_variables.rb:20:15:20:23 | call to source : | call to source : | +| instance_variables.rb:25:6:25:15 | call to field | instance_variables.rb:24:14:24:23 | call to source : | instance_variables.rb:25:6:25:15 | call to field | $@ | instance_variables.rb:24:14:24:23 | call to source : | call to source : | +| instance_variables.rb:29:6:29:19 | call to get_field | instance_variables.rb:28:14:28:23 | call to source : | instance_variables.rb:29:6:29:19 | call to get_field | $@ | instance_variables.rb:28:14:28:23 | call to source : | call to source : | +| instance_variables.rb:33:6:33:15 | call to field | instance_variables.rb:32:16:32:25 | call to source : | instance_variables.rb:33:6:33:15 | call to field | $@ | instance_variables.rb:32:16:32:25 | call to source : | call to source : | +| instance_variables.rb:37:6:37:15 | call to other | instance_variables.rb:36:14:36:23 | call to source : | instance_variables.rb:37:6:37:15 | call to other | $@ | instance_variables.rb:36:14:36:23 | call to source : | call to source : | diff --git a/ruby/ql/test/library-tests/dataflow/global/instance_variables.rb b/ruby/ql/test/library-tests/dataflow/global/instance_variables.rb index be91c6da8fb..93bdf207be2 100644 --- a/ruby/ql/test/library-tests/dataflow/global/instance_variables.rb +++ b/ruby/ql/test/library-tests/dataflow/global/instance_variables.rb @@ -18,4 +18,20 @@ sink(foo.get_field) # $ hasValueFlow=42 bar = Foo.new bar.set_field(source(5)) -sink(bar.inc_field) # $ hasTaintFlow=5 \ No newline at end of file +sink(bar.inc_field) # $ hasTaintFlow=5 + +foo1 = Foo.new +foo1.field = source(20) +sink(foo1.field) # $ hasValueFlow=20 + +foo2 = Foo.new +foo2.field = source(21) +sink(foo2.get_field) # $ hasValueFlow=21 + +foo3 = Foo.new +foo3.set_field(source(22)) +sink(foo3.field) # $ hasValueFlow=22 + +foo4 = "hello" +foo4.other = source(23) +sink(foo4.other) # $ hasValueFlow=23 diff --git a/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected b/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected index a573f2cfc99..a3ce961c7a9 100644 --- a/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/hash-flow/hash-flow.expected @@ -508,6 +508,24 @@ edges | hash_flow.rb:721:9:721:12 | hash [element :c] : | hash_flow.rb:721:9:721:31 | call to fetch_values [element] : | | hash_flow.rb:721:9:721:31 | call to fetch_values [element] : | hash_flow.rb:722:10:722:10 | b [element] : | | hash_flow.rb:722:10:722:10 | b [element] : | hash_flow.rb:722:10:722:13 | ...[...] | +| hash_flow.rb:729:15:729:25 | call to taint : | hash_flow.rb:738:16:738:20 | hash1 [element :a] : | +| hash_flow.rb:731:15:731:25 | call to taint : | hash_flow.rb:738:16:738:20 | hash1 [element :c] : | +| hash_flow.rb:734:15:734:25 | call to taint : | hash_flow.rb:738:44:738:48 | hash2 [element :d] : | +| hash_flow.rb:736:15:736:25 | call to taint : | hash_flow.rb:738:44:738:48 | hash2 [element :f] : | +| hash_flow.rb:738:14:738:20 | ** ... [element :a] : | hash_flow.rb:739:10:739:13 | hash [element :a] : | +| hash_flow.rb:738:14:738:20 | ** ... [element :c] : | hash_flow.rb:741:10:741:13 | hash [element :c] : | +| hash_flow.rb:738:16:738:20 | hash1 [element :a] : | hash_flow.rb:738:14:738:20 | ** ... [element :a] : | +| hash_flow.rb:738:16:738:20 | hash1 [element :c] : | hash_flow.rb:738:14:738:20 | ** ... [element :c] : | +| hash_flow.rb:738:29:738:39 | call to taint : | hash_flow.rb:745:10:745:13 | hash [element :g] : | +| hash_flow.rb:738:42:738:48 | ** ... [element :d] : | hash_flow.rb:742:10:742:13 | hash [element :d] : | +| hash_flow.rb:738:42:738:48 | ** ... [element :f] : | hash_flow.rb:744:10:744:13 | hash [element :f] : | +| hash_flow.rb:738:44:738:48 | hash2 [element :d] : | hash_flow.rb:738:42:738:48 | ** ... [element :d] : | +| hash_flow.rb:738:44:738:48 | hash2 [element :f] : | hash_flow.rb:738:42:738:48 | ** ... [element :f] : | +| hash_flow.rb:739:10:739:13 | hash [element :a] : | hash_flow.rb:739:10:739:17 | ...[...] | +| hash_flow.rb:741:10:741:13 | hash [element :c] : | hash_flow.rb:741:10:741:17 | ...[...] | +| hash_flow.rb:742:10:742:13 | hash [element :d] : | hash_flow.rb:742:10:742:17 | ...[...] | +| hash_flow.rb:744:10:744:13 | hash [element :f] : | hash_flow.rb:744:10:744:17 | ...[...] | +| hash_flow.rb:745:10:745:13 | hash [element :g] : | hash_flow.rb:745:10:745:17 | ...[...] | nodes | hash_flow.rb:11:15:11:24 | call to taint : | semmle.label | call to taint : | | hash_flow.rb:13:12:13:21 | call to taint : | semmle.label | call to taint : | @@ -1062,6 +1080,29 @@ nodes | hash_flow.rb:721:9:721:31 | call to fetch_values [element] : | semmle.label | call to fetch_values [element] : | | hash_flow.rb:722:10:722:10 | b [element] : | semmle.label | b [element] : | | hash_flow.rb:722:10:722:13 | ...[...] | semmle.label | ...[...] | +| hash_flow.rb:729:15:729:25 | call to taint : | semmle.label | call to taint : | +| hash_flow.rb:731:15:731:25 | call to taint : | semmle.label | call to taint : | +| hash_flow.rb:734:15:734:25 | call to taint : | semmle.label | call to taint : | +| hash_flow.rb:736:15:736:25 | call to taint : | semmle.label | call to taint : | +| hash_flow.rb:738:14:738:20 | ** ... [element :a] : | semmle.label | ** ... [element :a] : | +| hash_flow.rb:738:14:738:20 | ** ... [element :c] : | semmle.label | ** ... [element :c] : | +| hash_flow.rb:738:16:738:20 | hash1 [element :a] : | semmle.label | hash1 [element :a] : | +| hash_flow.rb:738:16:738:20 | hash1 [element :c] : | semmle.label | hash1 [element :c] : | +| hash_flow.rb:738:29:738:39 | call to taint : | semmle.label | call to taint : | +| hash_flow.rb:738:42:738:48 | ** ... [element :d] : | semmle.label | ** ... [element :d] : | +| hash_flow.rb:738:42:738:48 | ** ... [element :f] : | semmle.label | ** ... [element :f] : | +| hash_flow.rb:738:44:738:48 | hash2 [element :d] : | semmle.label | hash2 [element :d] : | +| hash_flow.rb:738:44:738:48 | hash2 [element :f] : | semmle.label | hash2 [element :f] : | +| hash_flow.rb:739:10:739:13 | hash [element :a] : | semmle.label | hash [element :a] : | +| hash_flow.rb:739:10:739:17 | ...[...] | semmle.label | ...[...] | +| hash_flow.rb:741:10:741:13 | hash [element :c] : | semmle.label | hash [element :c] : | +| hash_flow.rb:741:10:741:17 | ...[...] | semmle.label | ...[...] | +| hash_flow.rb:742:10:742:13 | hash [element :d] : | semmle.label | hash [element :d] : | +| hash_flow.rb:742:10:742:17 | ...[...] | semmle.label | ...[...] | +| hash_flow.rb:744:10:744:13 | hash [element :f] : | semmle.label | hash [element :f] : | +| hash_flow.rb:744:10:744:17 | ...[...] | semmle.label | ...[...] | +| hash_flow.rb:745:10:745:13 | hash [element :g] : | semmle.label | hash [element :g] : | +| hash_flow.rb:745:10:745:17 | ...[...] | semmle.label | ...[...] | subpaths #select | hash_flow.rb:22:10:22:17 | ...[...] | hash_flow.rb:11:15:11:24 | call to taint : | hash_flow.rb:22:10:22:17 | ...[...] | $@ | hash_flow.rb:11:15:11:24 | call to taint : | call to taint : | @@ -1229,3 +1270,8 @@ subpaths | hash_flow.rb:720:10:720:13 | ...[...] | hash_flow.rb:715:15:715:25 | call to taint : | hash_flow.rb:720:10:720:13 | ...[...] | $@ | hash_flow.rb:715:15:715:25 | call to taint : | call to taint : | | hash_flow.rb:722:10:722:13 | ...[...] | hash_flow.rb:715:15:715:25 | call to taint : | hash_flow.rb:722:10:722:13 | ...[...] | $@ | hash_flow.rb:715:15:715:25 | call to taint : | call to taint : | | hash_flow.rb:722:10:722:13 | ...[...] | hash_flow.rb:717:15:717:25 | call to taint : | hash_flow.rb:722:10:722:13 | ...[...] | $@ | hash_flow.rb:717:15:717:25 | call to taint : | call to taint : | +| hash_flow.rb:739:10:739:17 | ...[...] | hash_flow.rb:729:15:729:25 | call to taint : | hash_flow.rb:739:10:739:17 | ...[...] | $@ | hash_flow.rb:729:15:729:25 | call to taint : | call to taint : | +| hash_flow.rb:741:10:741:17 | ...[...] | hash_flow.rb:731:15:731:25 | call to taint : | hash_flow.rb:741:10:741:17 | ...[...] | $@ | hash_flow.rb:731:15:731:25 | call to taint : | call to taint : | +| hash_flow.rb:742:10:742:17 | ...[...] | hash_flow.rb:734:15:734:25 | call to taint : | hash_flow.rb:742:10:742:17 | ...[...] | $@ | hash_flow.rb:734:15:734:25 | call to taint : | call to taint : | +| hash_flow.rb:744:10:744:17 | ...[...] | hash_flow.rb:736:15:736:25 | call to taint : | hash_flow.rb:744:10:744:17 | ...[...] | $@ | hash_flow.rb:736:15:736:25 | call to taint : | call to taint : | +| hash_flow.rb:745:10:745:17 | ...[...] | hash_flow.rb:738:29:738:39 | call to taint : | hash_flow.rb:745:10:745:17 | ...[...] | $@ | hash_flow.rb:738:29:738:39 | call to taint : | call to taint : | diff --git a/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb b/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb index 065cc5d5bd3..f9de83dd47c 100644 --- a/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb +++ b/ruby/ql/test/library-tests/dataflow/hash-flow/hash_flow.rb @@ -723,3 +723,27 @@ def m44(x) end m44(:c) + +def m45() + hash1 = { + :a => taint(45.1), + :b => 1, + :c => taint(45.2) + } + hash2 = { + :d => taint(45.3), + :e => 2, + :f => taint(45.4) + } + hash = { **hash1, :g => taint(45.5), **hash2, :h => 3 } + sink(hash[:a]) # $ hasValueFlow=45.1 + sink(hash[:b]) + sink(hash[:c]) # $ hasValueFlow=45.2 + sink(hash[:d]) # $ hasValueFlow=45.3 + sink(hash[:e]) + sink(hash[:f]) # $ hasValueFlow=45.4 + sink(hash[:g]) # $ hasValueFlow=45.5 + sink(hash[:h]) +end + +m45() \ No newline at end of file diff --git a/ruby/ql/test/library-tests/dataflow/params/params-flow.expected b/ruby/ql/test/library-tests/dataflow/params/params-flow.expected index 1caa2604b11..3df4f046a07 100644 --- a/ruby/ql/test/library-tests/dataflow/params/params-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/params/params-flow.expected @@ -12,6 +12,20 @@ edges | params_flow.rb:22:27:22:34 | call to taint : | params_flow.rb:16:13:16:14 | p1 : | | params_flow.rb:23:16:23:23 | call to taint : | params_flow.rb:16:18:16:19 | p2 : | | params_flow.rb:23:33:23:40 | call to taint : | params_flow.rb:16:13:16:14 | p1 : | +| params_flow.rb:25:12:25:13 | p1 : | params_flow.rb:26:10:26:11 | p1 | +| params_flow.rb:25:17:25:24 | **kwargs [element :p2] : | params_flow.rb:28:11:28:16 | kwargs [element :p2] : | +| params_flow.rb:25:17:25:24 | **kwargs [element :p3] : | params_flow.rb:29:11:29:16 | kwargs [element :p3] : | +| params_flow.rb:28:11:28:16 | kwargs [element :p2] : | params_flow.rb:28:11:28:21 | ...[...] : | +| params_flow.rb:28:11:28:21 | ...[...] : | params_flow.rb:28:10:28:22 | ( ... ) | +| params_flow.rb:29:11:29:16 | kwargs [element :p3] : | params_flow.rb:29:11:29:21 | ...[...] : | +| params_flow.rb:29:11:29:21 | ...[...] : | params_flow.rb:29:10:29:22 | ( ... ) | +| params_flow.rb:33:12:33:19 | call to taint : | params_flow.rb:25:12:25:13 | p1 : | +| params_flow.rb:33:26:33:34 | call to taint : | params_flow.rb:25:17:25:24 | **kwargs [element :p2] : | +| params_flow.rb:33:41:33:49 | call to taint : | params_flow.rb:25:17:25:24 | **kwargs [element :p3] : | +| params_flow.rb:34:14:34:22 | call to taint : | params_flow.rb:35:25:35:28 | args [element :p3] : | +| params_flow.rb:35:12:35:20 | call to taint : | params_flow.rb:25:12:25:13 | p1 : | +| params_flow.rb:35:23:35:28 | ** ... [element :p3] : | params_flow.rb:25:17:25:24 | **kwargs [element :p3] : | +| params_flow.rb:35:25:35:28 | args [element :p3] : | params_flow.rb:35:23:35:28 | ** ... [element :p3] : | nodes | params_flow.rb:9:16:9:17 | p1 : | semmle.label | p1 : | | params_flow.rb:9:20:9:21 | p2 : | semmle.label | p2 : | @@ -29,6 +43,23 @@ nodes | params_flow.rb:22:27:22:34 | call to taint : | semmle.label | call to taint : | | params_flow.rb:23:16:23:23 | call to taint : | semmle.label | call to taint : | | params_flow.rb:23:33:23:40 | call to taint : | semmle.label | call to taint : | +| params_flow.rb:25:12:25:13 | p1 : | semmle.label | p1 : | +| params_flow.rb:25:17:25:24 | **kwargs [element :p2] : | semmle.label | **kwargs [element :p2] : | +| params_flow.rb:25:17:25:24 | **kwargs [element :p3] : | semmle.label | **kwargs [element :p3] : | +| params_flow.rb:26:10:26:11 | p1 | semmle.label | p1 | +| params_flow.rb:28:10:28:22 | ( ... ) | semmle.label | ( ... ) | +| params_flow.rb:28:11:28:16 | kwargs [element :p2] : | semmle.label | kwargs [element :p2] : | +| params_flow.rb:28:11:28:21 | ...[...] : | semmle.label | ...[...] : | +| params_flow.rb:29:10:29:22 | ( ... ) | semmle.label | ( ... ) | +| params_flow.rb:29:11:29:16 | kwargs [element :p3] : | semmle.label | kwargs [element :p3] : | +| params_flow.rb:29:11:29:21 | ...[...] : | semmle.label | ...[...] : | +| params_flow.rb:33:12:33:19 | call to taint : | semmle.label | call to taint : | +| params_flow.rb:33:26:33:34 | call to taint : | semmle.label | call to taint : | +| params_flow.rb:33:41:33:49 | call to taint : | semmle.label | call to taint : | +| params_flow.rb:34:14:34:22 | call to taint : | semmle.label | call to taint : | +| params_flow.rb:35:12:35:20 | call to taint : | semmle.label | call to taint : | +| params_flow.rb:35:23:35:28 | ** ... [element :p3] : | semmle.label | ** ... [element :p3] : | +| params_flow.rb:35:25:35:28 | args [element :p3] : | semmle.label | args [element :p3] : | subpaths #select | params_flow.rb:10:10:10:11 | p1 | params_flow.rb:14:12:14:19 | call to taint : | params_flow.rb:10:10:10:11 | p1 | $@ | params_flow.rb:14:12:14:19 | call to taint : | call to taint : | @@ -39,3 +70,8 @@ subpaths | params_flow.rb:18:10:18:11 | p2 | params_flow.rb:21:27:21:34 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:21:27:21:34 | call to taint : | call to taint : | | params_flow.rb:18:10:18:11 | p2 | params_flow.rb:22:13:22:20 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:22:13:22:20 | call to taint : | call to taint : | | params_flow.rb:18:10:18:11 | p2 | params_flow.rb:23:16:23:23 | call to taint : | params_flow.rb:18:10:18:11 | p2 | $@ | params_flow.rb:23:16:23:23 | call to taint : | call to taint : | +| params_flow.rb:26:10:26:11 | p1 | params_flow.rb:33:12:33:19 | call to taint : | params_flow.rb:26:10:26:11 | p1 | $@ | params_flow.rb:33:12:33:19 | call to taint : | call to taint : | +| params_flow.rb:26:10:26:11 | p1 | params_flow.rb:35:12:35:20 | call to taint : | params_flow.rb:26:10:26:11 | p1 | $@ | params_flow.rb:35:12:35:20 | call to taint : | call to taint : | +| params_flow.rb:28:10:28:22 | ( ... ) | params_flow.rb:33:26:33:34 | call to taint : | params_flow.rb:28:10:28:22 | ( ... ) | $@ | params_flow.rb:33:26:33:34 | call to taint : | call to taint : | +| params_flow.rb:29:10:29:22 | ( ... ) | params_flow.rb:33:41:33:49 | call to taint : | params_flow.rb:29:10:29:22 | ( ... ) | $@ | params_flow.rb:33:41:33:49 | call to taint : | call to taint : | +| params_flow.rb:29:10:29:22 | ( ... ) | params_flow.rb:34:14:34:22 | call to taint : | params_flow.rb:29:10:29:22 | ( ... ) | $@ | params_flow.rb:34:14:34:22 | call to taint : | call to taint : | diff --git a/ruby/ql/test/library-tests/dataflow/params/params_flow.rb b/ruby/ql/test/library-tests/dataflow/params/params_flow.rb index 27d82148403..d3a99e61f37 100644 --- a/ruby/ql/test/library-tests/dataflow/params/params_flow.rb +++ b/ruby/ql/test/library-tests/dataflow/params/params_flow.rb @@ -21,3 +21,15 @@ end keyword(p1: taint(3), p2: taint(4)) keyword(p2: taint(5), p1: taint(6)) keyword(:p2 => taint(7), :p1 => taint(8)) + +def kwargs(p1:, **kwargs) + sink p1 # $ hasValueFlow=9 $ hasValueFlow=13 + sink (kwargs[:p1]) + sink (kwargs[:p2]) # $ hasValueFlow=10 + sink (kwargs[:p3]) # $ hasValueFlow=11 $ hasValueFlow=12 + sink (kwargs[:p4]) +end + +kwargs(p1: taint(9), p2: taint(10), p3: taint(11), p4: "") +args = { p3: taint(12), p4: "" } +kwargs(p1: taint(13), **args) diff --git a/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected b/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected index 564c23d11b0..42d9ec15ec5 100644 --- a/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected +++ b/ruby/ql/test/library-tests/dataflow/summaries/Summaries.expected @@ -86,6 +86,12 @@ edges | summaries.rb:82:1:82:1 | a [element 2] : | summaries.rb:82:1:82:1 | [post] a [element 2] : | | summaries.rb:85:6:85:6 | a [element 2] : | summaries.rb:85:6:85:9 | ...[...] | | summaries.rb:85:6:85:6 | a [element 2] : | summaries.rb:85:6:85:9 | ...[...] | +| summaries.rb:88:1:88:1 | [post] x [@value] : | summaries.rb:89:6:89:6 | x [@value] : | +| summaries.rb:88:1:88:1 | [post] x [@value] : | summaries.rb:89:6:89:6 | x [@value] : | +| summaries.rb:88:13:88:26 | call to source : | summaries.rb:88:1:88:1 | [post] x [@value] : | +| summaries.rb:88:13:88:26 | call to source : | summaries.rb:88:1:88:1 | [post] x [@value] : | +| summaries.rb:89:6:89:6 | x [@value] : | summaries.rb:89:6:89:16 | call to get_value | +| summaries.rb:89:6:89:6 | x [@value] : | summaries.rb:89:6:89:16 | call to get_value | nodes | summaries.rb:1:11:1:36 | call to identity : | semmle.label | call to identity : | | summaries.rb:1:11:1:36 | call to identity : | semmle.label | call to identity : | @@ -183,6 +189,14 @@ nodes | summaries.rb:85:6:85:6 | a [element 2] : | semmle.label | a [element 2] : | | summaries.rb:85:6:85:9 | ...[...] | semmle.label | ...[...] | | summaries.rb:85:6:85:9 | ...[...] | semmle.label | ...[...] | +| summaries.rb:88:1:88:1 | [post] x [@value] : | semmle.label | [post] x [@value] : | +| summaries.rb:88:1:88:1 | [post] x [@value] : | semmle.label | [post] x [@value] : | +| summaries.rb:88:13:88:26 | call to source : | semmle.label | call to source : | +| summaries.rb:88:13:88:26 | call to source : | semmle.label | call to source : | +| summaries.rb:89:6:89:6 | x [@value] : | semmle.label | x [@value] : | +| summaries.rb:89:6:89:6 | x [@value] : | semmle.label | x [@value] : | +| summaries.rb:89:6:89:16 | call to get_value | semmle.label | call to get_value | +| summaries.rb:89:6:89:16 | call to get_value | semmle.label | call to get_value | subpaths invalidSpecComponent #select @@ -227,6 +241,8 @@ invalidSpecComponent | summaries.rb:80:6:80:9 | ...[...] | summaries.rb:74:15:74:29 | call to source : | summaries.rb:80:6:80:9 | ...[...] | $@ | summaries.rb:74:15:74:29 | call to source : | call to source : | | summaries.rb:85:6:85:9 | ...[...] | summaries.rb:74:32:74:46 | call to source : | summaries.rb:85:6:85:9 | ...[...] | $@ | summaries.rb:74:32:74:46 | call to source : | call to source : | | summaries.rb:85:6:85:9 | ...[...] | summaries.rb:74:32:74:46 | call to source : | summaries.rb:85:6:85:9 | ...[...] | $@ | summaries.rb:74:32:74:46 | call to source : | call to source : | +| summaries.rb:89:6:89:16 | call to get_value | summaries.rb:88:13:88:26 | call to source : | summaries.rb:89:6:89:16 | call to get_value | $@ | summaries.rb:88:13:88:26 | call to source : | call to source : | +| summaries.rb:89:6:89:16 | call to get_value | summaries.rb:88:13:88:26 | call to source : | summaries.rb:89:6:89:16 | call to get_value | $@ | summaries.rb:88:13:88:26 | call to source : | call to source : | warning | CSV type row should have 5 columns but has 2: test;TooFewColumns | | CSV type row should have 5 columns but has 8: test;TooManyColumns;;;Member[Foo].Instance;too;many;columns | diff --git a/ruby/ql/test/library-tests/dataflow/summaries/Summaries.ql b/ruby/ql/test/library-tests/dataflow/summaries/Summaries.ql index 189403547d9..4f9b344fa78 100644 --- a/ruby/ql/test/library-tests/dataflow/summaries/Summaries.ql +++ b/ruby/ql/test/library-tests/dataflow/summaries/Summaries.ql @@ -66,6 +66,8 @@ private class StepsFromModel extends ModelInput::SummaryModelCsv { override predicate row(string row) { row = [ + ";any;Method[set_value];Argument[0];Argument[self].Field[@value];value", + ";any;Method[get_value];Argument[self].Field[@value];ReturnValue;value", ";;Member[Foo].Method[firstArg];Argument[0];ReturnValue;taint", ";;Member[Foo].Method[secondArg];Argument[1];ReturnValue;taint", ";;Member[Foo].Method[onlyWithoutBlock].WithoutBlock;Argument[0];ReturnValue;taint", diff --git a/ruby/ql/test/library-tests/dataflow/summaries/summaries.rb b/ruby/ql/test/library-tests/dataflow/summaries/summaries.rb index c3b8bec1d01..eadcb57939f 100644 --- a/ruby/ql/test/library-tests/dataflow/summaries/summaries.rb +++ b/ruby/ql/test/library-tests/dataflow/summaries/summaries.rb @@ -82,4 +82,8 @@ sink(b[2]) a.withoutElementOne() sink(a[0]) sink(a[1]) -sink(a[2]) # $ hasValueFlow=elem2 \ No newline at end of file +sink(a[2]) # $ hasValueFlow=elem2 + +x = Foo.new +x.set_value(source("attr")) +sink(x.get_value) # $ hasValueFlow=attr \ No newline at end of file diff --git a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected index cd548ace1cd..2bb6368f552 100644 --- a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected +++ b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected @@ -139,6 +139,7 @@ track | type_tracker.rb:27:5:27:11 | call to puts | type tracker without call steps | type_tracker.rb:31:1:31:21 | call to keyword | | type_tracker.rb:27:5:27:11 | call to puts | type tracker without call steps | type_tracker.rb:32:1:32:27 | call to keyword | | type_tracker.rb:27:10:27:11 | [post] p2 | type tracker without call steps | type_tracker.rb:27:10:27:11 | [post] p2 | +| type_tracker.rb:30:1:30:21 | ** | type tracker without call steps | type_tracker.rb:30:1:30:21 | ** | | type_tracker.rb:30:1:30:21 | [post] self | type tracker with call steps | type_tracker.rb:25:1:28:3 | self (keyword) | | type_tracker.rb:30:1:30:21 | [post] self | type tracker with call steps | type_tracker.rb:25:1:28:3 | self in keyword | | type_tracker.rb:30:1:30:21 | [post] self | type tracker without call steps | type_tracker.rb:30:1:30:21 | [post] self | @@ -155,6 +156,7 @@ track | type_tracker.rb:30:20:30:20 | 4 | type tracker with call steps | type_tracker.rb:25:18:25:19 | p2 | | type_tracker.rb:30:20:30:20 | 4 | type tracker without call steps | type_tracker.rb:30:20:30:20 | 4 | | type_tracker.rb:30:20:30:20 | [post] 4 | type tracker without call steps | type_tracker.rb:30:20:30:20 | [post] 4 | +| type_tracker.rb:31:1:31:21 | ** | type tracker without call steps | type_tracker.rb:31:1:31:21 | ** | | type_tracker.rb:31:1:31:21 | [post] self | type tracker with call steps | type_tracker.rb:25:1:28:3 | self (keyword) | | type_tracker.rb:31:1:31:21 | [post] self | type tracker with call steps | type_tracker.rb:25:1:28:3 | self in keyword | | type_tracker.rb:31:1:31:21 | [post] self | type tracker without call steps | type_tracker.rb:31:1:31:21 | [post] self | @@ -171,6 +173,7 @@ track | type_tracker.rb:31:20:31:20 | 6 | type tracker with call steps | type_tracker.rb:25:13:25:14 | p1 | | type_tracker.rb:31:20:31:20 | 6 | type tracker without call steps | type_tracker.rb:31:20:31:20 | 6 | | type_tracker.rb:31:20:31:20 | [post] 6 | type tracker without call steps | type_tracker.rb:31:20:31:20 | [post] 6 | +| type_tracker.rb:32:1:32:27 | ** | type tracker without call steps | type_tracker.rb:32:1:32:27 | ** | | type_tracker.rb:32:1:32:27 | [post] self | type tracker without call steps | type_tracker.rb:32:1:32:27 | [post] self | | type_tracker.rb:32:1:32:27 | call to keyword | type tracker without call steps | type_tracker.rb:32:1:32:27 | call to keyword | | type_tracker.rb:32:9:32:11 | :p2 | type tracker without call steps | type_tracker.rb:32:9:32:11 | :p2 | @@ -393,6 +396,7 @@ trackEnd | type_tracker.rb:27:5:27:11 | call to puts | type_tracker.rb:31:1:31:21 | call to keyword | | type_tracker.rb:27:5:27:11 | call to puts | type_tracker.rb:32:1:32:27 | call to keyword | | type_tracker.rb:27:10:27:11 | [post] p2 | type_tracker.rb:27:10:27:11 | [post] p2 | +| type_tracker.rb:30:1:30:21 | ** | type_tracker.rb:30:1:30:21 | ** | | type_tracker.rb:30:1:30:21 | [post] self | type_tracker.rb:25:1:28:3 | self (keyword) | | type_tracker.rb:30:1:30:21 | [post] self | type_tracker.rb:25:1:28:3 | self in keyword | | type_tracker.rb:30:1:30:21 | [post] self | type_tracker.rb:26:5:26:11 | self | @@ -415,6 +419,7 @@ trackEnd | type_tracker.rb:30:20:30:20 | 4 | type_tracker.rb:27:10:27:11 | p2 | | type_tracker.rb:30:20:30:20 | 4 | type_tracker.rb:30:20:30:20 | 4 | | type_tracker.rb:30:20:30:20 | [post] 4 | type_tracker.rb:30:20:30:20 | [post] 4 | +| type_tracker.rb:31:1:31:21 | ** | type_tracker.rb:31:1:31:21 | ** | | type_tracker.rb:31:1:31:21 | [post] self | type_tracker.rb:25:1:28:3 | self (keyword) | | type_tracker.rb:31:1:31:21 | [post] self | type_tracker.rb:25:1:28:3 | self in keyword | | type_tracker.rb:31:1:31:21 | [post] self | type_tracker.rb:26:5:26:11 | self | @@ -436,6 +441,7 @@ trackEnd | type_tracker.rb:31:20:31:20 | 6 | type_tracker.rb:26:10:26:11 | p1 | | type_tracker.rb:31:20:31:20 | 6 | type_tracker.rb:31:20:31:20 | 6 | | type_tracker.rb:31:20:31:20 | [post] 6 | type_tracker.rb:31:20:31:20 | [post] 6 | +| type_tracker.rb:32:1:32:27 | ** | type_tracker.rb:32:1:32:27 | ** | | type_tracker.rb:32:1:32:27 | [post] self | type_tracker.rb:32:1:32:27 | [post] self | | type_tracker.rb:32:1:32:27 | call to keyword | type_tracker.rb:32:1:32:27 | call to keyword | | type_tracker.rb:32:9:32:11 | :p2 | type_tracker.rb:32:9:32:11 | :p2 | diff --git a/ruby/ql/test/library-tests/experimental/Rbi.expected b/ruby/ql/test/library-tests/experimental/Rbi.expected new file mode 100644 index 00000000000..355c9db3beb --- /dev/null +++ b/ruby/ql/test/library-tests/experimental/Rbi.expected @@ -0,0 +1,122 @@ +rbiTypes +| test_types.rb:7:17:7:23 | Integer | +| test_types.rb:10:19:10:25 | Integer | +| test_types.rb:10:31:10:37 | Integer | +| test_types.rb:10:48:10:54 | Integer | +| test_types.rb:13:19:13:25 | Integer | +| test_types.rb:13:36:13:36 | T | +| test_types.rb:13:36:13:45 | Boolean | +| test_types.rb:18:17:18:23 | MyClass | +| test_types.rb:21:17:21:22 | String | +| test_types.rb:24:17:24:23 | Integer | +| test_types.rb:29:10:29:15 | String | +| test_types.rb:30:14:30:14 | T | +| test_types.rb:30:14:30:54 | call to nilable | +| test_types.rb:30:24:30:24 | T | +| test_types.rb:30:24:30:29 | call to proc | +| test_types.rb:30:24:30:48 | call to params | +| test_types.rb:30:24:30:53 | call to void | +| test_types.rb:30:41:30:47 | Integer | +| test_types.rb:37:10:37:15 | String | +| test_types.rb:38:14:38:14 | T | +| test_types.rb:38:14:38:19 | call to proc | +| test_types.rb:38:14:38:38 | call to params | +| test_types.rb:38:14:38:54 | call to returns | +| test_types.rb:38:31:38:37 | Integer | +| test_types.rb:38:48:38:53 | String | +| test_types.rb:43:22:43:22 | T | +| test_types.rb:43:22:43:28 | Hash | +| test_types.rb:43:30:43:30 | T | +| test_types.rb:43:30:43:38 | call to untyped | +| test_types.rb:43:41:43:41 | T | +| test_types.rb:43:41:43:49 | call to untyped | +| test_types.rb:46:21:46:21 | T | +| test_types.rb:46:21:46:28 | Array | +| test_types.rb:46:30:46:35 | Symbol | +| test_types.rb:49:26:49:26 | T | +| test_types.rb:49:26:49:46 | call to any | +| test_types.rb:49:32:49:37 | String | +| test_types.rb:49:40:49:45 | Symbol | +| test_types.rb:49:57:49:62 | String | +| test_types.rb:52:23:52:23 | T | +| test_types.rb:52:23:52:32 | Boolean | +| test_types.rb:52:43:52:43 | T | +| test_types.rb:52:43:52:52 | Boolean | +unionTypes +| test_types.rb:49:26:49:46 | call to any | test_types.rb:49:32:49:37 | String | +| test_types.rb:49:26:49:46 | call to any | test_types.rb:49:40:49:45 | Symbol | +nilableTypes +| test_types.rb:30:14:30:54 | call to nilable | test_types.rb:30:24:30:53 | call to void | +typeAliases +arrayTypes +| test_types.rb:46:21:46:28 | Array | test_types.rb:46:30:46:35 | Symbol | +hashTypes +| test_types.rb:43:22:43:28 | Hash | test_types.rb:43:30:43:38 | call to untyped | test_types.rb:43:41:43:49 | call to untyped | +signatureCalls +| test_types.rb:4:3:4:14 | call to sig | (void) | +| test_types.rb:7:3:7:26 | call to sig | Integer | +| test_types.rb:10:3:10:57 | call to sig | Integer | +| test_types.rb:13:3:13:48 | call to sig | Boolean | +| test_types.rb:18:3:18:26 | call to sig | MyClass | +| test_types.rb:21:3:21:25 | call to sig | String | +| test_types.rb:24:3:24:26 | call to sig | Integer | +| test_types.rb:27:3:32:5 | call to sig | (void) | +| test_types.rb:30:24:30:29 | call to proc | (void) | +| test_types.rb:38:14:38:19 | call to proc | String | +| test_types.rb:43:3:43:58 | call to sig | (void) | +| test_types.rb:49:3:49:65 | call to sig | String | +| test_types.rb:52:3:52:55 | call to sig | Boolean | +paramsCalls +| test_types.rb:10:9:10:38 | call to params | +| test_types.rb:13:9:13:26 | call to params | +| test_types.rb:28:5:31:5 | call to params | +| test_types.rb:30:24:30:48 | call to params | +| test_types.rb:36:5:39:5 | call to params | +| test_types.rb:38:14:38:38 | call to params | +| test_types.rb:43:9:43:51 | call to params | +| test_types.rb:46:9:46:37 | call to params | +| test_types.rb:49:9:49:47 | call to params | +| test_types.rb:52:9:52:33 | call to params | +returnsCall +| test_types.rb:7:9:7:24 | call to returns | Integer | +| test_types.rb:10:9:10:55 | call to returns | Integer | +| test_types.rb:13:9:13:46 | call to returns | Boolean | +| test_types.rb:18:9:18:24 | call to returns | MyClass | +| test_types.rb:21:9:21:23 | call to returns | String | +| test_types.rb:24:9:24:24 | call to returns | Integer | +| test_types.rb:38:14:38:54 | call to returns | String | +| test_types.rb:49:9:49:63 | call to returns | String | +| test_types.rb:52:9:52:53 | call to returns | Boolean | +voidCall +| test_types.rb:4:9:4:12 | call to void | +| test_types.rb:28:5:31:10 | call to void | +| test_types.rb:30:24:30:53 | call to void | +| test_types.rb:43:9:43:56 | call to void | +parameterTypes +| test_types.rb:10:16:10:25 | Pair | test_types.rb:11:11:11:11 | a | test_types.rb:10:19:10:25 | Integer | +| test_types.rb:10:28:10:37 | Pair | test_types.rb:11:14:11:14 | b | test_types.rb:10:31:10:37 | Integer | +| test_types.rb:13:16:13:25 | Pair | test_types.rb:14:18:14:18 | a | test_types.rb:13:19:13:25 | Integer | +| test_types.rb:29:7:29:15 | Pair | test_types.rb:33:26:33:26 | a | test_types.rb:29:10:29:15 | String | +| test_types.rb:30:7:30:54 | Pair | test_types.rb:33:29:33:34 | &block | test_types.rb:30:14:30:54 | call to nilable | +| test_types.rb:37:7:37:15 | Pair | test_types.rb:41:18:41:18 | a | test_types.rb:37:10:37:15 | String | +| test_types.rb:38:7:38:54 | Pair | test_types.rb:41:21:41:26 | &block | test_types.rb:38:14:38:54 | call to returns | +| test_types.rb:49:16:49:46 | Pair | test_types.rb:50:14:50:21 | new_name | test_types.rb:49:26:49:46 | call to any | +| test_types.rb:52:16:52:32 | Pair | test_types.rb:53:24:53:28 | value | test_types.rb:52:23:52:32 | Boolean | +procParameterTypes +| test_types.rb:30:7:30:54 | Pair | test_types.rb:30:24:30:53 | call to void | test_types.rb:30:24:30:29 | call to proc | nilable | +| test_types.rb:38:7:38:54 | Pair | test_types.rb:38:14:38:54 | call to returns | test_types.rb:38:14:38:19 | call to proc | non_nilable | +sigMethods +| test_types.rb:4:3:4:14 | call to sig | test_types.rb:5:3:5:30 | perform_some_action | +| test_types.rb:7:3:7:26 | call to sig | test_types.rb:8:3:8:21 | return_one | +| test_types.rb:10:3:10:57 | call to sig | test_types.rb:11:3:11:20 | add | +| test_types.rb:13:3:13:48 | call to sig | test_types.rb:14:3:14:24 | isPositive | +| test_types.rb:18:3:18:26 | call to sig | test_types.rb:19:3:19:31 | getMyClassInstance | +| test_types.rb:27:3:32:5 | call to sig | test_types.rb:33:3:33:40 | blk_nilable_method | +| test_types.rb:35:3:40:5 | call to sig | test_types.rb:41:3:41:32 | blk_method | +| test_types.rb:43:3:43:58 | call to sig | test_types.rb:44:3:44:28 | read_hash | +| test_types.rb:46:3:46:39 | call to sig | test_types.rb:47:3:47:34 | read_symbol_array | +| test_types.rb:49:3:49:65 | call to sig | test_types.rb:50:3:50:27 | rename | +| test_types.rb:52:3:52:55 | call to sig | test_types.rb:53:3:53:34 | debug_mode= | +sigAttrReaders +| test_types.rb:21:3:21:25 | call to sig | test_types.rb:22:3:22:26 | call to attr_reader | +| test_types.rb:24:3:24:26 | call to sig | test_types.rb:25:3:25:24 | call to attr_accessor | diff --git a/ruby/ql/test/library-tests/experimental/Rbi.ql b/ruby/ql/test/library-tests/experimental/Rbi.ql new file mode 100644 index 00000000000..6a079008273 --- /dev/null +++ b/ruby/ql/test/library-tests/experimental/Rbi.ql @@ -0,0 +1,48 @@ +private import codeql.ruby.AST +private import codeql.ruby.experimental.Rbi::Rbi + +query predicate rbiTypes(RbiType t) { any() } + +query predicate unionTypes(RbiUnionType t, RbiType u) { u = t.getAType() } + +query predicate nilableTypes(RbiNilableType t, RbiType u) { u = t.getUnderlyingType() } + +query predicate typeAliases(RbiTypeAlias a, RbiType t) { t = a.getAliasedType() } + +query predicate arrayTypes(RbiArrayType at, RbiType et) { et = at.getElementType() } + +query predicate hashTypes(RbiHashType ht, RbiType kt, RbiType vt) { + kt = ht.getKeyType() and vt = ht.getValueType() +} + +query predicate signatureCalls(SignatureCall c, ReturnType r) { r = c.getReturnType() } + +query predicate paramsCalls(ParamsCall c) { any() } + +query predicate returnsCall(ReturnsCall c, ReturnType r) { r = c.getReturnType() } + +query predicate voidCall(VoidCall c) { any() } + +query predicate parameterTypes(ParameterType pt, NamedParameter p, RbiType t) { + p = pt.getParameter() and t = pt.getType() +} + +query predicate procParameterTypes( + ParameterType pt, ProcReturnsTypeCall prtc, ProcCall pc, string isNilable +) { + ( + exists(RbiNilableType nilable | nilable = pt.getType() | + prtc = nilable.getUnderlyingType() and + isNilable = "nilable" + ) + or + pt.getType() = prtc and isNilable = "non_nilable" + ) and + pc = prtc.getProcCall() +} + +query predicate sigMethods(MethodSignatureCall sig, MethodBase m) { m = sig.getAssociatedMethod() } + +query predicate sigAttrReaders(MethodSignatureCall sig, MethodCall attr_reader) { + attr_reader = sig.getAssociatedAttrReaderCall() +} diff --git a/ruby/ql/test/library-tests/experimental/test_types.rb b/ruby/ql/test/library-tests/experimental/test_types.rb new file mode 100644 index 00000000000..67308db1c2d --- /dev/null +++ b/ruby/ql/test/library-tests/experimental/test_types.rb @@ -0,0 +1,54 @@ +# TODO: this should be a .rbi file if we decide to extract them by default + +module TestTypes + sig { void } + def perform_some_action; end + + sig { returns(Integer) } + def return_one; end + + sig { params(a: Integer, b: Integer).returns(Integer) } + def add(a, b); end + + sig { params(a: Integer).returns(T::Boolean) } + def isPositive(a); end + + class MyClass; end + + sig { returns(MyClass) } + def getMyClassInstance(); end + + sig { returns(String) } + attr_reader :name, :kind + + sig { returns(Integer) } + attr_accessor :version + + sig do + params( + a: String, + block: T.nilable(T.proc.params(b: Integer).void) + ).void + end + def blk_nilable_method(a, &block); end + + sig do + params( + a: String, + block: T.proc.params(b: Integer).returns(String) + ) + end + def blk_method(a, &block); end + + sig { params(hash: T::Hash[T.untyped, T.untyped]).void } + def read_hash(**hash); end + + sig { params(arr: T::Array[Symbol]) } + def read_symbol_array(*arr); end + + sig { params(new_name: T.any(String, Symbol)).returns(String) } + def rename(new_name); end + + sig { params(value: T::Boolean).returns(T::Boolean) } + def self.debug_mode=(value); end +end diff --git a/ruby/ql/test/library-tests/frameworks/ActiveRecord.expected b/ruby/ql/test/library-tests/frameworks/ActiveRecord.expected index a18e9fa1167..0c2286528bd 100644 --- a/ruby/ql/test/library-tests/frameworks/ActiveRecord.expected +++ b/ruby/ql/test/library-tests/frameworks/ActiveRecord.expected @@ -2,6 +2,14 @@ activeRecordModelClasses | ActiveRecordInjection.rb:1:1:3:3 | UserGroup | | ActiveRecordInjection.rb:5:1:17:3 | User | | ActiveRecordInjection.rb:19:1:25:3 | Admin | +activeRecordInstances +| ActiveRecordInjection.rb:10:5:10:68 | call to find | +| ActiveRecordInjection.rb:15:5:15:40 | call to find_by | +| ActiveRecordInjection.rb:79:5:81:7 | if ... | +| ActiveRecordInjection.rb:79:43:80:40 | then ... | +| ActiveRecordInjection.rb:80:7:80:40 | call to find_by | +| ActiveRecordInjection.rb:85:5:85:33 | call to find_by | +| ActiveRecordInjection.rb:88:5:88:34 | call to find | activeRecordSqlExecutionRanges | ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | | ActiveRecordInjection.rb:23:16:23:24 | condition | @@ -45,9 +53,8 @@ potentiallyUnsafeSqlExecutingMethodCall | ActiveRecordInjection.rb:75:5:75:29 | call to order | | ActiveRecordInjection.rb:80:7:80:40 | call to find_by | activeRecordModelInstantiations -| ActiveRecordInjection.rb:8:3:11:5 | self (authenticate) | ActiveRecordInjection.rb:5:1:17:3 | User | +| ActiveRecordInjection.rb:10:5:10:68 | call to find | ActiveRecordInjection.rb:5:1:17:3 | User | | ActiveRecordInjection.rb:15:5:15:40 | call to find_by | ActiveRecordInjection.rb:1:1:3:3 | UserGroup | -| ActiveRecordInjection.rb:20:3:24:5 | self (delete_by) | ActiveRecordInjection.rb:19:1:25:3 | Admin | | ActiveRecordInjection.rb:80:7:80:40 | call to find_by | ActiveRecordInjection.rb:5:1:17:3 | User | | ActiveRecordInjection.rb:85:5:85:33 | call to find_by | ActiveRecordInjection.rb:5:1:17:3 | User | | ActiveRecordInjection.rb:88:5:88:34 | call to find | ActiveRecordInjection.rb:5:1:17:3 | User | diff --git a/ruby/ql/test/library-tests/frameworks/ActiveRecord.ql b/ruby/ql/test/library-tests/frameworks/ActiveRecord.ql index f7ce327b95a..6d19f9bb9ec 100644 --- a/ruby/ql/test/library-tests/frameworks/ActiveRecord.ql +++ b/ruby/ql/test/library-tests/frameworks/ActiveRecord.ql @@ -3,6 +3,8 @@ import codeql.ruby.frameworks.ActiveRecord query predicate activeRecordModelClasses(ActiveRecordModelClass cls) { any() } +query predicate activeRecordInstances(ActiveRecordInstance i) { any() } + query predicate activeRecordSqlExecutionRanges(ActiveRecordSqlExecutionRange range) { any() } query predicate activeRecordModelClassMethodCalls(ActiveRecordModelClassMethodCall call) { any() } diff --git a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection.expected b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection.expected index 6118b4b20c6..9022e848300 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection.expected @@ -12,6 +12,9 @@ edges | CommandInjection.rb:46:15:46:26 | ...[...] : | CommandInjection.rb:50:24:50:36 | "echo #{...}" | | CommandInjection.rb:64:18:64:23 | number : | CommandInjection.rb:65:14:65:29 | "echo #{...}" | | CommandInjection.rb:72:23:72:33 | blah_number : | CommandInjection.rb:73:14:73:34 | "echo #{...}" | +| CommandInjection.rb:81:20:81:25 | **args : | CommandInjection.rb:82:22:82:25 | args : | +| CommandInjection.rb:82:22:82:25 | args : | CommandInjection.rb:82:22:82:37 | ...[...] : | +| CommandInjection.rb:82:22:82:37 | ...[...] : | CommandInjection.rb:82:14:82:39 | "echo #{...}" | nodes | CommandInjection.rb:6:15:6:20 | call to params : | semmle.label | call to params : | | CommandInjection.rb:6:15:6:26 | ...[...] : | semmle.label | ...[...] : | @@ -30,6 +33,10 @@ nodes | CommandInjection.rb:65:14:65:29 | "echo #{...}" | semmle.label | "echo #{...}" | | CommandInjection.rb:72:23:72:33 | blah_number : | semmle.label | blah_number : | | CommandInjection.rb:73:14:73:34 | "echo #{...}" | semmle.label | "echo #{...}" | +| CommandInjection.rb:81:20:81:25 | **args : | semmle.label | **args : | +| CommandInjection.rb:82:14:82:39 | "echo #{...}" | semmle.label | "echo #{...}" | +| CommandInjection.rb:82:22:82:25 | args : | semmle.label | args : | +| CommandInjection.rb:82:22:82:37 | ...[...] : | semmle.label | ...[...] : | subpaths #select | CommandInjection.rb:7:10:7:15 | #{...} | CommandInjection.rb:6:15:6:20 | call to params : | CommandInjection.rb:7:10:7:15 | #{...} | This command depends on $@. | CommandInjection.rb:6:15:6:20 | call to params | a user-provided value | @@ -43,3 +50,4 @@ subpaths | CommandInjection.rb:50:24:50:36 | "echo #{...}" | CommandInjection.rb:46:15:46:20 | call to params : | CommandInjection.rb:50:24:50:36 | "echo #{...}" | This command depends on $@. | CommandInjection.rb:46:15:46:20 | call to params | a user-provided value | | CommandInjection.rb:65:14:65:29 | "echo #{...}" | CommandInjection.rb:64:18:64:23 | number : | CommandInjection.rb:65:14:65:29 | "echo #{...}" | This command depends on $@. | CommandInjection.rb:64:18:64:23 | number | a user-provided value | | CommandInjection.rb:73:14:73:34 | "echo #{...}" | CommandInjection.rb:72:23:72:33 | blah_number : | CommandInjection.rb:73:14:73:34 | "echo #{...}" | This command depends on $@. | CommandInjection.rb:72:23:72:33 | blah_number | a user-provided value | +| CommandInjection.rb:82:14:82:39 | "echo #{...}" | CommandInjection.rb:81:20:81:25 | **args : | CommandInjection.rb:82:14:82:39 | "echo #{...}" | This command depends on $@. | CommandInjection.rb:81:20:81:25 | **args | a user-provided value | diff --git a/swift/codegen/schema.yml b/swift/codegen/schema.yml index 03cdf16c208..ebdece63965 100644 --- a/swift/codegen/schema.yml +++ b/swift/codegen/schema.yml @@ -63,6 +63,7 @@ AnyFunctionType: param_types: Type* param_labels: string* is_throwing: predicate + is_async: predicate AnyGenericType: _extends: Type diff --git a/swift/extractor/visitors/TypeVisitor.h b/swift/extractor/visitors/TypeVisitor.h index 21c6978e325..3299d09eb8c 100644 --- a/swift/extractor/visitors/TypeVisitor.h +++ b/swift/extractor/visitors/TypeVisitor.h @@ -211,6 +211,14 @@ class TypeVisitor : public TypeVisitorBase { } ++i; } + + if (type->isThrowing()) { + dispatcher_.emit(AnyFunctionTypeIsThrowingTrap{label}); + } + + if (type->isAsync()) { + dispatcher_.emit(AnyFunctionTypeIsAsyncTrap{label}); + } } void emitBoundGenericType(swift::BoundGenericType* type, TrapLabel label) { diff --git a/swift/ql/lib/codeql/swift/controlflow/BasicBlocks.qll b/swift/ql/lib/codeql/swift/controlflow/BasicBlocks.qll index dd021a41ddf..462af68202f 100644 --- a/swift/ql/lib/codeql/swift/controlflow/BasicBlocks.qll +++ b/swift/ql/lib/codeql/swift/controlflow/BasicBlocks.qll @@ -3,6 +3,7 @@ private import swift private import ControlFlowGraph private import internal.ControlFlowGraphImpl +private import internal.ControlFlowElements private import CfgNodes private import SuccessorTypes @@ -198,8 +199,18 @@ private module JoinBlockPredecessors { private predicate idOf(AstNode x, int y) = equivalenceRelation(id/2)(x, y) + private AstNode projctToAst(ControlFlowElement n) { + result = n.asAstNode() + or + isPropertyGetterElement(n, _, result) + or + isPropertySetterElement(n, _, result) + or + isPropertyObserverElement(n, _, result) + } + int getId(JoinBlockPredecessor jbp) { - idOf(jbp.getFirstNode().(AstCfgNode).getNode(), result) + idOf(projctToAst(jbp.getFirstNode().(AstCfgNode).getNode()), result) or idOf(jbp.(EntryBasicBlock).getScope(), result) } diff --git a/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll b/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll index 1833089896c..6c9f3206e04 100644 --- a/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll +++ b/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll @@ -4,6 +4,7 @@ private import swift private import BasicBlocks private import ControlFlowGraph private import internal.ControlFlowGraphImpl +private import internal.ControlFlowElements private import internal.Splitting /** An entry node for a given scope. */ @@ -66,11 +67,11 @@ class ExitNode extends ControlFlowNode, TExitNode { */ class AstCfgNode extends ControlFlowNode, TElementNode { private Splits splits; - private AstNode n; + private ControlFlowElement n; AstCfgNode() { this = TElementNode(_, n, splits) } - final override AstNode getNode() { result = n } + final override ControlFlowElement getNode() { result = n } override Location getLocation() { result = n.getLocation() } @@ -96,7 +97,7 @@ class AstCfgNode extends ControlFlowNode, TElementNode { class ExprCfgNode extends AstCfgNode { Expr e; - ExprCfgNode() { e = this.getNode() } + ExprCfgNode() { e = this.getNode().asAstNode() } /** Gets the underlying expression. */ Expr getExpr() { result = e } diff --git a/swift/ql/lib/codeql/swift/controlflow/ControlFlowGraph.qll b/swift/ql/lib/codeql/swift/controlflow/ControlFlowGraph.qll index a54043499d6..d6eec89d939 100644 --- a/swift/ql/lib/codeql/swift/controlflow/ControlFlowGraph.qll +++ b/swift/ql/lib/codeql/swift/controlflow/ControlFlowGraph.qll @@ -6,13 +6,14 @@ private import SuccessorTypes private import internal.ControlFlowGraphImpl private import internal.Completion private import internal.Scope +private import internal.ControlFlowElements /** An AST node with an associated control-flow graph. */ class CfgScope extends Scope instanceof CfgScope::Range_ { /** Gets the CFG scope that this scope is nested under, if any. */ final CfgScope getOuterCfgScope() { - exists(AstNode parent | - parent = getParent(this) and + exists(ControlFlowElement parent | + parent.asAstNode() = getParentOfAst(this) and result = getCfgScope(parent) ) } @@ -31,7 +32,7 @@ class ControlFlowNode extends TCfgNode { string toString() { none() } /** Gets the AST node that this node corresponds to, if any. */ - AstNode getNode() { none() } + ControlFlowElement getNode() { none() } /** Gets the location of this control flow node. */ Location getLocation() { none() } diff --git a/swift/ql/lib/codeql/swift/controlflow/internal/AstControlFlowTrees.qll b/swift/ql/lib/codeql/swift/controlflow/internal/AstControlFlowTrees.qll new file mode 100644 index 00000000000..0fdf4d1735a --- /dev/null +++ b/swift/ql/lib/codeql/swift/controlflow/internal/AstControlFlowTrees.qll @@ -0,0 +1,40 @@ +private import swift +private import Completion +private import ControlFlowGraphImplShared +private import ControlFlowElements + +abstract class AstControlFlowTree extends ControlFlowTree { + AstNode ast; + + AstControlFlowTree() { ast = this.asAstNode() } + + AstNode getAst() { result = ast } +} + +/** + * Holds if `first` is the first element executed within control flow + * element `cft`. + */ +predicate astFirst(AstNode cft, ControlFlowElement first) { + first(any(ControlFlowTree tree | cft = tree.asAstNode()), first) +} + +/** + * Holds if `last` with completion `c` is a potential last element executed + * within control flow element `cft`. + */ +predicate astLast(AstNode cft, ControlFlowElement last, Completion c) { + last(any(ControlFlowTree tree | cft = tree.asAstNode()), last, c) +} + +abstract class AstPreOrderTree extends AstControlFlowTree, PreOrderTree { } + +abstract class AstPostOrderTree extends AstControlFlowTree, PostOrderTree { } + +abstract class AstStandardTree extends AstControlFlowTree, StandardTree { } + +abstract class AstStandardPreOrderTree extends AstStandardTree, StandardPreOrderTree { } + +abstract class AstStandardPostOrderTree extends AstStandardTree, StandardPostOrderTree { } + +abstract class AstLeafTree extends AstPreOrderTree, AstPostOrderTree, LeafTree { } diff --git a/swift/ql/lib/codeql/swift/controlflow/internal/Completion.qll b/swift/ql/lib/codeql/swift/controlflow/internal/Completion.qll index 8180e75f2f9..dd3d3219453 100644 --- a/swift/ql/lib/codeql/swift/controlflow/internal/Completion.qll +++ b/swift/ql/lib/codeql/swift/controlflow/internal/Completion.qll @@ -6,6 +6,7 @@ private import swift private import codeql.swift.controlflow.ControlFlowGraph +private import ControlFlowElements private import ControlFlowGraphImpl private import SuccessorTypes @@ -41,8 +42,8 @@ private predicate completionIsValidForStmt(Stmt stmt, Completion c) { /** A completion of a statement or an expression. */ abstract class Completion extends TCompletion { - private predicate isValidForSpecific(AstNode n) { - completionIsValidForStmt(n, this) + private predicate isValidForSpecific(ControlFlowElement n) { + completionIsValidForStmt(n.asAstNode(), this) or mustHaveBooleanCompletion(n) and ( @@ -52,22 +53,24 @@ abstract class Completion extends TCompletion { this = TBooleanCompletion(_) ) or - mustHaveMatchingCompletion(n) and + mustHaveMatchingCompletion(n.asAstNode()) and ( - exists(boolean value | isMatchingConstant(n, value) | this = TMatchingCompletion(value)) + exists(boolean value | isMatchingConstant(n.asAstNode(), value) | + this = TMatchingCompletion(value) + ) or - not isMatchingConstant(n, _) and + not isMatchingConstant(n.asAstNode(), _) and this = TMatchingCompletion(_) ) or - mustHaveThrowCompletion(n, this) + mustHaveThrowCompletion(n.asAstNode(), this) } /** Holds if this completion is valid for node `n`. */ - predicate isValidFor(AstNode n) { + predicate isValidFor(ControlFlowElement n) { this.isValidForSpecific(n) or - mayHaveThrowCompletion(n, this) + mayHaveThrowCompletion(n.asAstNode(), this) or not any(Completion c).isValidForSpecific(n) and this = TSimpleCompletion() @@ -87,25 +90,35 @@ abstract class Completion extends TCompletion { } /** Holds if node `n` has the Boolean constant value `value`. */ -private predicate isBooleanConstant(AstNode n, boolean value) { +private predicate isBooleanConstant(ControlFlowElement n, boolean value) { mustHaveBooleanCompletion(n) and - value = n.(BooleanLiteralExpr).getValue() + value = n.asAstNode().(BooleanLiteralExpr).getValue() or // Boolean consants hidden inside conversions are also // constants that resolve to the same value. - isBooleanConstant(n.getResolveStep(), value) + exists(ControlFlowElement parent | + parent.asAstNode() = n.asAstNode().getResolveStep() and + isBooleanConstant(parent, value) + ) } /** * Holds if a normal completion of `n` must be a Boolean completion. */ -private predicate mustHaveBooleanCompletion(AstNode n) { inBooleanContext(n) } +private predicate mustHaveBooleanCompletion(ControlFlowElement n) { inBooleanContext(n) } /** * Holds if `n` is used in a Boolean context. That is, the value * that `n` evaluates to determines a true/false branch successor. */ -private predicate inBooleanContext(AstNode n) { +private predicate inBooleanContext(ControlFlowElement n) { + astInBooleanContext(n.asAstNode()) or + astInBooleanContext(n.(PropertyGetterElement).getRef()) or + astInBooleanContext(n.(PropertySetterElement).getAssignExpr()) or + astInBooleanContext(n.(PropertyObserverElement).getAssignExpr()) +} + +private predicate astInBooleanContext(AstNode n) { n = any(ConditionElement condElem).getFullyUnresolved() or n = any(StmtCondition stmtCond).getFullyUnresolved() @@ -115,30 +128,30 @@ private predicate inBooleanContext(AstNode n) { exists(LogicalAndExpr parent | n = parent.getLeftOperand().getFullyConverted() or - inBooleanContext(parent) and + astInBooleanContext(parent) and n = parent.getRightOperand().getFullyConverted() ) or exists(LogicalOrExpr parent | n = parent.getLeftOperand().getFullyConverted() or - inBooleanContext(parent) and + astInBooleanContext(parent) and n = parent.getRightOperand().getFullyConverted() ) or - n = any(NotExpr parent | inBooleanContext(parent)).getOperand().getFullyConverted() + n = any(NotExpr parent | astInBooleanContext(parent)).getOperand().getFullyConverted() or exists(IfExpr ifExpr | ifExpr.getCondition().getFullyConverted() = n or - inBooleanContext(ifExpr) and + astInBooleanContext(ifExpr) and n = ifExpr.getBranch(_).getFullyConverted() ) or exists(ForEachStmt foreach | n = foreach.getWhere().getFullyConverted()) or exists(Exprs::Conversions::ConversionOrIdentityTree parent | - inBooleanContext(parent) and + astInBooleanContext(parent.getAst()) and parent.convertsFrom(n) ) } @@ -477,3 +490,18 @@ class ThrowCompletion extends TThrowCompletion, Completion { override string toString() { result = "throw" } } + +/** + * Hold if `c` represents normal evaluation of a statement or an + * expression. + */ +predicate completionIsNormal(Completion c) { c instanceof NormalCompletion } + +/** + * Hold if `c` represents simple (normal) evaluation of a statement or an + * expression. + */ +predicate completionIsSimple(Completion c) { c instanceof SimpleCompletion } + +/** Holds if `c` is a valid completion for `e`. */ +predicate completionIsValidFor(Completion c, ControlFlowElement e) { c.isValidFor(e) } diff --git a/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowElements.qll b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowElements.qll new file mode 100644 index 00000000000..b5557c71e86 --- /dev/null +++ b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowElements.qll @@ -0,0 +1,163 @@ +private import swift + +cached +newtype TControlFlowElement = + TAstElement(AstNode n) or + TPropertyGetterElement(Decl accessor, Expr ref) { isPropertyGetterElement(accessor, ref) } or + TPropertySetterElement(AccessorDecl accessor, AssignExpr assign) { + isPropertySetterElement(accessor, assign) + } or + TPropertyObserverElement(AccessorDecl observer, AssignExpr assign) { + isPropertyObserverElement(observer, assign) + } + +predicate isLValue(Expr e) { any(AssignExpr assign).getDest() = e } + +predicate isRValue(Expr e) { not isLValue(e) } + +predicate ignoreAstElement(AstNode n) { + isPropertyGetterElement(_, n) + or + isPropertySetterElement(_, n) +} + +private AccessorDecl getAnAccessorDecl(Decl d) { + result = d.(VarDecl).getAnAccessorDecl() or + result = d.(SubscriptDecl).getAnAccessorDecl() +} + +predicate isPropertyGetterElement(AccessorDecl accessor, Expr ref) { + hasDirectToImplementationOrOrdinarySemantics(ref) and + isRValue(ref) and + accessor.isGetter() and + accessor = getAnAccessorDecl([ref.(LookupExpr).getMember(), ref.(DeclRefExpr).getDecl()]) +} + +predicate isPropertyGetterElement(PropertyGetterElement pge, AccessorDecl accessor, Expr ref) { + pge = TPropertyGetterElement(accessor, ref) +} + +private predicate hasDirectToImplementationSemantics(Expr e) { + e.(MemberRefExpr).hasDirectToImplementationSemantics() + or + e.(SubscriptExpr).hasDirectToImplementationSemantics() + or + e.(DeclRefExpr).hasDirectToImplementationSemantics() +} + +private predicate hasOrdinarySemantics(Expr e) { + e.(MemberRefExpr).hasOrdinarySemantics() + or + e.(SubscriptExpr).hasOrdinarySemantics() + or + e.(DeclRefExpr).hasOrdinarySemantics() +} + +private predicate hasDirectToImplementationOrOrdinarySemantics(Expr e) { + hasDirectToImplementationSemantics(e) or hasOrdinarySemantics(e) +} + +private predicate isPropertySetterElement(AccessorDecl accessor, AssignExpr assign) { + exists(Expr lhs | lhs = assign.getDest() | + hasDirectToImplementationOrOrdinarySemantics(lhs) and + accessor.isSetter() and + isLValue(lhs) and + accessor = getAnAccessorDecl([lhs.(LookupExpr).getMember(), lhs.(DeclRefExpr).getDecl()]) + ) +} + +predicate isPropertySetterElement( + PropertySetterElement pse, AccessorDecl accessor, AssignExpr assign +) { + pse = TPropertySetterElement(accessor, assign) +} + +private predicate isPropertyObserverElement(AccessorDecl observer, AssignExpr assign) { + exists(Expr lhs | lhs = assign.getDest() | + hasDirectToImplementationOrOrdinarySemantics(lhs) and + observer.isPropertyObserver() and + isLValue(lhs) and + observer = getAnAccessorDecl([lhs.(LookupExpr).getMember(), lhs.(DeclRefExpr).getDecl()]) + ) +} + +predicate isPropertyObserverElement( + PropertyObserverElement poe, AccessorDecl accessor, AssignExpr assign +) { + poe = TPropertyObserverElement(accessor, assign) +} + +class ControlFlowElement extends TControlFlowElement { + string toString() { none() } // overriden in subclasses + + AstNode asAstNode() { none() } + + Location getLocation() { none() } // overriden in subclasses +} + +class AstElement extends ControlFlowElement, TAstElement { + AstNode n; + + AstElement() { this = TAstElement(n) } + + override string toString() { result = n.toString() } + + override AstNode asAstNode() { result = n } + + override Location getLocation() { result = n.getLocation() } +} + +class PropertyGetterElement extends ControlFlowElement, TPropertyGetterElement { + AccessorDecl accessor; + Expr ref; + + PropertyGetterElement() { this = TPropertyGetterElement(accessor, ref) } + + override string toString() { result = "getter for " + ref.toString() } + + override Location getLocation() { result = ref.getLocation() } + + Expr getRef() { result = ref } + + AccessorDecl getAccessorDecl() { result = accessor } +} + +class PropertySetterElement extends ControlFlowElement, TPropertySetterElement { + AccessorDecl accessor; + AssignExpr assign; + + PropertySetterElement() { this = TPropertySetterElement(accessor, assign) } + + override string toString() { result = "setter for " + assign } + + override Location getLocation() { result = assign.getLocation() } + + AccessorDecl getAccessorDecl() { result = accessor } + + AssignExpr getAssignExpr() { result = assign } +} + +class PropertyObserverElement extends ControlFlowElement, TPropertyObserverElement { + AccessorDecl observer; + AssignExpr assign; + + PropertyObserverElement() { this = TPropertyObserverElement(observer, assign) } + + override string toString() { + this.isWillSet() and + result = "willSet observer for " + assign.toString() + or + this.isDidSet() and + result = "didSet observer for " + assign.toString() + } + + override Location getLocation() { result = assign.getLocation() } + + AccessorDecl getObserver() { result = observer } + + predicate isWillSet() { observer.isWillSet() } + + predicate isDidSet() { observer.isDidSet() } + + AssignExpr getAssignExpr() { result = assign } +} diff --git a/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll index 446c1637101..4db8afaca7a 100644 --- a/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll +++ b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll @@ -36,59 +36,73 @@ private import codeql.swift.controlflow.ControlFlowGraph private import Completion private import Scope import ControlFlowGraphImplShared +private import ControlFlowElements +private import AstControlFlowTrees module CfgScope { abstract class Range_ extends AstNode { - abstract predicate entry(AstNode first); + abstract predicate entry(ControlFlowElement first); - abstract predicate exit(AstNode last, Completion c); + abstract predicate exit(ControlFlowElement last, Completion c); } private class BodyStmtCallableScope extends Range_ instanceof AbstractFunctionDecl { - final override predicate entry(AstNode first) { - super.getBody().(Stmts::BraceStmtTree).firstInner(first) + final override predicate entry(ControlFlowElement first) { + exists(Stmts::BraceStmtTree tree | + tree.getAst() = super.getBody() and + tree.firstInner(first) + ) } - final override predicate exit(AstNode last, Completion c) { - super.getBody().(Stmts::BraceStmtTree).last(last, c) + final override predicate exit(ControlFlowElement last, Completion c) { + exists(Stmts::BraceStmtTree tree | + tree.getAst() = super.getBody() and + tree.last(last, c) + ) } } } /** Holds if `first` is first executed when entering `scope`. */ pragma[nomagic] -predicate succEntry(CfgScope::Range_ scope, AstNode first) { scope.entry(first) } +predicate succEntry(CfgScope::Range_ scope, ControlFlowElement first) { scope.entry(first) } /** Holds if `last` with completion `c` can exit `scope`. */ pragma[nomagic] -predicate succExit(CfgScope::Range_ scope, AstNode last, Completion c) { scope.exit(last, c) } +predicate succExit(CfgScope::Range_ scope, ControlFlowElement last, Completion c) { + scope.exit(last, c) +} /** * Control-flow for statements. */ module Stmts { - class BraceStmtTree extends ControlFlowTree instanceof BraceStmt { - override predicate propagatesAbnormal(AstNode node) { none() } + class BraceStmtTree extends AstControlFlowTree { + override BraceStmt ast; - override predicate first(AstNode first) { + override predicate propagatesAbnormal(ControlFlowElement node) { none() } + + override predicate first(ControlFlowElement first) { this.firstInner(first) or - not exists(super.getFirstElement()) and first = this + not exists(ast.getFirstElement()) and first.asAstNode() = ast } - override predicate last(AstNode last, Completion c) { + override predicate last(ControlFlowElement last, Completion c) { this.lastInner(last, c) or - not exists(super.getFirstElement()) and last = this and c instanceof SimpleCompletion + not exists(ast.getFirstElement()) and + last.asAstNode() = ast and + c instanceof SimpleCompletion } - predicate firstInner(AstNode first) { first(super.getFirstElement(), first) } + predicate firstInner(ControlFlowElement first) { astFirst(ast.getFirstElement(), first) } /** Gets the body of the i'th `defer` statement. */ private BraceStmt getDeferStmtBody(int i) { result = rank[i](DeferStmt defer, int index | - defer = super.getElement(index) + defer = ast.getElement(index) | defer.getBody() order by index ) @@ -117,7 +131,7 @@ module Stmts { int getDeferIndex(int i) { exists(DeferStmt defer | this.getDeferStmtBody(i) = defer.getBody() and - super.getElement(result) = defer + ast.getElement(result) = defer ) } @@ -136,143 +150,153 @@ module Stmts { ) } - predicate lastInner(AstNode last, Completion c) { + predicate lastInner(ControlFlowElement last, Completion c) { // Normal exit and no defer statements - last(super.getLastElement(), last, c) and + astLast(ast.getLastElement(), last, c) and not exists(this.getFirstDeferStmtBody()) and c instanceof NormalCompletion or // Normal exit from the last defer statement to be executed - last(this.getLastDeferStmtBody(), last, c) and + astLast(this.getLastDeferStmtBody(), last, c) and c instanceof NormalCompletion or // Abnormal exit without any defer statements not c instanceof NormalCompletion and - last(super.getAnElement(), last, c) and + astLast(ast.getAnElement(), last, c) and not exists(this.getFirstDeferStmtBody()) } - override predicate succ(AstNode pred, AstNode succ, Completion c) { + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // left-to-right evaluation of statements exists(int i | - last(super.getElement(i), pred, c) and - first(super.getElement(i + 1), succ) and + astLast(ast.getElement(i), pred, c) and + astFirst(ast.getElement(i + 1), succ) and c instanceof NormalCompletion ) or // Flow from last elements to the first defer statement to be executed c instanceof NormalCompletion and - last(super.getLastElement(), pred, c) and - first(this.getFirstDeferStmtBody(), succ) + astLast(ast.getLastElement(), pred, c) and + astFirst(this.getFirstDeferStmtBody(), succ) or // Flow from a defer statement to the next defer to be executed c instanceof NormalCompletion and exists(int i | - last(this.getDeferStmtBody(i), pred, c) and - first(this.getDeferStmtBody(i - 1), succ) + astLast(this.getDeferStmtBody(i), pred, c) and + astFirst(this.getDeferStmtBody(i - 1), succ) ) or // Abnormal exit from an element to the first defer statement to be executed. not c instanceof NormalCompletion and exists(int i | - last(super.getElement(i), pred, c) and - first(this.getDeferStmtBodyAfterStmt(i), succ) + astLast(ast.getElement(i), pred, c) and + astFirst(this.getDeferStmtBodyAfterStmt(i), succ) ) } } - private class ReturnStmtTree extends StandardPostOrderTree, ReturnStmt { - final override ControlFlowTree getChildElement(int i) { - result = this.getResult().getFullyConverted() and i = 0 + private class ReturnStmtTree extends AstStandardPostOrderTree { + override ReturnStmt ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getResult().getFullyConverted() and i = 0 } } - private class FailTree extends LeafTree instanceof FailStmt { } + private class FailTree extends AstLeafTree { + override FailStmt ast; + } - private class StmtConditionTree extends PostOrderTree instanceof StmtCondition { - final override predicate propagatesAbnormal(AstNode child) { - child = super.getAnElement().getUnderlyingCondition() + private class StmtConditionTree extends AstPostOrderTree { + override StmtCondition ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getAnElement().getUnderlyingCondition() } - final override predicate first(AstNode first) { - first(super.getFirstElement().getUnderlyingCondition().getFullyUnresolved(), first) + final override predicate first(ControlFlowElement first) { + astFirst(ast.getFirstElement().getUnderlyingCondition().getFullyUnresolved(), first) } - final override predicate succ(AstNode pred, AstNode succ, Completion c) { + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Left-to-right evaluation of elements exists(int i | - last(super.getElement(i).getUnderlyingCondition().getFullyUnresolved(), pred, c) and + astLast(ast.getElement(i).getUnderlyingCondition().getFullyUnresolved(), pred, c) and c instanceof NormalCompletion and - first(super.getElement(i + 1).getUnderlyingCondition().getFullyUnresolved(), succ) + astFirst(ast.getElement(i + 1).getUnderlyingCondition().getFullyUnresolved(), succ) ) or // Post-order: flow from thrown expression to the throw statement. - last(super.getLastElement().getUnderlyingCondition().getFullyUnresolved(), pred, c) and + astLast(ast.getLastElement().getUnderlyingCondition().getFullyUnresolved(), pred, c) and c instanceof NormalCompletion and - succ = this + succ.asAstNode() = ast } } - private class IfStmtTree extends PreOrderTree instanceof IfStmt { - final override predicate propagatesAbnormal(AstNode child) { - child = super.getCondition().getFullyUnresolved() or - child = super.getThen() or - child = super.getElse() + private class IfStmtTree extends AstPreOrderTree { + override IfStmt ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getCondition().getFullyUnresolved() or + child.asAstNode() = ast.getThen() or + child.asAstNode() = ast.getElse() } - final override predicate last(AstNode last, Completion c) { + final override predicate last(ControlFlowElement last, Completion c) { // Condition exits with a false completion and there is no `else` branch - last(super.getCondition().getFullyUnresolved(), last, c) and + astLast(ast.getCondition().getFullyUnresolved(), last, c) and c instanceof FalseCompletion and - not exists(super.getElse()) + not exists(ast.getElse()) or // Then/Else branch exits with any completion - last(super.getBranch(_), last, c) + astLast(ast.getBranch(_), last, c) } - final override predicate succ(AstNode pred, AstNode succ, Completion c) { + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Pre-order: flow from statement itself to first element of condition - pred = this and - first(super.getCondition().getFullyUnresolved(), succ) and + pred.asAstNode() = ast and + astFirst(ast.getCondition().getFullyUnresolved(), succ) and c instanceof SimpleCompletion or - last(super.getCondition().getFullyUnresolved(), pred, c) and + astLast(ast.getCondition().getFullyUnresolved(), pred, c) and ( // Flow from last element of condition to first element of then branch - c instanceof TrueCompletion and first(super.getThen(), succ) + c instanceof TrueCompletion and astFirst(ast.getThen(), succ) or // Flow from last element of condition to first element of else branch - c instanceof FalseCompletion and first(super.getElse(), succ) + c instanceof FalseCompletion and astFirst(ast.getElse(), succ) ) } } - private class GuardTree extends PreOrderTree instanceof GuardStmt { - final override predicate propagatesAbnormal(AstNode child) { - child = super.getCondition().getFullyUnresolved() or - child = super.getBody() + private class GuardTree extends AstPreOrderTree { + override GuardStmt ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getCondition().getFullyUnresolved() or + child.asAstNode() = ast.getBody() } - final override predicate last(AstNode last, Completion c) { + final override predicate last(ControlFlowElement last, Completion c) { // Normal exit after evaluating the body - last(super.getBody(), last, c) and + astLast(ast.getBody(), last, c) and c instanceof NormalCompletion or // Exit when a condition is true - last(super.getCondition().getFullyUnresolved(), last, c) and + astLast(ast.getCondition().getFullyUnresolved(), last, c) and c instanceof TrueCompletion } - final override predicate succ(AstNode pred, AstNode succ, Completion c) { + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Pre-order: flow from statement itself to first element of condition - pred = this and - first(super.getCondition().getFullyUnresolved(), succ) and + pred.asAstNode() = ast and + astFirst(ast.getCondition().getFullyUnresolved(), succ) and c instanceof SimpleCompletion or // Flow to the body when the condition is false - last(super.getCondition().getFullyUnresolved(), pred, c) and + astLast(ast.getCondition().getFullyUnresolved(), pred, c) and c instanceof FalseCompletion and - first(super.getBody(), succ) + astFirst(ast.getBody(), succ) } } @@ -284,14 +308,18 @@ module Stmts { class LoopStmt = @for_each_stmt or ConditionalLoop; - abstract class LoopTree extends PreOrderTree instanceof ConditionalLoop { - abstract AstNode getCondition(); + abstract class LoopTree extends AstPreOrderTree { + LoopTree() { ast instanceof ConditionalLoop } - abstract AstNode getBody(); + abstract ControlFlowElement getCondition(); - final override predicate propagatesAbnormal(AstNode child) { child = this.getCondition() } + abstract ControlFlowElement getBody(); - final override predicate last(AstNode last, Completion c) { + final override predicate propagatesAbnormal(ControlFlowElement child) { + child = this.getCondition() + } + + final override predicate last(ControlFlowElement last, Completion c) { // Condition exits with a false completion last(this.getCondition(), last, c) and c instanceof FalseCompletion @@ -300,190 +328,204 @@ module Stmts { exists(BreakCompletion break | last(this.getBody(), last, break) and // Propagate the break upwards if we need to break out of multiple loops. - if break.getTarget() = this then c instanceof SimpleCompletion else c = break + if break.getTarget() = ast then c instanceof SimpleCompletion else c = break ) or // Body exits with a completion that does not continue the loop last(this.getBody(), last, c) and not c instanceof BreakCompletion and - not c.continuesLoop(this) + not c.continuesLoop(ast) } - override predicate succ(AstNode pred, AstNode succ, Completion c) { + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { last(this.getCondition(), pred, c) and c instanceof TrueCompletion and first(this.getBody(), succ) or last(this.getBody(), pred, c) and first(this.getCondition(), succ) and - c.continuesLoop(this) + c.continuesLoop(ast) } } - private class WhileTree extends LoopTree instanceof WhileStmt { - final override AstNode getCondition() { - result = WhileStmt.super.getCondition().getFullyUnresolved() + private class WhileTree extends LoopTree { + override WhileStmt ast; + + final override ControlFlowElement getCondition() { + result.asAstNode() = ast.getCondition().getFullyUnresolved() } - final override AstNode getBody() { result = WhileStmt.super.getBody() } + final override ControlFlowElement getBody() { result.asAstNode() = ast.getBody() } - final override predicate succ(AstNode pred, AstNode succ, Completion c) { + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { LoopTree.super.succ(pred, succ, c) or - pred = this and + pred.asAstNode() = ast and first(this.getCondition(), succ) and c instanceof SimpleCompletion } } - private class RepeatWhileTree extends LoopTree instanceof RepeatWhileStmt { - final override AstNode getCondition() { - result = RepeatWhileStmt.super.getCondition().getFullyConverted() + private class RepeatWhileTree extends LoopTree { + override RepeatWhileStmt ast; + + final override ControlFlowElement getCondition() { + result.asAstNode() = ast.getCondition().getFullyConverted() } - final override AstNode getBody() { result = RepeatWhileStmt.super.getBody() } + final override ControlFlowElement getBody() { result.asAstNode() = ast.getBody() } - final override predicate succ(AstNode pred, AstNode succ, Completion c) { + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { LoopTree.super.succ(pred, succ, c) or // Pre-order: Flow from the element to the body. - pred = this and + pred.asAstNode() = ast and first(this.getBody(), succ) and c instanceof SimpleCompletion } } - private class ForEachTree extends ControlFlowTree instanceof ForEachStmt { - final override predicate propagatesAbnormal(AstNode child) { - child = super.getSequence().getFullyConverted() + private class ForEachTree extends AstControlFlowTree { + override ForEachStmt ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getSequence().getFullyConverted() or - child = super.getPattern().getFullyUnresolved() + child.asAstNode() = ast.getPattern().getFullyUnresolved() } - final override predicate first(AstNode first) { + final override predicate first(ControlFlowElement first) { // Unlike most other statements, `foreach` statements are not modelled in // pre-order, because we use the `foreach` node itself to represent the // emptiness test that determines whether to execute the loop body - first(super.getSequence().getFullyConverted(), first) + astFirst(ast.getSequence().getFullyConverted(), first) } - final override predicate last(AstNode last, Completion c) { + final override predicate last(ControlFlowElement last, Completion c) { // Emptiness test exits with no more elements - last = this and + last.asAstNode() = ast and c.(EmptinessCompletion).isEmpty() or // Body exits with a break completion exists(BreakCompletion break | - last(super.getBody(), last, break) and + astLast(ast.getBody(), last, break) and // Propagate the break upwards if we need to break out of multiple loops. - if break.getTarget() = this then c instanceof SimpleCompletion else c = break + if break.getTarget() = ast then c instanceof SimpleCompletion else c = break ) or // Body exits abnormally - last(super.getBody(), last, c) and + astLast(ast.getBody(), last, c) and not c instanceof NormalCompletion and not c instanceof ContinueCompletion and not c instanceof BreakCompletion } - override predicate succ(AstNode pred, AstNode succ, Completion c) { + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Flow from last element of iterator expression to emptiness test - last(super.getSequence().getFullyConverted(), pred, c) and + astLast(ast.getSequence().getFullyConverted(), pred, c) and c instanceof NormalCompletion and - succ = this + succ.asAstNode() = ast or // Flow from emptiness test to first element of variable declaration/loop body - pred = this and + pred.asAstNode() = ast and c = any(EmptinessCompletion ec | not ec.isEmpty()) and - first(super.getPattern().getFullyUnresolved(), succ) + astFirst(ast.getPattern().getFullyUnresolved(), succ) or // Flow from last element of variable declaration ... - last(super.getPattern().getFullyUnresolved(), pred, c) and + astLast(ast.getPattern().getFullyUnresolved(), pred, c) and c instanceof SimpleCompletion and ( // ... to first element of loop body if no 'where' clause exists, - first(super.getBody(), succ) and - not exists(super.getWhere()) + astFirst(ast.getBody(), succ) and + not exists(ast.getWhere()) or // ... or to the 'where' clause. - first(super.getWhere().getFullyConverted(), succ) + astFirst(ast.getWhere().getFullyConverted(), succ) ) or // Flow from the where 'clause' ... - last(super.getWhere().getFullyConverted(), pred, c) and + astLast(ast.getWhere().getFullyConverted(), pred, c) and ( // to the loop body if the condition is true, c instanceof TrueCompletion and - first(super.getBody(), succ) + astFirst(ast.getBody(), succ) or // or to the emptiness test if the condition is false. c instanceof FalseCompletion and - succ = this + succ.asAstNode() = ast ) or // Flow from last element of loop body back to emptiness test. - last(super.getBody(), pred, c) and - c.continuesLoop(this) and - succ = this + astLast(ast.getBody(), pred, c) and + c.continuesLoop(ast) and + succ.asAstNode() = ast } } } - private class BreakTree extends LeafTree instanceof BreakStmt { } + private class BreakTree extends AstLeafTree { + override BreakStmt ast; + } - private class ContinueTree extends LeafTree instanceof ContinueStmt { } + private class ContinueTree extends AstLeafTree { + override ContinueStmt ast; + } - private class SwitchTree extends PreOrderTree instanceof SwitchStmt { - override predicate propagatesAbnormal(AstNode child) { - child = super.getExpr().getFullyConverted() + private class SwitchTree extends AstPreOrderTree { + override SwitchStmt ast; + + override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getExpr().getFullyConverted() } - final override predicate last(AstNode last, Completion c) { + final override predicate last(ControlFlowElement last, Completion c) { // Switch expression exits normally and there are no cases - not exists(super.getACase()) and - last(super.getExpr().getFullyConverted(), last, c) and + not exists(ast.getACase()) and + astLast(ast.getExpr().getFullyConverted(), last, c) and c instanceof NormalCompletion or // A statement exits (TODO: with a `break` completion?) - last(super.getACase().getBody(), last, c) and + astLast(ast.getACase().getBody(), last, c) and c instanceof NormalCompletion // Note: There's no need for an exit with a non-match as // Swift's switch statements are always exhaustive. } - override predicate succ(AstNode pred, AstNode succ, Completion c) { + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Flow from last element of switch expression to first element of first case c instanceof NormalCompletion and - last(super.getExpr().getFullyConverted(), pred, c) and - first(super.getFirstCase(), succ) + astLast(ast.getExpr().getFullyConverted(), pred, c) and + astFirst(ast.getFirstCase(), succ) or // Flow from last element of case pattern to next case - exists(CaseStmt case, int i | case = super.getCase(i) | - last(case.getLastLabel(), pred, c) and + exists(CaseStmt case, int i | case = ast.getCase(i) | + astLast(case.getLastLabel(), pred, c) and c.(MatchingCompletion).isNonMatch() and - first(super.getCase(i + 1), succ) + astFirst(ast.getCase(i + 1), succ) ) or // Flow from a case statement that ends in a fallthrough // statement to the next statement - last(super.getACase().getBody(), pred, c) and - first(c.(FallthroughCompletion).getDestination().getBody(), succ) + astLast(ast.getACase().getBody(), pred, c) and + astFirst(c.(FallthroughCompletion).getDestination().getBody(), succ) or // Pre-order: flow from statement itself to first switch expression - pred = this and - first(super.getExpr().getFullyConverted(), succ) and + pred.asAstNode() = ast and + astFirst(ast.getExpr().getFullyConverted(), succ) and c instanceof SimpleCompletion } } - private class CaseLabelItemTree extends PreOrderTree instanceof CaseLabelItem { - final override predicate propagatesAbnormal(AstNode child) { - child = super.getGuard().getFullyConverted() + private class CaseLabelItemTree extends AstPreOrderTree { + override CaseLabelItem ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getGuard().getFullyConverted() } - final override predicate last(AstNode last, Completion c) { + final override predicate last(ControlFlowElement last, Completion c) { // If the last node is the pattern ... - last(super.getPattern().getFullyUnresolved(), last, c) and + astLast(ast.getPattern().getFullyUnresolved(), last, c) and ( // then it's because we failed to match it c.(MatchingCompletion).isNonMatch() @@ -491,333 +533,466 @@ module Stmts { // Or because, there is no guard (in which case we can also finish the evaluation // here on a succesful match). c.(MatchingCompletion).isMatch() and - not super.hasGuard() + not ast.hasGuard() ) or // Or it can be the guard if a guard exists exists(BooleanCompletion booleanComp | - last(super.getGuard().getFullyUnresolved(), last, booleanComp) + astLast(ast.getGuard().getFullyUnresolved(), last, booleanComp) | booleanComp.getValue() = c.(MatchingCompletion).getValue() ) } - final override predicate succ(AstNode pred, AstNode succ, Completion c) { + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Pre-order: Flow from this to the pattern - pred = this and - first(super.getPattern().getFullyUnresolved(), succ) and + pred.asAstNode() = ast and + astFirst(ast.getPattern().getFullyUnresolved(), succ) and c instanceof SimpleCompletion or // Flow from a matching pattern to the guard, if any - last(super.getPattern().getFullyUnresolved(), pred, c) and + astLast(ast.getPattern().getFullyUnresolved(), pred, c) and c instanceof MatchingCompletion and - succ = super.getGuard().getFullyConverted() + succ.asAstNode() = ast.getGuard().getFullyConverted() } } - private class CaseTree extends PreOrderTree instanceof CaseStmt { - final override predicate propagatesAbnormal(AstNode child) { - child = super.getALabel() + private class CaseTree extends AstPreOrderTree { + override CaseStmt ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getALabel() or - child = super.getBody() + child.asAstNode() = ast.getBody() } - final override predicate last(AstNode last, Completion c) { + final override predicate last(ControlFlowElement last, Completion c) { // Case pattern exits with a non-match - last(super.getLastLabel().getFullyUnresolved(), last, c) and + astLast(ast.getLastLabel().getFullyUnresolved(), last, c) and not c.(MatchingCompletion).isMatch() or // Case body exits with any completion - last(super.getBody(), last, c) + astLast(ast.getBody(), last, c) } - override predicate succ(AstNode pred, AstNode succ, Completion c) { + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Pre-order: Flow from the case statement itself to the first label - pred = this and - first(super.getFirstLabel().getFullyUnresolved(), succ) and + pred.asAstNode() = ast and + astFirst(ast.getFirstLabel().getFullyUnresolved(), succ) and c instanceof SimpleCompletion or // Left-to-right evaluation of labels until we find a match exists(int i | - last(super.getLabel(i).getFullyUnresolved(), pred, c) and - first(super.getLabel(i + 1).getFullyUnresolved(), succ) and + astLast(ast.getLabel(i).getFullyUnresolved(), pred, c) and + astFirst(ast.getLabel(i + 1).getFullyUnresolved(), succ) and c.(MatchingCompletion).isNonMatch() ) or // Flow from last element of pattern to first element of body - last(super.getALabel().getFullyUnresolved(), pred, c) and - first(super.getBody(), succ) and + astLast(ast.getALabel().getFullyUnresolved(), pred, c) and + astFirst(ast.getBody(), succ) and c.(MatchingCompletion).isMatch() } } - private class FallThroughTree extends LeafTree instanceof FallthroughStmt { } + private class FallThroughTree extends AstLeafTree { + override FallthroughStmt ast; + } - private class DeferTree extends LeafTree instanceof DeferStmt { } + private class DeferTree extends AstLeafTree { + override DeferStmt ast; + } - private class ThrowExprTree extends PostOrderTree instanceof ThrowStmt { - final override predicate propagatesAbnormal(AstNode child) { - child = super.getSubExpr().getFullyConverted() + private class ThrowExprTree extends AstPostOrderTree { + override ThrowStmt ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getSubExpr().getFullyConverted() } - final override predicate first(AstNode first) { - first(super.getSubExpr().getFullyConverted(), first) + final override predicate first(ControlFlowElement first) { + astFirst(ast.getSubExpr().getFullyConverted(), first) } - final override predicate succ(AstNode pred, AstNode succ, Completion c) { + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Post-order: flow from thrown expression to the throw statement. - last(super.getSubExpr().getFullyConverted(), pred, c) and + astLast(ast.getSubExpr().getFullyConverted(), pred, c) and c instanceof NormalCompletion and - succ = this + succ.asAstNode() = ast } } - class DoOrDoCatchStmt = @do_stmt or @do_catch_stmt; + abstract class DoOrDoCatchTree extends AstPreOrderTree { + DoOrDoCatchTree() { + ast instanceof DoStmt + or + ast instanceof DoCatchStmt + } - abstract class DoOrDoCatchTree extends PreOrderTree instanceof DoOrDoCatchStmt { - abstract AstNode getBody(); + abstract ControlFlowElement getBody(); - override predicate last(AstNode last, Completion c) { + override predicate last(ControlFlowElement last, Completion c) { // The last element of the body is always a candidate for the last element of the statement. // Note that this is refined in `DoCatchTree` to only be the last statement if the body // doesn't end with a throw completion. last(this.getBody(), last, c) } - override predicate propagatesAbnormal(AstNode child) { none() } + override predicate propagatesAbnormal(ControlFlowElement child) { none() } - override predicate succ(AstNode pred, AstNode succ, Completion c) { + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Pre-order: flow from statement itself to first element of body - pred = this and + pred.asAstNode() = ast and first(this.getBody(), succ) and c instanceof SimpleCompletion } } - class DoCatchTree extends DoOrDoCatchTree instanceof DoCatchStmt { - final override AstNode getBody() { result = DoCatchStmt.super.getBody() } + class DoCatchTree extends DoOrDoCatchTree { + override DoCatchStmt ast; - override predicate last(AstNode last, Completion c) { + final override ControlFlowTree getBody() { result.asAstNode() = ast.getBody() } + + override predicate last(ControlFlowElement last, Completion c) { DoOrDoCatchTree.super.last(last, c) and not c instanceof ThrowCompletion or // Any catch can be the last element to be evaluated. - last(super.getACatch(), last, c) + astLast(ast.getACatch().getBody(), last, c) or // We failed to match on any of the clauses. // TODO: This can actually only happen if the enclosing function is marked with 'throws'. // So we could make this more precise. - last(super.getLastCatch(), last, c) and + astLast(ast.getLastCatch(), last, c) and c = any(MatchingCompletion mc | not mc.isMatch()) } - override predicate succ(AstNode pred, AstNode succ, Completion c) { + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { DoOrDoCatchTree.super.succ(pred, succ, c) or // Flow from the body to the first catch when an exception occurs last(this.getBody(), pred, c) and c instanceof ThrowCompletion and - first(super.getFirstCatch(), succ) + astFirst(ast.getFirstCatch(), succ) or exists(int i | // Flow from one `catch` clause to the next - last(super.getCatch(i), pred, c) and - first(super.getCatch(i + 1), succ) and + astLast(ast.getCatch(i), pred, c) and + astFirst(ast.getCatch(i + 1), succ) and c = any(MatchingCompletion mc | not mc.isMatch()) ) } } - class DoTree extends DoOrDoCatchTree instanceof DoStmt { - final override AstNode getBody() { result = DoStmt.super.getBody() } + class DoTree extends DoOrDoCatchTree { + override DoStmt ast; - final override predicate propagatesAbnormal(AstNode child) { child = this.getBody() } + final override ControlFlowElement getBody() { result.asAstNode() = ast.getBody() } + + final override predicate propagatesAbnormal(ControlFlowElement child) { child = this.getBody() } } } /** A class that exists to allow control-flow through incorrectly extracted AST nodes. */ -private class UnknownAstTree extends LeafTree instanceof UnknownElement { } +private class UnknownAstTree extends AstLeafTree { + UnknownAstTree() { ast.isUnknown() } +} /** * Control-flow for patterns (which appear in `switch` statements * and `catch` statements). */ module Patterns { - private class TypedTree extends StandardPostOrderTree instanceof TypedPattern { - final override ControlFlowTree getChildElement(int i) { + private class TypedTree extends AstStandardPostOrderTree { + override TypedPattern ast; + + final override ControlFlowElement getChildElement(int i) { i = 0 and - result = super.getSubPattern().getFullyUnresolved() + result.asAstNode() = ast.getSubPattern().getFullyUnresolved() } } - private class TupleTree extends PreOrderTree instanceof TuplePattern { - final override predicate propagatesAbnormal(AstNode n) { - n = super.getAnElement().getFullyUnresolved() + private class TupleTree extends AstPreOrderTree { + override TuplePattern ast; + + final override predicate propagatesAbnormal(ControlFlowElement n) { + n.asAstNode() = ast.getAnElement().getFullyUnresolved() } - final override predicate last(AstNode n, Completion c) { + final override predicate last(ControlFlowElement n, Completion c) { // A subpattern failed to match - last(super.getAnElement().getFullyUnresolved(), n, c) and + astLast(ast.getAnElement().getFullyUnresolved(), n, c) and not c.(MatchingCompletion).isMatch() or // We finished matching on all subpatterns - last(super.getLastElement().getFullyUnresolved(), n, c) and + astLast(ast.getLastElement().getFullyUnresolved(), n, c) and c instanceof NormalCompletion } - override predicate succ(AstNode pred, AstNode succ, Completion c) { + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Pre-order: Flow from this to the first subpattern - pred = this and - first(super.getFirstElement().getFullyUnresolved(), succ) and + pred.asAstNode() = ast and + astFirst(ast.getFirstElement().getFullyUnresolved(), succ) and c instanceof SimpleCompletion or // Flow from an element that matched to the next element exists(int i | - last(super.getElement(i).getFullyUnresolved(), pred, c) and + astLast(ast.getElement(i).getFullyUnresolved(), pred, c) and c.(MatchingCompletion).isMatch() and - first(super.getElement(i + 1).getFullyUnresolved(), succ) + astFirst(ast.getElement(i + 1).getFullyUnresolved(), succ) ) } } - private class ParenTree extends StandardPreOrderTree instanceof ParenPattern { - final override ControlFlowTree getChildElement(int i) { + private class ParenTree extends AstStandardPreOrderTree { + override ParenPattern ast; + + final override ControlFlowElement getChildElement(int i) { i = 0 and - result = ParenPattern.super.getResolveStep() + result.asAstNode() = ast.getResolveStep() } } - private class NamedTree extends LeafTree instanceof NamedPattern { } + private class NamedTree extends AstLeafTree { + override NamedPattern ast; + } - private class BoolTree extends LeafTree instanceof BoolPattern { } + private class BoolTree extends AstLeafTree { + override BoolPattern ast; + } - private class AnyTree extends LeafTree instanceof AnyPattern { } + private class AnyTree extends AstLeafTree { + override AnyPattern ast; + } - private class IsTree extends StandardPostOrderTree instanceof IsPattern { - final override ControlFlowTree getChildElement(int i) { + private class IsTree extends AstStandardPostOrderTree { + override IsPattern ast; + + final override ControlFlowElement getChildElement(int i) { // Note: `getSubPattern` only has a result if the `is` pattern is of the form `pattern as type`. i = 0 and - result = super.getSubPattern().getFullyUnresolved() + result.asAstNode() = ast.getSubPattern().getFullyUnresolved() or i = 1 and - result = super.getCastTypeRepr() + result.asAstNode() = ast.getCastTypeRepr() } } - private class EnumElementTree extends PreOrderTree instanceof EnumElementPattern { - final override predicate propagatesAbnormal(AstNode n) { - n = super.getSubPattern().getFullyUnresolved() + private class EnumElementTree extends AstPreOrderTree { + override EnumElementPattern ast; + + final override predicate propagatesAbnormal(ControlFlowElement n) { + n.asAstNode() = ast.getSubPattern().getFullyUnresolved() } - final override predicate last(AstNode n, Completion c) { + final override predicate last(ControlFlowElement n, Completion c) { // We finished the subpattern check - last(super.getSubPattern().getFullyUnresolved(), n, c) and + astLast(ast.getSubPattern().getFullyUnresolved(), n, c) and c instanceof NormalCompletion or // Or we got to the enum element check which failed - n = this and + n.asAstNode() = ast and c.(MatchingCompletion).isNonMatch() or // No sub pattern: We can either succeed or fail this match depending on the enum element check. - n = this and - not exists(super.getSubPattern()) and + n.asAstNode() = ast and + not exists(ast.getSubPattern()) and c instanceof MatchingCompletion } - override predicate succ(AstNode pred, AstNode succ, Completion c) { + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Pre-order: Flow from the enumeration check to the subpattern - pred = this and - first(super.getSubPattern().getFullyUnresolved(), succ) and + pred.asAstNode() = ast and + astFirst(ast.getSubPattern().getFullyUnresolved(), succ) and c.(MatchingCompletion).isMatch() } } - private class BindingTree extends PostOrderTree instanceof BindingPattern { - final override predicate propagatesAbnormal(AstNode n) { - n = super.getSubPattern().getFullyUnresolved() + private class BindingTree extends AstPostOrderTree { + override BindingPattern ast; + + final override predicate propagatesAbnormal(ControlFlowElement n) { + n.asAstNode() = ast.getSubPattern().getFullyUnresolved() } - final override predicate first(AstNode n) { - first(super.getSubPattern().getFullyUnresolved(), n) + final override predicate first(ControlFlowElement n) { + astFirst(ast.getSubPattern().getFullyUnresolved(), n) } - override predicate succ(AstNode pred, AstNode succ, Completion c) { - last(super.getSubPattern().getFullyUnresolved(), pred, c) and + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + astLast(ast.getSubPattern().getFullyUnresolved(), pred, c) and c.(MatchingCompletion).isMatch() and - succ = this + succ.asAstNode() = ast } } - private class ExprTree extends StandardPostOrderTree instanceof ExprPattern { - final override ControlFlowTree getChildElement(int i) { + private class ExprTree extends AstStandardPostOrderTree { + override ExprPattern ast; + + final override ControlFlowElement getChildElement(int i) { i = 0 and - result = super.getSubExpr().getFullyConverted() + result.asAstNode() = ast.getSubExpr().getFullyConverted() } } - private class OptionalSomeTree extends PreOrderTree instanceof OptionalSomePattern { - final override predicate propagatesAbnormal(AstNode n) { - n = super.getSubPattern().getFullyUnresolved() + private class OptionalSomeTree extends AstPreOrderTree { + override OptionalSomePattern ast; + + final override predicate propagatesAbnormal(ControlFlowElement n) { + n.asAstNode() = ast.getSubPattern().getFullyUnresolved() } - final override predicate last(AstNode n, Completion c) { + final override predicate last(ControlFlowElement n, Completion c) { // The subpattern check either failed or succeeded - last(super.getSubPattern().getFullyUnresolved(), n, c) and + astLast(ast.getSubPattern().getFullyUnresolved(), n, c) and c instanceof NormalCompletion or // Or we got to the some/none check and it failed - n = this and + n.asAstNode() = ast and not c.(MatchingCompletion).isMatch() } - override predicate succ(AstNode pred, AstNode succ, Completion c) { + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Pre-order: Flow from a matching some/none check to the subpattern - pred = this and - first(super.getSubPattern().getFullyUnresolved(), succ) and + pred.asAstNode() = ast and + astFirst(ast.getSubPattern().getFullyUnresolved(), succ) and c.(MatchingCompletion).isMatch() } } } module Decls { - private class VarDeclTree extends LeafTree instanceof VarDecl { } + private class VarDeclTree extends AstLeafTree { + override VarDecl ast; + } - private class PatternBindingDeclTree extends StandardPostOrderTree instanceof PatternBindingDecl { - final override ControlFlowTree getChildElement(int i) { + private class PatternBindingDeclTree extends AstStandardPostOrderTree { + override PatternBindingDecl ast; + + final override ControlFlowElement getChildElement(int i) { exists(int j | i = 2 * j and - result = super.getPattern(j).getFullyUnresolved() + result.asAstNode() = ast.getPattern(j).getFullyUnresolved() ) or exists(int j | i = 2 * j + 1 and - result = super.getInit(j).getFullyConverted() + result.asAstNode() = ast.getInit(j).getFullyConverted() ) } } } module Exprs { - private class AssignExprTree extends StandardPostOrderTree instanceof AssignExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getDest().getFullyConverted() and i = 0 - or - result = super.getSource().getFullyConverted() and i = 1 + module AssignExprs { + /** + * The control-flow of an assignment operation. + * + * There are two implementation of this base class: + * - One where the left-hand side has direct-to-storage-access semantics + * - One where the left-hand side has direct-to-implementation-access semantics + */ + abstract private class AssignExprTree extends AstControlFlowTree { + override AssignExpr ast; + + final override predicate first(ControlFlowElement first) { + astFirst(ast.getDest().getFullyConverted(), first) + } + + abstract predicate isSet(ControlFlowElement n); + + abstract predicate isLast(ControlFlowElement n, Completion c); + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getDest().getFullyConverted() or + child.asAstNode() = ast.getSource().getFullyConverted() + } + + predicate hasWillSetObserver() { isPropertyObserverElement(_, any(WillSetObserver obs), ast) } + + predicate hasDidSetObserver() { isPropertyObserverElement(_, any(DidSetObserver obs), ast) } + + final override predicate last(ControlFlowElement last, Completion c) { + isPropertyObserverElement(last, any(DidSetObserver obs), ast) and + completionIsValidFor(c, last) + or + not this.hasDidSetObserver() and + this.isLast(last, c) + } + + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + // Flow from the destination to the source + astLast(ast.getDest().getFullyConverted(), pred, c) and + c instanceof NormalCompletion and + astFirst(ast.getSource().getFullyConverted(), succ) + or + // Flow from the source to the `willSet` observer, if any. Otherwise, flow to the set operation + astLast(ast.getSource().getFullyConverted(), pred, c) and + c instanceof NormalCompletion and + ( + if this.hasWillSetObserver() + then isPropertyObserverElement(succ, any(WillSetObserver obs), ast) + else this.isSet(succ) + ) + or + // Flow from the set operation to the `didSet` observer, if any + this.isSet(pred) and + completionIsValidFor(c, pred) and + isPropertyObserverElement(succ, any(DidSetObserver obs), ast) + } + } + + /** + * The control-flow for assignments where the left-hand side has + * direct-to-implmentation-access semantics. + */ + class PropertyAssignExpr extends AssignExprTree { + AccessorDecl accessorDecl; + + PropertyAssignExpr() { isPropertySetterElement(_, accessorDecl, ast) } + + final override predicate isLast(ControlFlowElement last, Completion c) { + isPropertySetterElement(last, accessorDecl, ast) and + completionIsValidFor(c, last) + } + + final override predicate isSet(ControlFlowElement node) { + isPropertySetterElement(node, _, ast) + } + } + + /** + * The control-flow for assignments where the left-hand side has + * direct-to-storage-access semantics. + */ + class DirectAssignExpr extends AssignExprTree { + DirectAssignExpr() { not this instanceof PropertyAssignExpr } + + final override predicate isLast(ControlFlowElement last, Completion c) { + last.asAstNode() = ast and + completionIsValidFor(c, last) + } + + final override predicate isSet(ControlFlowElement node) { node.asAstNode() = ast } } } - private class BindOptionalTree extends StandardPostOrderTree instanceof BindOptionalExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getSubExpr().getFullyConverted() and i = 0 + private class BindOptionalTree extends AstStandardPostOrderTree { + override BindOptionalExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getSubExpr().getFullyConverted() and i = 0 } } - private class CaptureListTree extends StandardPostOrderTree instanceof CaptureListExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getBindingDecl(i).getFullyUnresolved() + private class CaptureListTree extends AstStandardPostOrderTree { + override CaptureListExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getBindingDecl(i).getFullyUnresolved() or - i = super.getNumberOfBindingDecls() and - result = super.getClosureBody().getFullyConverted() + i = ast.getNumberOfBindingDecls() and + result.asAstNode() = ast.getClosureBody().getFullyConverted() } } @@ -825,7 +1000,9 @@ module Exprs { class Closure = @auto_closure_expr or @closure_expr; // TODO: Traverse the expressions in the capture list once we extract it. - private class ClosureTree extends LeafTree instanceof ClosureExpr { } + private class ClosureTree extends AstLeafTree { + override ClosureExpr ast; + } /** * An autoclosure expression that is generated as part of a logical operation. @@ -837,298 +1014,532 @@ module Exprs { * So the `true` edge from `b1` cannot just go to `b2` since this is an implicit autoclosure. * To handle this dig into the autoclosure when it's an operand of a logical operator. */ - private class LogicalAutoClosureTree extends PreOrderTree instanceof AutoClosureExpr { - LogicalAutoClosureTree() { this = any(LogicalOperation op).getAnOperand() } + private class LogicalAutoClosureTree extends AstPreOrderTree { + override AutoClosureExpr ast; - override predicate last(AstNode last, Completion c) { - exists(Completion completion | last(super.getReturn(), last, completion) | + LogicalAutoClosureTree() { ast = any(LogicalOperation op).getAnOperand() } + + override predicate last(ControlFlowElement last, Completion c) { + exists(Completion completion | astLast(ast.getReturn(), last, completion) | if completion instanceof ReturnCompletion then c instanceof SimpleCompletion else c = completion ) } - override predicate propagatesAbnormal(AstNode child) { child = super.getReturn() } + override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getReturn() + } - override predicate succ(AstNode pred, AstNode succ, Completion c) { + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { // Pre order: Flow from this to the uniquely wrapped expr - pred = this and - first(super.getReturn(), succ) and + pred.asAstNode() = ast and + astFirst(ast.getReturn(), succ) and c instanceof SimpleCompletion } } /** An autoclosure expression that is _not_ part of a logical operation. */ - private class AutoClosureTree extends LeafTree instanceof AutoClosureExpr { + private class AutoClosureTree extends AstLeafTree { + override AutoClosureExpr ast; + AutoClosureTree() { not this instanceof LogicalAutoClosureTree } } } - private class InOutTree extends StandardPostOrderTree instanceof InOutExpr { - final override ControlFlowTree getChildElement(int i) { - i = 0 and result = super.getSubExpr().getFullyConverted() + private class InOutTree extends AstStandardPostOrderTree { + override InOutExpr ast; + + final override ControlFlowElement getChildElement(int i) { + i = 0 and result.asAstNode() = ast.getSubExpr().getFullyConverted() } } - private class SubScriptTree extends StandardPostOrderTree instanceof SubscriptExpr { - final override ControlFlowTree getChildElement(int i) { - i = 0 and result = super.getBaseExpr().getFullyConverted() + private class SubscriptTree extends AstControlFlowTree { + override SubscriptExpr ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getBaseExpr().getFullyConverted() or - i = 1 and result = super.getAnArgument().getExpr().getFullyConverted() + child.asAstNode() = ast.getAnArgument().getExpr().getFullyConverted() } - } - private class TupleTree extends StandardPostOrderTree instanceof TupleExpr { - TupleTree() { not this.getAnElement() = any(LogicalOperation op).getAnOperand() } - - final override ControlFlowTree getChildElement(int i) { - result = super.getElement(i).getFullyConverted() + final override predicate first(ControlFlowElement first) { + astFirst(ast.getBaseExpr().getFullyConverted(), first) } - } - private class TupleElementTree extends StandardPostOrderTree instanceof TupleElementExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getSubExpr().getFullyConverted() and i = 0 + final override predicate last(ControlFlowElement last, Completion c) { + ( + // If we need to do a call to a getter/setter, in which case + // the index expression is the last expression we compute before we call the property access. + if ignoreAstElement(ast) + then isPropertyGetterElement(last, _, ast) + else + // If the subscript has direct-to-storage semantics we transfer flow to th subscript + // expression itself. + last.asAstNode() = ast + ) and + completionIsValidFor(c, last) } - } - private class RebindSelfInConstructorTree extends StandardPostOrderTree instanceof RebindSelfInConstructorExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getSubExpr().getFullyConverted() and i = 0 - } - } - - private class SuperRefTree extends LeafTree instanceof SuperRefExpr { } - - private class DotSyntaxBaseIgnoredTree extends StandardPostOrderTree instanceof DotSyntaxBaseIgnoredExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getQualifier().getFullyConverted() and i = 0 + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + astLast(ast.getBaseExpr().getFullyConverted(), pred, c) and + c instanceof NormalCompletion and + astFirst(ast.getFirstArgument().getExpr().getFullyConverted(), succ) or - result = super.getSubExpr().getFullyConverted() and i = 1 + exists(int i | + astLast(ast.getArgument(i).getExpr().getFullyConverted(), pred, c) and + c instanceof NormalCompletion and + astFirst(ast.getArgument(i + 1).getExpr().getFullyConverted(), succ) + ) + or + astLast(ast.getLastArgument().getExpr().getFullyConverted(), pred, c) and + c instanceof NormalCompletion and + ( + if ignoreAstElement(ast) + then isPropertyGetterElement(succ, _, ast) + else succ.asAstNode() = ast + ) } } - private class TypeTree extends LeafTree instanceof TypeExpr { } + private class TupleTree extends AstStandardPostOrderTree { + override TupleExpr ast; - private class DynamicTypeTree extends StandardPostOrderTree instanceof DynamicTypeExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getBaseExpr().getFullyConverted() and i = 0 + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getElement(i).getFullyConverted() } } - private class LazyInitializerTree extends StandardPostOrderTree instanceof LazyInitializerExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getSubExpr().getFullyConverted() and i = 0 + private class TupleElementTree extends AstStandardPostOrderTree { + override TupleElementExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getSubExpr().getFullyConverted() and i = 0 } } - private class ObjCSelectorTree extends StandardPostOrderTree instanceof ObjCSelectorExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getSubExpr().getFullyConverted() and i = 0 + private class RebindSelfInConstructorTree extends AstStandardPostOrderTree { + override RebindSelfInConstructorExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getSubExpr().getFullyConverted() and i = 0 } } - private class OneWayTree extends StandardPostOrderTree instanceof OneWayExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getSubExpr().getFullyConverted() and i = 0 + private class SuperRefTree extends AstLeafTree { + override SuperRefExpr ast; + } + + private class DotSyntaxBaseIgnoredTree extends AstStandardPostOrderTree { + override DotSyntaxBaseIgnoredExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getQualifier().getFullyConverted() and i = 0 + or + result.asAstNode() = ast.getSubExpr().getFullyConverted() and i = 1 } } - private class OptionalEvaluationTree extends StandardPostOrderTree instanceof OptionalEvaluationExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getSubExpr().getFullyConverted() and i = 0 + private class TypeTree extends AstLeafTree { + override TypeExpr ast; + } + + private class DynamicTypeTree extends AstStandardPostOrderTree { + override DynamicTypeExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getBaseExpr().getFullyConverted() and i = 0 } } - private class NonInterpolatedLiteralExprTree extends LeafTree instanceof LiteralExpr { + private class LazyInitializerTree extends AstStandardPostOrderTree { + override LazyInitializerExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getSubExpr().getFullyConverted() and i = 0 + } + } + + private class ObjCSelectorTree extends AstStandardPostOrderTree { + override ObjCSelectorExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getSubExpr().getFullyConverted() and i = 0 + } + } + + private class OneWayTree extends AstStandardPostOrderTree { + override OneWayExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getSubExpr().getFullyConverted() and i = 0 + } + } + + private class OptionalEvaluationTree extends AstStandardPostOrderTree { + override OptionalEvaluationExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getSubExpr().getFullyConverted() and i = 0 + } + } + + private class NonInterpolatedLiteralExprTree extends AstLeafTree { + override LiteralExpr ast; + NonInterpolatedLiteralExprTree() { // This one needs special handling - not this instanceof InterpolatedStringLiteralExpr + not ast instanceof InterpolatedStringLiteralExpr } } - private class InterpolatedStringLiteralExprTree extends StandardPostOrderTree instanceof InterpolatedStringLiteralExpr { - final override ControlFlowTree getChildElement(int i) { + private class InterpolatedStringLiteralExprTree extends AstStandardPostOrderTree { + override InterpolatedStringLiteralExpr ast; + + final override ControlFlowElement getChildElement(int i) { none() // TODO } } - private class DeclRefExprTree extends LeafTree instanceof DeclRefExpr { } + module DeclRefExprs { + class DeclRefExprLValueTree extends AstLeafTree { + override DeclRefExpr ast; - private class MemberRefTree extends StandardPostOrderTree instanceof MemberRefExpr { - final override AstNode getChildElement(int i) { - result = super.getBaseExpr().getFullyConverted() and i = 0 + DeclRefExprLValueTree() { isLValue(ast) } + } + + abstract class DeclRefExprRValueTree extends AstControlFlowTree { + override DeclRefExpr ast; + + DeclRefExprRValueTree() { isRValue(ast) } + + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + none() + } + + override predicate propagatesAbnormal(ControlFlowElement child) { none() } + } + + private class PropertyDeclRefRValueTree extends DeclRefExprRValueTree { + AccessorDecl accessor; + + PropertyDeclRefRValueTree() { isPropertyGetterElement(_, accessor, ast) } + + final override predicate first(ControlFlowElement first) { + isPropertyGetterElement(first, accessor, ast) + } + + final override predicate last(ControlFlowElement last, Completion c) { + isPropertyGetterElement(last, accessor, ast) and + completionIsValidFor(c, last) + } + } + + private class DirectDeclRefRValueTree extends DeclRefExprRValueTree { + DirectDeclRefRValueTree() { not this instanceof PropertyDeclRefRValueTree } + + final override predicate first(ControlFlowElement first) { first.asAstNode() = ast } + + final override predicate last(ControlFlowElement last, Completion c) { + last.asAstNode() = ast and + completionIsValidFor(c, last) + } } } - private class ApplyExprTree extends StandardPostOrderTree instanceof ApplyExpr { + module MemberRefs { + /** + * The control-flow of a member reference expression. + * + * There are two implementation of this base class: + * - One for lvalues + * - One for rvalues + */ + abstract private class MemberRefTreeBase extends AstControlFlowTree { + override MemberRefExpr ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getBaseExpr().getFullyConverted() + } + + final override predicate first(ControlFlowElement first) { + astFirst(ast.getBaseExpr().getFullyConverted(), first) + } + } + + /** + * The lvalue implementation of `MemberRefTreeBase` + */ + private class MemberRefLValueTree extends MemberRefTreeBase { + MemberRefLValueTree() { isLValue(ast) } + + final override predicate last(ControlFlowElement last, Completion c) { + last.asAstNode() = ast and + completionIsValidFor(c, last) + } + + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + astLast(ast.getBaseExpr().getFullyConverted(), pred, c) and + c instanceof NormalCompletion and + succ.asAstNode() = ast + } + } + + /** + * The rvalue base implementation of `MemberRefTreeBase`. + * + * There are two implementations of this class: + * - One for direct-storage semantics + * - One for calls to getters + */ + abstract private class MemberRefRValueTree extends MemberRefTreeBase { + MemberRefRValueTree() { isRValue(ast) } + } + + /** + * Control-flow for rvalue member accesses with direct-to-storage semantics + * or ordinary semantics without a getter. + */ + private class DirectMemberRefRValue extends MemberRefRValueTree { + DirectMemberRefRValue() { not this instanceof PropertyMemberRefRValue } + + final override predicate last(ControlFlowElement last, Completion c) { + last.asAstNode() = ast and + completionIsValidFor(c, last) + } + + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + astLast(ast.getBaseExpr().getFullyConverted(), pred, c) and + c instanceof NormalCompletion and + succ.asAstNode() = ast + } + } + + /** + * Control-flow for rvalue member accesses with direct-to-implementation semantics + * or ordinary semantics that includes a getter. + */ + private class PropertyMemberRefRValue extends MemberRefRValueTree { + AccessorDecl accessor; + + PropertyMemberRefRValue() { isPropertyGetterElement(_, accessor, ast) } + + final override predicate last(ControlFlowElement last, Completion c) { + isPropertyGetterElement(last, accessor, ast) and + completionIsValidFor(c, last) + } + + override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + astLast(ast.getBaseExpr().getFullyConverted(), pred, c) and + c instanceof NormalCompletion and + isPropertyGetterElement(succ, accessor, ast) + } + } + } + + private class ApplyExprTree extends AstStandardPostOrderTree { + override ApplyExpr ast; + ApplyExprTree() { // This one is handled in `LogicalNotTree`. - not this instanceof UnaryLogicalOperation and + not ast instanceof UnaryLogicalOperation and // These are handled in `LogicalOrTree` and `LogicalAndTree`. - not this instanceof BinaryLogicalOperation + not ast instanceof BinaryLogicalOperation } - final override ControlFlowTree getChildElement(int i) { + final override ControlFlowElement getChildElement(int i) { i = -1 and - result = super.getFunction().getFullyConverted() + result.asAstNode() = ast.getFunction().getFullyConverted() or - result = super.getArgument(i).getExpr().getFullyConverted() + result.asAstNode() = ast.getArgument(i).getExpr().getFullyConverted() } } - private class DefaultArgumentTree extends LeafTree instanceof DefaultArgumentExpr { } + private class DefaultArgumentTree extends AstLeafTree { + override DefaultArgumentExpr ast; + } - private class ForceValueTree extends StandardPostOrderTree instanceof ForceValueExpr { - override AstNode getChildElement(int i) { + private class ForceValueTree extends AstStandardPostOrderTree { + override ForceValueExpr ast; + + override ControlFlowElement getChildElement(int i) { i = 0 and - result = super.getSubExpr().getFullyConverted() + result.asAstNode() = ast.getSubExpr().getFullyConverted() } } - private class LogicalAndTree extends PostOrderTree, LogicalAndExpr { - final override predicate propagatesAbnormal(AstNode child) { - child = this.getAnOperand().getFullyConverted() + private class LogicalAndTree extends AstPostOrderTree { + override LogicalAndExpr ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getAnOperand().getFullyConverted() } - final override predicate first(AstNode first) { - first(this.getLeftOperand().getFullyConverted(), first) + final override predicate first(ControlFlowElement first) { + astFirst(ast.getLeftOperand().getFullyConverted(), first) } - final override predicate succ(AstNode pred, AstNode succ, Completion c) { - last(this.getLeftOperand().getFullyConverted(), pred, c) and + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + astLast(ast.getLeftOperand().getFullyConverted(), pred, c) and c instanceof TrueCompletion and - first(this.getRightOperand().getFullyConverted(), succ) + astFirst(ast.getRightOperand().getFullyConverted(), succ) or - last(this.getLeftOperand().getFullyConverted(), pred, c) and + astLast(ast.getLeftOperand().getFullyConverted(), pred, c) and c instanceof FalseCompletion and - succ = this + succ.asAstNode() = ast or - last(this.getRightOperand().getFullyConverted(), pred, c) and + astLast(ast.getRightOperand().getFullyConverted(), pred, c) and c instanceof NormalCompletion and - succ = this + succ.asAstNode() = ast } } - private class LogicalNotTree extends PostOrderTree, NotExpr { - final override predicate propagatesAbnormal(AstNode child) { - child = this.getOperand().getFullyConverted() + private class LogicalNotTree extends AstPostOrderTree { + override NotExpr ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getOperand().getFullyConverted() } - final override predicate first(AstNode first) { - first(this.getOperand().getFullyConverted(), first) + final override predicate first(ControlFlowElement first) { + astFirst(ast.getOperand().getFullyConverted(), first) } - final override predicate succ(AstNode pred, AstNode succ, Completion c) { - succ = this and - last(this.getOperand().getFullyConverted(), pred, c) and + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + succ.asAstNode() = ast and + astLast(ast.getOperand().getFullyConverted(), pred, c) and c instanceof NormalCompletion } } - private class LogicalOrTree extends PostOrderTree, LogicalOrExpr { - final override predicate propagatesAbnormal(AstNode child) { - child = this.getAnOperand().getFullyConverted() + private class LogicalOrTree extends AstPostOrderTree { + override LogicalOrExpr ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getAnOperand().getFullyConverted() } - final override predicate first(AstNode first) { - first(this.getLeftOperand().getFullyConverted(), first) + final override predicate first(ControlFlowElement first) { + astFirst(ast.getLeftOperand().getFullyConverted(), first) } - final override predicate succ(AstNode pred, AstNode succ, Completion c) { - last(this.getLeftOperand().getFullyConverted(), pred, c) and + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + astLast(ast.getLeftOperand().getFullyConverted(), pred, c) and c instanceof FalseCompletion and - first(this.getRightOperand().getFullyConverted(), succ) + astFirst(ast.getRightOperand().getFullyConverted(), succ) or - last(this.getLeftOperand().getFullyConverted(), pred, c) and + astLast(ast.getLeftOperand().getFullyConverted(), pred, c) and c instanceof TrueCompletion and - succ = this + succ.asAstNode() = ast or - last(this.getRightOperand().getFullyConverted(), pred, c) and + astLast(ast.getRightOperand().getFullyConverted(), pred, c) and c instanceof NormalCompletion and - succ = this + succ.asAstNode() = ast } } - private class VarargExpansionTree extends StandardPostOrderTree instanceof VarargExpansionExpr { - final override ControlFlowTree getChildElement(int i) { + private class VarargExpansionTree extends AstStandardPostOrderTree { + override VarargExpansionExpr ast; + + final override ControlFlowElement getChildElement(int i) { i = 0 and - result = super.getSubExpr().getFullyConverted() + result.asAstNode() = ast.getSubExpr().getFullyConverted() } } - private class ArrayTree extends StandardPostOrderTree instanceof ArrayExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getElement(i).getFullyConverted() + private class ArrayTree extends AstStandardPostOrderTree { + override ArrayExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getElement(i).getFullyConverted() } } - private class EnumIsCaseTree extends StandardPostOrderTree instanceof EnumIsCaseExpr { - final override ControlFlowTree getChildElement(int i) { - result = super.getSubExpr().getFullyConverted() and i = 0 + private class EnumIsCaseTree extends AstStandardPostOrderTree { + override EnumIsCaseExpr ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getSubExpr().getFullyConverted() and i = 0 or - result = super.getTypeRepr().getFullyUnresolved() and i = 1 + result.asAstNode() = ast.getTypeRepr().getFullyUnresolved() and i = 1 } } - private class IfTree extends PostOrderTree instanceof IfExpr { - final override predicate propagatesAbnormal(AstNode child) { - child = super.getCondition().getFullyConverted() + private class IfTree extends AstPostOrderTree { + override IfExpr ast; + + final override predicate propagatesAbnormal(ControlFlowElement child) { + child.asAstNode() = ast.getCondition().getFullyConverted() or - child = super.getBranch(_).getFullyConverted() + child.asAstNode() = ast.getBranch(_).getFullyConverted() } - final override predicate first(AstNode first) { - first(super.getCondition().getFullyConverted(), first) + final override predicate first(ControlFlowElement first) { + astFirst(ast.getCondition().getFullyConverted(), first) } - final override predicate succ(AstNode pred, AstNode succ, Completion c) { - last(super.getCondition().getFullyConverted(), pred, c) and + final override predicate succ(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + astLast(ast.getCondition().getFullyConverted(), pred, c) and exists(boolean b | b = c.(BooleanCompletion).getValue() and - first(super.getBranch(b).getFullyConverted(), succ) + astFirst(ast.getBranch(b).getFullyConverted(), succ) ) or - last(super.getBranch(_).getFullyConverted(), pred, c) and - succ = this and + astLast(ast.getBranch(_).getFullyConverted(), pred, c) and + succ.asAstNode() = ast and c instanceof NormalCompletion } } - private class TryTree extends StandardPostOrderTree instanceof TryExpr { - override ControlFlowTree getChildElement(int i) { + private class TryTree extends AstStandardPostOrderTree { + override TryExpr ast; + + override ControlFlowElement getChildElement(int i) { i = 0 and - result = super.getSubExpr().getFullyConverted() + result.asAstNode() = ast.getSubExpr().getFullyConverted() } } - private class DictionaryLiteralTree extends StandardPostOrderTree instanceof DictionaryExpr { - override ControlFlowTree getChildElement(int i) { result = super.getElement(i) } + private class DictionaryLiteralTree extends AstStandardPostOrderTree { + override DictionaryExpr ast; + + override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getElement(i).getFullyConverted() + } } module Conversions { class ConversionOrIdentity = @identity_expr or @explicit_cast_expr or @implicit_conversion_expr; - abstract class ConversionOrIdentityTree extends StandardPostOrderTree instanceof ConversionOrIdentity { + abstract class ConversionOrIdentityTree extends AstStandardPostOrderTree { + ConversionOrIdentityTree() { ast instanceof ConversionOrIdentity } + abstract predicate convertsFrom(Expr e); - override ControlFlowTree getChildElement(int i) { + override ControlFlowElement getChildElement(int i) { i = 0 and - this.convertsFrom(result) + this.convertsFrom(result.asAstNode()) } } // This isn't actually a conversion, but it behaves like one. - private class IdentityTree extends ConversionOrIdentityTree instanceof IdentityExpr { - override predicate convertsFrom(Expr e) { IdentityExpr.super.convertsFrom(e) } + private class IdentityTree extends ConversionOrIdentityTree { + override IdentityExpr ast; + + override predicate convertsFrom(Expr e) { ast.convertsFrom(e) } } - private class ExplicitCastTree extends ConversionOrIdentityTree instanceof ExplicitCastExpr { - override predicate convertsFrom(Expr e) { ExplicitCastExpr.super.convertsFrom(e) } + private class ExplicitCastTree extends ConversionOrIdentityTree { + override ExplicitCastExpr ast; + + override predicate convertsFrom(Expr e) { ast.convertsFrom(e) } } - private class ImplicitConversionTree extends ConversionOrIdentityTree instanceof ImplicitConversionExpr { - override predicate convertsFrom(Expr e) { ImplicitConversionExpr.super.convertsFrom(e) } + private class ImplicitConversionTree extends ConversionOrIdentityTree { + override ImplicitConversionExpr ast; + + override predicate convertsFrom(Expr e) { ast.convertsFrom(e) } } } } @@ -1140,8 +1551,8 @@ private Scope parent(Scope n) { /** Gets the CFG scope of node `n`. */ pragma[inline] -CfgScope getCfgScope(AstNode n) { - exists(AstNode n0 | +CfgScope getCfgScope(ControlFlowElement n) { + exists(ControlFlowElement n0 | pragma[only_bind_into](n0) = n and pragma[only_bind_into](result) = getCfgScopeImpl(n0) ) @@ -1151,11 +1562,18 @@ cached private module Cached { /** Gets the CFG scope of node `n`. */ cached - CfgScope getCfgScopeImpl(AstNode n) { + CfgScope getCfgScopeImpl(ControlFlowElement n) { forceCachingInSameStage() and result = parent*(scopeOf(n)) } + private CfgScope scopeOf(ControlFlowElement n) { + result = scopeOfAst(n.asAstNode()) or + result = scopeOfAst(n.(PropertyGetterElement).getRef()) or + result = scopeOfAst(n.(PropertySetterElement).getAssignExpr()) or + result = scopeOfAst(n.(PropertyObserverElement).getAssignExpr()) + } + cached newtype TSuccessorType = TSuccessorSuccessor() or diff --git a/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImplSpecific.qll b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImplSpecific.qll index ff72929e41d..7c11c2c2f84 100644 --- a/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImplSpecific.qll +++ b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImplSpecific.qll @@ -1,30 +1,14 @@ private import swift as S private import ControlFlowGraphImpl as Impl -private import Completion as Comp +import Completion private import codeql.swift.controlflow.ControlFlowGraph as CFG private import Splitting as Splitting +private import Scope +import ControlFlowElements +import AstControlFlowTrees /** The base class for `ControlFlowTree`. */ -class ControlFlowTreeBase extends S::AstNode { } - -class ControlFlowElement = S::AstNode; - -class Completion = Comp::Completion; - -/** - * Hold if `c` represents normal evaluation of a statement or an - * expression. - */ -predicate completionIsNormal(Completion c) { c instanceof Comp::NormalCompletion } - -/** - * Hold if `c` represents simple (normal) evaluation of a statement or an - * expression. - */ -predicate completionIsSimple(Completion c) { c instanceof Comp::SimpleCompletion } - -/** Holds if `c` is a valid completion for `e`. */ -predicate completionIsValidFor(Completion c, ControlFlowElement e) { c.isValidFor(e) } +class ControlFlowTreeBase = ControlFlowElement; class CfgScope = CFG::CfgScope; diff --git a/swift/ql/lib/codeql/swift/controlflow/internal/Scope.qll b/swift/ql/lib/codeql/swift/controlflow/internal/Scope.qll index 99dc955d1e6..c06c67d1665 100644 --- a/swift/ql/lib/codeql/swift/controlflow/internal/Scope.qll +++ b/swift/ql/lib/codeql/swift/controlflow/internal/Scope.qll @@ -16,7 +16,7 @@ private module Scope { class TypeRange = Callable::TypeRange; class Range extends AstNode, TypeRange { - Range getOuterScope() { result = scopeOf(this) } + Range getOuterScope() { result = scopeOfAst(this) } } } @@ -235,14 +235,14 @@ private module Cached { } cached - AstNode getParent(AstNode ast) { getChild(result, _) = ast } + AstNode getParentOfAst(AstNode ast) { getChild(result, _) = ast } } /** Gets the enclosing scope of a node */ cached -AstNode scopeOf(AstNode n) { - exists(AstNode p | p = getParent(n) | - if p instanceof Scope then p = result else result = scopeOf(p) +AstNode scopeOfAst(AstNode n) { + exists(AstNode p | p = getParentOfAst(n) | + if p instanceof Scope then p = result else result = scopeOfAst(p) ) } diff --git a/swift/ql/lib/codeql/swift/controlflow/internal/Splitting.qll b/swift/ql/lib/codeql/swift/controlflow/internal/Splitting.qll index d09e9b2fd2b..e0b2961283b 100644 --- a/swift/ql/lib/codeql/swift/controlflow/internal/Splitting.qll +++ b/swift/ql/lib/codeql/swift/controlflow/internal/Splitting.qll @@ -6,6 +6,8 @@ private import swift private import Completion private import ControlFlowGraphImpl private import codeql.swift.controlflow.ControlFlowGraph +private import AstControlFlowTrees +private import ControlFlowElements cached private module Cached { @@ -37,7 +39,7 @@ private module ConditionalCompletionSplitting { private class ConditionalCompletionSplitKind extends SplitKind, TConditionalCompletionSplitKind { override int getListOrder() { result = 0 } - override predicate isEnabled(AstNode n) { this.appliesTo(n) } + override predicate isEnabled(ControlFlowElement n) { this.appliesTo(n) } override string toString() { result = "ConditionalCompletion" } } @@ -45,47 +47,50 @@ private module ConditionalCompletionSplitting { private class ConditionalCompletionSplitImpl extends SplitImpl, ConditionalCompletionSplit { override ConditionalCompletionSplitKind getKind() { any() } - override predicate hasEntry(AstNode pred, AstNode succ, Completion c) { + override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) { succ(pred, succ, c) and last(succ, _, completion) and ( - last(succ.(NotExpr).getOperand().getFullyConverted(), pred, c) and + astLast(succ.asAstNode().(NotExpr).getOperand().getFullyConverted(), pred, c) and completion.(BooleanCompletion).getDual() = c or - last(succ.(LogicalAndExpr).getAnOperand().getFullyConverted(), pred, c) and + astLast(succ.asAstNode().(LogicalAndExpr).getAnOperand().getFullyConverted(), pred, c) and completion = c or - last(succ.(LogicalOrExpr).getAnOperand().getFullyConverted(), pred, c) and + astLast(succ.asAstNode().(LogicalOrExpr).getAnOperand().getFullyConverted(), pred, c) and completion = c or - succ = + succ.asAstNode() = any(IfExpr ce | - last(ce.getBranch(_).getFullyConverted(), pred, c) and + astLast(ce.getBranch(_).getFullyConverted(), pred, c) and completion = c ) or - exists(Expr e | - succ.(Exprs::Conversions::ConversionOrIdentityTree).convertsFrom(e) and - last(e, pred, c) and + exists(Expr e, Exprs::Conversions::ConversionOrIdentityTree conv | + succ.asAstNode() = conv.getAst() and + conv.convertsFrom(e) and + astLast(e, pred, c) and completion = c ) ) } - override predicate hasEntryScope(CfgScope scope, AstNode succ) { none() } + override predicate hasEntryScope(CfgScope scope, ControlFlowElement succ) { none() } - override predicate hasExit(AstNode pred, AstNode succ, Completion c) { + override predicate hasExit(ControlFlowElement pred, ControlFlowElement succ, Completion c) { this.appliesTo(pred) and succ(pred, succ, c) and if c instanceof ConditionalCompletion then completion = c else any() } - override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) { + override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) { this.appliesTo(last) and succExit(scope, last, c) and if c instanceof ConditionalCompletion then completion = c else any() } - override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) { none() } + override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) { + none() + } } } diff --git a/swift/ql/lib/codeql/swift/dataflow/Ssa.qll b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll new file mode 100644 index 00000000000..9053428d4b0 --- /dev/null +++ b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll @@ -0,0 +1,69 @@ +cached +module Ssa { + private import swift + private import internal.SsaImplCommon as SsaImplCommon + private import internal.SsaImplSpecific as SsaImplSpecific + private import codeql.swift.controlflow.CfgNodes + private import codeql.swift.controlflow.ControlFlowGraph + private import codeql.swift.controlflow.BasicBlocks + + cached + class Definition extends SsaImplCommon::Definition { + cached + Location getLocation() { none() } + + cached + ControlFlowNode getARead() { + exists(VarDecl v, BasicBlock bb, int i | + SsaImplCommon::ssaDefReachesRead(v, this, bb, i) and + SsaImplSpecific::variableRead(bb, i, v, true) and + result = bb.getNode(i) + ) + } + + cached + ControlFlowNode getAFirstRead() { + exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 | + this.definesAt(_, bb1, i1) and + SsaImplCommon::adjacentDefNoUncertainReads(this, bb1, i1, bb2, i2) and + result = bb2.getNode(i2) + ) + } + + cached + predicate adjacentReadPair(ControlFlowNode read1, ControlFlowNode read2) { + exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 | + read1 = bb1.getNode(i1) and + SsaImplSpecific::variableRead(bb1, i1, _, true) and + SsaImplCommon::adjacentDefNoUncertainReads(this, bb1, i1, bb2, i2) and + read2 = bb2.getNode(i2) + ) + } + } + + cached + class WriteDefinition extends Definition, SsaImplCommon::WriteDefinition { + cached + override Location getLocation() { + exists(BasicBlock bb, int i | + this.definesAt(_, bb, i) and + result = bb.getNode(i).getLocation() + ) + } + + /** + * Holds if this SSA definition represents a direct assignment of `value` + * to the underlying variable. + */ + cached + predicate assigns(ExprCfgNode value) { + exists( + AssignExpr a, BasicBlock bb, int i // TODO: use CFG node for assignment expr + | + this.definesAt(_, bb, i) and + a = bb.getNode(i).getNode().asAstNode() and + value.getNode().asAstNode() = a.getSource() + ) + } + } +} diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll index c393950de90..fc3321d2263 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll @@ -1,6 +1,8 @@ private import swift private import DataFlowPublic private import DataFlowDispatch +private import codeql.swift.controlflow.CfgNodes +private import codeql.swift.dataflow.Ssa /** Gets the callable in which this node occurs. */ DataFlowCallable nodeGetEnclosingCallable(NodeImpl n) { result = n.getEnclosingCallable() } @@ -25,22 +27,54 @@ abstract class NodeImpl extends Node { abstract string toStringImpl(); } +private class ExprNodeImpl extends ExprNode, NodeImpl { + override Location getLocationImpl() { result = expr.getLocation() } + + override string toStringImpl() { result = expr.toString() } +} + +private class SsaDefinitionNodeImpl extends SsaDefinitionNode, NodeImpl { + override Location getLocationImpl() { result = def.getLocation() } + + override string toStringImpl() { result = def.toString() } +} + /** A collection of cached types and predicates to be evaluated in the same stage. */ cached private module Cached { cached - newtype TNode = TODO_TNode() + newtype TNode = + TExprNode(ExprCfgNode e) or + TNormalParameterNode(ParamDecl p) or + TSsaDefinitionNode(Ssa::Definition def) + + private predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) { + exists(Ssa::Definition def | + // Step from assignment RHS to def + def.(Ssa::WriteDefinition).assigns(nodeFrom.getCfgNode()) and + nodeTo.asDefinition() = def + or + // step from def to first read + nodeFrom.asDefinition() = def and + nodeTo.getCfgNode() = def.getAFirstRead() + or + // use-use flow + def.adjacentReadPair(nodeFrom.getCfgNode(), nodeTo.getCfgNode()) + ) + } /** * This is the local flow predicate that is used as a building block in global * data flow. */ cached - predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { none() } + predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { + localFlowStepCommon(nodeFrom, nodeTo) + } /** This is the local flow predicate that is exposed. */ cached - predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) { none() } + predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) { localFlowStepCommon(nodeFrom, nodeTo) } cached newtype TContentSet = TODO_TContentSet() @@ -58,6 +92,20 @@ private module ParameterNodes { abstract class ParameterNodeImpl extends NodeImpl { predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { none() } } + + class NormalParameterNode extends ParameterNodeImpl, TNormalParameterNode { + ParamDecl param; + + NormalParameterNode() { this = TNormalParameterNode(param) } + + override Location getLocationImpl() { result = param.getLocation() } + + override string toStringImpl() { result = param.toString() } + + override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { + none() // TODO + } + } } import ParameterNodes diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPublic.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPublic.qll index 4241640acff..70afd2651e1 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPublic.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPublic.qll @@ -3,6 +3,8 @@ private import DataFlowDispatch private import DataFlowPrivate private import codeql.swift.controlflow.ControlFlowGraph private import codeql.swift.controlflow.BasicBlocks +private import codeql.swift.controlflow.CfgNodes +private import codeql.swift.dataflow.Ssa /** * An element, viewed as a node in a data flow graph. Either an expression @@ -29,6 +31,21 @@ class Node extends TNode { ) { this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } + + /** + * Gets this node's underlying expression, if any. + */ + Expr asExpr() { none() } + + /** + * Gets this data flow node's corresponding control flow node. + */ + ControlFlowNode getCfgNode() { none() } + + /** + * Gets this node's underlying SSA definition, if any. + */ + Ssa::Definition asDefinition() { none() } } /** @@ -38,13 +55,31 @@ class Node extends TNode { * to multiple `ExprNode`s, just like it may correspond to multiple * `ControlFlow::Node`s. */ -class ExprNode extends Node { } +class ExprNode extends Node, TExprNode { + ExprCfgNode expr; + + ExprNode() { this = TExprNode(expr) } + + override Expr asExpr() { result = expr.getNode().asAstNode() } + + override ControlFlowNode getCfgNode() { result = expr } +} /** * The value of a parameter at function entry, viewed as a node in a data * flow graph. */ -class ParameterNode extends Node { } +class ParameterNode extends Node, TNormalParameterNode instanceof ParameterNodeImpl { } + +/** + */ +class SsaDefinitionNode extends Node, TSsaDefinitionNode { + Ssa::Definition def; + + SsaDefinitionNode() { this = TSsaDefinitionNode(def) } + + override Ssa::Definition asDefinition() { result = def } +} /** * A node associated with an object after an operation that might have diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/SsaImplSpecific.qll b/swift/ql/lib/codeql/swift/dataflow/internal/SsaImplSpecific.qll index 0eed5427740..bd7373935aa 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/SsaImplSpecific.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/SsaImplSpecific.qll @@ -16,10 +16,17 @@ class SourceVariable = VarDecl; predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { exists(AssignExpr assign | - bb.getNode(i).getNode() = assign and + bb.getNode(i).getNode().asAstNode() = assign and assign.getDest() = v.getAnAccess() and certain = true ) + or + exists(PatternBindingDecl decl, Pattern pattern | + bb.getNode(i).getNode().asAstNode() = pattern and + decl.getAPattern() = pattern and + v.getParentPattern() = pattern and + certain = true + ) } private predicate isLValue(DeclRefExpr ref) { any(AssignExpr assign).getDest() = ref } @@ -27,7 +34,7 @@ private predicate isLValue(DeclRefExpr ref) { any(AssignExpr assign).getDest() = predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { exists(DeclRefExpr ref | not isLValue(ref) and - bb.getNode(i).getNode() = ref and + bb.getNode(i).getNode().asAstNode() = ref and v = ref.getDecl() and certain = true ) diff --git a/swift/ql/lib/codeql/swift/elements/decl/AbstractFunctionDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/AbstractFunctionDecl.qll index 2e7aac740b4..514cec194fc 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/AbstractFunctionDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/AbstractFunctionDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.AbstractFunctionDecl -class AbstractFunctionDecl extends AbstractFunctionDeclBase { } +class AbstractFunctionDecl extends AbstractFunctionDeclBase { + override string toString() { result = this.getName() } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/AccessorDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/AccessorDecl.qll index 1d885e0c4c3..bd1fb6b2998 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/AccessorDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/AccessorDecl.qll @@ -1,4 +1,32 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.AccessorDecl -class AccessorDecl extends AccessorDeclBase { } +private predicate isKnownAccessorKind(AccessorDecl decl, string kind) { + decl.isGetter() and kind = "get" + or + decl.isSetter() and kind = "set" + or + decl.isWillSet() and kind = "willSet" + or + decl.isDidSet() and kind = "didSet" +} + +class AccessorDecl extends AccessorDeclBase { + predicate isPropertyObserver() { + this instanceof WillSetObserver or this instanceof DidSetObserver + } + + override string toString() { + isKnownAccessorKind(this, result) + or + not isKnownAccessorKind(this, _) and + result = super.toString() + } +} + +class WillSetObserver extends AccessorDecl { + WillSetObserver() { this.isWillSet() } +} + +class DidSetObserver extends AccessorDecl { + DidSetObserver() { this.isDidSet() } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/ConstructorDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/ConstructorDecl.qll index 375eff6acc3..6e34c2aa981 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/ConstructorDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/ConstructorDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.ConstructorDecl -class ConstructorDecl extends ConstructorDeclBase { } +class ConstructorDecl extends ConstructorDeclBase { + override string toString() { result = "deinit" } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/DestructorDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/DestructorDecl.qll index 8cc68eaf7c8..9f08e1eab3b 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/DestructorDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/DestructorDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.DestructorDecl -class DestructorDecl extends DestructorDeclBase { } +class DestructorDecl extends DestructorDeclBase { + override string toString() { result = "init" } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/EnumCaseDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/EnumCaseDecl.qll index 8af1fbe691c..d7aab6d9fe1 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/EnumCaseDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/EnumCaseDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.EnumCaseDecl -class EnumCaseDecl extends EnumCaseDeclBase { } +class EnumCaseDecl extends EnumCaseDeclBase { + override string toString() { result = "case ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/EnumElementDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/EnumElementDecl.qll index e0322c530a4..965e0b3efdd 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/EnumElementDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/EnumElementDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.EnumElementDecl -class EnumElementDecl extends EnumElementDeclBase { } +class EnumElementDecl extends EnumElementDeclBase { + override string toString() { result = this.getName() } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/ExtensionDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/ExtensionDecl.qll index 5f850f6a874..ce9e10da1af 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/ExtensionDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/ExtensionDecl.qll @@ -1,4 +1,7 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.ExtensionDecl -class ExtensionDecl extends ExtensionDeclBase { } +class ExtensionDecl extends ExtensionDeclBase { + override string toString() { + result = "extension" // TODO: Once we extract the name of this one we can provide a better `toString`. + } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/IfConfigDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/IfConfigDecl.qll index d23143374e9..6fe6302658c 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/IfConfigDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/IfConfigDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.IfConfigDecl -class IfConfigDecl extends IfConfigDeclBase { } +class IfConfigDecl extends IfConfigDeclBase { + override string toString() { result = "#if ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/ImportDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/ImportDecl.qll index 6fca161a726..db687ecfad8 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/ImportDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/ImportDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.ImportDecl -class ImportDecl extends ImportDeclBase { } +class ImportDecl extends ImportDeclBase { + override string toString() { result = "import ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/OperatorDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/OperatorDecl.qll index 677ebf6b41e..592cdf4fd50 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/OperatorDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/OperatorDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.OperatorDecl -class OperatorDecl extends OperatorDeclBase { } +class OperatorDecl extends OperatorDeclBase { + override string toString() { result = this.getName() } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/PatternBindingDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/PatternBindingDecl.qll index d33a36b4c08..6bf9c021224 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/PatternBindingDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/PatternBindingDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.PatternBindingDecl -class PatternBindingDecl extends PatternBindingDeclBase { } +class PatternBindingDecl extends PatternBindingDeclBase { + override string toString() { result = "var ... = ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/PoundDiagnosticDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/PoundDiagnosticDecl.qll index 9eedacc02bc..e80a0770dac 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/PoundDiagnosticDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/PoundDiagnosticDecl.qll @@ -1,4 +1,7 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.PoundDiagnosticDecl -class PoundDiagnosticDecl extends PoundDiagnosticDeclBase { } +class PoundDiagnosticDecl extends PoundDiagnosticDeclBase { + override string toString() { + result = "#..." // TODO: Once we extract whether this is an error or a warning we can improve this. + } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/PrecedenceGroupDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/PrecedenceGroupDecl.qll index 9364d2b796e..b2e59fcb896 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/PrecedenceGroupDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/PrecedenceGroupDecl.qll @@ -1,4 +1,7 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.PrecedenceGroupDecl -class PrecedenceGroupDecl extends PrecedenceGroupDeclBase { } +class PrecedenceGroupDecl extends PrecedenceGroupDeclBase { + override string toString() { + result = "precedencegroup ..." // TODO: Once we extract the name we can improve this. + } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/SubscriptDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/SubscriptDecl.qll index 9a44c97eb37..2da63cfb986 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/SubscriptDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/SubscriptDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.SubscriptDecl -class SubscriptDecl extends SubscriptDeclBase { } +class SubscriptDecl extends SubscriptDeclBase { + override string toString() { result = "subscript ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/TopLevelCodeDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/TopLevelCodeDecl.qll index 606f5906473..a84dfec4dc0 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/TopLevelCodeDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/TopLevelCodeDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.TopLevelCodeDecl -class TopLevelCodeDecl extends TopLevelCodeDeclBase { } +class TopLevelCodeDecl extends TopLevelCodeDeclBase { + override string toString() { result = this.getBody().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/TypeDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/TypeDecl.qll index a7dfd753222..61012b16023 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/TypeDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/TypeDecl.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.TypeDecl -class TypeDecl extends TypeDeclBase { } +class TypeDecl extends TypeDeclBase { + override string toString() { result = this.getName() } +} diff --git a/swift/ql/lib/codeql/swift/elements/decl/VarDecl.qll b/swift/ql/lib/codeql/swift/elements/decl/VarDecl.qll index f6940944c34..95a5801c1c1 100644 --- a/swift/ql/lib/codeql/swift/elements/decl/VarDecl.qll +++ b/swift/ql/lib/codeql/swift/elements/decl/VarDecl.qll @@ -1,4 +1,8 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.decl.VarDecl +private import codeql.swift.elements.expr.DeclRefExpr -class VarDecl extends VarDeclBase { } +class VarDecl extends VarDeclBase { + override string toString() { result = this.getName() } + + DeclRefExpr getAnAccess() { result.getDecl() = this } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/ApplyExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/ApplyExpr.qll index a18cb4a6b92..27083d41ce3 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ApplyExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ApplyExpr.qll @@ -4,4 +4,11 @@ private import codeql.swift.elements.expr.DeclRefExpr class ApplyExpr extends ApplyExprBase { FuncDecl getStaticTarget() { result = this.getFunction().(DeclRefExpr).getDecl() } + + override string toString() { + result = "call to " + this.getStaticTarget().toString() + or + not exists(this.getStaticTarget()) and + result = "call to ..." + } } diff --git a/swift/ql/lib/codeql/swift/elements/expr/Argument.qll b/swift/ql/lib/codeql/swift/elements/expr/Argument.qll index a4d2229a1e3..c2a25b877a4 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/Argument.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/Argument.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.Argument -class Argument extends ArgumentBase { } +class Argument extends ArgumentBase { + override string toString() { result = this.getLabel() + ": " + this.getExpr().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/ArrayExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/ArrayExpr.qll index 8bb5f7222bf..8722a9ca601 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ArrayExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ArrayExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.ArrayExpr -class ArrayExpr extends ArrayExprBase { } +class ArrayExpr extends ArrayExprBase { + override string toString() { result = "[...]" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/ArrowExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/ArrowExpr.qll index 301c0bdb557..94ea8624d68 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ArrowExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ArrowExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.ArrowExpr -class ArrowExpr extends ArrowExprBase { } +class ArrowExpr extends ArrowExprBase { + override string toString() { result = "... -> ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/AssignExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/AssignExpr.qll index d7d29d8682e..4669306bea1 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/AssignExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/AssignExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.AssignExpr -class AssignExpr extends AssignExprBase { } +class AssignExpr extends AssignExprBase { + override string toString() { result = " ... = ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/AutoClosureExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/AutoClosureExpr.qll index 00113f026d5..8782a913cca 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/AutoClosureExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/AutoClosureExpr.qll @@ -4,4 +4,6 @@ private import codeql.swift.elements.stmt.ReturnStmt class AutoClosureExpr extends AutoClosureExprBase { /** Gets the implicit return statement generated by this autoclosure expression. */ ReturnStmt getReturn() { result = unique( | | this.getBody().getAnElement()) } + + override string toString() { result = this.getBody().toString() } } diff --git a/swift/ql/lib/codeql/swift/elements/expr/AwaitExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/AwaitExpr.qll index 76a17b9d181..378296432bc 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/AwaitExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/AwaitExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.AwaitExpr -class AwaitExpr extends AwaitExprBase { } +class AwaitExpr extends AwaitExprBase { + override string toString() { result = "await ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/BinaryExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/BinaryExpr.qll index 45116c436e4..2ce90e38bb9 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/BinaryExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/BinaryExpr.qll @@ -7,4 +7,6 @@ class BinaryExpr extends BinaryExprBase { Expr getRightOperand() { result = this.getArgument(1).getExpr() } Expr getAnOperand() { result = [this.getLeftOperand(), this.getRightOperand()] } + + override string toString() { result = "... " + this.getFunction().toString() + " ..." } } diff --git a/swift/ql/lib/codeql/swift/elements/expr/BindOptionalExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/BindOptionalExpr.qll index 2b1aca34665..bcf3252ea17 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/BindOptionalExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/BindOptionalExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.BindOptionalExpr -class BindOptionalExpr extends BindOptionalExprBase { } +class BindOptionalExpr extends BindOptionalExprBase { + override string toString() { result = "...?" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/BooleanLiteralExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/BooleanLiteralExpr.qll index d9a9902efa6..7f013a801dc 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/BooleanLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/BooleanLiteralExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.BooleanLiteralExpr -class BooleanLiteralExpr extends BooleanLiteralExprBase { } +class BooleanLiteralExpr extends BooleanLiteralExprBase { + override string toString() { result = this.getValue().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/CaptureListExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/CaptureListExpr.qll index 2495a22c892..c0fe030390d 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/CaptureListExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/CaptureListExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.CaptureListExpr -class CaptureListExpr extends CaptureListExprBase { } +class CaptureListExpr extends CaptureListExprBase { + override string toString() { result = this.getClosureBody().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/ClosureExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/ClosureExpr.qll index 4f2158734ef..093deb19577 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ClosureExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ClosureExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.ClosureExpr -class ClosureExpr extends ClosureExprBase { } +class ClosureExpr extends ClosureExprBase { + override string toString() { result = "{ ... }" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/DeclRefExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/DeclRefExpr.qll index 9531860838e..3e9ebb8d589 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/DeclRefExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/DeclRefExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.DeclRefExpr -class DeclRefExpr extends DeclRefExprBase { } +class DeclRefExpr extends DeclRefExprBase { + override string toString() { result = this.getDecl().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/DefaultArgumentExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/DefaultArgumentExpr.qll index bb1435c97e7..c61d2680d74 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/DefaultArgumentExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/DefaultArgumentExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.DefaultArgumentExpr -class DefaultArgumentExpr extends DefaultArgumentExprBase { } +class DefaultArgumentExpr extends DefaultArgumentExprBase { + override string toString() { result = "default " + this.getParamDecl().getName() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/DictionaryExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/DictionaryExpr.qll index ac27502bf42..6f4edce8e45 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/DictionaryExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/DictionaryExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.DictionaryExpr -class DictionaryExpr extends DictionaryExprBase { } +class DictionaryExpr extends DictionaryExprBase { + override string toString() { result = "[...]" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/DiscardAssignmentExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/DiscardAssignmentExpr.qll index 298fa78d708..a31c6167bb6 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/DiscardAssignmentExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/DiscardAssignmentExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.DiscardAssignmentExpr -class DiscardAssignmentExpr extends DiscardAssignmentExprBase { } +class DiscardAssignmentExpr extends DiscardAssignmentExprBase { + override string toString() { result = "_" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/DotSelfExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/DotSelfExpr.qll index ebbec08fe2b..a82f55cc422 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/DotSelfExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/DotSelfExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.DotSelfExpr -class DotSelfExpr extends DotSelfExprBase { } +class DotSelfExpr extends DotSelfExprBase { + override string toString() { result = ".self" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/DotSyntaxBaseIgnoredExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/DotSyntaxBaseIgnoredExpr.qll index 74054ea1020..919bf1bfea1 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/DotSyntaxBaseIgnoredExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/DotSyntaxBaseIgnoredExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.DotSyntaxBaseIgnoredExpr -class DotSyntaxBaseIgnoredExpr extends DotSyntaxBaseIgnoredExprBase { } +class DotSyntaxBaseIgnoredExpr extends DotSyntaxBaseIgnoredExprBase { + override string toString() { result = "." + this.getSubExpr().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/DynamicMemberRefExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/DynamicMemberRefExpr.qll index e34a66e051f..757bc196e4d 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/DynamicMemberRefExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/DynamicMemberRefExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.DynamicMemberRefExpr -class DynamicMemberRefExpr extends DynamicMemberRefExprBase { } +class DynamicMemberRefExpr extends DynamicMemberRefExprBase { + override string toString() { result = "." + this.getMember().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/DynamicSubscriptExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/DynamicSubscriptExpr.qll index b3b19ed38b6..5114a6a4ebc 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/DynamicSubscriptExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/DynamicSubscriptExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.DynamicSubscriptExpr -class DynamicSubscriptExpr extends DynamicSubscriptExprBase { } +class DynamicSubscriptExpr extends DynamicSubscriptExprBase { + override string toString() { result = this.getMember().toString() + "[...]" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/DynamicTypeExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/DynamicTypeExpr.qll index 9b72774a885..3af1f67b7bb 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/DynamicTypeExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/DynamicTypeExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.DynamicTypeExpr -class DynamicTypeExpr extends DynamicTypeExprBase { } +class DynamicTypeExpr extends DynamicTypeExprBase { + override string toString() { result = "type(of: ...)" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/EnumIsCaseExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/EnumIsCaseExpr.qll index ee17c76f2b1..450fd199e49 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/EnumIsCaseExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/EnumIsCaseExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.EnumIsCaseExpr -class EnumIsCaseExpr extends EnumIsCaseExprBase { } +class EnumIsCaseExpr extends EnumIsCaseExprBase { + override string toString() { result = "... is " + this.getElement().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/ExplicitCastExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/ExplicitCastExpr.qll index b6928dbd936..8c1923fdfbb 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ExplicitCastExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ExplicitCastExpr.qll @@ -2,4 +2,6 @@ private import codeql.swift.generated.expr.ExplicitCastExpr class ExplicitCastExpr extends ExplicitCastExprBase { override predicate convertsFrom(Expr e) { explicit_cast_exprs(this, e) } + + override string toString() { result = "(" + this.getType() + ") ..." } } diff --git a/swift/ql/lib/codeql/swift/elements/expr/FloatLiteralExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/FloatLiteralExpr.qll index 91240e43acf..5a40548d1fc 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/FloatLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/FloatLiteralExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.FloatLiteralExpr -class FloatLiteralExpr extends FloatLiteralExprBase { } +class FloatLiteralExpr extends FloatLiteralExprBase { + override string toString() { result = this.getStringValue() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/ForceTryExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/ForceTryExpr.qll index 3f9ee33a2b8..90a1d4f82b6 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ForceTryExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ForceTryExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.ForceTryExpr -class ForceTryExpr extends ForceTryExprBase { } +class ForceTryExpr extends ForceTryExprBase { + override string toString() { result = "try! ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/ForceValueExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/ForceValueExpr.qll index c2b13fdbef4..bdb0645226b 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ForceValueExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ForceValueExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.ForceValueExpr -class ForceValueExpr extends ForceValueExprBase { } +class ForceValueExpr extends ForceValueExprBase { + override string toString() { result = "...!" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/IfExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/IfExpr.qll index 75d41d3b484..10a8a098180 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/IfExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/IfExpr.qll @@ -8,4 +8,6 @@ class IfExpr extends IfExprBase { b = false and result = this.getElseExpr() } + + override string toString() { result = "... ? ... : ..." } } diff --git a/swift/ql/lib/codeql/swift/elements/expr/ImplicitConversionExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/ImplicitConversionExpr.qll index ca00b7ec7ed..f8c2285978a 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ImplicitConversionExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ImplicitConversionExpr.qll @@ -2,4 +2,6 @@ private import codeql.swift.generated.expr.ImplicitConversionExpr class ImplicitConversionExpr extends ImplicitConversionExprBase { override predicate convertsFrom(Expr e) { implicit_conversion_exprs(this, e) } + + override string toString() { result = "(" + this.getType().toString() + ") ..." } } diff --git a/swift/ql/lib/codeql/swift/elements/expr/InOutExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/InOutExpr.qll index f4a29e0e1cc..f1e40ed36fe 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/InOutExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/InOutExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.InOutExpr -class InOutExpr extends InOutExprBase { } +class InOutExpr extends InOutExprBase { + override string toString() { result = "&..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/IntegerLiteralExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/IntegerLiteralExpr.qll index 121b1b9e3b3..87e7bdffae2 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/IntegerLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/IntegerLiteralExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.IntegerLiteralExpr -class IntegerLiteralExpr extends IntegerLiteralExprBase { } +class IntegerLiteralExpr extends IntegerLiteralExprBase { + override string toString() { result = this.getStringValue() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/InterpolatedStringLiteralExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/InterpolatedStringLiteralExpr.qll index 3095dc12001..599d780357f 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/InterpolatedStringLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/InterpolatedStringLiteralExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.InterpolatedStringLiteralExpr -class InterpolatedStringLiteralExpr extends InterpolatedStringLiteralExprBase { } +class InterpolatedStringLiteralExpr extends InterpolatedStringLiteralExprBase { + override string toString() { result = "\"...\"" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/IsExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/IsExpr.qll index e823adc489c..d87fc7fe05a 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/IsExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/IsExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.IsExpr -class IsExpr extends IsExprBase { } +class IsExpr extends IsExprBase { + override string toString() { result = "... is ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/KeyPathApplicationExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/KeyPathApplicationExpr.qll index 857981bbe5c..80c0f1d5678 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/KeyPathApplicationExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/KeyPathApplicationExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.KeyPathApplicationExpr -class KeyPathApplicationExpr extends KeyPathApplicationExprBase { } +class KeyPathApplicationExpr extends KeyPathApplicationExprBase { + override string toString() { result = "\\...[...]" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/KeyPathDotExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/KeyPathDotExpr.qll index 2882cbc4d87..18bd4ee4186 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/KeyPathDotExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/KeyPathDotExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.KeyPathDotExpr -class KeyPathDotExpr extends KeyPathDotExprBase { } +class KeyPathDotExpr extends KeyPathDotExprBase { + override string toString() { result = "\\...." } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/KeyPathExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/KeyPathExpr.qll index 4c7ef30c882..4869ac44bde 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/KeyPathExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/KeyPathExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.KeyPathExpr -class KeyPathExpr extends KeyPathExprBase { } +class KeyPathExpr extends KeyPathExprBase { + override string toString() { result = "#keyPath(...)" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/LazyInitializerExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/LazyInitializerExpr.qll index 55e2398782a..9564ece75e3 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/LazyInitializerExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/LazyInitializerExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.LazyInitializerExpr -class LazyInitializerExpr extends LazyInitializerExprBase { } +class LazyInitializerExpr extends LazyInitializerExprBase { + override string toString() { result = this.getSubExpr().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/MagicIdentifierLiteralExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/MagicIdentifierLiteralExpr.qll index 3fa5f6f1341..fd435f47dce 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/MagicIdentifierLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/MagicIdentifierLiteralExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.MagicIdentifierLiteralExpr -class MagicIdentifierLiteralExpr extends MagicIdentifierLiteralExprBase { } +class MagicIdentifierLiteralExpr extends MagicIdentifierLiteralExprBase { + override string toString() { result = "#..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/MakeTemporarilyEscapableExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/MakeTemporarilyEscapableExpr.qll index 085a6d213a6..342a799e1c9 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/MakeTemporarilyEscapableExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/MakeTemporarilyEscapableExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.MakeTemporarilyEscapableExpr -class MakeTemporarilyEscapableExpr extends MakeTemporarilyEscapableExprBase { } +class MakeTemporarilyEscapableExpr extends MakeTemporarilyEscapableExprBase { + override string toString() { result = this.getSubExpr().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/MemberRefExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/MemberRefExpr.qll index a85e5c8766d..fa56b0b8fba 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/MemberRefExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/MemberRefExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.MemberRefExpr -class MemberRefExpr extends MemberRefExprBase { } +class MemberRefExpr extends MemberRefExprBase { + override string toString() { result = "." + this.getMember().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/NilLiteralExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/NilLiteralExpr.qll index bd4731de537..a2e2281888f 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/NilLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/NilLiteralExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.NilLiteralExpr -class NilLiteralExpr extends NilLiteralExprBase { } +class NilLiteralExpr extends NilLiteralExprBase { + override string toString() { result = "nil" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/ObjCSelectorExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/ObjCSelectorExpr.qll index 8a4a8d34b69..45ccb04ee55 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ObjCSelectorExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ObjCSelectorExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.ObjCSelectorExpr -class ObjCSelectorExpr extends ObjCSelectorExprBase { } +class ObjCSelectorExpr extends ObjCSelectorExprBase { + override string toString() { result = "#selector(...)" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/ObjectLiteralExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/ObjectLiteralExpr.qll index 28702427376..61e2408c79c 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ObjectLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ObjectLiteralExpr.qll @@ -1,4 +1,7 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.ObjectLiteralExpr -class ObjectLiteralExpr extends ObjectLiteralExprBase { } +class ObjectLiteralExpr extends ObjectLiteralExprBase { + override string toString() { + result = "#...(...)" // TOOD: We can improve this once we extract the kind + } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/OneWayExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/OneWayExpr.qll index 702e661bba0..a10c3e4187e 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/OneWayExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/OneWayExpr.qll @@ -2,4 +2,6 @@ private import codeql.swift.generated.expr.OneWayExpr class OneWayExpr extends OneWayExprBase { override predicate convertsFrom(Expr e) { one_way_exprs(this, e) } + + override string toString() { result = this.getSubExpr().toString() } } diff --git a/swift/ql/lib/codeql/swift/elements/expr/OptionalTryExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/OptionalTryExpr.qll index 56bba573716..eb643b70079 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/OptionalTryExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/OptionalTryExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.OptionalTryExpr -class OptionalTryExpr extends OptionalTryExprBase { } +class OptionalTryExpr extends OptionalTryExprBase { + override string toString() { result = "try? ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/OtherConstructorDeclRefExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/OtherConstructorDeclRefExpr.qll index 2cfbd3ea4d9..f8b309ed3d0 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/OtherConstructorDeclRefExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/OtherConstructorDeclRefExpr.qll @@ -1,4 +1,7 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.OtherConstructorDeclRefExpr -class OtherConstructorDeclRefExpr extends OtherConstructorDeclRefExprBase { } +class OtherConstructorDeclRefExpr extends OtherConstructorDeclRefExprBase { + override string toString() { + result = "call to ..." // TODO: We can make this better once we extract the constructor call + } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/ParenExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/ParenExpr.qll index 7b0b8178c53..763a7106b98 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/ParenExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/ParenExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.ParenExpr -class ParenExpr extends ParenExprBase { } +class ParenExpr extends ParenExprBase { + override string toString() { result = "(...)" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/RebindSelfInConstructorExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/RebindSelfInConstructorExpr.qll index 5aa2711801d..8f42cf72c9e 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/RebindSelfInConstructorExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/RebindSelfInConstructorExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.RebindSelfInConstructorExpr -class RebindSelfInConstructorExpr extends RebindSelfInConstructorExprBase { } +class RebindSelfInConstructorExpr extends RebindSelfInConstructorExprBase { + override string toString() { result = "self = ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/RegexLiteralExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/RegexLiteralExpr.qll index ef087bc1681..dcb91129ca7 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/RegexLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/RegexLiteralExpr.qll @@ -1,4 +1,7 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.RegexLiteralExpr -class RegexLiteralExpr extends RegexLiteralExprBase { } +class RegexLiteralExpr extends RegexLiteralExprBase { + override string toString() { + result = "..." // TODO: We can improve this once we extract the regex + } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/StringLiteralExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/StringLiteralExpr.qll index cd2ff43a039..23b5dbab7bd 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/StringLiteralExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/StringLiteralExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.StringLiteralExpr -class StringLiteralExpr extends StringLiteralExprBase { } +class StringLiteralExpr extends StringLiteralExprBase { + override string toString() { result = this.getValue() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/SubscriptExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/SubscriptExpr.qll index 8ae51baae26..4d681e189de 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/SubscriptExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/SubscriptExpr.qll @@ -1,4 +1,19 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.SubscriptExpr -class SubscriptExpr extends SubscriptExprBase { } +class SubscriptExpr extends SubscriptExprBase { + Argument getFirstArgument() { + exists(int i | + result = this.getArgument(i) and + not exists(this.getArgument(i - 1)) + ) + } + + Argument getLastArgument() { + exists(int i | + result = this.getArgument(i) and + not exists(this.getArgument(i + 1)) + ) + } + + override string toString() { result = "...[...]" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/SuperRefExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/SuperRefExpr.qll index 292431be730..2a2def26a84 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/SuperRefExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/SuperRefExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.SuperRefExpr -class SuperRefExpr extends SuperRefExprBase { } +class SuperRefExpr extends SuperRefExprBase { + override string toString() { result = "super" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/TryExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/TryExpr.qll index 0c9fc51cfe0..76a23bb2a7b 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/TryExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/TryExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.TryExpr -class TryExpr extends TryExprBase { } +class TryExpr extends TryExprBase { + override string toString() { result = "try ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/TupleElementExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/TupleElementExpr.qll index 9e92dae7f00..f021deae540 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/TupleElementExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/TupleElementExpr.qll @@ -1,4 +1,7 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.TupleElementExpr -class TupleElementExpr extends TupleElementExprBase { } +class TupleElementExpr extends TupleElementExprBase { + override string toString() { + result = "." + this.getIndex() // TODO: Can be improved once we extract the name + } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/TupleExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/TupleExpr.qll index 1ffe11cf28b..c8465638645 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/TupleExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/TupleExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.TupleExpr -class TupleExpr extends TupleExprBase { } +class TupleExpr extends TupleExprBase { + override string toString() { result = "(...)" } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/TypeExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/TypeExpr.qll index 9ecde1d026d..ad9077a4c25 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/TypeExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/TypeExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.TypeExpr -class TypeExpr extends TypeExprBase { } +class TypeExpr extends TypeExprBase { + override string toString() { result = this.getType().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/expr/VarargExpansionExpr.qll b/swift/ql/lib/codeql/swift/elements/expr/VarargExpansionExpr.qll index 0769e7ce6dd..200c8735f07 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/VarargExpansionExpr.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/VarargExpansionExpr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.expr.VarargExpansionExpr -class VarargExpansionExpr extends VarargExpansionExprBase { } +class VarargExpansionExpr extends VarargExpansionExprBase { + override string toString() { result = this.getSubExpr().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/pattern/AnyPattern.qll b/swift/ql/lib/codeql/swift/elements/pattern/AnyPattern.qll index 3db71bff5db..f2f62d42906 100644 --- a/swift/ql/lib/codeql/swift/elements/pattern/AnyPattern.qll +++ b/swift/ql/lib/codeql/swift/elements/pattern/AnyPattern.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.pattern.AnyPattern -class AnyPattern extends AnyPatternBase { } +class AnyPattern extends AnyPatternBase { + override string toString() { result = "_" } +} diff --git a/swift/ql/lib/codeql/swift/elements/pattern/BindingPattern.qll b/swift/ql/lib/codeql/swift/elements/pattern/BindingPattern.qll index 2c9d534942b..ef081d052c6 100644 --- a/swift/ql/lib/codeql/swift/elements/pattern/BindingPattern.qll +++ b/swift/ql/lib/codeql/swift/elements/pattern/BindingPattern.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.pattern.BindingPattern -class BindingPattern extends BindingPatternBase { } +class BindingPattern extends BindingPatternBase { + override string toString() { result = "let ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/pattern/BoolPattern.qll b/swift/ql/lib/codeql/swift/elements/pattern/BoolPattern.qll index 69e915e0ac6..5fa2ec249a8 100644 --- a/swift/ql/lib/codeql/swift/elements/pattern/BoolPattern.qll +++ b/swift/ql/lib/codeql/swift/elements/pattern/BoolPattern.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.pattern.BoolPattern -class BoolPattern extends BoolPatternBase { } +class BoolPattern extends BoolPatternBase { + override string toString() { result = this.getValue().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/pattern/EnumElementPattern.qll b/swift/ql/lib/codeql/swift/elements/pattern/EnumElementPattern.qll index 4a8d71ab603..0244bce6cd3 100644 --- a/swift/ql/lib/codeql/swift/elements/pattern/EnumElementPattern.qll +++ b/swift/ql/lib/codeql/swift/elements/pattern/EnumElementPattern.qll @@ -1,4 +1,9 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.pattern.EnumElementPattern -class EnumElementPattern extends EnumElementPatternBase { } +class EnumElementPattern extends EnumElementPatternBase { + override string toString() { + if this.hasSubPattern() + then result = "." + this.getElement().toString() + "(...)" + else result = "." + this.getElement().toString() + } +} diff --git a/swift/ql/lib/codeql/swift/elements/pattern/ExprPattern.qll b/swift/ql/lib/codeql/swift/elements/pattern/ExprPattern.qll index 55ab31a698f..87f5b748622 100644 --- a/swift/ql/lib/codeql/swift/elements/pattern/ExprPattern.qll +++ b/swift/ql/lib/codeql/swift/elements/pattern/ExprPattern.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.pattern.ExprPattern -class ExprPattern extends ExprPatternBase { } +class ExprPattern extends ExprPatternBase { + override string toString() { result = this.getSubExpr().toString() } +} diff --git a/swift/ql/lib/codeql/swift/elements/pattern/IsPattern.qll b/swift/ql/lib/codeql/swift/elements/pattern/IsPattern.qll index e5b9fc22e53..b1a9594c927 100644 --- a/swift/ql/lib/codeql/swift/elements/pattern/IsPattern.qll +++ b/swift/ql/lib/codeql/swift/elements/pattern/IsPattern.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.pattern.IsPattern -class IsPattern extends IsPatternBase { } +class IsPattern extends IsPatternBase { + override string toString() { result = "... is ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/pattern/NamedPattern.qll b/swift/ql/lib/codeql/swift/elements/pattern/NamedPattern.qll index bfd06575bb9..7f980677196 100644 --- a/swift/ql/lib/codeql/swift/elements/pattern/NamedPattern.qll +++ b/swift/ql/lib/codeql/swift/elements/pattern/NamedPattern.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.pattern.NamedPattern -class NamedPattern extends NamedPatternBase { } +class NamedPattern extends NamedPatternBase { + override string toString() { result = this.getName() } +} diff --git a/swift/ql/lib/codeql/swift/elements/pattern/OptionalSomePattern.qll b/swift/ql/lib/codeql/swift/elements/pattern/OptionalSomePattern.qll index acd3ee82477..9fb71e55d6f 100644 --- a/swift/ql/lib/codeql/swift/elements/pattern/OptionalSomePattern.qll +++ b/swift/ql/lib/codeql/swift/elements/pattern/OptionalSomePattern.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.pattern.OptionalSomePattern -class OptionalSomePattern extends OptionalSomePatternBase { } +class OptionalSomePattern extends OptionalSomePatternBase { + override string toString() { result = "let ...?" } +} diff --git a/swift/ql/lib/codeql/swift/elements/pattern/ParenPattern.qll b/swift/ql/lib/codeql/swift/elements/pattern/ParenPattern.qll index 8d5c6db26fa..8f518e43d31 100644 --- a/swift/ql/lib/codeql/swift/elements/pattern/ParenPattern.qll +++ b/swift/ql/lib/codeql/swift/elements/pattern/ParenPattern.qll @@ -2,4 +2,6 @@ private import codeql.swift.generated.pattern.ParenPattern class ParenPattern extends ParenPatternBase { final override Pattern getResolveStep() { paren_patterns(this, result) } + + override string toString() { result = "(...)" } } diff --git a/swift/ql/lib/codeql/swift/elements/pattern/TuplePattern.qll b/swift/ql/lib/codeql/swift/elements/pattern/TuplePattern.qll index a09c5040b3b..fcd7f7fc238 100644 --- a/swift/ql/lib/codeql/swift/elements/pattern/TuplePattern.qll +++ b/swift/ql/lib/codeql/swift/elements/pattern/TuplePattern.qll @@ -9,4 +9,6 @@ class TuplePattern extends TuplePatternBase { not exists(this.getElement(i + 1)) ) } + + override string toString() { result = "(...)" } } diff --git a/swift/ql/lib/codeql/swift/elements/pattern/TypedPattern.qll b/swift/ql/lib/codeql/swift/elements/pattern/TypedPattern.qll index 95fea7f2302..728dede4977 100644 --- a/swift/ql/lib/codeql/swift/elements/pattern/TypedPattern.qll +++ b/swift/ql/lib/codeql/swift/elements/pattern/TypedPattern.qll @@ -1,4 +1,7 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.pattern.TypedPattern -class TypedPattern extends TypedPatternBase { } +class TypedPattern extends TypedPatternBase { + override string toString() { + if exists(this.getSubPattern()) then result = "... as ..." else result = "is ..." + } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/BraceStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/BraceStmt.qll index a0f497bb7c0..d22afad3efa 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/BraceStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/BraceStmt.qll @@ -9,4 +9,6 @@ class BraceStmt extends BraceStmtBase { not exists(this.getElement(i + 1)) ) } + + override string toString() { result = "{ ... }" } } diff --git a/swift/ql/lib/codeql/swift/elements/stmt/BreakStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/BreakStmt.qll index 7a756b97656..02caf1b8cc8 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/BreakStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/BreakStmt.qll @@ -1,4 +1,10 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.BreakStmt -class BreakStmt extends BreakStmtBase { } +class BreakStmt extends BreakStmtBase { + override string toString() { + result = "break " + this.getTargetName() + or + not this.hasTargetName() and + result = "break" + } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/CaseLabelItem.qll b/swift/ql/lib/codeql/swift/elements/stmt/CaseLabelItem.qll index 98b410005a1..8a8ea2e358e 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/CaseLabelItem.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/CaseLabelItem.qll @@ -1,4 +1,9 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.CaseLabelItem -class CaseLabelItem extends CaseLabelItemBase { } +class CaseLabelItem extends CaseLabelItemBase { + override string toString() { + if this.hasGuard() + then result = this.getPattern().toString() + " where ..." + else result = this.getPattern().toString() + } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/CaseStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/CaseStmt.qll index 3e9ba6acfd1..b2f3d5d952f 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/CaseStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/CaseStmt.qll @@ -9,4 +9,6 @@ class CaseStmt extends CaseStmtBase { not exists(this.getLabel(i + 1)) ) } + + override string toString() { result = "case ..." } } diff --git a/swift/ql/lib/codeql/swift/elements/stmt/ConditionElement.qll b/swift/ql/lib/codeql/swift/elements/stmt/ConditionElement.qll index e41f0d706e4..d11c1ef668b 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/ConditionElement.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/ConditionElement.qll @@ -9,4 +9,6 @@ class ConditionElement extends ConditionElementBase { or result = this.getPattern() } + + override string toString() { result = this.getUnderlyingCondition().toString() } } diff --git a/swift/ql/lib/codeql/swift/elements/stmt/ContinueStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/ContinueStmt.qll index b31996ae298..9e0dbc7eb65 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/ContinueStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/ContinueStmt.qll @@ -1,4 +1,10 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.ContinueStmt -class ContinueStmt extends ContinueStmtBase { } +class ContinueStmt extends ContinueStmtBase { + override string toString() { + result = "continue " + this.getTargetName() + or + not this.hasTargetName() and + result = "continue" + } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/DeferStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/DeferStmt.qll index 69fd1f37d96..017b13e6d59 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/DeferStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/DeferStmt.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.DeferStmt -class DeferStmt extends DeferStmtBase { } +class DeferStmt extends DeferStmtBase { + override string toString() { result = "defer { ... }" } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/DoCatchStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/DoCatchStmt.qll index b9d437d5725..c9fa1f85794 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/DoCatchStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/DoCatchStmt.qll @@ -9,4 +9,6 @@ class DoCatchStmt extends DoCatchStmtBase { not exists(this.getCatch(i + 1)) ) } + + override string toString() { result = "do { ... } catch { ... }" } } diff --git a/swift/ql/lib/codeql/swift/elements/stmt/DoStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/DoStmt.qll index c6cdd8af01f..057abb1d8c5 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/DoStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/DoStmt.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.DoStmt -class DoStmt extends DoStmtBase { } +class DoStmt extends DoStmtBase { + override string toString() { result = "do { ... }" } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/FailStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/FailStmt.qll index 568d812c506..c6ca7a0c923 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/FailStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/FailStmt.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.FailStmt -class FailStmt extends FailStmtBase { } +class FailStmt extends FailStmtBase { + override string toString() { result = "fail" } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/FallthroughStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/FallthroughStmt.qll index 9c8c21b8ffc..50a81c511f2 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/FallthroughStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/FallthroughStmt.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.FallthroughStmt -class FallthroughStmt extends FallthroughStmtBase { } +class FallthroughStmt extends FallthroughStmtBase { + override string toString() { result = "fallthrough" } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/ForEachStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/ForEachStmt.qll index 5a89881ee25..9024cea2cd2 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/ForEachStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/ForEachStmt.qll @@ -1,4 +1,9 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.ForEachStmt -class ForEachStmt extends ForEachStmtBase { } +class ForEachStmt extends ForEachStmtBase { + override string toString() { + if this.hasWhere() + then result = "for ... in ... where ... { ... }" + else result = "for ... in ... { ... }" + } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/GuardStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/GuardStmt.qll index 5604fa2388c..d2955b3d294 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/GuardStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/GuardStmt.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.GuardStmt -class GuardStmt extends GuardStmtBase { } +class GuardStmt extends GuardStmtBase { + override string toString() { result = "guard ... else { ... }" } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/IfStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/IfStmt.qll index ebd428bba5c..d7b274f3d21 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/IfStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/IfStmt.qll @@ -13,4 +13,10 @@ class IfStmt extends IfStmtBase { b = false and result = this.getElse() } + + override string toString() { + if this.hasElse() + then result = "if ... then { ... } else { ... }" + else result = "if ... then { ... }" + } } diff --git a/swift/ql/lib/codeql/swift/elements/stmt/LabeledStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/LabeledStmt.qll index 36c1c391db9..77bbe2129ad 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/LabeledStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/LabeledStmt.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.LabeledStmt -class LabeledStmt extends LabeledStmtBase { } +class LabeledStmt extends LabeledStmtBase { + override string toString() { result = this.getLabel() + ": ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/PoundAssertStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/PoundAssertStmt.qll index c65b5f02440..f2d9f2d74df 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/PoundAssertStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/PoundAssertStmt.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.PoundAssertStmt -class PoundAssertStmt extends PoundAssertStmtBase { } +class PoundAssertStmt extends PoundAssertStmtBase { + override string toString() { result = "#assert ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/RepeatWhileStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/RepeatWhileStmt.qll index 5de20648269..6bc3c44ec3a 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/RepeatWhileStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/RepeatWhileStmt.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.RepeatWhileStmt -class RepeatWhileStmt extends RepeatWhileStmtBase { } +class RepeatWhileStmt extends RepeatWhileStmtBase { + override string toString() { result = "repeat { ... } while ... " } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/ReturnStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/ReturnStmt.qll index 6ab3177f80d..ba3762a23bc 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/ReturnStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/ReturnStmt.qll @@ -1,4 +1,7 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.ReturnStmt -class ReturnStmt extends ReturnStmtBase { } +class ReturnStmt extends ReturnStmtBase { + override string toString() { + if this.hasResult() then result = "return ..." else result = "return" + } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/SwitchStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/SwitchStmt.qll index 11077d87e77..e71a211d69f 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/SwitchStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/SwitchStmt.qll @@ -9,4 +9,6 @@ class SwitchStmt extends SwitchStmtBase { not exists(this.getCase(i + 1)) ) } + + override string toString() { result = "switch " + this.getExpr().toString() + " { ... }" } } diff --git a/swift/ql/lib/codeql/swift/elements/stmt/ThrowStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/ThrowStmt.qll index 1991fac6e97..9296fd4d05c 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/ThrowStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/ThrowStmt.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.ThrowStmt -class ThrowStmt extends ThrowStmtBase { } +class ThrowStmt extends ThrowStmtBase { + override string toString() { result = "throw ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/WhileStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/WhileStmt.qll index 29aa526ea7e..28ff0bc1f66 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/WhileStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/WhileStmt.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.WhileStmt -class WhileStmt extends WhileStmtBase { } +class WhileStmt extends WhileStmtBase { + override string toString() { result = "while ... { ... }" } +} diff --git a/swift/ql/lib/codeql/swift/elements/stmt/YieldStmt.qll b/swift/ql/lib/codeql/swift/elements/stmt/YieldStmt.qll index 812e77fee99..6380e6ddb61 100644 --- a/swift/ql/lib/codeql/swift/elements/stmt/YieldStmt.qll +++ b/swift/ql/lib/codeql/swift/elements/stmt/YieldStmt.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.stmt.YieldStmt -class YieldStmt extends YieldStmtBase { } +class YieldStmt extends YieldStmtBase { + override string toString() { result = "yield ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/type/Type.qll b/swift/ql/lib/codeql/swift/elements/type/Type.qll index 50e9b94c746..264a32091e4 100644 --- a/swift/ql/lib/codeql/swift/elements/type/Type.qll +++ b/swift/ql/lib/codeql/swift/elements/type/Type.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.type.Type -class Type extends TypeBase { } +class Type extends TypeBase { + override string toString() { result = this.getDiagnosticsName() } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/ArrayTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/ArrayTypeRepr.qll index 84f2705b6fe..551e846daad 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/ArrayTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/ArrayTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.ArrayTypeRepr -class ArrayTypeRepr extends ArrayTypeReprBase { } +class ArrayTypeRepr extends ArrayTypeReprBase { + override string toString() { result = "[...]" } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/AttributedTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/AttributedTypeRepr.qll index 73d3ea97b8f..96ae6d613fc 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/AttributedTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/AttributedTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.AttributedTypeRepr -class AttributedTypeRepr extends AttributedTypeReprBase { } +class AttributedTypeRepr extends AttributedTypeReprBase { + override string toString() { result = "@..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/CompileTimeConstTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/CompileTimeConstTypeRepr.qll index 4235ccbcf50..0527a978c92 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/CompileTimeConstTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/CompileTimeConstTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.CompileTimeConstTypeRepr -class CompileTimeConstTypeRepr extends CompileTimeConstTypeReprBase { } +class CompileTimeConstTypeRepr extends CompileTimeConstTypeReprBase { + override string toString() { result = "_const ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/CompoundIdentTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/CompoundIdentTypeRepr.qll index aafc54489ac..6b0270e074f 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/CompoundIdentTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/CompoundIdentTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.CompoundIdentTypeRepr -class CompoundIdentTypeRepr extends CompoundIdentTypeReprBase { } +class CompoundIdentTypeRepr extends CompoundIdentTypeReprBase { + override string toString() { result = "...<...>" } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/DictionaryTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/DictionaryTypeRepr.qll index a226c72c1d1..d28f8e972e1 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/DictionaryTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/DictionaryTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.DictionaryTypeRepr -class DictionaryTypeRepr extends DictionaryTypeReprBase { } +class DictionaryTypeRepr extends DictionaryTypeReprBase { + override string toString() { result = "[... : ...]" } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/FunctionTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/FunctionTypeRepr.qll index 96cba609393..4441903d045 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/FunctionTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/FunctionTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.FunctionTypeRepr -class FunctionTypeRepr extends FunctionTypeReprBase { } +class FunctionTypeRepr extends FunctionTypeReprBase { + override string toString() { result = "... -> ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/GenericIdentTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/GenericIdentTypeRepr.qll index 48774afb51b..54e388d5e7b 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/GenericIdentTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/GenericIdentTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.GenericIdentTypeRepr -class GenericIdentTypeRepr extends GenericIdentTypeReprBase { } +class GenericIdentTypeRepr extends GenericIdentTypeReprBase { + override string toString() { result = "...<...>" } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/ImplicitlyUnwrappedOptionalTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/ImplicitlyUnwrappedOptionalTypeRepr.qll index d04f438d676..ace8103e1ca 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/ImplicitlyUnwrappedOptionalTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/ImplicitlyUnwrappedOptionalTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.ImplicitlyUnwrappedOptionalTypeRepr -class ImplicitlyUnwrappedOptionalTypeRepr extends ImplicitlyUnwrappedOptionalTypeReprBase { } +class ImplicitlyUnwrappedOptionalTypeRepr extends ImplicitlyUnwrappedOptionalTypeReprBase { + override string toString() { result = "...!" } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/InOutTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/InOutTypeRepr.qll index 3c17987ccb1..3be97d2f9fa 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/InOutTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/InOutTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.InOutTypeRepr -class InOutTypeRepr extends InOutTypeReprBase { } +class InOutTypeRepr extends InOutTypeReprBase { + override string toString() { result = "inout ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/IsolatedTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/IsolatedTypeRepr.qll index 1ba568bb793..d7a9eb48345 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/IsolatedTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/IsolatedTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.IsolatedTypeRepr -class IsolatedTypeRepr extends IsolatedTypeReprBase { } +class IsolatedTypeRepr extends IsolatedTypeReprBase { + override string toString() { result = "isolated ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/MetatypeTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/MetatypeTypeRepr.qll index 6eb6f16f733..f48ac07816d 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/MetatypeTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/MetatypeTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.MetatypeTypeRepr -class MetatypeTypeRepr extends MetatypeTypeReprBase { } +class MetatypeTypeRepr extends MetatypeTypeReprBase { + override string toString() { result = ".Type" } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/OptionalTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/OptionalTypeRepr.qll index 840cd191f52..b9046b00955 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/OptionalTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/OptionalTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.OptionalTypeRepr -class OptionalTypeRepr extends OptionalTypeReprBase { } +class OptionalTypeRepr extends OptionalTypeReprBase { + override string toString() { result = "...?" } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/OwnedTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/OwnedTypeRepr.qll index 4221a66b762..88e90d479d7 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/OwnedTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/OwnedTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.OwnedTypeRepr -class OwnedTypeRepr extends OwnedTypeReprBase { } +class OwnedTypeRepr extends OwnedTypeReprBase { + override string toString() { result = "owned ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/ProtocolTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/ProtocolTypeRepr.qll index ca229b0fad5..8701fceaf53 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/ProtocolTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/ProtocolTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.ProtocolTypeRepr -class ProtocolTypeRepr extends ProtocolTypeReprBase { } +class ProtocolTypeRepr extends ProtocolTypeReprBase { + override string toString() { result = ".Protocol" } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/SharedTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/SharedTypeRepr.qll index a2ab0f3a6fe..ed31dc0bf10 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/SharedTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/SharedTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.SharedTypeRepr -class SharedTypeRepr extends SharedTypeReprBase { } +class SharedTypeRepr extends SharedTypeReprBase { + override string toString() { result = "shared ..." } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/SilBoxTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/SilBoxTypeRepr.qll index f792f2fa348..7949d10849b 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/SilBoxTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/SilBoxTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.SilBoxTypeRepr -class SilBoxTypeRepr extends SilBoxTypeReprBase { } +class SilBoxTypeRepr extends SilBoxTypeReprBase { + override string toString() { result = "{ ... }" } +} diff --git a/swift/ql/lib/codeql/swift/elements/typerepr/TupleTypeRepr.qll b/swift/ql/lib/codeql/swift/elements/typerepr/TupleTypeRepr.qll index 44614dab3d2..745fb39b9e5 100644 --- a/swift/ql/lib/codeql/swift/elements/typerepr/TupleTypeRepr.qll +++ b/swift/ql/lib/codeql/swift/elements/typerepr/TupleTypeRepr.qll @@ -1,4 +1,5 @@ -// generated by codegen/codegen.py, remove this comment if you wish to edit this file private import codeql.swift.generated.typerepr.TupleTypeRepr -class TupleTypeRepr extends TupleTypeReprBase { } +class TupleTypeRepr extends TupleTypeReprBase { + override string toString() { result = "(...)" } +} diff --git a/swift/ql/lib/codeql/swift/generated/type/AnyFunctionType.qll b/swift/ql/lib/codeql/swift/generated/type/AnyFunctionType.qll index 6add8032bc1..da547ce7aac 100644 --- a/swift/ql/lib/codeql/swift/generated/type/AnyFunctionType.qll +++ b/swift/ql/lib/codeql/swift/generated/type/AnyFunctionType.qll @@ -27,4 +27,6 @@ class AnyFunctionTypeBase extends @any_function_type, Type { int getNumberOfParamLabels() { result = count(getAParamLabel()) } predicate isThrowing() { any_function_type_is_throwing(this) } + + predicate isAsync() { any_function_type_is_async(this) } } diff --git a/swift/ql/lib/swift.dbscheme b/swift/ql/lib/swift.dbscheme index d9497443044..47edbb550e8 100644 --- a/swift/ql/lib/swift.dbscheme +++ b/swift/ql/lib/swift.dbscheme @@ -176,6 +176,11 @@ any_function_type_is_throwing( int id: @any_function_type ref ); +#keyset[id] +any_function_type_is_async( + int id: @any_function_type ref +); + @any_generic_type = @nominal_or_bound_generic_nominal_type | @unbound_generic_type diff --git a/swift/ql/test/extractor-tests/declarations/accessor.expected b/swift/ql/test/extractor-tests/declarations/accessor.expected index 66db1b8fd0f..d47ce163c5d 100644 --- a/swift/ql/test/extractor-tests/declarations/accessor.expected +++ b/swift/ql/test/extractor-tests/declarations/accessor.expected @@ -1,53 +1,53 @@ -| test.swift:2:7:2:7 | AccessorDecl | ? | -| test.swift:2:7:2:7 | AccessorDecl | get | -| test.swift:2:7:2:7 | AccessorDecl | set | -| test.swift:3:7:3:7 | AccessorDecl | ? | -| test.swift:4:5:4:24 | AccessorDecl | get | -| test.swift:5:5:5:38 | AccessorDecl | set | -| test.swift:9:17:9:17 | AccessorDecl | ? | -| test.swift:9:17:9:17 | AccessorDecl | get | -| test.swift:9:17:9:17 | AccessorDecl | set | -| test.swift:23:9:23:9 | AccessorDecl | ? | -| test.swift:23:31:23:31 | AccessorDecl | get | -| test.swift:23:35:23:35 | AccessorDecl | set | -| test.swift:24:40:24:40 | AccessorDecl | get | -| test.swift:32:3:34:3 | AccessorDecl | get | -| test.swift:35:3:35:18 | AccessorDecl | set | -| test.swift:41:7:41:7 | AccessorDecl | ? | -| test.swift:41:7:41:7 | AccessorDecl | get | -| test.swift:41:7:41:7 | AccessorDecl | set | -| test.swift:70:5:72:5 | AccessorDecl | get | -| test.swift:77:20:77:20 | AccessorDecl | get | -| test.swift:82:7:82:7 | AccessorDecl | ? | -| test.swift:83:5:83:11 | AccessorDecl | set | -| test.swift:84:5:86:5 | AccessorDecl | get | -| test.swift:91:27:93:3 | AccessorDecl | get | -| test.swift:97:5:99:5 | AccessorDecl | get | -| test.swift:102:7:102:7 | AccessorDecl | ? | -| test.swift:102:7:102:7 | AccessorDecl | get | -| test.swift:102:7:102:7 | AccessorDecl | set | -| test.swift:104:3:104:3 | AccessorDecl | ? | -| test.swift:105:5:107:5 | AccessorDecl | get | -| test.swift:108:5:108:11 | AccessorDecl | set | -| test.swift:111:37:113:3 | AccessorDecl | get | -| test.swift:115:7:115:7 | AccessorDecl | ? | -| test.swift:115:7:115:7 | AccessorDecl | get | -| test.swift:115:7:115:7 | AccessorDecl | set | -| test.swift:116:5:116:25 | AccessorDecl | willSet | -| test.swift:119:7:119:7 | AccessorDecl | ? | -| test.swift:119:7:119:7 | AccessorDecl | get | -| test.swift:119:7:119:7 | AccessorDecl | set | -| test.swift:120:5:120:15 | AccessorDecl | willSet | -| test.swift:123:7:123:7 | AccessorDecl | ? | -| test.swift:123:7:123:7 | AccessorDecl | get | -| test.swift:123:7:123:7 | AccessorDecl | set | -| test.swift:124:5:124:24 | AccessorDecl | didSet | -| test.swift:127:7:127:7 | AccessorDecl | ? | -| test.swift:127:7:127:7 | AccessorDecl | get | -| test.swift:127:7:127:7 | AccessorDecl | set | -| test.swift:128:5:128:14 | AccessorDecl | didSet | -| test.swift:131:7:131:7 | AccessorDecl | ? | -| test.swift:131:7:131:7 | AccessorDecl | get | -| test.swift:131:7:131:7 | AccessorDecl | set | -| test.swift:132:5:132:15 | AccessorDecl | willSet | -| test.swift:134:5:134:14 | AccessorDecl | didSet | +| test.swift:2:7:2:7 | (unnamed function decl) | ? | +| test.swift:2:7:2:7 | get | get | +| test.swift:2:7:2:7 | set | set | +| test.swift:3:7:3:7 | (unnamed function decl) | ? | +| test.swift:4:5:4:24 | get | get | +| test.swift:5:5:5:38 | set | set | +| test.swift:9:17:9:17 | (unnamed function decl) | ? | +| test.swift:9:17:9:17 | get | get | +| test.swift:9:17:9:17 | set | set | +| test.swift:23:9:23:9 | (unnamed function decl) | ? | +| test.swift:23:31:23:31 | get | get | +| test.swift:23:35:23:35 | set | set | +| test.swift:24:40:24:40 | get | get | +| test.swift:32:3:34:3 | get | get | +| test.swift:35:3:35:18 | set | set | +| test.swift:41:7:41:7 | (unnamed function decl) | ? | +| test.swift:41:7:41:7 | get | get | +| test.swift:41:7:41:7 | set | set | +| test.swift:70:5:72:5 | get | get | +| test.swift:77:20:77:20 | get | get | +| test.swift:82:7:82:7 | (unnamed function decl) | ? | +| test.swift:83:5:83:11 | set | set | +| test.swift:84:5:86:5 | get | get | +| test.swift:91:27:93:3 | get | get | +| test.swift:97:5:99:5 | get | get | +| test.swift:102:7:102:7 | (unnamed function decl) | ? | +| test.swift:102:7:102:7 | get | get | +| test.swift:102:7:102:7 | set | set | +| test.swift:104:3:104:3 | (unnamed function decl) | ? | +| test.swift:105:5:107:5 | get | get | +| test.swift:108:5:108:11 | set | set | +| test.swift:111:37:113:3 | get | get | +| test.swift:115:7:115:7 | (unnamed function decl) | ? | +| test.swift:115:7:115:7 | get | get | +| test.swift:115:7:115:7 | set | set | +| test.swift:116:5:116:25 | willSet | willSet | +| test.swift:119:7:119:7 | (unnamed function decl) | ? | +| test.swift:119:7:119:7 | get | get | +| test.swift:119:7:119:7 | set | set | +| test.swift:120:5:120:15 | willSet | willSet | +| test.swift:123:7:123:7 | (unnamed function decl) | ? | +| test.swift:123:7:123:7 | get | get | +| test.swift:123:7:123:7 | set | set | +| test.swift:124:5:124:24 | didSet | didSet | +| test.swift:127:7:127:7 | (unnamed function decl) | ? | +| test.swift:127:7:127:7 | get | get | +| test.swift:127:7:127:7 | set | set | +| test.swift:128:5:128:14 | didSet | didSet | +| test.swift:131:7:131:7 | (unnamed function decl) | ? | +| test.swift:131:7:131:7 | get | get | +| test.swift:131:7:131:7 | set | set | +| test.swift:132:5:132:15 | willSet | willSet | +| test.swift:134:5:134:14 | didSet | didSet | diff --git a/swift/ql/test/extractor-tests/declarations/all.expected b/swift/ql/test/extractor-tests/declarations/all.expected index a8e81767731..17398ce97a9 100644 --- a/swift/ql/test/extractor-tests/declarations/all.expected +++ b/swift/ql/test/extractor-tests/declarations/all.expected @@ -1,196 +1,196 @@ -| test.swift:1:1:7:1 | StructDecl | -| test.swift:1:8:1:8 | ConstructorDecl | -| test.swift:1:8:1:8 | ConstructorDecl | -| test.swift:1:8:1:8 | ParamDecl | -| test.swift:2:3:2:11 | PatternBindingDecl | -| test.swift:2:7:2:7 | AccessorDecl | -| test.swift:2:7:2:7 | AccessorDecl | -| test.swift:2:7:2:7 | AccessorDecl | -| test.swift:2:7:2:7 | ConcreteVarDecl | -| test.swift:2:7:2:7 | ParamDecl | -| test.swift:2:7:2:7 | ParamDecl | -| test.swift:2:7:2:7 | ParamDecl | -| test.swift:3:3:6:3 | PatternBindingDecl | -| test.swift:3:7:3:7 | AccessorDecl | -| test.swift:3:7:3:7 | ConcreteVarDecl | -| test.swift:4:5:4:5 | ParamDecl | -| test.swift:4:5:4:24 | AccessorDecl | -| test.swift:5:5:5:5 | ParamDecl | -| test.swift:5:5:5:38 | AccessorDecl | -| test.swift:5:9:5:9 | ParamDecl | -| test.swift:9:1:9:34 | ClassDecl | -| test.swift:9:7:9:7 | ConstructorDecl | -| test.swift:9:7:9:7 | DestructorDecl | -| test.swift:9:13:9:30 | PatternBindingDecl | -| test.swift:9:17:9:17 | AccessorDecl | -| test.swift:9:17:9:17 | AccessorDecl | -| test.swift:9:17:9:17 | AccessorDecl | -| test.swift:9:17:9:17 | ConcreteVarDecl | -| test.swift:9:17:9:17 | ParamDecl | -| test.swift:9:17:9:17 | ParamDecl | -| test.swift:9:17:9:17 | ParamDecl | -| test.swift:11:1:14:1 | EnumDecl | -| test.swift:12:5:12:18 | EnumCaseDecl | -| test.swift:12:10:12:10 | EnumElementDecl | -| test.swift:12:18:12:18 | EnumElementDecl | -| test.swift:13:5:13:26 | EnumCaseDecl | -| test.swift:13:10:13:10 | EnumElementDecl | -| test.swift:13:18:13:18 | EnumElementDecl | -| test.swift:13:26:13:26 | EnumElementDecl | -| test.swift:16:1:20:1 | EnumDecl | -| test.swift:17:5:17:22 | EnumCaseDecl | -| test.swift:17:10:17:22 | EnumElementDecl | -| test.swift:17:18:17:18 | ParamDecl | -| test.swift:18:5:18:21 | EnumCaseDecl | -| test.swift:18:10:18:21 | EnumElementDecl | -| test.swift:18:18:18:18 | ParamDecl | -| test.swift:19:5:19:35 | EnumCaseDecl | -| test.swift:19:10:19:35 | EnumElementDecl | -| test.swift:19:16:19:16 | ParamDecl | -| test.swift:19:21:19:21 | ParamDecl | -| test.swift:19:29:19:29 | ParamDecl | -| test.swift:22:1:26:1 | ProtocolDecl | -| test.swift:23:5:23:39 | PatternBindingDecl | -| test.swift:23:9:23:9 | AccessorDecl | -| test.swift:23:9:23:9 | ConcreteVarDecl | -| test.swift:23:31:23:31 | AccessorDecl | -| test.swift:23:35:23:35 | AccessorDecl | -| test.swift:23:35:23:35 | ParamDecl | -| test.swift:24:5:24:44 | PatternBindingDecl | -| test.swift:24:9:24:9 | ConcreteVarDecl | -| test.swift:24:40:24:40 | AccessorDecl | -| test.swift:25:5:25:22 | ConcreteFuncDecl | -| test.swift:28:1:28:37 | ConcreteFuncDecl | -| test.swift:28:17:28:31 | ParamDecl | -| test.swift:30:1:30:18 | PatternBindingDecl | -| test.swift:30:1:30:18 | TopLevelCodeDecl | -| test.swift:30:5:30:5 | ConcreteVarDecl | -| test.swift:31:1:36:1 | PatternBindingDecl | -| test.swift:31:1:36:1 | TopLevelCodeDecl | -| test.swift:31:5:31:5 | ConcreteVarDecl | -| test.swift:32:3:34:3 | AccessorDecl | -| test.swift:35:3:35:18 | AccessorDecl | -| test.swift:35:7:35:7 | ParamDecl | -| test.swift:38:1:38:33 | TopLevelCodeDecl | -| test.swift:40:1:53:1 | ClassDecl | -| test.swift:41:3:41:14 | PatternBindingDecl | -| test.swift:41:7:41:7 | AccessorDecl | -| test.swift:41:7:41:7 | AccessorDecl | -| test.swift:41:7:41:7 | AccessorDecl | -| test.swift:41:7:41:7 | ConcreteVarDecl | -| test.swift:41:7:41:7 | ParamDecl | -| test.swift:41:7:41:7 | ParamDecl | -| test.swift:41:7:41:7 | ParamDecl | -| test.swift:42:3:42:3 | ParamDecl | -| test.swift:42:3:44:3 | ConstructorDecl | -| test.swift:46:3:46:3 | ParamDecl | -| test.swift:46:3:48:3 | DestructorDecl | -| test.swift:50:3:52:3 | ConcreteFuncDecl | -| test.swift:50:26:50:33 | ParamDecl | -| test.swift:55:8:55:17 | PrefixOperatorDecl | -| test.swift:57:1:62:1 | PrecedenceGroupDecl | -| test.swift:64:7:64:16 | InfixOperatorDecl | -| test.swift:66:7:66:21 | InfixOperatorDecl | -| test.swift:68:18:74:1 | StructDecl | -| test.swift:68:25:68:25 | ConstructorDecl | -| test.swift:69:3:73:3 | PatternBindingDecl | -| test.swift:69:7:69:7 | ConcreteVarDecl | -| test.swift:70:5:72:5 | AccessorDecl | -| test.swift:76:1:79:1 | ConcreteFuncDecl | -| test.swift:77:16:77:23 | PatternBindingDecl | -| test.swift:77:20:77:20 | AccessorDecl | -| test.swift:77:20:77:20 | ConcreteVarDecl | -| test.swift:77:20:77:20 | ConcreteVarDecl | -| test.swift:81:1:136:1 | StructDecl | -| test.swift:81:8:81:8 | ConstructorDecl | -| test.swift:81:8:81:8 | ParamDecl | -| test.swift:81:8:81:8 | ParamDecl | -| test.swift:81:8:81:8 | ParamDecl | -| test.swift:81:8:81:8 | ParamDecl | -| test.swift:81:8:81:8 | ParamDecl | -| test.swift:81:8:81:8 | ParamDecl | -| test.swift:82:3:87:3 | PatternBindingDecl | -| test.swift:82:7:82:7 | AccessorDecl | -| test.swift:82:7:82:7 | ConcreteVarDecl | -| test.swift:83:5:83:5 | ParamDecl | -| test.swift:83:5:83:11 | AccessorDecl | -| test.swift:84:5:86:5 | AccessorDecl | -| test.swift:91:3:93:3 | PatternBindingDecl | -| test.swift:91:7:91:7 | ConcreteVarDecl | -| test.swift:91:27:93:3 | AccessorDecl | -| test.swift:96:3:100:3 | PatternBindingDecl | -| test.swift:96:7:96:7 | ConcreteVarDecl | -| test.swift:97:5:99:5 | AccessorDecl | -| test.swift:102:3:102:21 | PatternBindingDecl | -| test.swift:102:7:102:7 | AccessorDecl | -| test.swift:102:7:102:7 | AccessorDecl | -| test.swift:102:7:102:7 | AccessorDecl | -| test.swift:102:7:102:7 | ConcreteVarDecl | -| test.swift:102:7:102:7 | ParamDecl | -| test.swift:102:7:102:7 | ParamDecl | -| test.swift:102:7:102:7 | ParamDecl | -| test.swift:104:3:104:3 | AccessorDecl | -| test.swift:104:3:109:3 | SubscriptDecl | -| test.swift:104:13:104:13 | ParamDecl | -| test.swift:104:13:104:13 | ParamDecl | -| test.swift:104:13:104:16 | ParamDecl | -| test.swift:105:5:107:5 | AccessorDecl | -| test.swift:108:5:108:5 | ParamDecl | -| test.swift:108:5:108:11 | AccessorDecl | -| test.swift:111:3:113:3 | SubscriptDecl | -| test.swift:111:13:111:13 | ParamDecl | -| test.swift:111:13:111:16 | ParamDecl | -| test.swift:111:21:111:21 | ParamDecl | -| test.swift:111:21:111:25 | ParamDecl | -| test.swift:111:37:113:3 | AccessorDecl | -| test.swift:115:3:117:3 | PatternBindingDecl | -| test.swift:115:7:115:7 | AccessorDecl | -| test.swift:115:7:115:7 | AccessorDecl | -| test.swift:115:7:115:7 | AccessorDecl | -| test.swift:115:7:115:7 | ConcreteVarDecl | -| test.swift:115:7:115:7 | ParamDecl | -| test.swift:115:7:115:7 | ParamDecl | -| test.swift:115:7:115:7 | ParamDecl | -| test.swift:116:5:116:25 | AccessorDecl | -| test.swift:116:13:116:13 | ParamDecl | -| test.swift:119:3:121:3 | PatternBindingDecl | -| test.swift:119:7:119:7 | AccessorDecl | -| test.swift:119:7:119:7 | AccessorDecl | -| test.swift:119:7:119:7 | AccessorDecl | -| test.swift:119:7:119:7 | ConcreteVarDecl | -| test.swift:119:7:119:7 | ParamDecl | -| test.swift:119:7:119:7 | ParamDecl | -| test.swift:119:7:119:7 | ParamDecl | -| test.swift:120:5:120:5 | ParamDecl | -| test.swift:120:5:120:15 | AccessorDecl | -| test.swift:123:3:125:3 | PatternBindingDecl | -| test.swift:123:7:123:7 | AccessorDecl | -| test.swift:123:7:123:7 | AccessorDecl | -| test.swift:123:7:123:7 | AccessorDecl | -| test.swift:123:7:123:7 | ConcreteVarDecl | -| test.swift:123:7:123:7 | ParamDecl | -| test.swift:123:7:123:7 | ParamDecl | -| test.swift:123:7:123:7 | ParamDecl | -| test.swift:124:5:124:24 | AccessorDecl | -| test.swift:124:12:124:12 | ParamDecl | -| test.swift:127:3:129:3 | PatternBindingDecl | -| test.swift:127:7:127:7 | AccessorDecl | -| test.swift:127:7:127:7 | AccessorDecl | -| test.swift:127:7:127:7 | AccessorDecl | -| test.swift:127:7:127:7 | ConcreteVarDecl | -| test.swift:127:7:127:7 | ParamDecl | -| test.swift:127:7:127:7 | ParamDecl | -| test.swift:127:7:127:7 | ParamDecl | -| test.swift:127:7:127:7 | ParamDecl | -| test.swift:128:5:128:14 | AccessorDecl | -| test.swift:131:3:135:3 | PatternBindingDecl | -| test.swift:131:7:131:7 | AccessorDecl | -| test.swift:131:7:131:7 | AccessorDecl | -| test.swift:131:7:131:7 | AccessorDecl | -| test.swift:131:7:131:7 | ConcreteVarDecl | -| test.swift:131:7:131:7 | ParamDecl | -| test.swift:131:7:131:7 | ParamDecl | -| test.swift:131:7:131:7 | ParamDecl | -| test.swift:132:5:132:5 | ParamDecl | -| test.swift:132:5:132:15 | AccessorDecl | -| test.swift:134:5:134:14 | AccessorDecl | +| test.swift:1:1:7:1 | Foo | +| test.swift:1:8:1:8 | deinit | +| test.swift:1:8:1:8 | deinit | +| test.swift:1:8:1:8 | x | +| test.swift:2:3:2:11 | var ... = ... | +| test.swift:2:7:2:7 | (unnamed function decl) | +| test.swift:2:7:2:7 | get | +| test.swift:2:7:2:7 | self | +| test.swift:2:7:2:7 | self | +| test.swift:2:7:2:7 | set | +| test.swift:2:7:2:7 | value | +| test.swift:2:7:2:7 | x | +| test.swift:3:3:6:3 | var ... = ... | +| test.swift:3:7:3:7 | (unnamed function decl) | +| test.swift:3:7:3:7 | next | +| test.swift:4:5:4:5 | self | +| test.swift:4:5:4:24 | get | +| test.swift:5:5:5:5 | self | +| test.swift:5:5:5:38 | set | +| test.swift:5:9:5:9 | newValue | +| test.swift:9:1:9:34 | Bar | +| test.swift:9:7:9:7 | deinit | +| test.swift:9:7:9:7 | init | +| test.swift:9:13:9:30 | var ... = ... | +| test.swift:9:17:9:17 | (unnamed function decl) | +| test.swift:9:17:9:17 | get | +| test.swift:9:17:9:17 | self | +| test.swift:9:17:9:17 | self | +| test.swift:9:17:9:17 | set | +| test.swift:9:17:9:17 | value | +| test.swift:9:17:9:17 | x | +| test.swift:11:1:14:1 | EnumValues | +| test.swift:12:5:12:18 | case ... | +| test.swift:12:10:12:10 | value1 | +| test.swift:12:18:12:18 | value2 | +| test.swift:13:5:13:26 | case ... | +| test.swift:13:10:13:10 | value3 | +| test.swift:13:18:13:18 | value4 | +| test.swift:13:26:13:26 | value5 | +| test.swift:16:1:20:1 | EnumWithParams | +| test.swift:17:5:17:22 | case ... | +| test.swift:17:10:17:22 | nodata1 | +| test.swift:17:18:17:18 | _ | +| test.swift:18:5:18:21 | case ... | +| test.swift:18:10:18:21 | intdata | +| test.swift:18:18:18:18 | _ | +| test.swift:19:5:19:35 | case ... | +| test.swift:19:10:19:35 | tuple | +| test.swift:19:16:19:16 | _ | +| test.swift:19:21:19:21 | _ | +| test.swift:19:29:19:29 | _ | +| test.swift:22:1:26:1 | MyProtocol | +| test.swift:23:5:23:39 | var ... = ... | +| test.swift:23:9:23:9 | (unnamed function decl) | +| test.swift:23:9:23:9 | mustBeSettable | +| test.swift:23:31:23:31 | get | +| test.swift:23:35:23:35 | newValue | +| test.swift:23:35:23:35 | set | +| test.swift:24:5:24:44 | var ... = ... | +| test.swift:24:9:24:9 | doesNotNeedToBeSettable | +| test.swift:24:40:24:40 | get | +| test.swift:25:5:25:22 | random | +| test.swift:28:1:28:37 | a_function | +| test.swift:28:17:28:31 | a_parameter | +| test.swift:30:1:30:18 | var ... = ... | +| test.swift:30:1:30:18 | { ... } | +| test.swift:30:5:30:5 | a_variable | +| test.swift:31:1:36:1 | var ... = ... | +| test.swift:31:1:36:1 | { ... } | +| test.swift:31:5:31:5 | a_property | +| test.swift:32:3:34:3 | get | +| test.swift:35:3:35:18 | set | +| test.swift:35:7:35:7 | newValue | +| test.swift:38:1:38:33 | { ... } | +| test.swift:40:1:53:1 | Baz | +| test.swift:41:3:41:14 | var ... = ... | +| test.swift:41:7:41:7 | (unnamed function decl) | +| test.swift:41:7:41:7 | field | +| test.swift:41:7:41:7 | get | +| test.swift:41:7:41:7 | self | +| test.swift:41:7:41:7 | self | +| test.swift:41:7:41:7 | set | +| test.swift:41:7:41:7 | value | +| test.swift:42:3:42:3 | self | +| test.swift:42:3:44:3 | deinit | +| test.swift:46:3:46:3 | self | +| test.swift:46:3:48:3 | init | +| test.swift:50:3:52:3 | +- | +| test.swift:50:26:50:33 | other | +| test.swift:55:8:55:17 | +- | +| test.swift:57:1:62:1 | precedencegroup ... | +| test.swift:64:7:64:16 | +++ | +| test.swift:66:7:66:21 | *** | +| test.swift:68:18:74:1 | ZeroWrapper | +| test.swift:68:25:68:25 | deinit | +| test.swift:69:3:73:3 | var ... = ... | +| test.swift:69:7:69:7 | wrappedValue | +| test.swift:70:5:72:5 | get | +| test.swift:76:1:79:1 | foo | +| test.swift:77:16:77:23 | var ... = ... | +| test.swift:77:20:77:20 | _x | +| test.swift:77:20:77:20 | get | +| test.swift:77:20:77:20 | x | +| test.swift:81:1:136:1 | HasPropertyAndObserver | +| test.swift:81:8:81:8 | deinit | +| test.swift:81:8:81:8 | hasBoth | +| test.swift:81:8:81:8 | hasDidSet1 | +| test.swift:81:8:81:8 | hasDidSet2 | +| test.swift:81:8:81:8 | hasWillSet1 | +| test.swift:81:8:81:8 | hasWillSet2 | +| test.swift:81:8:81:8 | normalField | +| test.swift:82:3:87:3 | var ... = ... | +| test.swift:82:7:82:7 | (unnamed function decl) | +| test.swift:82:7:82:7 | settableField | +| test.swift:83:5:83:5 | newValue | +| test.swift:83:5:83:11 | set | +| test.swift:84:5:86:5 | get | +| test.swift:91:3:93:3 | var ... = ... | +| test.swift:91:7:91:7 | readOnlyField1 | +| test.swift:91:27:93:3 | get | +| test.swift:96:3:100:3 | var ... = ... | +| test.swift:96:7:96:7 | readOnlyField2 | +| test.swift:97:5:99:5 | get | +| test.swift:102:3:102:21 | var ... = ... | +| test.swift:102:7:102:7 | (unnamed function decl) | +| test.swift:102:7:102:7 | get | +| test.swift:102:7:102:7 | normalField | +| test.swift:102:7:102:7 | self | +| test.swift:102:7:102:7 | self | +| test.swift:102:7:102:7 | set | +| test.swift:102:7:102:7 | value | +| test.swift:104:3:104:3 | (unnamed function decl) | +| test.swift:104:3:109:3 | subscript ... | +| test.swift:104:13:104:13 | x | +| test.swift:104:13:104:13 | x | +| test.swift:104:13:104:16 | x | +| test.swift:105:5:107:5 | get | +| test.swift:108:5:108:5 | newValue | +| test.swift:108:5:108:11 | set | +| test.swift:111:3:113:3 | subscript ... | +| test.swift:111:13:111:13 | x | +| test.swift:111:13:111:16 | x | +| test.swift:111:21:111:21 | y | +| test.swift:111:21:111:25 | y | +| test.swift:111:37:113:3 | get | +| test.swift:115:3:117:3 | var ... = ... | +| test.swift:115:7:115:7 | (unnamed function decl) | +| test.swift:115:7:115:7 | get | +| test.swift:115:7:115:7 | hasWillSet1 | +| test.swift:115:7:115:7 | self | +| test.swift:115:7:115:7 | self | +| test.swift:115:7:115:7 | set | +| test.swift:115:7:115:7 | value | +| test.swift:116:5:116:25 | willSet | +| test.swift:116:13:116:13 | newValue | +| test.swift:119:3:121:3 | var ... = ... | +| test.swift:119:7:119:7 | (unnamed function decl) | +| test.swift:119:7:119:7 | get | +| test.swift:119:7:119:7 | hasWillSet2 | +| test.swift:119:7:119:7 | self | +| test.swift:119:7:119:7 | self | +| test.swift:119:7:119:7 | set | +| test.swift:119:7:119:7 | value | +| test.swift:120:5:120:5 | newValue | +| test.swift:120:5:120:15 | willSet | +| test.swift:123:3:125:3 | var ... = ... | +| test.swift:123:7:123:7 | (unnamed function decl) | +| test.swift:123:7:123:7 | get | +| test.swift:123:7:123:7 | hasDidSet1 | +| test.swift:123:7:123:7 | self | +| test.swift:123:7:123:7 | self | +| test.swift:123:7:123:7 | set | +| test.swift:123:7:123:7 | value | +| test.swift:124:5:124:24 | didSet | +| test.swift:124:12:124:12 | oldValue | +| test.swift:127:3:129:3 | var ... = ... | +| test.swift:127:7:127:7 | (unnamed function decl) | +| test.swift:127:7:127:7 | get | +| test.swift:127:7:127:7 | hasDidSet2 | +| test.swift:127:7:127:7 | self | +| test.swift:127:7:127:7 | self | +| test.swift:127:7:127:7 | self | +| test.swift:127:7:127:7 | set | +| test.swift:127:7:127:7 | value | +| test.swift:128:5:128:14 | didSet | +| test.swift:131:3:135:3 | var ... = ... | +| test.swift:131:7:131:7 | (unnamed function decl) | +| test.swift:131:7:131:7 | get | +| test.swift:131:7:131:7 | hasBoth | +| test.swift:131:7:131:7 | self | +| test.swift:131:7:131:7 | self | +| test.swift:131:7:131:7 | set | +| test.swift:131:7:131:7 | value | +| test.swift:132:5:132:5 | newValue | +| test.swift:132:5:132:15 | willSet | +| test.swift:134:5:134:14 | didSet | diff --git a/swift/ql/test/extractor-tests/declarations/func.expected b/swift/ql/test/extractor-tests/declarations/func.expected index b96781829d3..5eb8c4e6f30 100644 --- a/swift/ql/test/extractor-tests/declarations/func.expected +++ b/swift/ql/test/extractor-tests/declarations/func.expected @@ -1,57 +1,57 @@ -| test.swift:2:7:2:7 | AccessorDecl | (unnamed function decl) | -| test.swift:2:7:2:7 | AccessorDecl | (unnamed function decl) | -| test.swift:2:7:2:7 | AccessorDecl | (unnamed function decl) | -| test.swift:3:7:3:7 | AccessorDecl | (unnamed function decl) | -| test.swift:4:5:4:24 | AccessorDecl | (unnamed function decl) | -| test.swift:5:5:5:38 | AccessorDecl | (unnamed function decl) | -| test.swift:9:17:9:17 | AccessorDecl | (unnamed function decl) | -| test.swift:9:17:9:17 | AccessorDecl | (unnamed function decl) | -| test.swift:9:17:9:17 | AccessorDecl | (unnamed function decl) | -| test.swift:23:9:23:9 | AccessorDecl | (unnamed function decl) | -| test.swift:23:31:23:31 | AccessorDecl | (unnamed function decl) | -| test.swift:23:35:23:35 | AccessorDecl | (unnamed function decl) | -| test.swift:24:40:24:40 | AccessorDecl | (unnamed function decl) | -| test.swift:25:5:25:22 | ConcreteFuncDecl | random | -| test.swift:28:1:28:37 | ConcreteFuncDecl | a_function | -| test.swift:32:3:34:3 | AccessorDecl | (unnamed function decl) | -| test.swift:35:3:35:18 | AccessorDecl | (unnamed function decl) | -| test.swift:41:7:41:7 | AccessorDecl | (unnamed function decl) | -| test.swift:41:7:41:7 | AccessorDecl | (unnamed function decl) | -| test.swift:41:7:41:7 | AccessorDecl | (unnamed function decl) | -| test.swift:50:3:52:3 | ConcreteFuncDecl | +- | -| test.swift:70:5:72:5 | AccessorDecl | (unnamed function decl) | -| test.swift:76:1:79:1 | ConcreteFuncDecl | foo | -| test.swift:77:20:77:20 | AccessorDecl | (unnamed function decl) | -| test.swift:82:7:82:7 | AccessorDecl | (unnamed function decl) | -| test.swift:83:5:83:11 | AccessorDecl | (unnamed function decl) | -| test.swift:84:5:86:5 | AccessorDecl | (unnamed function decl) | -| test.swift:91:27:93:3 | AccessorDecl | (unnamed function decl) | -| test.swift:97:5:99:5 | AccessorDecl | (unnamed function decl) | -| test.swift:102:7:102:7 | AccessorDecl | (unnamed function decl) | -| test.swift:102:7:102:7 | AccessorDecl | (unnamed function decl) | -| test.swift:102:7:102:7 | AccessorDecl | (unnamed function decl) | -| test.swift:104:3:104:3 | AccessorDecl | (unnamed function decl) | -| test.swift:105:5:107:5 | AccessorDecl | (unnamed function decl) | -| test.swift:108:5:108:11 | AccessorDecl | (unnamed function decl) | -| test.swift:111:37:113:3 | AccessorDecl | (unnamed function decl) | -| test.swift:115:7:115:7 | AccessorDecl | (unnamed function decl) | -| test.swift:115:7:115:7 | AccessorDecl | (unnamed function decl) | -| test.swift:115:7:115:7 | AccessorDecl | (unnamed function decl) | -| test.swift:116:5:116:25 | AccessorDecl | (unnamed function decl) | -| test.swift:119:7:119:7 | AccessorDecl | (unnamed function decl) | -| test.swift:119:7:119:7 | AccessorDecl | (unnamed function decl) | -| test.swift:119:7:119:7 | AccessorDecl | (unnamed function decl) | -| test.swift:120:5:120:15 | AccessorDecl | (unnamed function decl) | -| test.swift:123:7:123:7 | AccessorDecl | (unnamed function decl) | -| test.swift:123:7:123:7 | AccessorDecl | (unnamed function decl) | -| test.swift:123:7:123:7 | AccessorDecl | (unnamed function decl) | -| test.swift:124:5:124:24 | AccessorDecl | (unnamed function decl) | -| test.swift:127:7:127:7 | AccessorDecl | (unnamed function decl) | -| test.swift:127:7:127:7 | AccessorDecl | (unnamed function decl) | -| test.swift:127:7:127:7 | AccessorDecl | (unnamed function decl) | -| test.swift:128:5:128:14 | AccessorDecl | (unnamed function decl) | -| test.swift:131:7:131:7 | AccessorDecl | (unnamed function decl) | -| test.swift:131:7:131:7 | AccessorDecl | (unnamed function decl) | -| test.swift:131:7:131:7 | AccessorDecl | (unnamed function decl) | -| test.swift:132:5:132:15 | AccessorDecl | (unnamed function decl) | -| test.swift:134:5:134:14 | AccessorDecl | (unnamed function decl) | +| test.swift:2:7:2:7 | (unnamed function decl) | (unnamed function decl) | +| test.swift:2:7:2:7 | get | (unnamed function decl) | +| test.swift:2:7:2:7 | set | (unnamed function decl) | +| test.swift:3:7:3:7 | (unnamed function decl) | (unnamed function decl) | +| test.swift:4:5:4:24 | get | (unnamed function decl) | +| test.swift:5:5:5:38 | set | (unnamed function decl) | +| test.swift:9:17:9:17 | (unnamed function decl) | (unnamed function decl) | +| test.swift:9:17:9:17 | get | (unnamed function decl) | +| test.swift:9:17:9:17 | set | (unnamed function decl) | +| test.swift:23:9:23:9 | (unnamed function decl) | (unnamed function decl) | +| test.swift:23:31:23:31 | get | (unnamed function decl) | +| test.swift:23:35:23:35 | set | (unnamed function decl) | +| test.swift:24:40:24:40 | get | (unnamed function decl) | +| test.swift:25:5:25:22 | random | random | +| test.swift:28:1:28:37 | a_function | a_function | +| test.swift:32:3:34:3 | get | (unnamed function decl) | +| test.swift:35:3:35:18 | set | (unnamed function decl) | +| test.swift:41:7:41:7 | (unnamed function decl) | (unnamed function decl) | +| test.swift:41:7:41:7 | get | (unnamed function decl) | +| test.swift:41:7:41:7 | set | (unnamed function decl) | +| test.swift:50:3:52:3 | +- | +- | +| test.swift:70:5:72:5 | get | (unnamed function decl) | +| test.swift:76:1:79:1 | foo | foo | +| test.swift:77:20:77:20 | get | (unnamed function decl) | +| test.swift:82:7:82:7 | (unnamed function decl) | (unnamed function decl) | +| test.swift:83:5:83:11 | set | (unnamed function decl) | +| test.swift:84:5:86:5 | get | (unnamed function decl) | +| test.swift:91:27:93:3 | get | (unnamed function decl) | +| test.swift:97:5:99:5 | get | (unnamed function decl) | +| test.swift:102:7:102:7 | (unnamed function decl) | (unnamed function decl) | +| test.swift:102:7:102:7 | get | (unnamed function decl) | +| test.swift:102:7:102:7 | set | (unnamed function decl) | +| test.swift:104:3:104:3 | (unnamed function decl) | (unnamed function decl) | +| test.swift:105:5:107:5 | get | (unnamed function decl) | +| test.swift:108:5:108:11 | set | (unnamed function decl) | +| test.swift:111:37:113:3 | get | (unnamed function decl) | +| test.swift:115:7:115:7 | (unnamed function decl) | (unnamed function decl) | +| test.swift:115:7:115:7 | get | (unnamed function decl) | +| test.swift:115:7:115:7 | set | (unnamed function decl) | +| test.swift:116:5:116:25 | willSet | (unnamed function decl) | +| test.swift:119:7:119:7 | (unnamed function decl) | (unnamed function decl) | +| test.swift:119:7:119:7 | get | (unnamed function decl) | +| test.swift:119:7:119:7 | set | (unnamed function decl) | +| test.swift:120:5:120:15 | willSet | (unnamed function decl) | +| test.swift:123:7:123:7 | (unnamed function decl) | (unnamed function decl) | +| test.swift:123:7:123:7 | get | (unnamed function decl) | +| test.swift:123:7:123:7 | set | (unnamed function decl) | +| test.swift:124:5:124:24 | didSet | (unnamed function decl) | +| test.swift:127:7:127:7 | (unnamed function decl) | (unnamed function decl) | +| test.swift:127:7:127:7 | get | (unnamed function decl) | +| test.swift:127:7:127:7 | set | (unnamed function decl) | +| test.swift:128:5:128:14 | didSet | (unnamed function decl) | +| test.swift:131:7:131:7 | (unnamed function decl) | (unnamed function decl) | +| test.swift:131:7:131:7 | get | (unnamed function decl) | +| test.swift:131:7:131:7 | set | (unnamed function decl) | +| test.swift:132:5:132:15 | willSet | (unnamed function decl) | +| test.swift:134:5:134:14 | didSet | (unnamed function decl) | diff --git a/swift/ql/test/extractor-tests/declarations/func_body.expected b/swift/ql/test/extractor-tests/declarations/func_body.expected index 02ddacad327..15652c1b37c 100644 --- a/swift/ql/test/extractor-tests/declarations/func_body.expected +++ b/swift/ql/test/extractor-tests/declarations/func_body.expected @@ -1,52 +1,52 @@ -| test.swift:2:7:2:7 | AccessorDecl | test.swift:2:7:2:7 | BraceStmt | -| test.swift:2:7:2:7 | AccessorDecl | test.swift:2:7:2:7 | BraceStmt | -| test.swift:2:7:2:7 | AccessorDecl | test.swift:2:7:2:7 | BraceStmt | -| test.swift:3:7:3:7 | AccessorDecl | test.swift:3:7:3:7 | BraceStmt | -| test.swift:4:5:4:24 | AccessorDecl | test.swift:4:9:4:24 | BraceStmt | -| test.swift:5:5:5:38 | AccessorDecl | test.swift:5:19:5:38 | BraceStmt | -| test.swift:9:17:9:17 | AccessorDecl | test.swift:9:17:9:17 | BraceStmt | -| test.swift:9:17:9:17 | AccessorDecl | test.swift:9:17:9:17 | BraceStmt | -| test.swift:9:17:9:17 | AccessorDecl | test.swift:9:17:9:17 | BraceStmt | -| test.swift:28:1:28:37 | ConcreteFuncDecl | test.swift:28:36:28:37 | BraceStmt | -| test.swift:32:3:34:3 | AccessorDecl | test.swift:32:7:34:3 | BraceStmt | -| test.swift:35:3:35:18 | AccessorDecl | test.swift:35:17:35:18 | BraceStmt | -| test.swift:41:7:41:7 | AccessorDecl | test.swift:41:7:41:7 | BraceStmt | -| test.swift:41:7:41:7 | AccessorDecl | test.swift:41:7:41:7 | BraceStmt | -| test.swift:41:7:41:7 | AccessorDecl | test.swift:41:7:41:7 | BraceStmt | -| test.swift:50:3:52:3 | ConcreteFuncDecl | test.swift:50:45:52:3 | BraceStmt | -| test.swift:70:5:72:5 | AccessorDecl | test.swift:70:9:72:5 | BraceStmt | -| test.swift:76:1:79:1 | ConcreteFuncDecl | test.swift:76:19:79:1 | BraceStmt | -| test.swift:77:20:77:20 | AccessorDecl | test.swift:77:20:77:20 | BraceStmt | -| test.swift:82:7:82:7 | AccessorDecl | test.swift:82:7:82:7 | BraceStmt | -| test.swift:83:5:83:11 | AccessorDecl | test.swift:83:9:83:11 | BraceStmt | -| test.swift:84:5:86:5 | AccessorDecl | test.swift:84:9:86:5 | BraceStmt | -| test.swift:91:27:93:3 | AccessorDecl | test.swift:91:27:93:3 | BraceStmt | -| test.swift:97:5:99:5 | AccessorDecl | test.swift:97:9:99:5 | BraceStmt | -| test.swift:102:7:102:7 | AccessorDecl | test.swift:102:7:102:7 | BraceStmt | -| test.swift:102:7:102:7 | AccessorDecl | test.swift:102:7:102:7 | BraceStmt | -| test.swift:102:7:102:7 | AccessorDecl | test.swift:102:7:102:7 | BraceStmt | -| test.swift:104:3:104:3 | AccessorDecl | test.swift:104:3:104:3 | BraceStmt | -| test.swift:105:5:107:5 | AccessorDecl | test.swift:105:9:107:5 | BraceStmt | -| test.swift:108:5:108:11 | AccessorDecl | test.swift:108:9:108:11 | BraceStmt | -| test.swift:111:37:113:3 | AccessorDecl | test.swift:111:37:113:3 | BraceStmt | -| test.swift:115:7:115:7 | AccessorDecl | test.swift:115:7:115:7 | BraceStmt | -| test.swift:115:7:115:7 | AccessorDecl | test.swift:115:7:115:7 | BraceStmt | -| test.swift:115:7:115:7 | AccessorDecl | test.swift:115:7:115:7 | BraceStmt | -| test.swift:116:5:116:25 | AccessorDecl | test.swift:116:23:116:25 | BraceStmt | -| test.swift:119:7:119:7 | AccessorDecl | test.swift:119:7:119:7 | BraceStmt | -| test.swift:119:7:119:7 | AccessorDecl | test.swift:119:7:119:7 | BraceStmt | -| test.swift:119:7:119:7 | AccessorDecl | test.swift:119:7:119:7 | BraceStmt | -| test.swift:120:5:120:15 | AccessorDecl | test.swift:120:13:120:15 | BraceStmt | -| test.swift:123:7:123:7 | AccessorDecl | test.swift:123:7:123:7 | BraceStmt | -| test.swift:123:7:123:7 | AccessorDecl | test.swift:123:7:123:7 | BraceStmt | -| test.swift:123:7:123:7 | AccessorDecl | test.swift:123:7:123:7 | BraceStmt | -| test.swift:124:5:124:24 | AccessorDecl | test.swift:124:22:124:24 | BraceStmt | -| test.swift:127:7:127:7 | AccessorDecl | test.swift:127:7:127:7 | BraceStmt | -| test.swift:127:7:127:7 | AccessorDecl | test.swift:127:7:127:7 | BraceStmt | -| test.swift:127:7:127:7 | AccessorDecl | test.swift:127:7:127:7 | BraceStmt | -| test.swift:128:5:128:14 | AccessorDecl | test.swift:128:12:128:14 | BraceStmt | -| test.swift:131:7:131:7 | AccessorDecl | test.swift:131:7:131:7 | BraceStmt | -| test.swift:131:7:131:7 | AccessorDecl | test.swift:131:7:131:7 | BraceStmt | -| test.swift:131:7:131:7 | AccessorDecl | test.swift:131:7:131:7 | BraceStmt | -| test.swift:132:5:132:15 | AccessorDecl | test.swift:132:13:132:15 | BraceStmt | -| test.swift:134:5:134:14 | AccessorDecl | test.swift:134:12:134:14 | BraceStmt | +| test.swift:2:7:2:7 | (unnamed function decl) | test.swift:2:7:2:7 | { ... } | +| test.swift:2:7:2:7 | get | test.swift:2:7:2:7 | { ... } | +| test.swift:2:7:2:7 | set | test.swift:2:7:2:7 | { ... } | +| test.swift:3:7:3:7 | (unnamed function decl) | test.swift:3:7:3:7 | { ... } | +| test.swift:4:5:4:24 | get | test.swift:4:9:4:24 | { ... } | +| test.swift:5:5:5:38 | set | test.swift:5:19:5:38 | { ... } | +| test.swift:9:17:9:17 | (unnamed function decl) | test.swift:9:17:9:17 | { ... } | +| test.swift:9:17:9:17 | get | test.swift:9:17:9:17 | { ... } | +| test.swift:9:17:9:17 | set | test.swift:9:17:9:17 | { ... } | +| test.swift:28:1:28:37 | a_function | test.swift:28:36:28:37 | { ... } | +| test.swift:32:3:34:3 | get | test.swift:32:7:34:3 | { ... } | +| test.swift:35:3:35:18 | set | test.swift:35:17:35:18 | { ... } | +| test.swift:41:7:41:7 | (unnamed function decl) | test.swift:41:7:41:7 | { ... } | +| test.swift:41:7:41:7 | get | test.swift:41:7:41:7 | { ... } | +| test.swift:41:7:41:7 | set | test.swift:41:7:41:7 | { ... } | +| test.swift:50:3:52:3 | +- | test.swift:50:45:52:3 | { ... } | +| test.swift:70:5:72:5 | get | test.swift:70:9:72:5 | { ... } | +| test.swift:76:1:79:1 | foo | test.swift:76:19:79:1 | { ... } | +| test.swift:77:20:77:20 | get | test.swift:77:20:77:20 | { ... } | +| test.swift:82:7:82:7 | (unnamed function decl) | test.swift:82:7:82:7 | { ... } | +| test.swift:83:5:83:11 | set | test.swift:83:9:83:11 | { ... } | +| test.swift:84:5:86:5 | get | test.swift:84:9:86:5 | { ... } | +| test.swift:91:27:93:3 | get | test.swift:91:27:93:3 | { ... } | +| test.swift:97:5:99:5 | get | test.swift:97:9:99:5 | { ... } | +| test.swift:102:7:102:7 | (unnamed function decl) | test.swift:102:7:102:7 | { ... } | +| test.swift:102:7:102:7 | get | test.swift:102:7:102:7 | { ... } | +| test.swift:102:7:102:7 | set | test.swift:102:7:102:7 | { ... } | +| test.swift:104:3:104:3 | (unnamed function decl) | test.swift:104:3:104:3 | { ... } | +| test.swift:105:5:107:5 | get | test.swift:105:9:107:5 | { ... } | +| test.swift:108:5:108:11 | set | test.swift:108:9:108:11 | { ... } | +| test.swift:111:37:113:3 | get | test.swift:111:37:113:3 | { ... } | +| test.swift:115:7:115:7 | (unnamed function decl) | test.swift:115:7:115:7 | { ... } | +| test.swift:115:7:115:7 | get | test.swift:115:7:115:7 | { ... } | +| test.swift:115:7:115:7 | set | test.swift:115:7:115:7 | { ... } | +| test.swift:116:5:116:25 | willSet | test.swift:116:23:116:25 | { ... } | +| test.swift:119:7:119:7 | (unnamed function decl) | test.swift:119:7:119:7 | { ... } | +| test.swift:119:7:119:7 | get | test.swift:119:7:119:7 | { ... } | +| test.swift:119:7:119:7 | set | test.swift:119:7:119:7 | { ... } | +| test.swift:120:5:120:15 | willSet | test.swift:120:13:120:15 | { ... } | +| test.swift:123:7:123:7 | (unnamed function decl) | test.swift:123:7:123:7 | { ... } | +| test.swift:123:7:123:7 | get | test.swift:123:7:123:7 | { ... } | +| test.swift:123:7:123:7 | set | test.swift:123:7:123:7 | { ... } | +| test.swift:124:5:124:24 | didSet | test.swift:124:22:124:24 | { ... } | +| test.swift:127:7:127:7 | (unnamed function decl) | test.swift:127:7:127:7 | { ... } | +| test.swift:127:7:127:7 | get | test.swift:127:7:127:7 | { ... } | +| test.swift:127:7:127:7 | set | test.swift:127:7:127:7 | { ... } | +| test.swift:128:5:128:14 | didSet | test.swift:128:12:128:14 | { ... } | +| test.swift:131:7:131:7 | (unnamed function decl) | test.swift:131:7:131:7 | { ... } | +| test.swift:131:7:131:7 | get | test.swift:131:7:131:7 | { ... } | +| test.swift:131:7:131:7 | set | test.swift:131:7:131:7 | { ... } | +| test.swift:132:5:132:15 | willSet | test.swift:132:13:132:15 | { ... } | +| test.swift:134:5:134:14 | didSet | test.swift:134:12:134:14 | { ... } | diff --git a/swift/ql/test/extractor-tests/declarations/func_params.expected b/swift/ql/test/extractor-tests/declarations/func_params.expected index b490c20ceed..aa94a212e37 100644 --- a/swift/ql/test/extractor-tests/declarations/func_params.expected +++ b/swift/ql/test/extractor-tests/declarations/func_params.expected @@ -1,25 +1,25 @@ -| test.swift:2:7:2:7 | AccessorDecl | 0 | test.swift:2:7:2:7 | ParamDecl | -| test.swift:5:5:5:38 | AccessorDecl | 0 | test.swift:5:9:5:9 | ParamDecl | -| test.swift:9:17:9:17 | AccessorDecl | 0 | test.swift:9:17:9:17 | ParamDecl | -| test.swift:23:35:23:35 | AccessorDecl | 0 | test.swift:23:35:23:35 | ParamDecl | -| test.swift:28:1:28:37 | ConcreteFuncDecl | 0 | test.swift:28:17:28:31 | ParamDecl | -| test.swift:35:3:35:18 | AccessorDecl | 0 | test.swift:35:7:35:7 | ParamDecl | -| test.swift:41:7:41:7 | AccessorDecl | 0 | test.swift:41:7:41:7 | ParamDecl | -| test.swift:50:3:52:3 | ConcreteFuncDecl | 0 | test.swift:50:26:50:33 | ParamDecl | -| test.swift:83:5:83:11 | AccessorDecl | 0 | test.swift:83:5:83:5 | ParamDecl | -| test.swift:102:7:102:7 | AccessorDecl | 0 | test.swift:102:7:102:7 | ParamDecl | -| test.swift:104:3:104:3 | AccessorDecl | 0 | file://:0:0:0:0 | ParamDecl | -| test.swift:105:5:107:5 | AccessorDecl | 0 | test.swift:104:13:104:13 | ParamDecl | -| test.swift:108:5:108:11 | AccessorDecl | 0 | test.swift:108:5:108:5 | ParamDecl | -| test.swift:108:5:108:11 | AccessorDecl | 1 | test.swift:104:13:104:13 | ParamDecl | -| test.swift:111:37:113:3 | AccessorDecl | 0 | test.swift:111:13:111:13 | ParamDecl | -| test.swift:111:37:113:3 | AccessorDecl | 1 | test.swift:111:21:111:21 | ParamDecl | -| test.swift:115:7:115:7 | AccessorDecl | 0 | test.swift:115:7:115:7 | ParamDecl | -| test.swift:116:5:116:25 | AccessorDecl | 0 | test.swift:116:13:116:13 | ParamDecl | -| test.swift:119:7:119:7 | AccessorDecl | 0 | test.swift:119:7:119:7 | ParamDecl | -| test.swift:120:5:120:15 | AccessorDecl | 0 | test.swift:120:5:120:5 | ParamDecl | -| test.swift:123:7:123:7 | AccessorDecl | 0 | test.swift:123:7:123:7 | ParamDecl | -| test.swift:124:5:124:24 | AccessorDecl | 0 | test.swift:124:12:124:12 | ParamDecl | -| test.swift:127:7:127:7 | AccessorDecl | 0 | test.swift:127:7:127:7 | ParamDecl | -| test.swift:131:7:131:7 | AccessorDecl | 0 | test.swift:131:7:131:7 | ParamDecl | -| test.swift:132:5:132:15 | AccessorDecl | 0 | test.swift:132:5:132:5 | ParamDecl | +| test.swift:2:7:2:7 | set | 0 | test.swift:2:7:2:7 | value | +| test.swift:5:5:5:38 | set | 0 | test.swift:5:9:5:9 | newValue | +| test.swift:9:17:9:17 | set | 0 | test.swift:9:17:9:17 | value | +| test.swift:23:35:23:35 | set | 0 | test.swift:23:35:23:35 | newValue | +| test.swift:28:1:28:37 | a_function | 0 | test.swift:28:17:28:31 | a_parameter | +| test.swift:35:3:35:18 | set | 0 | test.swift:35:7:35:7 | newValue | +| test.swift:41:7:41:7 | set | 0 | test.swift:41:7:41:7 | value | +| test.swift:50:3:52:3 | +- | 0 | test.swift:50:26:50:33 | other | +| test.swift:83:5:83:11 | set | 0 | test.swift:83:5:83:5 | newValue | +| test.swift:102:7:102:7 | set | 0 | test.swift:102:7:102:7 | value | +| test.swift:104:3:104:3 | (unnamed function decl) | 0 | file://:0:0:0:0 | x | +| test.swift:105:5:107:5 | get | 0 | test.swift:104:13:104:13 | x | +| test.swift:108:5:108:11 | set | 0 | test.swift:108:5:108:5 | newValue | +| test.swift:108:5:108:11 | set | 1 | test.swift:104:13:104:13 | x | +| test.swift:111:37:113:3 | get | 0 | test.swift:111:13:111:13 | x | +| test.swift:111:37:113:3 | get | 1 | test.swift:111:21:111:21 | y | +| test.swift:115:7:115:7 | set | 0 | test.swift:115:7:115:7 | value | +| test.swift:116:5:116:25 | willSet | 0 | test.swift:116:13:116:13 | newValue | +| test.swift:119:7:119:7 | set | 0 | test.swift:119:7:119:7 | value | +| test.swift:120:5:120:15 | willSet | 0 | test.swift:120:5:120:5 | newValue | +| test.swift:123:7:123:7 | set | 0 | test.swift:123:7:123:7 | value | +| test.swift:124:5:124:24 | didSet | 0 | test.swift:124:12:124:12 | oldValue | +| test.swift:127:7:127:7 | set | 0 | test.swift:127:7:127:7 | value | +| test.swift:131:7:131:7 | set | 0 | test.swift:131:7:131:7 | value | +| test.swift:132:5:132:15 | willSet | 0 | test.swift:132:5:132:5 | newValue | diff --git a/swift/ql/test/extractor-tests/expressions/all.expected b/swift/ql/test/extractor-tests/expressions/all.expected index 59aab6efe71..d8094e7f54f 100644 --- a/swift/ql/test/extractor-tests/expressions/all.expected +++ b/swift/ql/test/extractor-tests/expressions/all.expected @@ -1,231 +1,234 @@ -| expressions.swift:1:9:1:9 | IntegerLiteralExpr | -| expressions.swift:2:9:2:9 | FloatLiteralExpr | -| expressions.swift:3:10:3:10 | BooleanLiteralExpr | -| expressions.swift:4:10:4:10 | BooleanLiteralExpr | -| expressions.swift:5:9:5:9 | MagicIdentifierLiteralExpr | -| expressions.swift:6:9:6:9 | StringLiteralExpr | -| expressions.swift:7:10:7:10 | InterpolatedStringLiteralExpr | +| expressions.swift:1:9:1:9 | 15 | +| expressions.swift:2:9:2:9 | 15.15 | +| expressions.swift:3:10:3:10 | true | +| expressions.swift:4:10:4:10 | false | +| expressions.swift:5:9:5:9 | #... | +| expressions.swift:6:9:6:9 | hello world | +| expressions.swift:7:10:7:10 | "..." | | expressions.swift:7:10:7:10 | OpaqueValueExpr | -| expressions.swift:7:10:7:10 | StringLiteralExpr | | expressions.swift:7:10:7:10 | TapExpr | -| expressions.swift:7:11:7:10 | CallExpr | -| expressions.swift:7:11:7:11 | DeclRefExpr | -| expressions.swift:7:11:7:11 | DotSyntaxCallExpr | -| expressions.swift:7:11:7:11 | InOutExpr | -| expressions.swift:7:18:7:18 | DeclRefExpr | -| expressions.swift:7:18:7:18 | DeclRefExpr | -| expressions.swift:7:18:7:18 | DotSyntaxCallExpr | -| expressions.swift:7:18:7:18 | InOutExpr | -| expressions.swift:7:18:7:20 | CallExpr | -| expressions.swift:7:19:7:19 | DeclRefExpr | -| expressions.swift:7:21:7:21 | CallExpr | -| expressions.swift:7:21:7:21 | DeclRefExpr | -| expressions.swift:7:21:7:21 | DotSyntaxCallExpr | -| expressions.swift:7:21:7:21 | InOutExpr | -| expressions.swift:7:21:7:21 | StringLiteralExpr | -| expressions.swift:8:15:8:15 | NilLiteralExpr | -| expressions.swift:15:9:15:9 | DeclRefExpr | -| expressions.swift:15:9:15:14 | BinaryExpr | -| expressions.swift:15:11:15:11 | DeclRefExpr | -| expressions.swift:15:11:15:11 | DotSyntaxCallExpr | -| expressions.swift:15:11:15:11 | TypeExpr | -| expressions.swift:15:14:15:14 | IntegerLiteralExpr | -| expressions.swift:16:11:16:11 | TypeExpr | -| expressions.swift:16:11:16:19 | DotSyntaxCallExpr | -| expressions.swift:16:11:16:19 | ErasureExpr | -| expressions.swift:16:19:16:19 | DeclRefExpr | -| expressions.swift:20:1:20:16 | ForceTryExpr | -| expressions.swift:20:6:20:6 | DeclRefExpr | -| expressions.swift:20:6:20:16 | CallExpr | -| expressions.swift:20:14:20:14 | IntegerLiteralExpr | -| expressions.swift:21:1:21:16 | OptionalTryExpr | -| expressions.swift:21:6:21:6 | DeclRefExpr | -| expressions.swift:21:6:21:16 | CallExpr | -| expressions.swift:21:6:21:16 | InjectIntoOptionalExpr | -| expressions.swift:21:14:21:14 | IntegerLiteralExpr | -| expressions.swift:27:13:27:13 | ConstructorRefCallExpr | -| expressions.swift:27:13:27:13 | DeclRefExpr | -| expressions.swift:27:13:27:13 | TypeExpr | -| expressions.swift:27:13:27:19 | CallExpr | -| expressions.swift:29:9:29:19 | DictionaryExpr | -| expressions.swift:29:10:29:10 | StringLiteralExpr | -| expressions.swift:29:10:29:16 | TupleExpr | -| expressions.swift:29:16:29:16 | StringLiteralExpr | -| expressions.swift:30:1:30:1 | DiscardAssignmentExpr | -| expressions.swift:30:1:30:5 | AssignExpr | -| expressions.swift:30:5:30:5 | IntegerLiteralExpr | -| expressions.swift:31:1:31:1 | DiscardAssignmentExpr | -| expressions.swift:31:1:31:11 | AssignExpr | -| expressions.swift:31:5:31:5 | IntegerLiteralExpr | -| expressions.swift:31:5:31:11 | IsExpr | -| expressions.swift:32:1:32:1 | DiscardAssignmentExpr | -| expressions.swift:32:1:32:11 | AssignExpr | -| expressions.swift:32:5:32:5 | IntegerLiteralExpr | -| expressions.swift:32:5:32:11 | CoerceExpr | -| expressions.swift:33:1:33:1 | DiscardAssignmentExpr | -| expressions.swift:33:1:33:12 | AssignExpr | -| expressions.swift:33:5:33:5 | IntegerLiteralExpr | -| expressions.swift:33:5:33:12 | ConditionalCheckedCastExpr | -| expressions.swift:34:1:34:1 | DiscardAssignmentExpr | -| expressions.swift:34:1:34:12 | AssignExpr | -| expressions.swift:34:5:34:5 | IntegerLiteralExpr | -| expressions.swift:34:5:34:12 | ForcedCheckedCastExpr | -| expressions.swift:35:1:35:1 | DeclRefExpr | -| expressions.swift:35:1:35:13 | CallExpr | -| expressions.swift:35:6:35:6 | DefaultArgumentExpr | -| expressions.swift:35:6:35:6 | DefaultArgumentExpr | -| expressions.swift:35:7:35:7 | DeclRefExpr | -| expressions.swift:35:7:35:12 | ArrayExpr | -| expressions.swift:35:7:35:12 | ErasureExpr | -| expressions.swift:35:7:35:12 | SubscriptExpr | -| expressions.swift:35:7:35:12 | VarargExpansionExpr | -| expressions.swift:35:9:35:9 | StringLiteralExpr | -| expressions.swift:38:3:38:3 | DeclRefExpr | -| expressions.swift:38:3:38:15 | CallExpr | -| expressions.swift:38:11:38:11 | IntegerLiteralExpr | -| expressions.swift:38:14:38:14 | IntegerLiteralExpr | -| expressions.swift:41:1:41:1 | DeclRefExpr | -| expressions.swift:41:1:43:1 | CallExpr | -| expressions.swift:41:10:43:1 | ClosureExpr | -| expressions.swift:42:12:42:12 | DeclRefExpr | -| expressions.swift:42:12:42:16 | BinaryExpr | -| expressions.swift:42:14:42:14 | DeclRefExpr | -| expressions.swift:42:14:42:14 | DotSyntaxCallExpr | -| expressions.swift:42:14:42:14 | TypeExpr | -| expressions.swift:42:16:42:16 | DeclRefExpr | -| expressions.swift:44:1:44:1 | DeclRefExpr | -| expressions.swift:44:1:46:1 | CallExpr | -| expressions.swift:44:10:46:1 | ClosureExpr | -| expressions.swift:45:12:45:12 | DeclRefExpr | -| expressions.swift:45:12:45:16 | BinaryExpr | -| expressions.swift:45:14:45:14 | DeclRefExpr | -| expressions.swift:45:14:45:14 | DotSyntaxCallExpr | -| expressions.swift:45:14:45:14 | TypeExpr | -| expressions.swift:45:16:45:16 | DeclRefExpr | -| expressions.swift:47:1:47:1 | DeclRefExpr | -| expressions.swift:47:1:47:27 | CallExpr | -| expressions.swift:47:10:47:27 | ClosureExpr | -| expressions.swift:47:19:47:19 | DeclRefExpr | -| expressions.swift:47:19:47:24 | BinaryExpr | -| expressions.swift:47:22:47:22 | DeclRefExpr | -| expressions.swift:47:22:47:22 | DotSyntaxCallExpr | -| expressions.swift:47:22:47:22 | TypeExpr | -| expressions.swift:47:24:47:24 | DeclRefExpr | -| expressions.swift:48:1:48:1 | DeclRefExpr | -| expressions.swift:48:1:48:20 | CallExpr | -| expressions.swift:48:10:48:20 | ClosureExpr | -| expressions.swift:48:12:48:12 | DeclRefExpr | -| expressions.swift:48:12:48:17 | BinaryExpr | -| expressions.swift:48:15:48:15 | DeclRefExpr | -| expressions.swift:48:15:48:15 | DotSyntaxCallExpr | -| expressions.swift:48:15:48:15 | TypeExpr | -| expressions.swift:48:17:48:17 | DeclRefExpr | -| expressions.swift:54:1:54:1 | DiscardAssignmentExpr | -| expressions.swift:54:1:54:8 | AssignExpr | -| expressions.swift:54:5:54:8 | KeyPathExpr | -| expressions.swift:58:16:58:16 | IntegerLiteralExpr | -| expressions.swift:59:1:59:1 | DeclRefExpr | -| expressions.swift:59:1:59:34 | CallExpr | -| expressions.swift:59:25:59:26 | InOutExpr | -| expressions.swift:59:25:59:26 | InOutToPointerExpr | -| expressions.swift:59:26:59:26 | DeclRefExpr | -| expressions.swift:60:1:60:1 | DeclRefExpr | -| expressions.swift:60:1:60:63 | CallExpr | -| expressions.swift:60:23:60:23 | DeclRefExpr | -| expressions.swift:60:23:60:23 | LoadExpr | -| expressions.swift:60:33:60:63 | ClosureExpr | -| expressions.swift:60:33:60:63 | FunctionConversionExpr | -| expressions.swift:60:35:60:35 | DeclRefExpr | -| expressions.swift:60:35:60:61 | CallExpr | -| expressions.swift:60:59:60:59 | DeclRefExpr | -| expressions.swift:64:8:64:8 | DeclRefExpr | -| expressions.swift:64:8:64:12 | BinaryExpr | -| expressions.swift:64:10:64:10 | DeclRefExpr | -| expressions.swift:64:10:64:10 | DotSyntaxCallExpr | -| expressions.swift:64:10:64:10 | TypeExpr | -| expressions.swift:64:12:64:12 | IntegerLiteralExpr | -| expressions.swift:73:5:73:5 | DeclRefExpr | -| expressions.swift:73:5:73:5 | MemberRefExpr | -| expressions.swift:73:5:73:10 | AssignExpr | -| expressions.swift:73:10:73:10 | DeclRefExpr | -| expressions.swift:77:7:77:7 | CallExpr | -| expressions.swift:77:7:77:7 | DeclRefExpr | -| expressions.swift:77:7:77:7 | MagicIdentifierLiteralExpr | -| expressions.swift:77:7:77:7 | MagicIdentifierLiteralExpr | -| expressions.swift:77:7:77:7 | MagicIdentifierLiteralExpr | -| expressions.swift:77:7:77:7 | MagicIdentifierLiteralExpr | -| expressions.swift:77:7:77:7 | StringLiteralExpr | -| expressions.swift:79:5:79:5 | SuperRefExpr | -| expressions.swift:79:5:79:11 | DotSyntaxCallExpr | -| expressions.swift:79:5:79:21 | CallExpr | -| expressions.swift:79:5:79:21 | RebindSelfInConstructorExpr | +| expressions.swift:7:10:7:10 | hello | +| expressions.swift:7:11:7:10 | call to ... | +| expressions.swift:7:11:7:11 | $interpolation | +| expressions.swift:7:11:7:11 | &... | +| expressions.swift:7:11:7:11 | call to appendLiteral | +| expressions.swift:7:18:7:18 | $interpolation | +| expressions.swift:7:18:7:18 | &... | +| expressions.swift:7:18:7:18 | appendInterpolation | +| expressions.swift:7:18:7:18 | call to appendInterpolation | +| expressions.swift:7:18:7:20 | call to ... | +| expressions.swift:7:19:7:19 | a | +| expressions.swift:7:21:7:21 | | +| expressions.swift:7:21:7:21 | $interpolation | +| expressions.swift:7:21:7:21 | &... | +| expressions.swift:7:21:7:21 | call to ... | +| expressions.swift:7:21:7:21 | call to appendLiteral | +| expressions.swift:8:15:8:15 | nil | +| expressions.swift:15:9:15:9 | x | +| expressions.swift:15:9:15:14 | ... call to != ... | +| expressions.swift:15:11:15:11 | != | +| expressions.swift:15:11:15:11 | Int.Type | +| expressions.swift:15:11:15:11 | call to != | +| expressions.swift:15:14:15:14 | 0 | +| expressions.swift:16:11:16:11 | AnError.Type | +| expressions.swift:16:11:16:19 | (Error) ... | +| expressions.swift:16:11:16:19 | (TBD (ExistentialType)) ... | +| expressions.swift:16:11:16:19 | call to ... | +| expressions.swift:16:19:16:19 | failed | +| expressions.swift:20:1:20:16 | try! ... | +| expressions.swift:20:6:20:6 | failure | +| expressions.swift:20:6:20:16 | call to failure | +| expressions.swift:20:14:20:14 | 11 | +| expressions.swift:21:1:21:16 | try? ... | +| expressions.swift:21:6:21:6 | failure | +| expressions.swift:21:6:21:16 | (()?) ... | +| expressions.swift:21:6:21:16 | call to failure | +| expressions.swift:21:14:21:14 | 11 | +| expressions.swift:27:13:27:13 | Klass.Type | +| expressions.swift:27:13:27:13 | call to ... | +| expressions.swift:27:13:27:13 | deinit | +| expressions.swift:27:13:27:19 | call to ... | +| expressions.swift:29:9:29:19 | [...] | +| expressions.swift:29:10:29:10 | 1 | +| expressions.swift:29:10:29:16 | (...) | +| expressions.swift:29:16:29:16 | 2 | +| expressions.swift:30:1:30:1 | _ | +| expressions.swift:30:1:30:5 | ... = ... | +| expressions.swift:30:5:30:5 | 15 | +| expressions.swift:31:1:31:1 | _ | +| expressions.swift:31:1:31:11 | ... = ... | +| expressions.swift:31:5:31:5 | 15 | +| expressions.swift:31:5:31:11 | ... is ... | +| expressions.swift:32:1:32:1 | _ | +| expressions.swift:32:1:32:11 | ... = ... | +| expressions.swift:32:5:32:5 | 15 | +| expressions.swift:32:5:32:11 | (Double) ... | +| expressions.swift:33:1:33:1 | _ | +| expressions.swift:33:1:33:12 | ... = ... | +| expressions.swift:33:5:33:5 | 15 | +| expressions.swift:33:5:33:12 | (Double?) ... | +| expressions.swift:34:1:34:1 | _ | +| expressions.swift:34:1:34:12 | ... = ... | +| expressions.swift:34:5:34:5 | 15 | +| expressions.swift:34:5:34:12 | (Double) ... | +| expressions.swift:35:1:35:1 | print | +| expressions.swift:35:1:35:13 | call to print | +| expressions.swift:35:6:35:6 | default separator | +| expressions.swift:35:6:35:6 | default terminator | +| expressions.swift:35:7:35:7 | d | +| expressions.swift:35:7:35:12 | (Any) ... | +| expressions.swift:35:7:35:12 | (TBD (ProtocolCompositionType)) ... | +| expressions.swift:35:7:35:12 | ...[...] | +| expressions.swift:35:7:35:12 | [...] | +| expressions.swift:35:7:35:12 | [...] | +| expressions.swift:35:9:35:9 | 1 | +| expressions.swift:38:3:38:3 | closure | +| expressions.swift:38:3:38:15 | call to ... | +| expressions.swift:38:11:38:11 | 5 | +| expressions.swift:38:14:38:14 | 7 | +| expressions.swift:41:1:41:1 | closured | +| expressions.swift:41:1:43:1 | call to closured | +| expressions.swift:41:10:43:1 | { ... } | +| expressions.swift:42:12:42:12 | x | +| expressions.swift:42:12:42:16 | ... call to + ... | +| expressions.swift:42:14:42:14 | + | +| expressions.swift:42:14:42:14 | Int.Type | +| expressions.swift:42:14:42:14 | call to + | +| expressions.swift:42:16:42:16 | y | +| expressions.swift:44:1:44:1 | closured | +| expressions.swift:44:1:46:1 | call to closured | +| expressions.swift:44:10:46:1 | { ... } | +| expressions.swift:45:12:45:12 | x | +| expressions.swift:45:12:45:16 | ... call to + ... | +| expressions.swift:45:14:45:14 | + | +| expressions.swift:45:14:45:14 | Int.Type | +| expressions.swift:45:14:45:14 | call to + | +| expressions.swift:45:16:45:16 | y | +| expressions.swift:47:1:47:1 | closured | +| expressions.swift:47:1:47:27 | call to closured | +| expressions.swift:47:10:47:27 | { ... } | +| expressions.swift:47:19:47:19 | $0 | +| expressions.swift:47:19:47:24 | ... call to + ... | +| expressions.swift:47:22:47:22 | + | +| expressions.swift:47:22:47:22 | Int.Type | +| expressions.swift:47:22:47:22 | call to + | +| expressions.swift:47:24:47:24 | $1 | +| expressions.swift:48:1:48:1 | closured | +| expressions.swift:48:1:48:20 | call to closured | +| expressions.swift:48:10:48:20 | { ... } | +| expressions.swift:48:12:48:12 | $0 | +| expressions.swift:48:12:48:17 | ... call to + ... | +| expressions.swift:48:15:48:15 | + | +| expressions.swift:48:15:48:15 | Int.Type | +| expressions.swift:48:15:48:15 | call to + | +| expressions.swift:48:17:48:17 | $1 | +| expressions.swift:54:1:54:1 | _ | +| expressions.swift:54:1:54:8 | ... = ... | +| expressions.swift:54:5:54:8 | #keyPath(...) | +| expressions.swift:58:16:58:16 | 1234 | +| expressions.swift:59:1:59:1 | unsafeFunction | +| expressions.swift:59:1:59:34 | call to unsafeFunction | +| expressions.swift:59:25:59:26 | &... | +| expressions.swift:59:25:59:26 | (UnsafePointer) ... | +| expressions.swift:59:26:59:26 | myNumber | +| expressions.swift:60:1:60:1 | withUnsafePointer | +| expressions.swift:60:1:60:63 | call to withUnsafePointer | +| expressions.swift:60:23:60:23 | (Int) ... | +| expressions.swift:60:23:60:23 | myNumber | +| expressions.swift:60:33:60:63 | ((UnsafePointer) throws -> ()) ... | +| expressions.swift:60:33:60:63 | { ... } | +| expressions.swift:60:35:60:35 | unsafeFunction | +| expressions.swift:60:35:60:61 | call to unsafeFunction | +| expressions.swift:60:59:60:59 | $0 | +| expressions.swift:64:8:64:8 | x | +| expressions.swift:64:8:64:12 | ... call to < ... | +| expressions.swift:64:10:64:10 | < | +| expressions.swift:64:10:64:10 | Int.Type | +| expressions.swift:64:10:64:10 | call to < | +| expressions.swift:64:12:64:12 | 0 | +| expressions.swift:73:5:73:5 | .xx | +| expressions.swift:73:5:73:5 | self | +| expressions.swift:73:5:73:10 | ... = ... | +| expressions.swift:73:10:73:10 | x | +| expressions.swift:77:7:77:7 | #... | +| expressions.swift:77:7:77:7 | #... | +| expressions.swift:77:7:77:7 | #... | +| expressions.swift:77:7:77:7 | #... | +| expressions.swift:77:7:77:7 | _unimplementedInitializer | +| expressions.swift:77:7:77:7 | call to _unimplementedInitializer | +| expressions.swift:77:7:77:7 | expressions.Derived | +| expressions.swift:79:5:79:5 | super | +| expressions.swift:79:5:79:11 | call to ... | +| expressions.swift:79:5:79:21 | call to ... | +| expressions.swift:79:5:79:21 | self = ... | | expressions.swift:79:11:79:11 | TBD (OtherConstructorDeclRefExpr) | -| expressions.swift:79:19:79:19 | IntegerLiteralExpr | -| expressions.swift:83:15:83:15 | ConstructorRefCallExpr | -| expressions.swift:83:15:83:15 | DeclRefExpr | -| expressions.swift:83:15:83:15 | TypeExpr | -| expressions.swift:83:15:83:23 | CallExpr | -| expressions.swift:84:1:84:1 | DiscardAssignmentExpr | -| expressions.swift:84:1:84:13 | AssignExpr | -| expressions.swift:84:5:84:5 | DeclRefExpr | -| expressions.swift:84:5:84:5 | DerivedToBaseExpr | -| expressions.swift:84:5:84:13 | MemberRefExpr | -| expressions.swift:87:1:87:1 | DeclRefExpr | -| expressions.swift:87:1:87:4 | ForceValueExpr | -| expressions.swift:88:1:88:1 | DeclRefExpr | -| expressions.swift:88:1:88:6 | SubscriptExpr | -| expressions.swift:88:1:88:7 | ForceValueExpr | -| expressions.swift:88:3:88:3 | StringLiteralExpr | -| expressions.swift:92:14:92:14 | TypeExpr | -| expressions.swift:92:14:92:24 | DotSyntaxCallExpr | -| expressions.swift:92:14:92:44 | CallExpr | -| expressions.swift:92:14:92:46 | DotSyntaxCallExpr | -| expressions.swift:92:14:92:55 | CallExpr | -| expressions.swift:92:24:92:24 | DeclRefExpr | -| expressions.swift:92:37:92:37 | ConstructorRefCallExpr | -| expressions.swift:92:37:92:37 | DeclRefExpr | -| expressions.swift:92:37:92:37 | TypeExpr | -| expressions.swift:92:37:92:43 | CallExpr | -| expressions.swift:92:46:92:46 | DeclRefExpr | -| expressions.swift:93:1:93:16 | TypeExpr | -| expressions.swift:93:1:93:18 | DotSyntaxCallExpr | -| expressions.swift:93:1:93:35 | CallExpr | -| expressions.swift:93:18:93:18 | DeclRefExpr | -| expressions.swift:93:29:93:29 | DeclRefExpr | -| expressions.swift:93:29:93:29 | PointerToPointerExpr | -| expressions.swift:99:14:99:14 | IntegerLiteralExpr | -| expressions.swift:106:12:106:12 | IntegerLiteralExpr | -| expressions.swift:112:14:112:14 | IntegerLiteralExpr | -| expressions.swift:120:14:120:14 | IntegerLiteralExpr | -| expressions.swift:126:12:126:12 | IntegerLiteralExpr | -| expressions.swift:131:3:131:3 | DeclRefExpr | -| expressions.swift:131:3:131:6 | MemberRefExpr | -| expressions.swift:131:3:131:22 | AssignExpr | -| expressions.swift:131:22:131:22 | IntegerLiteralExpr | -| expressions.swift:132:11:132:11 | DeclRefExpr | -| expressions.swift:132:11:132:14 | LoadExpr | -| expressions.swift:132:11:132:14 | MemberRefExpr | -| expressions.swift:133:11:133:11 | DeclRefExpr | -| expressions.swift:133:11:133:11 | LoadExpr | -| expressions.swift:133:11:133:14 | MemberRefExpr | -| expressions.swift:134:11:134:11 | DeclRefExpr | -| expressions.swift:134:11:134:11 | LoadExpr | -| expressions.swift:134:11:134:14 | MemberRefExpr | -| expressions.swift:135:3:135:3 | DeclRefExpr | -| expressions.swift:135:3:135:6 | MemberRefExpr | -| expressions.swift:135:3:135:20 | AssignExpr | -| expressions.swift:135:20:135:20 | IntegerLiteralExpr | -| expressions.swift:136:11:136:11 | DeclRefExpr | -| expressions.swift:136:11:136:14 | LoadExpr | -| expressions.swift:136:11:136:14 | MemberRefExpr | -| expressions.swift:137:3:137:3 | DeclRefExpr | -| expressions.swift:137:3:137:3 | InOutExpr | -| expressions.swift:137:3:137:7 | SubscriptExpr | -| expressions.swift:137:3:137:11 | AssignExpr | -| expressions.swift:137:6:137:6 | IntegerLiteralExpr | -| expressions.swift:137:11:137:11 | IntegerLiteralExpr | -| expressions.swift:138:10:138:10 | DeclRefExpr | -| expressions.swift:138:10:138:10 | LoadExpr | -| expressions.swift:138:10:138:17 | SubscriptExpr | -| expressions.swift:138:13:138:13 | IntegerLiteralExpr | -| expressions.swift:138:16:138:16 | IntegerLiteralExpr | +| expressions.swift:79:11:79:11 | call to ... | +| expressions.swift:79:19:79:19 | 22 | +| expressions.swift:83:15:83:15 | Derived.Type | +| expressions.swift:83:15:83:15 | call to ... | +| expressions.swift:83:15:83:15 | deinit | +| expressions.swift:83:15:83:23 | call to ... | +| expressions.swift:84:1:84:1 | _ | +| expressions.swift:84:1:84:13 | ... = ... | +| expressions.swift:84:5:84:5 | (Base) ... | +| expressions.swift:84:5:84:5 | derived | +| expressions.swift:84:5:84:13 | .xx | +| expressions.swift:87:1:87:1 | opt | +| expressions.swift:87:1:87:4 | ...! | +| expressions.swift:88:1:88:1 | d | +| expressions.swift:88:1:88:6 | ...[...] | +| expressions.swift:88:1:88:7 | ...! | +| expressions.swift:88:3:88:3 | a | +| expressions.swift:92:14:92:14 | Unmanaged.Type | +| expressions.swift:92:14:92:24 | call to passRetained | +| expressions.swift:92:14:92:44 | call to ... | +| expressions.swift:92:14:92:46 | call to toOpaque | +| expressions.swift:92:14:92:55 | call to ... | +| expressions.swift:92:24:92:24 | passRetained | +| expressions.swift:92:37:92:37 | ToPtr.Type | +| expressions.swift:92:37:92:37 | call to ... | +| expressions.swift:92:37:92:37 | deinit | +| expressions.swift:92:37:92:43 | call to ... | +| expressions.swift:92:46:92:46 | toOpaque | +| expressions.swift:93:1:93:16 | Unmanaged.Type | +| expressions.swift:93:1:93:18 | call to fromOpaque | +| expressions.swift:93:1:93:35 | call to ... | +| expressions.swift:93:18:93:18 | fromOpaque | +| expressions.swift:93:29:93:29 | (UnsafeRawPointer) ... | +| expressions.swift:93:29:93:29 | opaque | +| expressions.swift:99:14:99:14 | 0 | +| expressions.swift:106:12:106:12 | 0 | +| expressions.swift:112:14:112:14 | 0 | +| expressions.swift:120:14:120:14 | 0 | +| expressions.swift:126:12:126:12 | 0 | +| expressions.swift:131:3:131:3 | hp | +| expressions.swift:131:3:131:6 | .settableField | +| expressions.swift:131:3:131:22 | ... = ... | +| expressions.swift:131:22:131:22 | 42 | +| expressions.swift:132:11:132:11 | hp | +| expressions.swift:132:11:132:14 | (Int) ... | +| expressions.swift:132:11:132:14 | .settableField | +| expressions.swift:133:11:133:11 | (HasProperty) ... | +| expressions.swift:133:11:133:11 | hp | +| expressions.swift:133:11:133:14 | .readOnlyField1 | +| expressions.swift:134:11:134:11 | (HasProperty) ... | +| expressions.swift:134:11:134:11 | hp | +| expressions.swift:134:11:134:14 | .readOnlyField2 | +| expressions.swift:135:3:135:3 | hp | +| expressions.swift:135:3:135:6 | .normalField | +| expressions.swift:135:3:135:20 | ... = ... | +| expressions.swift:135:20:135:20 | 99 | +| expressions.swift:136:11:136:11 | hp | +| expressions.swift:136:11:136:14 | (Int) ... | +| expressions.swift:136:11:136:14 | .normalField | +| expressions.swift:137:3:137:3 | &... | +| expressions.swift:137:3:137:3 | hp | +| expressions.swift:137:3:137:7 | ...[...] | +| expressions.swift:137:3:137:11 | ... = ... | +| expressions.swift:137:6:137:6 | 1 | +| expressions.swift:137:11:137:11 | 2 | +| expressions.swift:138:10:138:10 | (HasProperty) ... | +| expressions.swift:138:10:138:10 | hp | +| expressions.swift:138:10:138:17 | ...[...] | +| expressions.swift:138:13:138:13 | 3 | +| expressions.swift:138:16:138:16 | 4 | diff --git a/swift/ql/test/extractor-tests/expressions/semantics.expected b/swift/ql/test/extractor-tests/expressions/semantics.expected index c20d4a29b93..5f07b18715f 100644 --- a/swift/ql/test/extractor-tests/expressions/semantics.expected +++ b/swift/ql/test/extractor-tests/expressions/semantics.expected @@ -1,70 +1,70 @@ -| expressions.swift:7:11:7:11 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:7:18:7:18 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:7:18:7:18 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:7:19:7:19 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:7:21:7:21 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:15:9:15:9 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:15:11:15:11 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:16:19:16:19 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:20:6:20:6 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:21:6:21:6 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:27:13:27:13 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:35:1:35:1 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:35:7:35:7 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:35:7:35:12 | SubscriptExpr | OrdinarySemantics | -| expressions.swift:38:3:38:3 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:41:1:41:1 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:42:12:42:12 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:42:14:42:14 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:42:16:42:16 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:44:1:44:1 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:45:12:45:12 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:45:14:45:14 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:45:16:45:16 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:47:1:47:1 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:47:19:47:19 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:47:22:47:22 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:47:24:47:24 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:48:1:48:1 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:48:12:48:12 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:48:15:48:15 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:48:17:48:17 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:59:1:59:1 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:59:26:59:26 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:60:1:60:1 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:60:23:60:23 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:60:35:60:35 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:60:59:60:59 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:64:8:64:8 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:64:10:64:10 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:73:5:73:5 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:73:5:73:5 | MemberRefExpr | DirectToStorage | -| expressions.swift:73:10:73:10 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:77:7:77:7 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:83:15:83:15 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:84:5:84:5 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:84:5:84:13 | MemberRefExpr | OrdinarySemantics | -| expressions.swift:87:1:87:1 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:88:1:88:1 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:88:1:88:6 | SubscriptExpr | OrdinarySemantics | -| expressions.swift:92:24:92:24 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:92:37:92:37 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:92:46:92:46 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:93:18:93:18 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:93:29:93:29 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:131:3:131:3 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:131:3:131:6 | MemberRefExpr | OrdinarySemantics | -| expressions.swift:132:11:132:11 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:132:11:132:14 | MemberRefExpr | OrdinarySemantics | -| expressions.swift:133:11:133:11 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:133:11:133:14 | MemberRefExpr | OrdinarySemantics | -| expressions.swift:134:11:134:11 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:134:11:134:14 | MemberRefExpr | OrdinarySemantics | -| expressions.swift:135:3:135:3 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:135:3:135:6 | MemberRefExpr | OrdinarySemantics | -| expressions.swift:136:11:136:11 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:136:11:136:14 | MemberRefExpr | OrdinarySemantics | -| expressions.swift:137:3:137:3 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:137:3:137:7 | SubscriptExpr | OrdinarySemantics | -| expressions.swift:138:10:138:10 | DeclRefExpr | OrdinarySemantics | -| expressions.swift:138:10:138:17 | SubscriptExpr | OrdinarySemantics | +| expressions.swift:7:11:7:11 | $interpolation | OrdinarySemantics | +| expressions.swift:7:18:7:18 | $interpolation | OrdinarySemantics | +| expressions.swift:7:18:7:18 | appendInterpolation | OrdinarySemantics | +| expressions.swift:7:19:7:19 | a | OrdinarySemantics | +| expressions.swift:7:21:7:21 | $interpolation | OrdinarySemantics | +| expressions.swift:15:9:15:9 | x | OrdinarySemantics | +| expressions.swift:15:11:15:11 | != | OrdinarySemantics | +| expressions.swift:16:19:16:19 | failed | OrdinarySemantics | +| expressions.swift:20:6:20:6 | failure | OrdinarySemantics | +| expressions.swift:21:6:21:6 | failure | OrdinarySemantics | +| expressions.swift:27:13:27:13 | deinit | OrdinarySemantics | +| expressions.swift:35:1:35:1 | print | OrdinarySemantics | +| expressions.swift:35:7:35:7 | d | OrdinarySemantics | +| expressions.swift:35:7:35:12 | ...[...] | OrdinarySemantics | +| expressions.swift:38:3:38:3 | closure | OrdinarySemantics | +| expressions.swift:41:1:41:1 | closured | OrdinarySemantics | +| expressions.swift:42:12:42:12 | x | OrdinarySemantics | +| expressions.swift:42:14:42:14 | + | OrdinarySemantics | +| expressions.swift:42:16:42:16 | y | OrdinarySemantics | +| expressions.swift:44:1:44:1 | closured | OrdinarySemantics | +| expressions.swift:45:12:45:12 | x | OrdinarySemantics | +| expressions.swift:45:14:45:14 | + | OrdinarySemantics | +| expressions.swift:45:16:45:16 | y | OrdinarySemantics | +| expressions.swift:47:1:47:1 | closured | OrdinarySemantics | +| expressions.swift:47:19:47:19 | $0 | OrdinarySemantics | +| expressions.swift:47:22:47:22 | + | OrdinarySemantics | +| expressions.swift:47:24:47:24 | $1 | OrdinarySemantics | +| expressions.swift:48:1:48:1 | closured | OrdinarySemantics | +| expressions.swift:48:12:48:12 | $0 | OrdinarySemantics | +| expressions.swift:48:15:48:15 | + | OrdinarySemantics | +| expressions.swift:48:17:48:17 | $1 | OrdinarySemantics | +| expressions.swift:59:1:59:1 | unsafeFunction | OrdinarySemantics | +| expressions.swift:59:26:59:26 | myNumber | OrdinarySemantics | +| expressions.swift:60:1:60:1 | withUnsafePointer | OrdinarySemantics | +| expressions.swift:60:23:60:23 | myNumber | OrdinarySemantics | +| expressions.swift:60:35:60:35 | unsafeFunction | OrdinarySemantics | +| expressions.swift:60:59:60:59 | $0 | OrdinarySemantics | +| expressions.swift:64:8:64:8 | x | OrdinarySemantics | +| expressions.swift:64:10:64:10 | < | OrdinarySemantics | +| expressions.swift:73:5:73:5 | .xx | DirectToStorage | +| expressions.swift:73:5:73:5 | self | OrdinarySemantics | +| expressions.swift:73:10:73:10 | x | OrdinarySemantics | +| expressions.swift:77:7:77:7 | _unimplementedInitializer | OrdinarySemantics | +| expressions.swift:83:15:83:15 | deinit | OrdinarySemantics | +| expressions.swift:84:5:84:5 | derived | OrdinarySemantics | +| expressions.swift:84:5:84:13 | .xx | OrdinarySemantics | +| expressions.swift:87:1:87:1 | opt | OrdinarySemantics | +| expressions.swift:88:1:88:1 | d | OrdinarySemantics | +| expressions.swift:88:1:88:6 | ...[...] | OrdinarySemantics | +| expressions.swift:92:24:92:24 | passRetained | OrdinarySemantics | +| expressions.swift:92:37:92:37 | deinit | OrdinarySemantics | +| expressions.swift:92:46:92:46 | toOpaque | OrdinarySemantics | +| expressions.swift:93:18:93:18 | fromOpaque | OrdinarySemantics | +| expressions.swift:93:29:93:29 | opaque | OrdinarySemantics | +| expressions.swift:131:3:131:3 | hp | OrdinarySemantics | +| expressions.swift:131:3:131:6 | .settableField | OrdinarySemantics | +| expressions.swift:132:11:132:11 | hp | OrdinarySemantics | +| expressions.swift:132:11:132:14 | .settableField | OrdinarySemantics | +| expressions.swift:133:11:133:11 | hp | OrdinarySemantics | +| expressions.swift:133:11:133:14 | .readOnlyField1 | OrdinarySemantics | +| expressions.swift:134:11:134:11 | hp | OrdinarySemantics | +| expressions.swift:134:11:134:14 | .readOnlyField2 | OrdinarySemantics | +| expressions.swift:135:3:135:3 | hp | OrdinarySemantics | +| expressions.swift:135:3:135:6 | .normalField | OrdinarySemantics | +| expressions.swift:136:11:136:11 | hp | OrdinarySemantics | +| expressions.swift:136:11:136:14 | .normalField | OrdinarySemantics | +| expressions.swift:137:3:137:3 | hp | OrdinarySemantics | +| expressions.swift:137:3:137:7 | ...[...] | OrdinarySemantics | +| expressions.swift:138:10:138:10 | hp | OrdinarySemantics | +| expressions.swift:138:10:138:17 | ...[...] | OrdinarySemantics | diff --git a/swift/ql/test/extractor-tests/patterns/all.expected b/swift/ql/test/extractor-tests/patterns/all.expected index af4caf5feff..5547d4efbd5 100644 --- a/swift/ql/test/extractor-tests/patterns/all.expected +++ b/swift/ql/test/extractor-tests/patterns/all.expected @@ -1,41 +1,41 @@ -| patterns.swift:2:9:2:9 | NamedPattern | -| patterns.swift:3:9:3:9 | NamedPattern | -| patterns.swift:3:9:3:19 | TypedPattern | -| patterns.swift:4:9:4:17 | TuplePattern | -| patterns.swift:4:10:4:10 | NamedPattern | -| patterns.swift:4:13:4:13 | NamedPattern | -| patterns.swift:4:16:4:16 | NamedPattern | -| patterns.swift:5:9:5:9 | AnyPattern | -| patterns.swift:6:9:6:11 | ParenPattern | -| patterns.swift:6:10:6:10 | AnyPattern | -| patterns.swift:10:9:10:9 | NamedPattern | -| patterns.swift:12:10:12:21 | BindingPattern | -| patterns.swift:12:14:12:21 | TuplePattern | -| patterns.swift:12:15:12:15 | NamedPattern | -| patterns.swift:12:19:12:19 | NamedPattern | -| patterns.swift:16:10:16:14 | ExprPattern | -| patterns.swift:17:10:17:10 | AnyPattern | -| patterns.swift:24:9:24:9 | NamedPattern | -| patterns.swift:24:9:24:12 | TypedPattern | -| patterns.swift:27:10:27:11 | EnumElementPattern | -| patterns.swift:28:10:28:23 | BindingPattern | -| patterns.swift:28:14:28:23 | EnumElementPattern | -| patterns.swift:28:18:28:23 | TuplePattern | -| patterns.swift:28:19:28:19 | NamedPattern | -| patterns.swift:28:22:28:22 | NamedPattern | -| patterns.swift:31:9:31:9 | NamedPattern | -| patterns.swift:31:9:31:15 | TypedPattern | -| patterns.swift:34:10:34:15 | BindingPattern | -| patterns.swift:34:14:34:14 | NamedPattern | -| patterns.swift:34:14:34:15 | OptionalSomePattern | -| patterns.swift:35:10:35:10 | AnyPattern | -| patterns.swift:38:9:38:9 | NamedPattern | -| patterns.swift:38:9:38:12 | TypedPattern | -| patterns.swift:41:10:41:13 | IsPattern | -| patterns.swift:42:10:42:19 | BindingPattern | -| patterns.swift:42:14:42:14 | NamedPattern | -| patterns.swift:42:14:42:19 | IsPattern | -| patterns.swift:43:10:43:10 | AnyPattern | -| patterns.swift:46:9:46:9 | NamedPattern | -| patterns.swift:49:10:49:10 | BoolPattern | -| patterns.swift:50:10:50:10 | BoolPattern | +| patterns.swift:2:9:2:9 | an_int | +| patterns.swift:3:9:3:9 | a_string | +| patterns.swift:3:9:3:19 | ... as ... | +| patterns.swift:4:9:4:17 | (...) | +| patterns.swift:4:10:4:10 | x | +| patterns.swift:4:13:4:13 | y | +| patterns.swift:4:16:4:16 | z | +| patterns.swift:5:9:5:9 | _ | +| patterns.swift:6:9:6:11 | (...) | +| patterns.swift:6:10:6:10 | _ | +| patterns.swift:10:9:10:9 | point | +| patterns.swift:12:10:12:21 | let ... | +| patterns.swift:12:14:12:21 | (...) | +| patterns.swift:12:15:12:15 | xx | +| patterns.swift:12:19:12:19 | yy | +| patterns.swift:16:10:16:14 | TBD (SequenceExpr) | +| patterns.swift:17:10:17:10 | _ | +| patterns.swift:24:9:24:9 | v | +| patterns.swift:24:9:24:12 | ... as ... | +| patterns.swift:27:10:27:11 | .bar | +| patterns.swift:28:10:28:23 | let ... | +| patterns.swift:28:14:28:23 | .baz(...) | +| patterns.swift:28:18:28:23 | (...) | +| patterns.swift:28:19:28:19 | i | +| patterns.swift:28:22:28:22 | s | +| patterns.swift:31:9:31:9 | w | +| patterns.swift:31:9:31:15 | ... as ... | +| patterns.swift:34:10:34:15 | let ... | +| patterns.swift:34:14:34:14 | n | +| patterns.swift:34:14:34:15 | let ...? | +| patterns.swift:35:10:35:10 | _ | +| patterns.swift:38:9:38:9 | a | +| patterns.swift:38:9:38:12 | ... as ... | +| patterns.swift:41:10:41:13 | ... is ... | +| patterns.swift:42:10:42:19 | let ... | +| patterns.swift:42:14:42:14 | x | +| patterns.swift:42:14:42:19 | ... is ... | +| patterns.swift:43:10:43:10 | _ | +| patterns.swift:46:9:46:9 | b | +| patterns.swift:49:10:49:10 | true | +| patterns.swift:50:10:50:10 | false | diff --git a/swift/ql/test/extractor-tests/statements/ConditionElements.expected b/swift/ql/test/extractor-tests/statements/ConditionElements.expected index 7b7c3eb3de8..9800a5a6967 100644 --- a/swift/ql/test/extractor-tests/statements/ConditionElements.expected +++ b/swift/ql/test/extractor-tests/statements/ConditionElements.expected @@ -1,7 +1,11 @@ -| main.swift:3:8:3:13 | ConditionElement | main.swift:3:8:3:13 | BinaryExpr | -| main.swift:10:17:10:24 | ConditionElement | main.swift:10:18:10:22 | BinaryExpr | -| main.swift:39:9:39:14 | ConditionElement | main.swift:39:9:39:14 | BinaryExpr | -| main.swift:65:4:65:19 | ConditionElement | main.swift:65:9:65:15 | BindingPattern | -| main.swift:65:4:65:19 | ConditionElement | main.swift:65:19:65:19 | DeclRefExpr | -| main.swift:67:4:67:20 | ConditionElement | main.swift:67:9:67:16 | EnumElementPattern | -| main.swift:67:4:67:20 | ConditionElement | main.swift:67:20:67:20 | DeclRefExpr | +| main.swift:3:8:3:13 | ... call to == ... | main.swift:3:8:3:13 | ... call to == ... | +| main.swift:10:17:10:24 | ... call to < ... | main.swift:10:18:10:22 | ... call to < ... | +| main.swift:39:9:39:14 | ... call to != ... | main.swift:39:9:39:14 | ... call to != ... | +| main.swift:65:4:65:19 | let ... | main.swift:65:9:65:15 | let ... | +| main.swift:65:4:65:19 | let ... | main.swift:65:19:65:19 | x | +| main.swift:65:4:65:19 | x | main.swift:65:9:65:15 | let ... | +| main.swift:65:4:65:19 | x | main.swift:65:19:65:19 | x | +| main.swift:67:4:67:20 | .some(...) | main.swift:67:9:67:16 | .some(...) | +| main.swift:67:4:67:20 | .some(...) | main.swift:67:20:67:20 | x | +| main.swift:67:4:67:20 | x | main.swift:67:9:67:16 | .some(...) | +| main.swift:67:4:67:20 | x | main.swift:67:20:67:20 | x | diff --git a/swift/ql/test/extractor-tests/statements/LabeledStmts.expected b/swift/ql/test/extractor-tests/statements/LabeledStmts.expected index 99a58ea9e82..8f7e9199113 100644 --- a/swift/ql/test/extractor-tests/statements/LabeledStmts.expected +++ b/swift/ql/test/extractor-tests/statements/LabeledStmts.expected @@ -1,12 +1,12 @@ -| main.swift:2:3:8:3 | ForEachStmt | -| main.swift:3:5:7:5 | IfStmt | -| main.swift:10:3:12:3 | WhileStmt | -| main.swift:15:3:17:18 | RepeatWhileStmt | -| main.swift:19:3:23:3 | DoCatchStmt | -| main.swift:25:3:31:3 | DoCatchStmt | -| main.swift:39:3:41:3 | GuardStmt | -| main.swift:48:1:50:1 | DoStmt | -| main.swift:53:1:62:1 | SwitchStmt | -| main.swift:65:1:66:1 | IfStmt | -| main.swift:67:1:68:1 | IfStmt | -| main.swift:71:1:72:1 | ForEachStmt | +| main.swift:2:3:8:3 | for ... in ... { ... } | +| main.swift:3:5:7:5 | if ... then { ... } else { ... } | +| main.swift:10:3:12:3 | while ... { ... } | +| main.swift:15:3:17:18 | repeat { ... } while ... | +| main.swift:19:3:23:3 | do { ... } catch { ... } | +| main.swift:25:3:31:3 | do { ... } catch { ... } | +| main.swift:39:3:41:3 | guard ... else { ... } | +| main.swift:48:1:50:1 | do { ... } | +| main.swift:53:1:62:1 | switch index { ... } | +| main.swift:65:1:66:1 | if ... then { ... } | +| main.swift:67:1:68:1 | if ... then { ... } | +| main.swift:71:1:72:1 | for ... in ... where ... { ... } | diff --git a/swift/ql/test/extractor-tests/statements/Labels.expected b/swift/ql/test/extractor-tests/statements/Labels.expected index d00e90e0260..035b823b168 100644 --- a/swift/ql/test/extractor-tests/statements/Labels.expected +++ b/swift/ql/test/extractor-tests/statements/Labels.expected @@ -1,3 +1,3 @@ -| main.swift:2:3:8:3 | ForEachStmt | label1 | -| main.swift:10:3:12:3 | WhileStmt | label2 | -| main.swift:15:3:17:18 | RepeatWhileStmt | label3 | +| main.swift:2:3:8:3 | for ... in ... { ... } | label1 | +| main.swift:10:3:12:3 | while ... { ... } | label2 | +| main.swift:15:3:17:18 | repeat { ... } while ... | label3 | diff --git a/swift/ql/test/extractor-tests/types/ClassDecls.expected b/swift/ql/test/extractor-tests/types/ClassDecls.expected index d70b5531583..28ca13f6199 100644 --- a/swift/ql/test/extractor-tests/types/ClassDecls.expected +++ b/swift/ql/test/extractor-tests/types/ClassDecls.expected @@ -1,2 +1,2 @@ -| types.swift:9:1:11:1 | ClassDecl | ClassType | | -| types.swift:10:1:10:15 | ClassDecl | ClassType | ClassType | +| types.swift:9:1:11:1 | C | C | | +| types.swift:10:1:10:15 | Nested | C.Nested | C | diff --git a/swift/ql/test/extractor-tests/types/StructDecls.expected b/swift/ql/test/extractor-tests/types/StructDecls.expected index a080b049f0b..f25c1d052dc 100644 --- a/swift/ql/test/extractor-tests/types/StructDecls.expected +++ b/swift/ql/test/extractor-tests/types/StructDecls.expected @@ -1 +1 @@ -| types.swift:5:1:5:11 | StructDecl | StructType | | +| types.swift:5:1:5:11 | X | X | | diff --git a/swift/ql/test/extractor-tests/types/ThrowingAndAsync.expected b/swift/ql/test/extractor-tests/types/ThrowingAndAsync.expected new file mode 100644 index 00000000000..c9fe5db7b41 --- /dev/null +++ b/swift/ql/test/extractor-tests/types/ThrowingAndAsync.expected @@ -0,0 +1,4 @@ +| types.swift:24:1:26:1 | throwingFunc | () throws -> Int | throws | +| types.swift:28:1:28:36 | asyncFunction | (Int) async -> () | async | +| types.swift:30:1:30:54 | throwingAndAsyncFunction | (Int) async throws -> () | async | +| types.swift:30:1:30:54 | throwingAndAsyncFunction | (Int) async throws -> () | throws | diff --git a/swift/ql/test/extractor-tests/types/ThrowingAndAsync.ql b/swift/ql/test/extractor-tests/types/ThrowingAndAsync.ql new file mode 100644 index 00000000000..f0f6c90f879 --- /dev/null +++ b/swift/ql/test/extractor-tests/types/ThrowingAndAsync.ql @@ -0,0 +1,12 @@ +import codeql.swift.elements + +from FuncDecl f, AnyFunctionType t, string s +where + f.getInterfaceType() = t and + f.getLocation().getFile().getName().matches("%swift/ql/test%") and + ( + t.isAsync() and s = "async" + or + t.isThrowing() and s = "throws" + ) +select f, t, s diff --git a/swift/ql/test/extractor-tests/types/Types.expected b/swift/ql/test/extractor-tests/types/Types.expected index 052c66b8b74..3f08b50968c 100644 --- a/swift/ql/test/extractor-tests/types/Types.expected +++ b/swift/ql/test/extractor-tests/types/Types.expected @@ -1,35 +1,41 @@ -| types.swift:1:9:1:9 | IntegerLiteralExpr | StructType | -| types.swift:3:1:3:1 | DeclRefExpr | FunctionType | -| types.swift:3:1:3:13 | CallExpr | TupleType | -| types.swift:3:6:3:6 | DefaultArgumentExpr | StructType | -| types.swift:3:6:3:6 | DefaultArgumentExpr | StructType | -| types.swift:3:7:3:7 | DeclRefExpr | StructType | -| types.swift:3:7:3:11 | ArrayExpr | TBD (VariadicSequenceType) | -| types.swift:3:7:3:11 | BinaryExpr | StructType | -| types.swift:3:7:3:11 | ErasureExpr | TBD (ProtocolCompositionType) | -| types.swift:3:7:3:11 | VarargExpansionExpr | TBD (VariadicSequenceType) | -| types.swift:3:9:3:9 | DeclRefExpr | FunctionType | -| types.swift:3:9:3:9 | DotSyntaxCallExpr | FunctionType | -| types.swift:3:9:3:9 | TypeExpr | MetatypeType | -| types.swift:3:11:3:11 | IntegerLiteralExpr | StructType | -| types.swift:7:16:7:16 | ConstructorRefCallExpr | FunctionType | -| types.swift:7:16:7:16 | DeclRefExpr | FunctionType | -| types.swift:7:16:7:16 | TypeExpr | MetatypeType | -| types.swift:7:16:7:18 | CallExpr | StructType | -| types.swift:13:17:13:17 | ConstructorRefCallExpr | FunctionType | -| types.swift:13:17:13:17 | DeclRefExpr | FunctionType | -| types.swift:13:17:13:17 | TypeExpr | MetatypeType | -| types.swift:13:17:13:19 | CallExpr | ClassType | -| types.swift:14:22:14:24 | ConstructorRefCallExpr | FunctionType | -| types.swift:14:22:14:24 | TypeExpr | MetatypeType | -| types.swift:14:22:14:31 | CallExpr | ClassType | -| types.swift:14:24:14:24 | DeclRefExpr | FunctionType | -| types.swift:17:10:17:10 | DeclRefExpr | StructType | -| types.swift:17:10:17:14 | BinaryExpr | StructType | -| types.swift:17:12:17:12 | DeclRefExpr | FunctionType | -| types.swift:17:12:17:12 | DotSyntaxCallExpr | FunctionType | -| types.swift:17:12:17:12 | TypeExpr | MetatypeType | -| types.swift:17:14:17:14 | DeclRefExpr | StructType | -| types.swift:21:10:21:10 | DeclRefExpr | FunctionType | -| types.swift:21:10:21:13 | CallExpr | StructType | -| types.swift:21:12:21:12 | DeclRefExpr | StructType | +| types.swift:1:9:1:9 | 42 | Int | +| types.swift:3:1:3:1 | print | (Any..., String, String) -> () | +| types.swift:3:1:3:13 | call to print | () | +| types.swift:3:6:3:6 | default separator | String | +| types.swift:3:6:3:6 | default terminator | String | +| types.swift:3:7:3:7 | x | Int | +| types.swift:3:7:3:11 | (Any) ... | Any | +| types.swift:3:7:3:11 | (Any) ... | TBD (ProtocolCompositionType) | +| types.swift:3:7:3:11 | (TBD (ProtocolCompositionType)) ... | Any | +| types.swift:3:7:3:11 | (TBD (ProtocolCompositionType)) ... | TBD (ProtocolCompositionType) | +| types.swift:3:7:3:11 | ... call to + ... | Int | +| types.swift:3:7:3:11 | [...] | Any... | +| types.swift:3:7:3:11 | [...] | Any... | +| types.swift:3:7:3:11 | [...] | TBD (VariadicSequenceType) | +| types.swift:3:7:3:11 | [...] | TBD (VariadicSequenceType) | +| types.swift:3:9:3:9 | + | (Int.Type) -> (Int, Int) -> Int | +| types.swift:3:9:3:9 | Int.Type | Int.Type | +| types.swift:3:9:3:9 | call to + | (Int, Int) -> Int | +| types.swift:3:11:3:11 | 10 | Int | +| types.swift:7:16:7:16 | X.Type | X.Type | +| types.swift:7:16:7:16 | call to ... | () -> X | +| types.swift:7:16:7:16 | deinit | (X.Type) -> () -> X | +| types.swift:7:16:7:18 | call to ... | X | +| types.swift:13:17:13:17 | C.Type | C.Type | +| types.swift:13:17:13:17 | call to ... | () -> C | +| types.swift:13:17:13:17 | deinit | (C.Type) -> () -> C | +| types.swift:13:17:13:19 | call to ... | C | +| types.swift:14:22:14:24 | C.Nested.Type | C.Nested.Type | +| types.swift:14:22:14:24 | call to ... | () -> C.Nested | +| types.swift:14:22:14:31 | call to ... | C.Nested | +| types.swift:14:24:14:24 | deinit | (C.Nested.Type) -> () -> C.Nested | +| types.swift:17:10:17:10 | x | Int | +| types.swift:17:10:17:14 | ... call to + ... | Int | +| types.swift:17:12:17:12 | + | (Int.Type) -> (Int, Int) -> Int | +| types.swift:17:12:17:12 | Int.Type | Int.Type | +| types.swift:17:12:17:12 | call to + | (Int, Int) -> Int | +| types.swift:17:14:17:14 | y | Int | +| types.swift:21:10:21:10 | f | (Int) -> Int | +| types.swift:21:10:21:13 | call to ... | Int | +| types.swift:21:12:21:12 | x | Int | +| types.swift:25:10:25:10 | 42 | Int | diff --git a/swift/ql/test/extractor-tests/types/types.swift b/swift/ql/test/extractor-tests/types/types.swift index 1eb8a56c452..b7b225d07db 100644 --- a/swift/ql/test/extractor-tests/types/types.swift +++ b/swift/ql/test/extractor-tests/types/types.swift @@ -20,3 +20,11 @@ func f(x: Int, y: Int) -> Int { func g(_ f: (Int) -> Int, _ x: Int) -> Int { return f(x) } + +func throwingFunc() throws -> Int { + return 42 +} + +func asyncFunction(x: Int) async { } + +func throwingAndAsyncFunction(x: Int) async throws { } \ No newline at end of file diff --git a/swift/ql/test/library-tests/controlflow/graph/Cfg.expected b/swift/ql/test/library-tests/controlflow/graph/Cfg.expected index 08ecb747577..1a6485f84f6 100644 --- a/swift/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/swift/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -1,4790 +1,4935 @@ cfg.swift: -# 5| enter ConcreteFuncDecl -#-----| -> IntegerLiteralExpr +# 5| enter returnZero +#-----| -> 0 -# 5| exit ConcreteFuncDecl +# 5| exit returnZero -# 5| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 5| exit returnZero (normal) +#-----| -> exit returnZero -# 5| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 5| return ... +#-----| return -> exit returnZero (normal) -# 5| IntegerLiteralExpr -#-----| -> ReturnStmt +# 5| 0 +#-----| -> return ... -# 15| enter ConcreteFuncDecl -#-----| -> DeclRefExpr +# 15| enter isZero +#-----| -> == -# 15| exit ConcreteFuncDecl +# 15| exit isZero -# 15| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 15| exit isZero (normal) +#-----| -> exit isZero -# 15| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 15| return ... +#-----| return -> exit isZero (normal) -# 15| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 15| x +#-----| -> 0 -# 15| BinaryExpr -#-----| -> ReturnStmt +# 15| ... call to == ... +#-----| -> return ... -# 15| DeclRefExpr -#-----| -> TypeExpr +# 15| == +#-----| -> Int.Type -# 15| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 15| Int.Type +#-----| -> call to == -# 15| TypeExpr -#-----| -> DotSyntaxCallExpr +# 15| call to == +#-----| exception -> exit isZero (normal) +#-----| -> x -# 15| IntegerLiteralExpr -#-----| -> BinaryExpr +# 15| 0 +#-----| -> ... call to == ... -# 17| enter ConcreteFuncDecl -#-----| -> GuardStmt +# 17| enter mightThrow +#-----| -> guard ... else { ... } -# 17| exit ConcreteFuncDecl +# 17| exit mightThrow -# 17| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 17| exit mightThrow (normal) +#-----| -> exit mightThrow -# 18| GuardStmt -#-----| -> DeclRefExpr +# 18| guard ... else { ... } +#-----| -> >= -# 18| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 18| x +#-----| -> 0 -# 18| BinaryExpr +# 18| ... call to >= ... #-----| -> StmtCondition # 18| StmtCondition -#-----| false -> DeclRefExpr -#-----| true -> GuardStmt +#-----| false -> error1 +#-----| true -> guard ... else { ... } -# 18| DeclRefExpr -#-----| -> TypeExpr +# 18| >= +#-----| -> Int.Type -# 18| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 18| Int.Type +#-----| -> call to >= -# 18| TypeExpr -#-----| -> DotSyntaxCallExpr +# 18| call to >= +#-----| exception -> exit mightThrow (normal) +#-----| -> x -# 18| IntegerLiteralExpr -#-----| -> BinaryExpr +# 18| 0 +#-----| -> ... call to >= ... -# 19| ThrowStmt -#-----| exception -> exit ConcreteFuncDecl (normal) +# 19| throw ... +#-----| exception -> exit mightThrow (normal) -# 19| TypeExpr -#-----| -> DotSyntaxCallExpr +# 19| MyError.Type +#-----| -> call to ... -# 19| DotSyntaxCallExpr -#-----| -> ErasureExpr +# 19| (Error) ... +#-----| -> throw ... -# 19| ErasureExpr -#-----| -> ThrowStmt +# 19| (TBD (ExistentialType)) ... +#-----| -> throw ... -# 19| DeclRefExpr -#-----| -> TypeExpr +# 19| call to ... +#-----| -> (Error) ... +#-----| -> (TBD (ExistentialType)) ... -# 21| GuardStmt -#-----| -> DeclRefExpr +# 19| error1 +#-----| -> MyError.Type -# 21| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 21| guard ... else { ... } +#-----| -> <= -# 21| BinaryExpr +# 21| x +#-----| -> 0 + +# 21| ... call to <= ... #-----| -> StmtCondition # 21| StmtCondition -#-----| true -> exit ConcreteFuncDecl (normal) -#-----| false -> DeclRefExpr +#-----| true -> exit mightThrow (normal) +#-----| false -> error3 -# 21| DeclRefExpr -#-----| -> TypeExpr +# 21| <= +#-----| -> Int.Type -# 21| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 21| Int.Type +#-----| -> call to <= -# 21| TypeExpr -#-----| -> DotSyntaxCallExpr +# 21| call to <= +#-----| exception -> exit mightThrow (normal) +#-----| -> x -# 21| IntegerLiteralExpr -#-----| -> BinaryExpr +# 21| 0 +#-----| -> ... call to <= ... -# 22| ThrowStmt -#-----| exception -> exit ConcreteFuncDecl (normal) +# 22| throw ... +#-----| exception -> exit mightThrow (normal) -# 22| TypeExpr -#-----| -> DotSyntaxCallExpr +# 22| MyError.Type +#-----| -> call to ... -# 22| DotSyntaxCallExpr -#-----| -> DeclRefExpr +# 22| call to ... +#-----| -> + -# 22| CallExpr -#-----| -> ErasureExpr +# 22| (Error) ... +#-----| -> throw ... -# 22| ErasureExpr -#-----| -> ThrowStmt +# 22| (TBD (ExistentialType)) ... +#-----| -> throw ... -# 22| DeclRefExpr -#-----| -> TypeExpr +# 22| call to ... +#-----| -> (Error) ... +#-----| -> (TBD (ExistentialType)) ... -# 22| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 22| error3 +#-----| -> MyError.Type -# 22| BinaryExpr -#-----| -> CallExpr +# 22| x +#-----| -> 1 -# 22| DeclRefExpr -#-----| -> TypeExpr +# 22| ... call to + ... +#-----| -> call to ... -# 22| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 22| + +#-----| -> Int.Type -# 22| TypeExpr -#-----| -> DotSyntaxCallExpr +# 22| Int.Type +#-----| -> call to + -# 22| IntegerLiteralExpr -#-----| -> BinaryExpr +# 22| call to + +#-----| exception -> exit mightThrow (normal) +#-----| -> x -# 26| enter ConcreteFuncDecl -#-----| -> DoCatchStmt +# 22| 1 +#-----| -> ... call to + ... -# 26| exit ConcreteFuncDecl +# 26| enter tryCatch +#-----| -> do { ... } catch { ... } -# 26| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 26| exit tryCatch -# 27| DoCatchStmt -#-----| -> DeclRefExpr +# 26| exit tryCatch (normal) +#-----| -> exit tryCatch -# 28| TryExpr -#-----| -> DeclRefExpr +# 27| do { ... } catch { ... } +#-----| -> mightThrow -# 28| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 28| try ... +#-----| -> print -# 28| CallExpr -#-----| -> TryExpr -#-----| exception -> CaseStmt +# 28| mightThrow +#-----| -> 0 -# 28| IntegerLiteralExpr -#-----| -> CallExpr +# 28| call to mightThrow +#-----| -> try ... +#-----| exception -> case ... -# 29| DeclRefExpr -#-----| -> StringLiteralExpr +# 28| 0 +#-----| -> call to mightThrow -# 29| CallExpr -#-----| exception -> CaseStmt +# 29| print +#-----| -> Did not throw. -# 29| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 29| call to print +#-----| exception -> case ... -# 29| DefaultArgumentExpr -#-----| -> CallExpr +# 29| default separator +#-----| -> default terminator -# 29| ArrayExpr -#-----| -> VarargExpansionExpr +# 29| default terminator +#-----| -> call to print -# 29| ErasureExpr -#-----| -> ArrayExpr +# 29| (Any) ... +#-----| -> [...] -# 29| StringLiteralExpr -#-----| -> ErasureExpr +# 29| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 29| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 29| Did not throw. +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 33| CaseStmt -#-----| -> CaseLabelItem +# 29| [...] +#-----| -> default separator -# 33| CaseLabelItem -#-----| -> EnumElementPattern +# 29| [...] +#-----| -> [...] -# 33| IsPattern -#-----| no-match -> CaseLabelItem -#-----| match -> IntegerLiteralExpr +# 33| case ... +#-----| -> ... is ... -# 33| EnumElementPattern -#-----| match -> IsPattern +# 33| ... is ... +#-----| -> .error1 -# 33| IsPattern -#-----| match -> IntegerLiteralExpr -#-----| no-match -> CaseStmt -#-----| no-match -> IntegerLiteralExpr +# 33| ... is ... +#-----| no-match -> ... is ... +#-----| match -> 0 -# 33| EnumElementPattern -#-----| match -> IsPattern +# 33| .error1 +#-----| no-match -> ... is ... -# 33| CaseLabelItem -#-----| -> EnumElementPattern +# 33| ... is ... +#-----| match -> 0 +#-----| no-match -> case ... -# 34| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 33| .error2 +#-----| no-match -> ... is ... -# 34| IntegerLiteralExpr -#-----| -> ReturnStmt +# 33| ... is ... +#-----| -> .error2 -# 35| CaseStmt -#-----| -> CaseLabelItem +# 34| return ... +#-----| return -> exit tryCatch (normal) -# 35| CaseLabelItem -#-----| -> EnumElementPattern +# 34| 0 +#-----| -> return ... -# 35| IsPattern -#-----| match -> DeclRefExpr -#-----| no-match -> CaseStmt -#-----| no-match -> IntegerLiteralExpr +# 35| case ... +#-----| -> ... is ... -# 35| EnumElementPattern -#-----| no-match -> IsPattern -#-----| match -> TuplePattern +# 35| ... is ... +#-----| match -> withParam +#-----| no-match -> case ... -# 35| TuplePattern -#-----| -> NamedPattern +# 35| ... is ... +#-----| -> .error3(...) -# 35| BindingPattern -#-----| match -> IsPattern +# 35| .error3(...) +#-----| no-match -> ... is ... +#-----| match -> (...) -# 35| NamedPattern -#-----| match -> BindingPattern +# 35| (...) +#-----| -> withParam -# 36| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 35| let ... +#-----| no-match -> ... is ... -# 36| DeclRefExpr -#-----| -> ReturnStmt +# 35| withParam +#-----| match -> let ... -# 37| CaseStmt -#-----| -> CaseLabelItem +# 36| return ... +#-----| return -> exit tryCatch (normal) -# 37| CaseLabelItem +# 36| withParam +#-----| -> return ... + +# 37| case ... +#-----| -> ... is ... + +# 37| ... is ... #-----| -> TBD (SimpleIdentTypeRepr) -# 37| IsPattern -#-----| match -> DeclRefExpr -#-----| no-match -> CaseStmt -#-----| no-match -> IntegerLiteralExpr +# 37| ... is ... +#-----| match -> print +#-----| no-match -> case ... # 37| TBD (SimpleIdentTypeRepr) -#-----| -> IsPattern +#-----| -> ... is ... -# 38| DeclRefExpr -#-----| -> StringLiteralExpr +# 38| print +#-----| -> MyError -# 38| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> IntegerLiteralExpr +# 38| call to print +#-----| exception -> exit tryCatch (normal) +#-----| -> 0 -# 38| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 38| default separator +#-----| -> default terminator -# 38| DefaultArgumentExpr -#-----| -> CallExpr +# 38| default terminator +#-----| -> call to print -# 38| ArrayExpr -#-----| -> VarargExpansionExpr +# 38| (Any) ... +#-----| -> [...] -# 38| ErasureExpr -#-----| -> ArrayExpr +# 38| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 38| StringLiteralExpr -#-----| -> ErasureExpr +# 38| MyError +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 38| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 38| [...] +#-----| -> default separator -# 39| CaseStmt -#-----| -> CaseLabelItem +# 38| [...] +#-----| -> [...] -# 39| BindingPattern -#-----| match -> DeclRefExpr -#-----| no-match -> IntegerLiteralExpr +# 39| case ... +#-----| -> let ... -# 39| CaseLabelItem -#-----| -> NamedPattern +# 39| error +#-----| match -> let ... -# 39| NamedPattern -#-----| match -> BindingPattern +# 39| let ... +#-----| match -> print +#-----| no-match -> 0 -# 40| DeclRefExpr -#-----| -> InterpolatedStringLiteralExpr +# 39| let ... +#-----| -> error -# 40| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> IntegerLiteralExpr +# 40| print +#-----| -> "..." -# 40| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 40| call to print +#-----| exception -> exit tryCatch (normal) +#-----| -> 0 -# 40| DefaultArgumentExpr -#-----| -> CallExpr +# 40| default separator +#-----| -> default terminator -# 40| ArrayExpr -#-----| -> VarargExpansionExpr +# 40| default terminator +#-----| -> call to print -# 40| ErasureExpr -#-----| -> ArrayExpr +# 40| "..." +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 40| InterpolatedStringLiteralExpr -#-----| -> ErasureExpr +# 40| (Any) ... +#-----| -> [...] -# 40| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 40| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 42| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 40| [...] +#-----| -> default separator -# 42| IntegerLiteralExpr -#-----| -> ReturnStmt +# 40| [...] +#-----| -> [...] -# 45| enter ConcreteFuncDecl -#-----| -> ClosureExpr +# 42| return ... +#-----| return -> exit tryCatch (normal) -# 45| exit ConcreteFuncDecl +# 42| 0 +#-----| -> return ... -# 45| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 45| enter createClosure1 +#-----| -> { ... } -# 46| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 45| exit createClosure1 -# 46| ClosureExpr -#-----| -> ReturnStmt +# 45| exit createClosure1 (normal) +#-----| -> exit createClosure1 -# 52| enter ConcreteFuncDecl -#-----| -> DeclRefExpr +# 46| return ... +#-----| return -> exit createClosure1 (normal) -# 52| exit ConcreteFuncDecl +# 46| { ... } +#-----| -> return ... -# 52| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 52| enter f +#-----| -> + -# 53| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 52| exit f -# 53| DeclRefExpr -#-----| -> DeclRefExpr +# 52| exit f (normal) +#-----| -> exit f -# 53| BinaryExpr -#-----| -> ReturnStmt +# 53| return ... +#-----| return -> exit f (normal) -# 53| DeclRefExpr -#-----| -> TypeExpr +# 53| x +#-----| -> y -# 53| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 53| ... call to + ... +#-----| -> return ... -# 53| TypeExpr -#-----| -> DotSyntaxCallExpr +# 53| + +#-----| -> Int.Type -# 53| DeclRefExpr -#-----| -> BinaryExpr +# 53| Int.Type +#-----| -> call to + -# 58| enter ConcreteFuncDecl -#-----| -> ClosureExpr +# 53| call to + +#-----| exception -> exit f (normal) +#-----| -> x -# 58| exit ConcreteFuncDecl +# 53| y +#-----| -> ... call to + ... -# 58| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 58| enter createClosure3 +#-----| -> { ... } -# 59| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 58| exit createClosure3 -# 59| ClosureExpr -#-----| -> ReturnStmt +# 58| exit createClosure3 (normal) +#-----| -> exit createClosure3 -# 64| enter ConcreteFuncDecl -#-----| -> NamedPattern +# 59| return ... +#-----| return -> exit createClosure3 (normal) -# 64| exit ConcreteFuncDecl +# 59| { ... } +#-----| -> return ... -# 64| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 64| enter callClosures +#-----| -> x1 -# 65| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 64| exit callClosures -# 65| ConcreteVarDecl -#-----| -> NamedPattern +# 64| exit callClosures (normal) +#-----| -> exit callClosures -# 65| NamedPattern -#-----| -> DeclRefExpr +# 65| var ... = ... +#-----| -> x1 -# 65| DeclRefExpr -#-----| -> StringLiteralExpr +# 65| x1 +#-----| -> createClosure1 -# 65| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 65| x1 +#-----| -> x2 -# 65| CallExpr -#-----| -> PatternBindingDecl +# 65| createClosure1 +#-----| -> -# 65| StringLiteralExpr -#-----| -> CallExpr +# 65| call to createClosure1 +#-----| exception -> exit callClosures (normal) +#-----| -> call to ... -# 66| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 65| call to ... +#-----| -> var ... = ... -# 66| ConcreteVarDecl -#-----| -> NamedPattern +# 65| +#-----| -> call to createClosure1 -# 66| NamedPattern -#-----| -> DeclRefExpr +# 66| var ... = ... +#-----| -> x2 -# 66| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 66| x2 +#-----| -> createClosure2 -# 66| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> IntegerLiteralExpr +# 66| x2 +#-----| -> x3 -# 66| CallExpr -#-----| -> PatternBindingDecl +# 66| createClosure2 +#-----| -> 0 -# 66| IntegerLiteralExpr -#-----| -> CallExpr +# 66| call to createClosure2 +#-----| exception -> exit callClosures (normal) +#-----| -> 10 -# 66| IntegerLiteralExpr -#-----| -> CallExpr +# 66| call to ... +#-----| -> var ... = ... -# 67| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 66| 0 +#-----| -> call to createClosure2 -# 67| ConcreteVarDecl -#-----| -> exit ConcreteFuncDecl (normal) +# 66| 10 +#-----| -> call to ... -# 67| NamedPattern -#-----| -> DeclRefExpr +# 67| var ... = ... +#-----| -> x3 -# 67| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 67| x3 +#-----| -> createClosure3 -# 67| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> IntegerLiteralExpr +# 67| x3 +#-----| -> exit callClosures (normal) -# 67| CallExpr -#-----| -> PatternBindingDecl +# 67| createClosure3 +#-----| -> 0 -# 67| IntegerLiteralExpr -#-----| -> CallExpr +# 67| call to createClosure3 +#-----| exception -> exit callClosures (normal) +#-----| -> 10 -# 67| IntegerLiteralExpr -#-----| -> CallExpr +# 67| call to ... +#-----| -> var ... = ... -# 70| enter ConcreteFuncDecl -#-----| -> NamedPattern +# 67| 0 +#-----| -> call to createClosure3 -# 70| exit ConcreteFuncDecl +# 67| 10 +#-----| -> call to ... -# 70| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 70| enter maybeParseInt +#-----| -> n -# 71| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 70| exit maybeParseInt -# 71| ConcreteVarDecl -#-----| -> DeclRefExpr +# 70| exit maybeParseInt (normal) +#-----| -> exit maybeParseInt -# 71| NamedPattern -#-----| -> TypedPattern +# 71| var ... = ... +#-----| -> n -# 71| TypedPattern -#-----| -> DeclRefExpr +# 71| n +#-----| -> ... as ... -# 71| ConstructorRefCallExpr -#-----| -> DeclRefExpr +# 71| n +#-----| -> n -# 71| DeclRefExpr -#-----| -> TypeExpr +# 71| ... as ... +#-----| -> deinit -# 71| TypeExpr -#-----| -> ConstructorRefCallExpr +# 71| Int.Type +#-----| -> call to ... -# 71| CallExpr -#-----| -> PatternBindingDecl +# 71| call to ... +#-----| -> s -# 71| DeclRefExpr -#-----| -> CallExpr +# 71| deinit +#-----| -> Int.Type -# 72| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 71| call to ... +#-----| -> var ... = ... -# 72| DeclRefExpr -#-----| -> LoadExpr +# 71| s +#-----| -> call to ... -# 72| LoadExpr -#-----| -> ReturnStmt +# 72| return ... +#-----| return -> exit maybeParseInt (normal) -# 75| enter ConcreteFuncDecl -#-----| -> NamedPattern +# 72| (Int?) ... +#-----| -> return ... -# 75| exit ConcreteFuncDecl +# 72| n +#-----| -> (Int?) ... -# 75| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 75| enter forceAndBackToOptional +#-----| -> nBang -# 76| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 75| exit forceAndBackToOptional -# 76| ConcreteVarDecl -#-----| -> NamedPattern +# 75| exit forceAndBackToOptional (normal) +#-----| -> exit forceAndBackToOptional -# 76| NamedPattern -#-----| -> DeclRefExpr +# 76| var ... = ... +#-----| -> nBang -# 76| DeclRefExpr -#-----| -> StringLiteralExpr +# 76| nBang +#-----| -> maybeParseInt -# 76| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> ForceValueExpr +# 76| nBang +#-----| -> n -# 76| ForceValueExpr -#-----| -> PatternBindingDecl +# 76| maybeParseInt +#-----| -> 42 -# 76| StringLiteralExpr -#-----| -> CallExpr +# 76| call to maybeParseInt +#-----| exception -> exit forceAndBackToOptional (normal) +#-----| -> ...! -# 77| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 76| ...! +#-----| -> var ... = ... -# 77| ConcreteVarDecl -#-----| -> DeclRefExpr +# 76| 42 +#-----| -> call to maybeParseInt -# 77| NamedPattern -#-----| -> DeclRefExpr +# 77| var ... = ... +#-----| -> n -# 77| DeclRefExpr -#-----| -> StringLiteralExpr +# 77| n +#-----| -> maybeParseInt -# 77| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> PatternBindingDecl +# 77| n +#-----| -> + -# 77| StringLiteralExpr -#-----| -> CallExpr +# 77| maybeParseInt +#-----| -> 42 -# 78| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 77| call to maybeParseInt +#-----| exception -> exit forceAndBackToOptional (normal) +#-----| -> var ... = ... -# 78| DeclRefExpr -#-----| -> LoadExpr +# 77| 42 +#-----| -> call to maybeParseInt -# 78| LoadExpr -#-----| -> DeclRefExpr +# 78| return ... +#-----| return -> exit forceAndBackToOptional (normal) -# 78| BinaryExpr -#-----| -> InjectIntoOptionalExpr +# 78| (Int) ... +#-----| -> n -# 78| InjectIntoOptionalExpr -#-----| -> ReturnStmt +# 78| nBang +#-----| -> (Int) ... -# 78| DeclRefExpr -#-----| -> TypeExpr +# 78| (Int?) ... +#-----| -> return ... -# 78| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 78| ... call to + ... +#-----| -> (Int?) ... -# 78| TypeExpr -#-----| -> DotSyntaxCallExpr +# 78| + +#-----| -> Int.Type -# 78| DeclRefExpr -#-----| -> LoadExpr +# 78| Int.Type +#-----| -> call to + -# 78| LoadExpr -#-----| -> ForceValueExpr +# 78| call to + +#-----| exception -> exit forceAndBackToOptional (normal) +#-----| -> nBang -# 78| ForceValueExpr -#-----| -> BinaryExpr +# 78| (Int?) ... +#-----| -> ...! -# 81| enter ConcreteFuncDecl -#-----| -> NamedPattern +# 78| n +#-----| -> (Int?) ... -# 82| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 78| ...! +#-----| -> ... call to + ... -# 82| ConcreteVarDecl +# 81| enter testInOut +#-----| -> temp -# 82| NamedPattern -#-----| -> IntegerLiteralExpr +# 82| var ... = ... +#-----| -> temp -# 82| IntegerLiteralExpr -#-----| -> PatternBindingDecl +# 82| temp +#-----| -> 10 -# 84| enter ConcreteFuncDecl -#-----| -> DeclRefExpr +# 82| temp -# 84| exit ConcreteFuncDecl +# 82| 10 +#-----| -> var ... = ... -# 84| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 84| enter add +#-----| -> a -# 85| DeclRefExpr -#-----| -> DeclRefExpr +# 84| exit add -# 85| AssignExpr -#-----| -> exit ConcreteFuncDecl (normal) +# 84| exit add (normal) +#-----| -> exit add -# 85| DeclRefExpr -#-----| -> LoadExpr +# 85| a +#-----| -> + -# 85| LoadExpr -#-----| -> IntegerLiteralExpr +# 85| ... = ... +#-----| -> exit add (normal) -# 85| BinaryExpr -#-----| -> AssignExpr +# 85| (Int) ... +#-----| -> 1 -# 85| DeclRefExpr -#-----| -> TypeExpr +# 85| a +#-----| -> (Int) ... -# 85| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 85| ... call to + ... +#-----| -> ... = ... -# 85| TypeExpr -#-----| -> DotSyntaxCallExpr +# 85| + +#-----| -> Int.Type -# 85| IntegerLiteralExpr -#-----| -> BinaryExpr +# 85| Int.Type +#-----| -> call to + -# 88| enter ConcreteFuncDecl -#-----| -> DeclRefExpr +# 85| call to + +#-----| exception -> exit add (normal) +#-----| -> a -# 88| exit ConcreteFuncDecl +# 85| 1 +#-----| -> ... call to + ... -# 88| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 88| enter addOptional +#-----| -> a -# 89| DeclRefExpr -#-----| -> NilLiteralExpr +# 88| exit addOptional -# 89| AssignExpr -#-----| -> exit ConcreteFuncDecl (normal) +# 88| exit addOptional (normal) +#-----| -> exit addOptional -# 89| NilLiteralExpr -#-----| -> AssignExpr +# 89| a +#-----| -> nil -# 99| enter AccessorDecl +# 89| ... = ... +#-----| -> exit addOptional (normal) -# 99| exit AccessorDecl +# 89| nil +#-----| -> ... = ... -# 99| exit AccessorDecl (normal) -#-----| -> exit AccessorDecl +# 99| enter get -# 100| enter ConstructorDecl -#-----| -> DeclRefExpr +# 99| exit get -# 100| exit ConstructorDecl +# 99| exit get (normal) +#-----| -> exit get -# 100| exit ConstructorDecl (normal) -#-----| -> exit ConstructorDecl +# 100| enter deinit +#-----| -> self -# 101| DeclRefExpr -#-----| -> MemberRefExpr +# 100| exit deinit -# 101| MemberRefExpr -#-----| -> DeclRefExpr +# 100| exit deinit (normal) +#-----| -> exit deinit -# 101| AssignExpr -#-----| -> ReturnStmt +# 101| .myInt +#-----| -> n -# 101| DeclRefExpr -#-----| -> AssignExpr +# 101| self +#-----| -> .myInt -# 102| ReturnStmt -#-----| return -> exit ConstructorDecl (normal) +# 101| ... = ... +#-----| -> return -# 104| enter ConcreteFuncDecl -#-----| -> DeclRefExpr +# 101| n +#-----| -> ... = ... -# 104| exit ConcreteFuncDecl +# 102| return +#-----| return -> exit deinit (normal) -# 104| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 104| enter getMyInt +#-----| -> self -# 105| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 104| exit getMyInt -# 105| DeclRefExpr -#-----| -> MemberRefExpr +# 104| exit getMyInt (normal) +#-----| -> exit getMyInt -# 105| MemberRefExpr -#-----| -> ReturnStmt +# 105| return ... +#-----| return -> exit getMyInt (normal) -# 109| enter ConcreteFuncDecl -#-----| -> NamedPattern +# 105| getter for .myInt +#-----| -> return ... -# 109| exit ConcreteFuncDecl +# 105| self +#-----| -> getter for .myInt -# 109| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 109| enter testMemberRef +#-----| -> c -# 110| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 109| exit testMemberRef -# 110| ConcreteVarDecl -#-----| -> NamedPattern +# 109| exit testMemberRef (normal) +#-----| -> exit testMemberRef -# 110| NamedPattern -#-----| -> DeclRefExpr +# 110| var ... = ... +#-----| -> c -# 110| ConstructorRefCallExpr -#-----| -> IntegerLiteralExpr +# 110| c +#-----| -> deinit -# 110| DeclRefExpr -#-----| -> TypeExpr +# 110| c +#-----| -> n1 -# 110| TypeExpr -#-----| -> ConstructorRefCallExpr +# 110| C.Type +#-----| -> call to ... -# 110| CallExpr -#-----| -> PatternBindingDecl +# 110| call to ... +#-----| -> 42 -# 110| IntegerLiteralExpr -#-----| -> CallExpr +# 110| deinit +#-----| -> C.Type -# 111| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 110| call to ... +#-----| -> var ... = ... -# 111| ConcreteVarDecl -#-----| -> NamedPattern +# 110| 42 +#-----| -> call to ... -# 111| NamedPattern -#-----| -> DeclRefExpr +# 111| var ... = ... +#-----| -> n1 -# 111| DeclRefExpr -#-----| -> MemberRefExpr +# 111| n1 +#-----| -> c -# 111| MemberRefExpr -#-----| -> PatternBindingDecl +# 111| n1 +#-----| -> n2 -# 112| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 111| c +#-----| -> getter for .myInt -# 112| ConcreteVarDecl -#-----| -> NamedPattern +# 111| getter for .myInt +#-----| -> var ... = ... -# 112| NamedPattern +# 112| var ... = ... +#-----| -> n2 + +# 112| n2 +#-----| -> .self #-----| -> TBD (DotSelfExpr) +# 112| n2 +#-----| -> n3 + +# 112| .self +#-----| -> getter for .myInt + # 112| TBD (DotSelfExpr) -#-----| -> MemberRefExpr +#-----| -> getter for .myInt -# 112| MemberRefExpr -#-----| -> PatternBindingDecl +# 112| getter for .myInt +#-----| -> var ... = ... -# 113| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 113| var ... = ... +#-----| -> n3 -# 113| ConcreteVarDecl -#-----| -> NamedPattern +# 113| n3 +#-----| -> getMyInt -# 113| NamedPattern -#-----| -> DeclRefExpr +# 113| n3 +#-----| -> n4 -# 113| DeclRefExpr -#-----| -> DotSyntaxCallExpr +# 113| c +#-----| -> call to getMyInt -# 113| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 113| call to getMyInt +#-----| exception -> exit testMemberRef (normal) +#-----| -> call to ... -# 113| CallExpr -#-----| -> PatternBindingDecl +# 113| call to ... +#-----| -> var ... = ... -# 113| DeclRefExpr -#-----| -> DeclRefExpr +# 113| getMyInt +#-----| -> c -# 114| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 114| var ... = ... +#-----| -> n4 -# 114| ConcreteVarDecl -#-----| -> NamedPattern +# 114| n4 +#-----| -> getMyInt -# 114| NamedPattern -#-----| -> DeclRefExpr +# 114| n4 +#-----| -> n5 + +# 114| .self +#-----| -> call to getMyInt # 114| TBD (DotSelfExpr) -#-----| -> DotSyntaxCallExpr +#-----| -> call to getMyInt -# 114| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 114| call to getMyInt +#-----| exception -> exit testMemberRef (normal) +#-----| -> call to ... -# 114| CallExpr -#-----| -> PatternBindingDecl +# 114| call to ... +#-----| -> var ... = ... -# 114| DeclRefExpr +# 114| getMyInt +#-----| -> .self #-----| -> TBD (DotSelfExpr) -# 116| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 116| var ... = ... +#-----| -> n5 -# 116| ConcreteVarDecl -#-----| -> NamedPattern +# 116| n5 +#-----| -> param -# 116| NamedPattern -#-----| -> DeclRefExpr +# 116| n5 +#-----| -> n6 -# 116| DeclRefExpr -#-----| -> MemberRefExpr +# 116| param +#-----| -> getter for .myInt -# 116| MemberRefExpr -#-----| -> PatternBindingDecl +# 116| getter for .myInt +#-----| -> var ... = ... -# 117| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 117| var ... = ... +#-----| -> n6 -# 117| ConcreteVarDecl -#-----| -> NamedPattern - -# 117| NamedPattern +# 117| n6 +#-----| -> .self #-----| -> TBD (DotSelfExpr) +# 117| n6 +#-----| -> n7 + +# 117| .self +#-----| -> getter for .myInt + # 117| TBD (DotSelfExpr) -#-----| -> MemberRefExpr +#-----| -> getter for .myInt -# 117| MemberRefExpr -#-----| -> PatternBindingDecl +# 117| getter for .myInt +#-----| -> var ... = ... -# 118| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 118| var ... = ... +#-----| -> n7 -# 118| ConcreteVarDecl -#-----| -> NamedPattern +# 118| n7 +#-----| -> getMyInt -# 118| NamedPattern -#-----| -> DeclRefExpr +# 118| n7 +#-----| -> n8 -# 118| DeclRefExpr -#-----| -> DotSyntaxCallExpr +# 118| param +#-----| -> call to getMyInt -# 118| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 118| call to getMyInt +#-----| exception -> exit testMemberRef (normal) +#-----| -> call to ... -# 118| CallExpr -#-----| -> PatternBindingDecl +# 118| call to ... +#-----| -> var ... = ... -# 118| DeclRefExpr -#-----| -> DeclRefExpr +# 118| getMyInt +#-----| -> param -# 119| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 119| var ... = ... +#-----| -> n8 -# 119| ConcreteVarDecl -#-----| -> NamedPattern +# 119| n8 +#-----| -> getMyInt -# 119| NamedPattern -#-----| -> DeclRefExpr +# 119| n8 +#-----| -> n9 + +# 119| .self +#-----| -> call to getMyInt # 119| TBD (DotSelfExpr) -#-----| -> DotSyntaxCallExpr +#-----| -> call to getMyInt -# 119| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 119| call to getMyInt +#-----| exception -> exit testMemberRef (normal) +#-----| -> call to ... -# 119| CallExpr -#-----| -> PatternBindingDecl +# 119| call to ... +#-----| -> var ... = ... -# 119| DeclRefExpr +# 119| getMyInt +#-----| -> .self #-----| -> TBD (DotSelfExpr) -# 121| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 121| var ... = ... +#-----| -> n9 -# 121| ConcreteVarDecl -#-----| -> NamedPattern +# 121| n9 +#-----| -> inoutParam -# 121| NamedPattern -#-----| -> DeclRefExpr +# 121| n9 +#-----| -> n10 -# 121| DeclRefExpr -#-----| -> LoadExpr +# 121| (C) ... +#-----| -> getter for .myInt -# 121| LoadExpr -#-----| -> MemberRefExpr +# 121| inoutParam +#-----| -> (C) ... -# 121| MemberRefExpr -#-----| -> PatternBindingDecl +# 121| getter for .myInt +#-----| -> var ... = ... -# 122| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 122| var ... = ... +#-----| -> n10 -# 122| ConcreteVarDecl -#-----| -> NamedPattern - -# 122| NamedPattern +# 122| n10 +#-----| -> .self #-----| -> TBD (DotSelfExpr) -# 122| LoadExpr -#-----| -> MemberRefExpr +# 122| n10 +#-----| -> n11 + +# 122| (C) ... +#-----| -> getter for .myInt + +# 122| .self +#-----| -> (C) ... # 122| TBD (DotSelfExpr) -#-----| -> LoadExpr +#-----| -> (C) ... -# 122| MemberRefExpr -#-----| -> PatternBindingDecl +# 122| getter for .myInt +#-----| -> var ... = ... -# 123| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 123| var ... = ... +#-----| -> n11 -# 123| ConcreteVarDecl -#-----| -> NamedPattern +# 123| n11 +#-----| -> getMyInt -# 123| NamedPattern -#-----| -> DeclRefExpr +# 123| n11 +#-----| -> n12 -# 123| DeclRefExpr -#-----| -> LoadExpr +# 123| (C) ... +#-----| -> call to getMyInt -# 123| LoadExpr -#-----| -> DotSyntaxCallExpr +# 123| inoutParam +#-----| -> (C) ... -# 123| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 123| call to getMyInt +#-----| exception -> exit testMemberRef (normal) +#-----| -> call to ... -# 123| CallExpr -#-----| -> PatternBindingDecl +# 123| call to ... +#-----| -> var ... = ... -# 123| DeclRefExpr -#-----| -> DeclRefExpr +# 123| getMyInt +#-----| -> inoutParam -# 124| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 124| var ... = ... +#-----| -> n12 -# 124| ConcreteVarDecl -#-----| -> NamedPattern +# 124| n12 +#-----| -> getMyInt -# 124| NamedPattern -#-----| -> DeclRefExpr +# 124| n12 +#-----| -> n13 -# 124| LoadExpr -#-----| -> DotSyntaxCallExpr +# 124| (C) ... +#-----| -> call to getMyInt + +# 124| .self +#-----| -> (C) ... # 124| TBD (DotSelfExpr) -#-----| -> LoadExpr +#-----| -> (C) ... -# 124| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 124| call to getMyInt +#-----| exception -> exit testMemberRef (normal) +#-----| -> call to ... -# 124| CallExpr -#-----| -> PatternBindingDecl +# 124| call to ... +#-----| -> var ... = ... -# 124| DeclRefExpr +# 124| getMyInt +#-----| -> .self #-----| -> TBD (DotSelfExpr) -# 126| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 126| var ... = ... +#-----| -> n13 -# 126| ConcreteVarDecl -#-----| -> NamedPattern +# 126| n13 +#-----| -> opt -# 126| NamedPattern -#-----| -> DeclRefExpr +# 126| n13 +#-----| -> n14 -# 126| DeclRefExpr -#-----| -> ForceValueExpr +# 126| opt +#-----| -> ...! -# 126| ForceValueExpr -#-----| -> MemberRefExpr +# 126| ...! +#-----| -> getter for .myInt -# 126| MemberRefExpr -#-----| -> PatternBindingDecl +# 126| getter for .myInt +#-----| -> var ... = ... -# 127| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 127| var ... = ... +#-----| -> n14 -# 127| ConcreteVarDecl -#-----| -> NamedPattern - -# 127| NamedPattern +# 127| n14 +#-----| -> .self #-----| -> TBD (DotSelfExpr) +# 127| n14 +#-----| -> n15 + +# 127| .self +#-----| -> getter for .myInt + # 127| TBD (DotSelfExpr) -#-----| -> MemberRefExpr +#-----| -> getter for .myInt -# 127| MemberRefExpr -#-----| -> PatternBindingDecl +# 127| getter for .myInt +#-----| -> var ... = ... -# 128| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 128| var ... = ... +#-----| -> n15 -# 128| ConcreteVarDecl -#-----| -> NamedPattern +# 128| n15 +#-----| -> getMyInt -# 128| NamedPattern -#-----| -> DeclRefExpr +# 128| n15 +#-----| -> n16 -# 128| DeclRefExpr -#-----| -> ForceValueExpr +# 128| opt +#-----| -> ...! -# 128| ForceValueExpr -#-----| -> DotSyntaxCallExpr +# 128| ...! +#-----| -> call to getMyInt -# 128| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 128| call to getMyInt +#-----| exception -> exit testMemberRef (normal) +#-----| -> call to ... -# 128| CallExpr -#-----| -> PatternBindingDecl +# 128| call to ... +#-----| -> var ... = ... -# 128| DeclRefExpr -#-----| -> DeclRefExpr +# 128| getMyInt +#-----| -> opt -# 129| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 129| var ... = ... +#-----| -> n16 -# 129| ConcreteVarDecl -#-----| -> NamedPattern +# 129| n16 +#-----| -> getMyInt -# 129| NamedPattern -#-----| -> DeclRefExpr +# 129| n16 +#-----| -> n17 + +# 129| .self +#-----| -> call to getMyInt # 129| TBD (DotSelfExpr) -#-----| -> DotSyntaxCallExpr +#-----| -> call to getMyInt -# 129| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 129| call to getMyInt +#-----| exception -> exit testMemberRef (normal) +#-----| -> call to ... -# 129| CallExpr -#-----| -> PatternBindingDecl +# 129| call to ... +#-----| -> var ... = ... -# 129| DeclRefExpr +# 129| getMyInt +#-----| -> .self #-----| -> TBD (DotSelfExpr) -# 131| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 131| var ... = ... +#-----| -> n17 -# 131| ConcreteVarDecl -#-----| -> NamedPattern +# 131| n17 +#-----| -> opt -# 131| NamedPattern -#-----| -> DeclRefExpr +# 131| n17 +#-----| -> n18 -# 131| DeclRefExpr -#-----| -> BindOptionalExpr +# 131| opt +#-----| -> ...? -# 131| BindOptionalExpr -#-----| -> MemberRefExpr +# 131| ...? +#-----| -> getter for .myInt -# 131| InjectIntoOptionalExpr +# 131| (Int?) ... #-----| -> OptionalEvaluationExpr -# 131| MemberRefExpr -#-----| -> InjectIntoOptionalExpr - # 131| OptionalEvaluationExpr -#-----| -> PatternBindingDecl +#-----| -> var ... = ... -# 132| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 131| getter for .myInt +#-----| -> (Int?) ... -# 132| ConcreteVarDecl -#-----| -> NamedPattern +# 132| var ... = ... +#-----| -> n18 -# 132| NamedPattern +# 132| n18 +#-----| -> .self #-----| -> TBD (DotSelfExpr) -# 132| TBD (DotSelfExpr) -#-----| -> MemberRefExpr +# 132| n18 +#-----| -> n19 -# 132| InjectIntoOptionalExpr +# 132| .self +#-----| -> getter for .myInt + +# 132| TBD (DotSelfExpr) +#-----| -> getter for .myInt + +# 132| (Int?) ... #-----| -> OptionalEvaluationExpr -# 132| MemberRefExpr -#-----| -> InjectIntoOptionalExpr - # 132| OptionalEvaluationExpr -#-----| -> PatternBindingDecl +#-----| -> var ... = ... -# 133| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 132| getter for .myInt +#-----| -> (Int?) ... -# 133| ConcreteVarDecl -#-----| -> NamedPattern +# 133| var ... = ... +#-----| -> n19 -# 133| NamedPattern -#-----| -> DeclRefExpr +# 133| n19 +#-----| -> getMyInt -# 133| DeclRefExpr -#-----| -> BindOptionalExpr +# 133| n19 +#-----| -> n20 -# 133| BindOptionalExpr -#-----| -> DotSyntaxCallExpr +# 133| opt +#-----| -> ...? -# 133| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 133| ...? +#-----| -> call to getMyInt -# 133| CallExpr -#-----| -> InjectIntoOptionalExpr +# 133| call to getMyInt +#-----| exception -> exit testMemberRef (normal) +#-----| -> call to ... -# 133| InjectIntoOptionalExpr +# 133| (Int?) ... #-----| -> OptionalEvaluationExpr # 133| OptionalEvaluationExpr -#-----| -> PatternBindingDecl +#-----| -> var ... = ... -# 133| DeclRefExpr -#-----| -> DeclRefExpr +# 133| call to ... +#-----| -> (Int?) ... -# 134| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 133| getMyInt +#-----| -> opt -# 134| ConcreteVarDecl -#-----| -> exit ConcreteFuncDecl (normal) +# 134| var ... = ... +#-----| -> n20 -# 134| NamedPattern -#-----| -> DeclRefExpr +# 134| n20 +#-----| -> getMyInt + +# 134| n20 +#-----| -> exit testMemberRef (normal) + +# 134| .self +#-----| -> call to getMyInt # 134| TBD (DotSelfExpr) -#-----| -> DotSyntaxCallExpr +#-----| -> call to getMyInt -# 134| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 134| call to getMyInt +#-----| exception -> exit testMemberRef (normal) +#-----| -> call to ... -# 134| CallExpr -#-----| -> InjectIntoOptionalExpr - -# 134| InjectIntoOptionalExpr +# 134| (Int?) ... #-----| -> OptionalEvaluationExpr # 134| OptionalEvaluationExpr -#-----| -> PatternBindingDecl +#-----| -> var ... = ... -# 134| DeclRefExpr +# 134| call to ... +#-----| -> (Int?) ... + +# 134| getMyInt +#-----| -> .self #-----| -> TBD (DotSelfExpr) -# 137| enter ConcreteFuncDecl -#-----| -> DeclRefExpr +# 137| enter patterns +#-----| -> ... -# 137| exit ConcreteFuncDecl +# 137| exit patterns -# 137| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 137| exit patterns (normal) +#-----| -> exit patterns -# 138| ForEachStmt -#-----| non-empty -> AnyPattern -#-----| empty -> SwitchStmt +# 138| for ... in ... { ... } +#-----| non-empty -> _ +#-----| empty -> switch x { ... } -# 138| AnyPattern -#-----| -> BraceStmt +# 138| _ +#-----| -> { ... } -# 138| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 138| 0 +#-----| -> 10 -# 138| BinaryExpr -#-----| -> ForEachStmt +# 138| ... call to ... ... +#-----| -> for ... in ... { ... } -# 138| DeclRefExpr -#-----| -> TypeExpr +# 138| ... +#-----| -> Int.Type -# 138| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> IntegerLiteralExpr +# 138| Int.Type +#-----| -> call to ... -# 138| TypeExpr -#-----| -> DotSyntaxCallExpr +# 138| call to ... +#-----| exception -> exit patterns (normal) +#-----| -> 0 -# 138| IntegerLiteralExpr -#-----| -> BinaryExpr +# 138| 10 +#-----| -> ... call to ... ... -# 138| BraceStmt -#-----| -> ForEachStmt +# 138| { ... } +#-----| -> for ... in ... { ... } -# 140| SwitchStmt -#-----| -> DeclRefExpr +# 140| switch x { ... } +#-----| -> x -# 140| DeclRefExpr -#-----| -> CaseStmt +# 140| x +#-----| -> case ... -# 141| CaseStmt -#-----| -> CaseLabelItem +# 141| case ... +#-----| -> 0 -# 141| CaseLabelItem -#-----| -> IntegerLiteralExpr +# 141| 0 +#-----| -> 0 -# 141| ExprPattern -#-----| no-match -> CaseLabelItem -#-----| match -> BooleanLiteralExpr +# 141| 0 +#-----| no-match -> 1 +#-----| match -> true -# 141| IntegerLiteralExpr -#-----| -> ExprPattern +# 141| 0 +#-----| -> 0 -# 141| CaseLabelItem -#-----| -> IntegerLiteralExpr +# 141| 1 +#-----| -> 1 -# 141| ExprPattern -#-----| match -> BooleanLiteralExpr -#-----| no-match -> CaseStmt +# 141| 1 +#-----| match -> true +#-----| no-match -> case ... -# 141| IntegerLiteralExpr -#-----| -> ExprPattern +# 141| 1 +#-----| -> 1 -# 142| ReturnStmt +# 142| return ... -# 142| BooleanLiteralExpr -#-----| -> ReturnStmt +# 142| true +#-----| -> return ... -# 144| CaseStmt -#-----| -> CaseLabelItem +# 144| case ... +#-----| -> x -# 144| DeclRefExpr -#-----| -> ExprPattern +# 144| x +#-----| match -> true +#-----| no-match -> case ... -# 144| ExprPattern -#-----| match -> BooleanLiteralExpr -#-----| no-match -> CaseStmt +# 144| x +#-----| -> x -# 144| CaseLabelItem -#-----| -> DeclRefExpr +# 144| x +#-----| -> x -# 145| ReturnStmt +# 145| return ... -# 145| BooleanLiteralExpr -#-----| -> ReturnStmt +# 145| true +#-----| -> return ... -# 146| AnyPattern -#-----| match -> BooleanLiteralExpr +# 146| _ +#-----| -> _ -# 146| CaseLabelItem -#-----| -> AnyPattern +# 146| _ +#-----| match -> false -# 146| CaseStmt -#-----| -> CaseLabelItem +# 146| case ... +#-----| -> _ -# 147| ReturnStmt +# 147| return ... -# 147| BooleanLiteralExpr -#-----| -> ReturnStmt +# 147| false +#-----| -> return ... -# 163| enter ConcreteFuncDecl -#-----| -> DeferStmt +# 163| enter testDefer +#-----| -> defer { ... } -# 163| exit ConcreteFuncDecl +# 163| exit testDefer -# 163| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 163| exit testDefer (normal) +#-----| -> exit testDefer -# 165| DeferStmt -#-----| -> DeferStmt +# 165| defer { ... } +#-----| -> defer { ... } -# 166| DeclRefExpr -#-----| -> StringLiteralExpr +# 166| print +#-----| -> 4 -# 166| CallExpr -#-----| -> exit ConcreteFuncDecl (normal) +# 166| call to print +#-----| -> exit testDefer (normal) -# 166| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 166| default separator +#-----| -> default terminator -# 166| DefaultArgumentExpr -#-----| -> CallExpr +# 166| default terminator +#-----| -> call to print -# 166| ArrayExpr -#-----| -> VarargExpansionExpr +# 166| (Any) ... +#-----| -> [...] -# 166| ErasureExpr -#-----| -> ArrayExpr +# 166| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 166| StringLiteralExpr -#-----| -> ErasureExpr +# 166| 4 +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 166| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 166| [...] +#-----| -> default separator -# 169| DeferStmt -#-----| -> DeferStmt +# 166| [...] +#-----| -> [...] -# 170| DeclRefExpr -#-----| -> StringLiteralExpr +# 169| defer { ... } +#-----| -> defer { ... } -# 170| CallExpr -#-----| -> DeclRefExpr +# 170| print +#-----| -> 3 -# 170| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 170| call to print +#-----| -> print -# 170| DefaultArgumentExpr -#-----| -> CallExpr +# 170| default separator +#-----| -> default terminator -# 170| ArrayExpr -#-----| -> VarargExpansionExpr +# 170| default terminator +#-----| -> call to print -# 170| ErasureExpr -#-----| -> ArrayExpr +# 170| (Any) ... +#-----| -> [...] -# 170| StringLiteralExpr -#-----| -> ErasureExpr +# 170| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 170| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 170| 3 +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 173| DeferStmt -#-----| -> DeclRefExpr +# 170| [...] +#-----| -> default separator -# 174| DeclRefExpr -#-----| -> StringLiteralExpr +# 170| [...] +#-----| -> [...] -# 174| CallExpr -#-----| -> DeferStmt +# 173| defer { ... } +#-----| -> print -# 174| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 174| print +#-----| -> 1 -# 174| DefaultArgumentExpr -#-----| -> CallExpr +# 174| call to print +#-----| -> defer { ... } -# 174| ArrayExpr -#-----| -> VarargExpansionExpr +# 174| default separator +#-----| -> default terminator -# 174| ErasureExpr -#-----| -> ArrayExpr +# 174| default terminator +#-----| -> call to print -# 174| StringLiteralExpr -#-----| -> ErasureExpr +# 174| (Any) ... +#-----| -> [...] -# 174| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 174| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 175| DeferStmt -#-----| -> DeclRefExpr +# 174| 1 +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 176| DeclRefExpr -#-----| -> StringLiteralExpr +# 174| [...] +#-----| -> default separator -# 176| CallExpr -#-----| -> DeclRefExpr +# 174| [...] +#-----| -> [...] -# 176| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 175| defer { ... } +#-----| -> print -# 176| DefaultArgumentExpr -#-----| -> CallExpr +# 176| print +#-----| -> 2 -# 176| ArrayExpr -#-----| -> VarargExpansionExpr +# 176| call to print +#-----| -> print -# 176| ErasureExpr -#-----| -> ArrayExpr +# 176| default separator +#-----| -> default terminator -# 176| StringLiteralExpr -#-----| -> ErasureExpr +# 176| default terminator +#-----| -> call to print -# 176| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 176| (Any) ... +#-----| -> [...] -# 181| enter ConcreteFuncDecl -#-----| -> IfStmt +# 176| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 181| exit ConcreteFuncDecl +# 176| 2 +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 181| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 176| [...] +#-----| -> default separator -# 182| IfStmt -#-----| -> DeclRefExpr +# 176| [...] +#-----| -> [...] -# 182| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 181| enter m1 +#-----| -> if ... then { ... } else { ... } -# 182| BinaryExpr +# 181| exit m1 + +# 181| exit m1 (normal) +#-----| -> exit m1 + +# 182| if ... then { ... } else { ... } +#-----| -> > + +# 182| x +#-----| -> 2 + +# 182| ... call to > ... #-----| -> StmtCondition # 182| StmtCondition -#-----| true -> DeclRefExpr -#-----| false -> IfStmt +#-----| true -> print +#-----| false -> if ... then { ... } else { ... } -# 182| DeclRefExpr -#-----| -> TypeExpr +# 182| > +#-----| -> Int.Type -# 182| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 182| Int.Type +#-----| -> call to > -# 182| TypeExpr -#-----| -> DotSyntaxCallExpr +# 182| call to > +#-----| exception -> exit m1 (normal) +#-----| -> x -# 182| IntegerLiteralExpr -#-----| -> BinaryExpr +# 182| 2 +#-----| -> ... call to > ... -# 183| DeclRefExpr -#-----| -> StringLiteralExpr +# 183| print +#-----| -> x is greater than 2 -# 183| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) +# 183| call to print +#-----| exception -> exit m1 (normal) -# 183| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 183| default separator +#-----| -> default terminator -# 183| DefaultArgumentExpr -#-----| -> CallExpr +# 183| default terminator +#-----| -> call to print -# 183| ArrayExpr -#-----| -> VarargExpansionExpr +# 183| (Any) ... +#-----| -> [...] -# 183| ErasureExpr -#-----| -> ArrayExpr +# 183| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 183| StringLiteralExpr -#-----| -> ErasureExpr +# 183| [...] +#-----| -> default separator -# 183| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 183| [...] +#-----| -> [...] -# 185| IfStmt -#-----| -> DeclRefExpr +# 183| x is greater than 2 +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 185| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 185| if ... then { ... } else { ... } +#-----| -> <= -# 185| BinaryExpr -#-----| false -> [false] BinaryExpr -#-----| true -> AutoClosureExpr +# 185| x +#-----| -> 2 -# 185| BinaryExpr -#-----| false -> BinaryExpr -#-----| true -> AutoClosureExpr +# 185| ... call to <= ... +#-----| false -> [false] ... call to && ... +#-----| true -> { ... } -# 185| [false] BinaryExpr -#-----| false -> BinaryExpr +# 185| ... call to && ... +#-----| false -> ... call to && ... +#-----| true -> { ... } -# 185| BinaryExpr +# 185| [false] ... call to && ... +#-----| false -> ... call to && ... + +# 185| ... call to && ... #-----| -> StmtCondition # 185| StmtCondition -#-----| true -> DeclRefExpr -#-----| false -> DeclRefExpr +#-----| true -> print +#-----| false -> print -# 185| DeclRefExpr -#-----| -> TypeExpr +# 185| <= +#-----| -> Int.Type -# 185| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 185| Int.Type +#-----| -> call to <= -# 185| TypeExpr -#-----| -> DotSyntaxCallExpr +# 185| call to <= +#-----| exception -> exit m1 (normal) +#-----| -> x -# 185| IntegerLiteralExpr -#-----| -> BinaryExpr +# 185| 2 +#-----| -> ... call to <= ... -# 185| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 185| x +#-----| -> 0 -# 185| AutoClosureExpr -#-----| -> DeclRefExpr +# 185| ... call to > ... +#-----| -> return ... -# 185| BinaryExpr -#-----| -> ReturnStmt +# 185| return ... +#-----| -> ... call to && ... -# 185| ReturnStmt -#-----| -> BinaryExpr +# 185| { ... } +#-----| -> > -# 185| DeclRefExpr -#-----| -> TypeExpr +# 185| > +#-----| -> Int.Type -# 185| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 185| Int.Type +#-----| -> call to > -# 185| TypeExpr -#-----| -> DotSyntaxCallExpr +# 185| call to > +#-----| exception -> exit m1 (normal) +#-----| -> x -# 185| IntegerLiteralExpr -#-----| -> BinaryExpr +# 185| 0 +#-----| -> ... call to > ... -# 185| AutoClosureExpr -#-----| -> DeclRefExpr +# 185| call to ... +#-----| -> return ... -# 185| PrefixUnaryExpr -#-----| -> ReturnStmt +# 185| return ... +#-----| -> ... call to && ... -# 185| ReturnStmt -#-----| -> BinaryExpr +# 185| { ... } +#-----| -> == -# 185| ParenExpr -#-----| -> PrefixUnaryExpr +# 185| (...) +#-----| -> call to ... -# 185| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 185| x +#-----| -> 5 -# 185| BinaryExpr -#-----| -> ParenExpr +# 185| ... call to == ... +#-----| -> (...) -# 185| DeclRefExpr -#-----| -> TypeExpr +# 185| == +#-----| -> Int.Type -# 185| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 185| Int.Type +#-----| -> call to == -# 185| TypeExpr -#-----| -> DotSyntaxCallExpr +# 185| call to == +#-----| exception -> exit m1 (normal) +#-----| -> x -# 185| IntegerLiteralExpr -#-----| -> BinaryExpr +# 185| 5 +#-----| -> ... call to == ... -# 186| DeclRefExpr -#-----| -> StringLiteralExpr +# 186| print +#-----| -> x is 1 -# 186| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) +# 186| call to print +#-----| exception -> exit m1 (normal) -# 186| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 186| default separator +#-----| -> default terminator -# 186| DefaultArgumentExpr -#-----| -> CallExpr +# 186| default terminator +#-----| -> call to print -# 186| ArrayExpr -#-----| -> VarargExpansionExpr +# 186| (Any) ... +#-----| -> [...] -# 186| ErasureExpr -#-----| -> ArrayExpr +# 186| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 186| StringLiteralExpr -#-----| -> ErasureExpr +# 186| [...] +#-----| -> default separator -# 186| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 186| [...] +#-----| -> [...] -# 189| DeclRefExpr -#-----| -> StringLiteralExpr +# 186| x is 1 +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 189| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) +# 189| print +#-----| -> I can't guess the number -# 189| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 189| call to print +#-----| exception -> exit m1 (normal) -# 189| DefaultArgumentExpr -#-----| -> CallExpr +# 189| default separator +#-----| -> default terminator -# 189| ArrayExpr -#-----| -> VarargExpansionExpr +# 189| default terminator +#-----| -> call to print -# 189| ErasureExpr -#-----| -> ArrayExpr +# 189| (Any) ... +#-----| -> [...] -# 189| StringLiteralExpr -#-----| -> ErasureExpr +# 189| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 189| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 189| I can't guess the number +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 193| enter ConcreteFuncDecl -#-----| -> IfStmt +# 189| [...] +#-----| -> default separator -# 193| exit ConcreteFuncDecl +# 189| [...] +#-----| -> [...] -# 193| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 193| enter m2 +#-----| -> if ... then { ... } -# 194| IfStmt -#-----| -> DeclRefExpr +# 193| exit m2 -# 194| DeclRefExpr -#-----| -> StmtCondition +# 193| exit m2 (normal) +#-----| -> exit m2 + +# 194| if ... then { ... } +#-----| -> b # 194| StmtCondition -#-----| true -> IntegerLiteralExpr -#-----| false -> IntegerLiteralExpr +#-----| true -> 0 +#-----| false -> 1 -# 195| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 194| b +#-----| -> StmtCondition -# 195| IntegerLiteralExpr -#-----| -> ReturnStmt +# 195| return ... +#-----| return -> exit m2 (normal) -# 197| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 195| 0 +#-----| -> return ... -# 197| IntegerLiteralExpr -#-----| -> ReturnStmt +# 197| return ... +#-----| return -> exit m2 (normal) -# 200| enter ConcreteFuncDecl -#-----| -> IfStmt +# 197| 1 +#-----| -> return ... -# 200| exit ConcreteFuncDecl +# 200| enter m3 +#-----| -> if ... then { ... } -# 200| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 200| exit m3 -# 201| IfStmt -#-----| -> DeclRefExpr +# 200| exit m3 (normal) +#-----| -> exit m3 -# 201| DeclRefExpr -#-----| -> LoadExpr +# 201| if ... then { ... } +#-----| -> < -# 201| LoadExpr -#-----| -> IntegerLiteralExpr +# 201| (Int) ... +#-----| -> 0 -# 201| BinaryExpr +# 201| x +#-----| -> (Int) ... + +# 201| ... call to < ... #-----| -> StmtCondition # 201| StmtCondition -#-----| true -> DeclRefExpr -#-----| false -> DeclRefExpr +#-----| true -> x +#-----| false -> x -# 201| DeclRefExpr -#-----| -> TypeExpr +# 201| < +#-----| -> Int.Type -# 201| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 201| Int.Type +#-----| -> call to < -# 201| TypeExpr -#-----| -> DotSyntaxCallExpr +# 201| call to < +#-----| exception -> exit m3 (normal) +#-----| -> x -# 201| IntegerLiteralExpr -#-----| -> BinaryExpr +# 201| 0 +#-----| -> ... call to < ... -# 202| DeclRefExpr -#-----| -> DeclRefExpr +# 202| x +#-----| -> - -# 202| AssignExpr -#-----| -> IfStmt +# 202| ... = ... +#-----| -> if ... then { ... } -# 202| DeclRefExpr -#-----| -> TypeExpr +# 202| - +#-----| -> Int.Type -# 202| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 202| Int.Type +#-----| -> call to - -# 202| TypeExpr -#-----| -> DotSyntaxCallExpr +# 202| call to - +#-----| exception -> exit m3 (normal) +#-----| -> x -# 202| PrefixUnaryExpr -#-----| -> AssignExpr +# 202| call to ... +#-----| -> ... = ... -# 202| DeclRefExpr -#-----| -> LoadExpr +# 202| (Int) ... +#-----| -> call to ... -# 202| LoadExpr -#-----| -> PrefixUnaryExpr +# 202| x +#-----| -> (Int) ... -# 203| IfStmt -#-----| -> DeclRefExpr +# 203| if ... then { ... } +#-----| -> > -# 203| DeclRefExpr -#-----| -> LoadExpr +# 203| (Int) ... +#-----| -> 10 -# 203| LoadExpr -#-----| -> IntegerLiteralExpr +# 203| x +#-----| -> (Int) ... -# 203| BinaryExpr +# 203| ... call to > ... #-----| -> StmtCondition # 203| StmtCondition -#-----| true -> DeclRefExpr -#-----| false -> DeclRefExpr +#-----| true -> x +#-----| false -> x -# 203| DeclRefExpr -#-----| -> TypeExpr +# 203| > +#-----| -> Int.Type -# 203| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 203| Int.Type +#-----| -> call to > -# 203| TypeExpr -#-----| -> DotSyntaxCallExpr +# 203| call to > +#-----| exception -> exit m3 (normal) +#-----| -> x -# 203| IntegerLiteralExpr -#-----| -> BinaryExpr +# 203| 10 +#-----| -> ... call to > ... -# 204| DeclRefExpr -#-----| -> DeclRefExpr +# 204| x +#-----| -> - -# 204| AssignExpr -#-----| -> DeclRefExpr +# 204| ... = ... +#-----| -> x -# 204| DeclRefExpr -#-----| -> LoadExpr +# 204| (Int) ... +#-----| -> 1 -# 204| LoadExpr -#-----| -> IntegerLiteralExpr +# 204| x +#-----| -> (Int) ... -# 204| BinaryExpr -#-----| -> AssignExpr +# 204| ... call to - ... +#-----| -> ... = ... -# 204| DeclRefExpr -#-----| -> TypeExpr +# 204| - +#-----| -> Int.Type -# 204| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 204| Int.Type +#-----| -> call to - -# 204| TypeExpr -#-----| -> DotSyntaxCallExpr +# 204| call to - +#-----| exception -> exit m3 (normal) +#-----| -> x -# 204| IntegerLiteralExpr -#-----| -> BinaryExpr +# 204| 1 +#-----| -> ... call to - ... -# 207| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 207| return ... +#-----| return -> exit m3 (normal) -# 207| DeclRefExpr -#-----| -> LoadExpr +# 207| (Int) ... +#-----| -> return ... -# 207| LoadExpr -#-----| -> ReturnStmt +# 207| x +#-----| -> (Int) ... -# 210| enter ConcreteFuncDecl -#-----| -> DeclRefExpr +# 210| enter m4 +#-----| -> b1 -# 210| exit ConcreteFuncDecl +# 210| exit m4 -# 210| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 210| exit m4 (normal) +#-----| -> exit m4 -# 211| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 211| return ... +#-----| return -> exit m4 (normal) -# 211| [false] ParenExpr -#-----| false -> StringLiteralExpr +# 211| [false] (...) +#-----| false -> !b2 || !b3 -# 211| [true] ParenExpr -#-----| true -> StringLiteralExpr +# 211| [true] (...) +#-----| true -> b2 || b3 -# 211| IfExpr -#-----| -> ReturnStmt +# 211| ... ? ... : ... +#-----| -> return ... -# 211| DeclRefExpr -#-----| true -> DeclRefExpr -#-----| false -> DeclRefExpr +# 211| b1 +#-----| true -> b2 +#-----| false -> b3 -# 211| [false] IfExpr -#-----| false -> [false] ParenExpr +# 211| [false] ... ? ... : ... +#-----| false -> [false] (...) -# 211| [true] IfExpr -#-----| true -> [true] ParenExpr +# 211| [true] ... ? ... : ... +#-----| true -> [true] (...) -# 211| DeclRefExpr -#-----| false -> [false] IfExpr -#-----| true -> [true] IfExpr +# 211| b2 +#-----| false -> [false] ... ? ... : ... +#-----| true -> [true] ... ? ... : ... -# 211| DeclRefExpr -#-----| false -> [false] IfExpr -#-----| true -> [true] IfExpr +# 211| b3 +#-----| false -> [false] ... ? ... : ... +#-----| true -> [true] ... ? ... : ... -# 211| StringLiteralExpr -#-----| -> IfExpr +# 211| b2 || b3 +#-----| -> ... ? ... : ... -# 211| StringLiteralExpr -#-----| -> IfExpr +# 211| !b2 || !b3 +#-----| -> ... ? ... : ... -# 214| enter ConcreteFuncDecl -#-----| -> IfStmt +# 214| enter conversionsInSplitEntry +#-----| -> if ... then { ... } else { ... } -# 214| exit ConcreteFuncDecl +# 214| exit conversionsInSplitEntry -# 214| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 214| exit conversionsInSplitEntry (normal) +#-----| -> exit conversionsInSplitEntry -# 215| IfStmt -#-----| -> DeclRefExpr +# 215| if ... then { ... } else { ... } +#-----| -> b -# 215| DeclRefExpr -#-----| true -> BooleanLiteralExpr -#-----| false -> BooleanLiteralExpr +# 215| b +#-----| true -> true +#-----| false -> false -# 215| IfExpr +# 215| ... ? ... : ... #-----| -> StmtCondition # 215| StmtCondition -#-----| true -> StringLiteralExpr -#-----| false -> StringLiteralExpr +#-----| true -> b +#-----| false -> !b -# 215| ParenExpr -#-----| -> IfExpr +# 215| (...) +#-----| -> ... ? ... : ... -# 215| BooleanLiteralExpr -#-----| -> ParenExpr +# 215| true +#-----| -> (...) -# 215| CoerceExpr -#-----| -> IfExpr +# 215| (Bool) ... +#-----| -> ... ? ... : ... -# 215| BooleanLiteralExpr -#-----| -> CoerceExpr +# 215| false +#-----| -> (Bool) ... -# 216| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 216| return ... +#-----| return -> exit conversionsInSplitEntry (normal) -# 216| StringLiteralExpr -#-----| -> ReturnStmt +# 216| b +#-----| -> return ... -# 219| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 219| return ... +#-----| return -> exit conversionsInSplitEntry (normal) -# 219| StringLiteralExpr -#-----| -> ReturnStmt +# 219| !b +#-----| -> return ... -# 223| enter ConcreteFuncDecl -#-----| -> IfStmt +# 223| enter constant_condition +#-----| -> if ... then { ... } -# 223| exit ConcreteFuncDecl +# 223| exit constant_condition -# 223| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 223| exit constant_condition (normal) +#-----| -> exit constant_condition -# 224| IfStmt -#-----| -> BooleanLiteralExpr - -# 224| PrefixUnaryExpr -#-----| -> StmtCondition +# 224| if ... then { ... } +#-----| -> true # 224| StmtCondition -#-----| false -> exit ConcreteFuncDecl (normal) -#-----| true -> DeclRefExpr +#-----| false -> exit constant_condition (normal) +#-----| true -> print -# 224| BooleanLiteralExpr -#-----| -> PrefixUnaryExpr - -# 225| DeclRefExpr -#-----| -> StringLiteralExpr - -# 225| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) - -# 225| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr - -# 225| DefaultArgumentExpr -#-----| -> CallExpr - -# 225| ArrayExpr -#-----| -> VarargExpansionExpr - -# 225| ErasureExpr -#-----| -> ArrayExpr - -# 225| StringLiteralExpr -#-----| -> ErasureExpr - -# 225| VarargExpansionExpr -#-----| -> DefaultArgumentExpr - -# 229| enter ConcreteFuncDecl -#-----| -> IfStmt - -# 229| exit ConcreteFuncDecl - -# 229| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl - -# 230| IfStmt -#-----| -> DeclRefExpr - -# 230| DeclRefExpr +# 224| call to ... #-----| -> StmtCondition +# 224| true +#-----| -> call to ... + +# 225| print +#-----| -> Impossible + +# 225| call to print +#-----| exception -> exit constant_condition (normal) + +# 225| default separator +#-----| -> default terminator + +# 225| default terminator +#-----| -> call to print + +# 225| (Any) ... +#-----| -> [...] + +# 225| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] + +# 225| Impossible +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... + +# 225| [...] +#-----| -> default separator + +# 225| [...] +#-----| -> [...] + +# 229| enter empty_else +#-----| -> if ... then { ... } else { ... } + +# 229| exit empty_else + +# 229| exit empty_else (normal) +#-----| -> exit empty_else + +# 230| if ... then { ... } else { ... } +#-----| -> b + # 230| StmtCondition -#-----| true -> DeclRefExpr -#-----| false -> BraceStmt +#-----| true -> print +#-----| false -> { ... } -# 231| DeclRefExpr -#-----| -> StringLiteralExpr +# 230| b +#-----| -> StmtCondition -# 231| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 231| print +#-----| -> true -# 231| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 231| call to print +#-----| exception -> exit empty_else (normal) +#-----| -> print -# 231| DefaultArgumentExpr -#-----| -> CallExpr +# 231| default separator +#-----| -> default terminator -# 231| ArrayExpr -#-----| -> VarargExpansionExpr +# 231| default terminator +#-----| -> call to print -# 231| ErasureExpr -#-----| -> ArrayExpr +# 231| (Any) ... +#-----| -> [...] -# 231| StringLiteralExpr -#-----| -> ErasureExpr +# 231| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 231| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 231| [...] +#-----| -> default separator -# 233| BraceStmt -#-----| -> DeclRefExpr +# 231| [...] +#-----| -> [...] -# 234| DeclRefExpr -#-----| -> StringLiteralExpr +# 231| true +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 234| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) +# 233| { ... } +#-----| -> print -# 234| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 234| print +#-----| -> done -# 234| DefaultArgumentExpr -#-----| -> CallExpr +# 234| call to print +#-----| exception -> exit empty_else (normal) -# 234| ArrayExpr -#-----| -> VarargExpansionExpr +# 234| default separator +#-----| -> default terminator -# 234| ErasureExpr -#-----| -> ArrayExpr +# 234| default terminator +#-----| -> call to print -# 234| StringLiteralExpr -#-----| -> ErasureExpr +# 234| (Any) ... +#-----| -> [...] -# 234| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 234| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 237| enter ConcreteFuncDecl -#-----| -> IfStmt +# 234| [...] +#-----| -> default separator -# 237| exit ConcreteFuncDecl +# 234| [...] +#-----| -> [...] -# 237| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 234| done +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 238| IfStmt -#-----| -> DeclRefExpr +# 237| enter disjunct +#-----| -> if ... then { ... } -# 238| ParenExpr +# 237| exit disjunct + +# 237| exit disjunct (normal) +#-----| -> exit disjunct + +# 238| if ... then { ... } +#-----| -> b1 + +# 238| (...) #-----| -> StmtCondition # 238| StmtCondition -#-----| false -> exit ConcreteFuncDecl (normal) -#-----| true -> DeclRefExpr +#-----| false -> exit disjunct (normal) +#-----| true -> print -# 238| DeclRefExpr -#-----| true -> BinaryExpr -#-----| false -> AutoClosureExpr +# 238| b1 +#-----| true -> ... call to || ... +#-----| false -> { ... } -# 238| BinaryExpr -#-----| -> ParenExpr +# 238| ... call to || ... +#-----| -> (...) -# 238| AutoClosureExpr -#-----| -> DeclRefExpr +# 238| b2 +#-----| -> return ... -# 238| DeclRefExpr -#-----| -> ReturnStmt +# 238| return ... +#-----| -> ... call to || ... -# 238| ReturnStmt -#-----| -> BinaryExpr +# 238| { ... } +#-----| -> b2 -# 239| DeclRefExpr -#-----| -> StringLiteralExpr +# 239| print +#-----| -> b1 or b2 -# 239| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) +# 239| call to print +#-----| exception -> exit disjunct (normal) -# 239| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 239| default separator +#-----| -> default terminator -# 239| DefaultArgumentExpr -#-----| -> CallExpr +# 239| default terminator +#-----| -> call to print -# 239| ArrayExpr -#-----| -> VarargExpansionExpr +# 239| (Any) ... +#-----| -> [...] -# 239| ErasureExpr -#-----| -> ArrayExpr +# 239| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 239| StringLiteralExpr -#-----| -> ErasureExpr +# 239| [...] +#-----| -> default separator -# 239| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 239| [...] +#-----| -> [...] -# 243| enter ConcreteFuncDecl -#-----| -> NamedPattern +# 239| b1 or b2 +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 243| exit ConcreteFuncDecl +# 243| enter binaryExprs +#-----| -> c -# 243| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 243| exit binaryExprs -# 244| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 243| exit binaryExprs (normal) +#-----| -> exit binaryExprs -# 244| ConcreteVarDecl -#-----| -> NamedPattern +# 244| var ... = ... +#-----| -> c -# 244| NamedPattern -#-----| -> DeclRefExpr +# 244| c +#-----| -> + -# 244| DeclRefExpr -#-----| -> DeclRefExpr +# 244| c +#-----| -> d -# 244| BinaryExpr -#-----| -> PatternBindingDecl +# 244| a +#-----| -> b -# 244| DeclRefExpr -#-----| -> TypeExpr +# 244| ... call to + ... +#-----| -> var ... = ... -# 244| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 244| + +#-----| -> Int.Type -# 244| TypeExpr -#-----| -> DotSyntaxCallExpr +# 244| Int.Type +#-----| -> call to + -# 244| DeclRefExpr -#-----| -> BinaryExpr +# 244| call to + +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 245| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 244| b +#-----| -> ... call to + ... -# 245| ConcreteVarDecl -#-----| -> NamedPattern +# 245| var ... = ... +#-----| -> d -# 245| NamedPattern -#-----| -> DeclRefExpr +# 245| d +#-----| -> - -# 245| DeclRefExpr -#-----| -> DeclRefExpr +# 245| d +#-----| -> e -# 245| BinaryExpr -#-----| -> PatternBindingDecl +# 245| a +#-----| -> b -# 245| DeclRefExpr -#-----| -> TypeExpr +# 245| ... call to - ... +#-----| -> var ... = ... -# 245| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 245| - +#-----| -> Int.Type -# 245| TypeExpr -#-----| -> DotSyntaxCallExpr +# 245| Int.Type +#-----| -> call to - -# 245| DeclRefExpr -#-----| -> BinaryExpr +# 245| call to - +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 246| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 245| b +#-----| -> ... call to - ... -# 246| ConcreteVarDecl -#-----| -> NamedPattern +# 246| var ... = ... +#-----| -> e -# 246| NamedPattern -#-----| -> DeclRefExpr +# 246| e +#-----| -> * -# 246| DeclRefExpr -#-----| -> DeclRefExpr +# 246| e +#-----| -> f -# 246| BinaryExpr -#-----| -> PatternBindingDecl +# 246| a +#-----| -> b -# 246| DeclRefExpr -#-----| -> TypeExpr +# 246| ... call to * ... +#-----| -> var ... = ... -# 246| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 246| * +#-----| -> Int.Type -# 246| TypeExpr -#-----| -> DotSyntaxCallExpr +# 246| Int.Type +#-----| -> call to * -# 246| DeclRefExpr -#-----| -> BinaryExpr +# 246| call to * +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 247| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 246| b +#-----| -> ... call to * ... -# 247| ConcreteVarDecl -#-----| -> NamedPattern +# 247| var ... = ... +#-----| -> f -# 247| NamedPattern -#-----| -> DeclRefExpr +# 247| f +#-----| -> / -# 247| DeclRefExpr -#-----| -> DeclRefExpr +# 247| f +#-----| -> g -# 247| BinaryExpr -#-----| -> PatternBindingDecl +# 247| a +#-----| -> b -# 247| DeclRefExpr -#-----| -> TypeExpr +# 247| ... call to / ... +#-----| -> var ... = ... -# 247| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 247| / +#-----| -> Int.Type -# 247| TypeExpr -#-----| -> DotSyntaxCallExpr +# 247| Int.Type +#-----| -> call to / -# 247| DeclRefExpr -#-----| -> BinaryExpr +# 247| call to / +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 248| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 247| b +#-----| -> ... call to / ... -# 248| ConcreteVarDecl -#-----| -> NamedPattern +# 248| var ... = ... +#-----| -> g -# 248| NamedPattern -#-----| -> DeclRefExpr +# 248| g +#-----| -> % -# 248| DeclRefExpr -#-----| -> DeclRefExpr +# 248| g +#-----| -> h -# 248| BinaryExpr -#-----| -> PatternBindingDecl +# 248| a +#-----| -> b -# 248| DeclRefExpr -#-----| -> TypeExpr +# 248| ... call to % ... +#-----| -> var ... = ... -# 248| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 248| % +#-----| -> Int.Type -# 248| TypeExpr -#-----| -> DotSyntaxCallExpr +# 248| Int.Type +#-----| -> call to % -# 248| DeclRefExpr -#-----| -> BinaryExpr +# 248| call to % +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 249| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 248| b +#-----| -> ... call to % ... -# 249| ConcreteVarDecl -#-----| -> NamedPattern +# 249| var ... = ... +#-----| -> h -# 249| NamedPattern -#-----| -> DeclRefExpr +# 249| h +#-----| -> & -# 249| DeclRefExpr -#-----| -> DeclRefExpr +# 249| h +#-----| -> i -# 249| BinaryExpr -#-----| -> PatternBindingDecl +# 249| a +#-----| -> b -# 249| DeclRefExpr -#-----| -> TypeExpr +# 249| ... call to & ... +#-----| -> var ... = ... -# 249| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 249| & +#-----| -> Int.Type -# 249| TypeExpr -#-----| -> DotSyntaxCallExpr +# 249| Int.Type +#-----| -> call to & -# 249| DeclRefExpr -#-----| -> BinaryExpr +# 249| call to & +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 250| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 249| b +#-----| -> ... call to & ... -# 250| ConcreteVarDecl -#-----| -> NamedPattern +# 250| var ... = ... +#-----| -> i -# 250| NamedPattern -#-----| -> DeclRefExpr +# 250| i +#-----| -> | -# 250| DeclRefExpr -#-----| -> DeclRefExpr +# 250| i +#-----| -> j -# 250| BinaryExpr -#-----| -> PatternBindingDecl +# 250| a +#-----| -> b -# 250| DeclRefExpr -#-----| -> TypeExpr +# 250| ... call to | ... +#-----| -> var ... = ... -# 250| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 250| Int.Type +#-----| -> call to | -# 250| TypeExpr -#-----| -> DotSyntaxCallExpr +# 250| call to | +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 250| DeclRefExpr -#-----| -> BinaryExpr +# 250| | +#-----| -> Int.Type -# 251| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 250| b +#-----| -> ... call to | ... -# 251| ConcreteVarDecl -#-----| -> NamedPattern +# 251| var ... = ... +#-----| -> j -# 251| NamedPattern -#-----| -> DeclRefExpr +# 251| j +#-----| -> ^ -# 251| DeclRefExpr -#-----| -> DeclRefExpr +# 251| j +#-----| -> k -# 251| BinaryExpr -#-----| -> PatternBindingDecl +# 251| a +#-----| -> b -# 251| DeclRefExpr -#-----| -> TypeExpr +# 251| ... call to ^ ... +#-----| -> var ... = ... -# 251| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 251| Int.Type +#-----| -> call to ^ -# 251| TypeExpr -#-----| -> DotSyntaxCallExpr +# 251| ^ +#-----| -> Int.Type -# 251| DeclRefExpr -#-----| -> BinaryExpr +# 251| call to ^ +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 252| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 251| b +#-----| -> ... call to ^ ... -# 252| ConcreteVarDecl -#-----| -> NamedPattern +# 252| var ... = ... +#-----| -> k -# 252| NamedPattern -#-----| -> DeclRefExpr +# 252| k +#-----| -> << -# 252| DeclRefExpr -#-----| -> DeclRefExpr +# 252| k +#-----| -> l -# 252| BinaryExpr -#-----| -> PatternBindingDecl +# 252| a +#-----| -> b -# 252| DeclRefExpr -#-----| -> TypeExpr +# 252| ... call to << ... +#-----| -> var ... = ... -# 252| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 252| << +#-----| -> Int.Type -# 252| TypeExpr -#-----| -> DotSyntaxCallExpr +# 252| Int.Type +#-----| -> call to << -# 252| DeclRefExpr -#-----| -> BinaryExpr +# 252| call to << +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 253| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 252| b +#-----| -> ... call to << ... -# 253| ConcreteVarDecl -#-----| -> NamedPattern +# 253| var ... = ... +#-----| -> l -# 253| NamedPattern -#-----| -> DeclRefExpr +# 253| l +#-----| -> >> -# 253| DeclRefExpr -#-----| -> DeclRefExpr +# 253| l +#-----| -> o -# 253| BinaryExpr -#-----| -> PatternBindingDecl +# 253| a +#-----| -> b -# 253| DeclRefExpr -#-----| -> TypeExpr +# 253| ... call to >> ... +#-----| -> var ... = ... -# 253| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 253| >> +#-----| -> Int.Type -# 253| TypeExpr -#-----| -> DotSyntaxCallExpr +# 253| Int.Type +#-----| -> call to >> -# 253| DeclRefExpr -#-----| -> BinaryExpr +# 253| call to >> +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 254| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 253| b +#-----| -> ... call to >> ... -# 254| ConcreteVarDecl -#-----| -> NamedPattern +# 254| var ... = ... +#-----| -> o -# 254| NamedPattern -#-----| -> DeclRefExpr +# 254| o +#-----| -> == -# 254| DeclRefExpr -#-----| -> DeclRefExpr +# 254| o +#-----| -> p -# 254| BinaryExpr -#-----| -> PatternBindingDecl +# 254| a +#-----| -> b -# 254| DeclRefExpr -#-----| -> TypeExpr +# 254| ... call to == ... +#-----| -> var ... = ... -# 254| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 254| == +#-----| -> Int.Type -# 254| TypeExpr -#-----| -> DotSyntaxCallExpr +# 254| Int.Type +#-----| -> call to == -# 254| DeclRefExpr -#-----| -> BinaryExpr +# 254| call to == +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 255| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 254| b +#-----| -> ... call to == ... -# 255| ConcreteVarDecl -#-----| -> NamedPattern +# 255| var ... = ... +#-----| -> p -# 255| NamedPattern -#-----| -> DeclRefExpr +# 255| p +#-----| -> != -# 255| DeclRefExpr -#-----| -> DeclRefExpr +# 255| p +#-----| -> q -# 255| BinaryExpr -#-----| -> PatternBindingDecl +# 255| a +#-----| -> b -# 255| DeclRefExpr -#-----| -> TypeExpr +# 255| ... call to != ... +#-----| -> var ... = ... -# 255| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 255| != +#-----| -> Int.Type -# 255| TypeExpr -#-----| -> DotSyntaxCallExpr +# 255| Int.Type +#-----| -> call to != -# 255| DeclRefExpr -#-----| -> BinaryExpr +# 255| call to != +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 256| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 255| b +#-----| -> ... call to != ... -# 256| ConcreteVarDecl -#-----| -> NamedPattern +# 256| var ... = ... +#-----| -> q -# 256| NamedPattern -#-----| -> DeclRefExpr +# 256| q +#-----| -> < -# 256| DeclRefExpr -#-----| -> DeclRefExpr +# 256| q +#-----| -> r -# 256| BinaryExpr -#-----| -> PatternBindingDecl +# 256| a +#-----| -> b -# 256| DeclRefExpr -#-----| -> TypeExpr +# 256| ... call to < ... +#-----| -> var ... = ... -# 256| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 256| < +#-----| -> Int.Type -# 256| TypeExpr -#-----| -> DotSyntaxCallExpr +# 256| Int.Type +#-----| -> call to < -# 256| DeclRefExpr -#-----| -> BinaryExpr +# 256| call to < +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 257| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 256| b +#-----| -> ... call to < ... -# 257| ConcreteVarDecl -#-----| -> NamedPattern +# 257| var ... = ... +#-----| -> r -# 257| NamedPattern -#-----| -> DeclRefExpr +# 257| r +#-----| -> <= -# 257| DeclRefExpr -#-----| -> DeclRefExpr +# 257| r +#-----| -> s -# 257| BinaryExpr -#-----| -> PatternBindingDecl +# 257| a +#-----| -> b -# 257| DeclRefExpr -#-----| -> TypeExpr +# 257| ... call to <= ... +#-----| -> var ... = ... -# 257| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 257| <= +#-----| -> Int.Type -# 257| TypeExpr -#-----| -> DotSyntaxCallExpr +# 257| Int.Type +#-----| -> call to <= -# 257| DeclRefExpr -#-----| -> BinaryExpr +# 257| call to <= +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 258| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 257| b +#-----| -> ... call to <= ... -# 258| ConcreteVarDecl -#-----| -> NamedPattern +# 258| var ... = ... +#-----| -> s -# 258| NamedPattern -#-----| -> DeclRefExpr +# 258| s +#-----| -> > -# 258| DeclRefExpr -#-----| -> DeclRefExpr +# 258| s +#-----| -> t -# 258| BinaryExpr -#-----| -> PatternBindingDecl +# 258| a +#-----| -> b -# 258| DeclRefExpr -#-----| -> TypeExpr +# 258| ... call to > ... +#-----| -> var ... = ... -# 258| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 258| > +#-----| -> Int.Type -# 258| TypeExpr -#-----| -> DotSyntaxCallExpr +# 258| Int.Type +#-----| -> call to > -# 258| DeclRefExpr -#-----| -> BinaryExpr +# 258| call to > +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 259| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 258| b +#-----| -> ... call to > ... -# 259| ConcreteVarDecl -#-----| -> exit ConcreteFuncDecl (normal) +# 259| var ... = ... +#-----| -> t -# 259| NamedPattern -#-----| -> DeclRefExpr +# 259| t +#-----| -> >= -# 259| DeclRefExpr -#-----| -> DeclRefExpr +# 259| t +#-----| -> exit binaryExprs (normal) -# 259| BinaryExpr -#-----| -> PatternBindingDecl +# 259| a +#-----| -> b -# 259| DeclRefExpr -#-----| -> TypeExpr +# 259| ... call to >= ... +#-----| -> var ... = ... -# 259| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 259| >= +#-----| -> Int.Type -# 259| TypeExpr -#-----| -> DotSyntaxCallExpr +# 259| Int.Type +#-----| -> call to >= -# 259| DeclRefExpr -#-----| -> BinaryExpr +# 259| call to >= +#-----| exception -> exit binaryExprs (normal) +#-----| -> a -# 262| enter ConcreteFuncDecl -#-----| -> InterpolatedStringLiteralExpr +# 259| b +#-----| -> ... call to >= ... -# 262| exit ConcreteFuncDecl +# 262| enter interpolatedString +#-----| -> "..." -# 262| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 262| exit interpolatedString -# 263| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 262| exit interpolatedString (normal) +#-----| -> exit interpolatedString -# 263| InterpolatedStringLiteralExpr -#-----| -> ReturnStmt +# 263| return ... +#-----| return -> exit interpolatedString (normal) -# 266| enter ConcreteFuncDecl -#-----| -> NamedPattern +# 263| "..." +#-----| -> return ... -# 266| exit ConcreteFuncDecl +# 266| enter testSubscriptExpr +#-----| -> a -# 266| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 266| exit testSubscriptExpr -# 267| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 266| exit testSubscriptExpr (normal) +#-----| -> exit testSubscriptExpr -# 267| ConcreteVarDecl -#-----| -> DeclRefExpr +# 267| var ... = ... +#-----| -> a -# 267| NamedPattern -#-----| -> IntegerLiteralExpr +# 267| a +#-----| -> 0 -# 267| ArrayExpr -#-----| -> PatternBindingDecl +# 267| a +#-----| -> a -# 267| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 267| [...] +#-----| -> var ... = ... -# 267| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 267| 0 +#-----| -> 1 -# 267| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 267| 1 +#-----| -> 2 -# 267| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 267| 2 +#-----| -> 3 -# 267| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 267| 3 +#-----| -> 4 -# 267| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 267| 4 +#-----| -> 5 -# 267| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 267| 5 +#-----| -> 6 -# 267| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 267| 6 +#-----| -> 7 -# 267| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 267| 7 +#-----| -> 8 -# 267| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 267| 8 +#-----| -> 9 -# 267| IntegerLiteralExpr -#-----| -> ArrayExpr +# 267| 9 +#-----| -> 10 -# 268| DeclRefExpr -#-----| -> InOutExpr +# 267| 10 +#-----| -> [...] -# 268| InOutExpr -#-----| -> IntegerLiteralExpr +# 268| &... +#-----| -> 0 -# 268| SubscriptExpr -#-----| -> IntegerLiteralExpr +# 268| a +#-----| -> &... -# 268| AssignExpr -#-----| -> DeclRefExpr +# 268| ...[...] +#-----| -> 0 -# 268| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 268| setter for ... = ... +#-----| -> += -# 268| IntegerLiteralExpr -#-----| -> AssignExpr +# 268| 0 +#-----| -> ...[...] -# 269| DeclRefExpr -#-----| -> InOutExpr +# 268| 0 +#-----| -> setter for ... = ... -# 269| InOutExpr -#-----| -> IntegerLiteralExpr +# 269| &... +#-----| -> 1 -# 269| InOutExpr -#-----| -> IntegerLiteralExpr +# 269| a +#-----| -> &... -# 269| SubscriptExpr -#-----| -> InOutExpr +# 269| &... +#-----| -> 1 -# 269| BinaryExpr -#-----| -> DeclRefExpr +# 269| getter for ...[...] +#-----| -> &... -# 269| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 269| ... call to += ... +#-----| -> -= -# 269| DeclRefExpr -#-----| -> TypeExpr +# 269| 1 +#-----| -> getter for ...[...] -# 269| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 269| += +#-----| -> Int.Type -# 269| TypeExpr -#-----| -> DotSyntaxCallExpr +# 269| Int.Type +#-----| -> call to += -# 269| IntegerLiteralExpr -#-----| -> BinaryExpr +# 269| call to += +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a -# 270| DeclRefExpr -#-----| -> InOutExpr +# 269| 1 +#-----| -> ... call to += ... -# 270| InOutExpr -#-----| -> IntegerLiteralExpr +# 270| &... +#-----| -> 2 -# 270| InOutExpr -#-----| -> IntegerLiteralExpr +# 270| a +#-----| -> &... -# 270| SubscriptExpr -#-----| -> InOutExpr +# 270| &... +#-----| -> 1 -# 270| BinaryExpr -#-----| -> DeclRefExpr +# 270| getter for ...[...] +#-----| -> &... -# 270| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 270| ... call to -= ... +#-----| -> *= -# 270| DeclRefExpr -#-----| -> TypeExpr +# 270| 2 +#-----| -> getter for ...[...] -# 270| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 270| -= +#-----| -> Int.Type -# 270| TypeExpr -#-----| -> DotSyntaxCallExpr +# 270| Int.Type +#-----| -> call to -= -# 270| IntegerLiteralExpr -#-----| -> BinaryExpr +# 270| call to -= +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a -# 271| DeclRefExpr -#-----| -> InOutExpr +# 270| 1 +#-----| -> ... call to -= ... -# 271| InOutExpr -#-----| -> IntegerLiteralExpr +# 271| &... +#-----| -> 3 -# 271| InOutExpr -#-----| -> IntegerLiteralExpr +# 271| a +#-----| -> &... -# 271| SubscriptExpr -#-----| -> InOutExpr +# 271| &... +#-----| -> 1 -# 271| BinaryExpr -#-----| -> DeclRefExpr +# 271| getter for ...[...] +#-----| -> &... -# 271| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 271| ... call to *= ... +#-----| -> /= -# 271| DeclRefExpr -#-----| -> TypeExpr +# 271| 3 +#-----| -> getter for ...[...] -# 271| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 271| *= +#-----| -> Int.Type -# 271| TypeExpr -#-----| -> DotSyntaxCallExpr +# 271| Int.Type +#-----| -> call to *= -# 271| IntegerLiteralExpr -#-----| -> BinaryExpr +# 271| call to *= +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a -# 272| DeclRefExpr -#-----| -> InOutExpr +# 271| 1 +#-----| -> ... call to *= ... -# 272| InOutExpr -#-----| -> IntegerLiteralExpr +# 272| &... +#-----| -> 4 -# 272| InOutExpr -#-----| -> IntegerLiteralExpr +# 272| a +#-----| -> &... -# 272| SubscriptExpr -#-----| -> InOutExpr +# 272| &... +#-----| -> 1 -# 272| BinaryExpr -#-----| -> DeclRefExpr +# 272| getter for ...[...] +#-----| -> &... -# 272| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 272| ... call to /= ... +#-----| -> %= -# 272| DeclRefExpr -#-----| -> TypeExpr +# 272| 4 +#-----| -> getter for ...[...] -# 272| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 272| /= +#-----| -> Int.Type -# 272| TypeExpr -#-----| -> DotSyntaxCallExpr +# 272| Int.Type +#-----| -> call to /= -# 272| IntegerLiteralExpr -#-----| -> BinaryExpr +# 272| call to /= +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a -# 273| DeclRefExpr -#-----| -> InOutExpr +# 272| 1 +#-----| -> ... call to /= ... -# 273| InOutExpr -#-----| -> IntegerLiteralExpr +# 273| &... +#-----| -> 5 -# 273| InOutExpr -#-----| -> IntegerLiteralExpr +# 273| a +#-----| -> &... -# 273| SubscriptExpr -#-----| -> InOutExpr +# 273| &... +#-----| -> 1 -# 273| BinaryExpr -#-----| -> DeclRefExpr +# 273| getter for ...[...] +#-----| -> &... -# 273| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 273| ... call to %= ... +#-----| -> &= -# 273| DeclRefExpr -#-----| -> TypeExpr +# 273| 5 +#-----| -> getter for ...[...] -# 273| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 273| %= +#-----| -> Int.Type -# 273| TypeExpr -#-----| -> DotSyntaxCallExpr +# 273| Int.Type +#-----| -> call to %= -# 273| IntegerLiteralExpr -#-----| -> BinaryExpr +# 273| call to %= +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a -# 274| DeclRefExpr -#-----| -> InOutExpr +# 273| 1 +#-----| -> ... call to %= ... -# 274| InOutExpr -#-----| -> IntegerLiteralExpr +# 274| &... +#-----| -> 6 -# 274| InOutExpr -#-----| -> IntegerLiteralExpr +# 274| a +#-----| -> &... -# 274| SubscriptExpr -#-----| -> InOutExpr +# 274| &... +#-----| -> 1 -# 274| BinaryExpr -#-----| -> DeclRefExpr +# 274| getter for ...[...] +#-----| -> &... -# 274| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 274| ... call to &= ... +#-----| -> |= -# 274| DeclRefExpr -#-----| -> TypeExpr +# 274| 6 +#-----| -> getter for ...[...] -# 274| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 274| &= +#-----| -> Int.Type -# 274| TypeExpr -#-----| -> DotSyntaxCallExpr +# 274| Int.Type +#-----| -> call to &= -# 274| IntegerLiteralExpr -#-----| -> BinaryExpr +# 274| call to &= +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a -# 275| DeclRefExpr -#-----| -> InOutExpr +# 274| 1 +#-----| -> ... call to &= ... -# 275| InOutExpr -#-----| -> IntegerLiteralExpr +# 275| &... +#-----| -> 7 -# 275| InOutExpr -#-----| -> IntegerLiteralExpr +# 275| a +#-----| -> &... -# 275| SubscriptExpr -#-----| -> InOutExpr +# 275| &... +#-----| -> 1 -# 275| BinaryExpr -#-----| -> DeclRefExpr +# 275| getter for ...[...] +#-----| -> &... -# 275| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 275| ... call to |= ... +#-----| -> ^= -# 275| DeclRefExpr -#-----| -> TypeExpr +# 275| 7 +#-----| -> getter for ...[...] -# 275| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 275| Int.Type +#-----| -> call to |= -# 275| TypeExpr -#-----| -> DotSyntaxCallExpr +# 275| call to |= +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a -# 275| IntegerLiteralExpr -#-----| -> BinaryExpr +# 275| |= +#-----| -> Int.Type -# 276| DeclRefExpr -#-----| -> InOutExpr +# 275| 1 +#-----| -> ... call to |= ... -# 276| InOutExpr -#-----| -> IntegerLiteralExpr +# 276| &... +#-----| -> 8 -# 276| InOutExpr -#-----| -> IntegerLiteralExpr +# 276| a +#-----| -> &... -# 276| SubscriptExpr -#-----| -> InOutExpr +# 276| &... +#-----| -> 1 -# 276| BinaryExpr -#-----| -> DeclRefExpr +# 276| getter for ...[...] +#-----| -> &... -# 276| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 276| ... call to ^= ... +#-----| -> <<= -# 276| DeclRefExpr -#-----| -> TypeExpr +# 276| 8 +#-----| -> getter for ...[...] -# 276| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 276| Int.Type +#-----| -> call to ^= -# 276| TypeExpr -#-----| -> DotSyntaxCallExpr +# 276| ^= +#-----| -> Int.Type -# 276| IntegerLiteralExpr -#-----| -> BinaryExpr +# 276| call to ^= +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a -# 277| DeclRefExpr -#-----| -> InOutExpr +# 276| 1 +#-----| -> ... call to ^= ... -# 277| InOutExpr -#-----| -> IntegerLiteralExpr +# 277| &... +#-----| -> 9 -# 277| InOutExpr -#-----| -> IntegerLiteralExpr +# 277| a +#-----| -> &... -# 277| SubscriptExpr -#-----| -> InOutExpr +# 277| &... +#-----| -> 1 -# 277| BinaryExpr -#-----| -> DeclRefExpr +# 277| getter for ...[...] +#-----| -> &... -# 277| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 277| ... call to <<= ... +#-----| -> >>= -# 277| DeclRefExpr -#-----| -> TypeExpr +# 277| 9 +#-----| -> getter for ...[...] -# 277| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 277| <<= +#-----| -> Int.Type -# 277| TypeExpr -#-----| -> DotSyntaxCallExpr +# 277| Int.Type +#-----| -> call to <<= -# 277| IntegerLiteralExpr -#-----| -> BinaryExpr +# 277| call to <<= +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a -# 278| DeclRefExpr -#-----| -> InOutExpr +# 277| 1 +#-----| -> ... call to <<= ... -# 278| InOutExpr -#-----| -> IntegerLiteralExpr +# 278| &... +#-----| -> 10 -# 278| InOutExpr -#-----| -> IntegerLiteralExpr +# 278| a +#-----| -> &... -# 278| SubscriptExpr -#-----| -> InOutExpr +# 278| &... +#-----| -> 1 -# 278| BinaryExpr -#-----| -> NamedPattern +# 278| getter for ...[...] +#-----| -> &... -# 278| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 278| ... call to >>= ... +#-----| -> tupleWithA -# 278| DeclRefExpr -#-----| -> TypeExpr +# 278| 10 +#-----| -> getter for ...[...] -# 278| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 278| >>= +#-----| -> Int.Type -# 278| TypeExpr -#-----| -> DotSyntaxCallExpr +# 278| Int.Type +#-----| -> call to >>= -# 278| IntegerLiteralExpr -#-----| -> BinaryExpr +# 278| call to >>= +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a -# 280| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 278| 1 +#-----| -> ... call to >>= ... -# 280| ConcreteVarDecl -#-----| -> NamedPattern +# 280| var ... = ... +#-----| -> tupleWithA -# 280| NamedPattern -#-----| -> DeclRefExpr +# 280| tupleWithA +#-----| -> a -# 280| TupleExpr -#-----| -> PatternBindingDecl +# 280| tupleWithA +#-----| -> b -# 280| DeclRefExpr -#-----| -> InOutExpr +# 280| (...) +#-----| -> var ... = ... -# 280| InOutExpr -#-----| -> IntegerLiteralExpr +# 280| &... +#-----| -> 0 -# 280| LoadExpr -#-----| -> DeclRefExpr +# 280| a +#-----| -> &... -# 280| SubscriptExpr -#-----| -> LoadExpr +# 280| (Int) ... +#-----| -> a -# 280| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 280| getter for ...[...] +#-----| -> (Int) ... -# 280| DeclRefExpr -#-----| -> InOutExpr +# 280| 0 +#-----| -> getter for ...[...] -# 280| InOutExpr -#-----| -> IntegerLiteralExpr +# 280| &... +#-----| -> 1 -# 280| LoadExpr -#-----| -> DeclRefExpr +# 280| a +#-----| -> &... -# 280| SubscriptExpr -#-----| -> LoadExpr +# 280| (Int) ... +#-----| -> a -# 280| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 280| getter for ...[...] +#-----| -> (Int) ... -# 280| DeclRefExpr -#-----| -> InOutExpr +# 280| 1 +#-----| -> getter for ...[...] -# 280| InOutExpr -#-----| -> IntegerLiteralExpr +# 280| &... +#-----| -> 2 -# 280| LoadExpr -#-----| -> DeclRefExpr +# 280| a +#-----| -> &... -# 280| SubscriptExpr -#-----| -> LoadExpr +# 280| (Int) ... +#-----| -> a -# 280| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 280| getter for ...[...] +#-----| -> (Int) ... -# 280| DeclRefExpr -#-----| -> InOutExpr +# 280| 2 +#-----| -> getter for ...[...] -# 280| InOutExpr -#-----| -> IntegerLiteralExpr +# 280| &... +#-----| -> 3 -# 280| LoadExpr -#-----| -> DeclRefExpr +# 280| a +#-----| -> &... -# 280| SubscriptExpr -#-----| -> LoadExpr +# 280| (Int) ... +#-----| -> a -# 280| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 280| getter for ...[...] +#-----| -> (Int) ... -# 280| DeclRefExpr -#-----| -> InOutExpr +# 280| 3 +#-----| -> getter for ...[...] -# 280| InOutExpr -#-----| -> IntegerLiteralExpr +# 280| &... +#-----| -> 4 -# 280| LoadExpr -#-----| -> TupleExpr +# 280| a +#-----| -> &... -# 280| SubscriptExpr -#-----| -> LoadExpr +# 280| (Int) ... +#-----| -> (...) -# 280| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 280| getter for ...[...] +#-----| -> (Int) ... -# 282| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 280| 4 +#-----| -> getter for ...[...] -# 282| ConcreteVarDecl -#-----| -> DeclRefExpr +# 282| var ... = ... +#-----| -> b -# 282| NamedPattern -#-----| -> IntegerLiteralExpr +# 282| b +#-----| -> 0 -# 282| ArrayExpr -#-----| -> PatternBindingDecl +# 282| b +#-----| -> b -# 282| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 282| [...] +#-----| -> var ... = ... -# 282| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 282| 0 +#-----| -> 1 -# 282| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 282| 1 +#-----| -> 2 -# 282| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 282| 2 +#-----| -> 3 -# 282| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 282| 3 +#-----| -> 4 -# 282| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 282| 4 +#-----| -> 5 -# 282| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 282| 5 +#-----| -> 6 -# 282| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 282| 6 +#-----| -> 7 -# 282| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 282| 7 +#-----| -> 8 -# 282| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 282| 8 +#-----| -> 9 -# 282| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 282| 9 +#-----| -> 10 -# 282| IntegerLiteralExpr -#-----| -> ArrayExpr +# 282| 10 +#-----| -> 11 -# 283| DeclRefExpr -#-----| -> InOutExpr +# 282| 11 +#-----| -> [...] -# 283| InOutExpr -#-----| -> IntegerLiteralExpr +# 283| &... +#-----| -> 0 -# 283| SubscriptExpr -#-----| -> DeclRefExpr +# 283| b +#-----| -> &... -# 283| AssignExpr -#-----| -> DeclRefExpr +# 283| ...[...] +#-----| -> a -# 283| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 283| setter for ... = ... +#-----| -> b -# 283| DeclRefExpr -#-----| -> InOutExpr +# 283| 0 +#-----| -> ...[...] -# 283| InOutExpr -#-----| -> IntegerLiteralExpr +# 283| &... +#-----| -> 10 -# 283| LoadExpr -#-----| -> AssignExpr +# 283| a +#-----| -> &... -# 283| SubscriptExpr -#-----| -> LoadExpr +# 283| (Int) ... +#-----| -> setter for ... = ... -# 283| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 283| getter for ...[...] +#-----| -> (Int) ... -# 284| DeclRefExpr -#-----| -> InOutExpr +# 283| 10 +#-----| -> getter for ...[...] -# 284| InOutExpr -#-----| -> IntegerLiteralExpr +# 284| &... +#-----| -> 1 -# 284| SubscriptExpr -#-----| -> DeclRefExpr +# 284| b +#-----| -> &... -# 284| AssignExpr -#-----| -> DeclRefExpr +# 284| ...[...] +#-----| -> + -# 284| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 284| setter for ... = ... +#-----| -> b -# 284| DeclRefExpr -#-----| -> InOutExpr +# 284| 1 +#-----| -> ...[...] -# 284| InOutExpr -#-----| -> IntegerLiteralExpr +# 284| &... +#-----| -> 0 -# 284| LoadExpr -#-----| -> IntegerLiteralExpr +# 284| b +#-----| -> &... -# 284| SubscriptExpr -#-----| -> LoadExpr +# 284| (Int) ... +#-----| -> 1 -# 284| BinaryExpr -#-----| -> AssignExpr +# 284| getter for ...[...] +#-----| -> (Int) ... -# 284| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 284| ... call to + ... +#-----| -> setter for ... = ... -# 284| DeclRefExpr -#-----| -> TypeExpr +# 284| 0 +#-----| -> getter for ...[...] -# 284| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 284| + +#-----| -> Int.Type -# 284| TypeExpr -#-----| -> DotSyntaxCallExpr +# 284| Int.Type +#-----| -> call to + -# 284| IntegerLiteralExpr -#-----| -> BinaryExpr +# 284| call to + +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> b -# 285| DeclRefExpr -#-----| -> InOutExpr +# 284| 1 +#-----| -> ... call to + ... -# 285| InOutExpr -#-----| -> IntegerLiteralExpr +# 285| &... +#-----| -> 2 -# 285| SubscriptExpr -#-----| -> DeclRefExpr +# 285| b +#-----| -> &... -# 285| AssignExpr -#-----| -> DeclRefExpr +# 285| ...[...] +#-----| -> - -# 285| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 285| setter for ... = ... +#-----| -> b -# 285| DeclRefExpr -#-----| -> InOutExpr +# 285| 2 +#-----| -> ...[...] -# 285| InOutExpr -#-----| -> IntegerLiteralExpr +# 285| &... +#-----| -> 1 -# 285| LoadExpr -#-----| -> IntegerLiteralExpr +# 285| b +#-----| -> &... -# 285| SubscriptExpr -#-----| -> LoadExpr +# 285| (Int) ... +#-----| -> 1 -# 285| BinaryExpr -#-----| -> AssignExpr +# 285| getter for ...[...] +#-----| -> (Int) ... -# 285| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 285| ... call to - ... +#-----| -> setter for ... = ... -# 285| DeclRefExpr -#-----| -> TypeExpr +# 285| 1 +#-----| -> getter for ...[...] -# 285| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 285| - +#-----| -> Int.Type -# 285| TypeExpr -#-----| -> DotSyntaxCallExpr +# 285| Int.Type +#-----| -> call to - -# 285| IntegerLiteralExpr -#-----| -> BinaryExpr +# 285| call to - +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> b -# 286| DeclRefExpr -#-----| -> InOutExpr +# 285| 1 +#-----| -> ... call to - ... -# 286| InOutExpr -#-----| -> IntegerLiteralExpr +# 286| &... +#-----| -> 3 -# 286| SubscriptExpr -#-----| -> DeclRefExpr +# 286| b +#-----| -> &... -# 286| AssignExpr -#-----| -> DeclRefExpr +# 286| ...[...] +#-----| -> * -# 286| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 286| setter for ... = ... +#-----| -> b -# 286| DeclRefExpr -#-----| -> InOutExpr +# 286| 3 +#-----| -> ...[...] -# 286| InOutExpr -#-----| -> IntegerLiteralExpr +# 286| &... +#-----| -> 2 -# 286| LoadExpr -#-----| -> IntegerLiteralExpr +# 286| b +#-----| -> &... -# 286| SubscriptExpr -#-----| -> LoadExpr +# 286| (Int) ... +#-----| -> 1 -# 286| BinaryExpr -#-----| -> AssignExpr +# 286| getter for ...[...] +#-----| -> (Int) ... -# 286| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 286| ... call to * ... +#-----| -> setter for ... = ... -# 286| DeclRefExpr -#-----| -> TypeExpr +# 286| 2 +#-----| -> getter for ...[...] -# 286| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 286| * +#-----| -> Int.Type -# 286| TypeExpr -#-----| -> DotSyntaxCallExpr +# 286| Int.Type +#-----| -> call to * -# 286| IntegerLiteralExpr -#-----| -> BinaryExpr +# 286| call to * +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> b -# 287| DeclRefExpr -#-----| -> InOutExpr +# 286| 1 +#-----| -> ... call to * ... -# 287| InOutExpr -#-----| -> IntegerLiteralExpr +# 287| &... +#-----| -> 4 -# 287| SubscriptExpr -#-----| -> DeclRefExpr +# 287| b +#-----| -> &... -# 287| AssignExpr -#-----| -> DeclRefExpr +# 287| ...[...] +#-----| -> / -# 287| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 287| setter for ... = ... +#-----| -> b -# 287| DeclRefExpr -#-----| -> InOutExpr +# 287| 4 +#-----| -> ...[...] -# 287| InOutExpr -#-----| -> IntegerLiteralExpr +# 287| &... +#-----| -> 3 -# 287| LoadExpr -#-----| -> IntegerLiteralExpr +# 287| b +#-----| -> &... -# 287| SubscriptExpr -#-----| -> LoadExpr +# 287| (Int) ... +#-----| -> 1 -# 287| BinaryExpr -#-----| -> AssignExpr +# 287| getter for ...[...] +#-----| -> (Int) ... -# 287| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 287| ... call to / ... +#-----| -> setter for ... = ... -# 287| DeclRefExpr -#-----| -> TypeExpr +# 287| 3 +#-----| -> getter for ...[...] -# 287| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 287| / +#-----| -> Int.Type -# 287| TypeExpr -#-----| -> DotSyntaxCallExpr +# 287| Int.Type +#-----| -> call to / -# 287| IntegerLiteralExpr -#-----| -> BinaryExpr +# 287| call to / +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> b -# 288| DeclRefExpr -#-----| -> InOutExpr +# 287| 1 +#-----| -> ... call to / ... -# 288| InOutExpr -#-----| -> IntegerLiteralExpr +# 288| &... +#-----| -> 5 -# 288| SubscriptExpr -#-----| -> DeclRefExpr +# 288| b +#-----| -> &... -# 288| AssignExpr -#-----| -> DeclRefExpr +# 288| ...[...] +#-----| -> % -# 288| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 288| setter for ... = ... +#-----| -> b -# 288| DeclRefExpr -#-----| -> InOutExpr +# 288| 5 +#-----| -> ...[...] -# 288| InOutExpr -#-----| -> IntegerLiteralExpr +# 288| &... +#-----| -> 4 -# 288| LoadExpr -#-----| -> IntegerLiteralExpr +# 288| b +#-----| -> &... -# 288| SubscriptExpr -#-----| -> LoadExpr +# 288| (Int) ... +#-----| -> 1 -# 288| BinaryExpr -#-----| -> AssignExpr +# 288| getter for ...[...] +#-----| -> (Int) ... -# 288| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 288| ... call to % ... +#-----| -> setter for ... = ... -# 288| DeclRefExpr -#-----| -> TypeExpr +# 288| 4 +#-----| -> getter for ...[...] -# 288| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 288| % +#-----| -> Int.Type -# 288| TypeExpr -#-----| -> DotSyntaxCallExpr +# 288| Int.Type +#-----| -> call to % -# 288| IntegerLiteralExpr -#-----| -> BinaryExpr +# 288| call to % +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> b -# 289| DeclRefExpr -#-----| -> InOutExpr +# 288| 1 +#-----| -> ... call to % ... -# 289| InOutExpr -#-----| -> IntegerLiteralExpr +# 289| &... +#-----| -> 6 -# 289| SubscriptExpr -#-----| -> DeclRefExpr +# 289| b +#-----| -> &... -# 289| AssignExpr -#-----| -> DeclRefExpr +# 289| ...[...] +#-----| -> & -# 289| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 289| setter for ... = ... +#-----| -> b -# 289| DeclRefExpr -#-----| -> InOutExpr +# 289| 6 +#-----| -> ...[...] -# 289| InOutExpr -#-----| -> IntegerLiteralExpr +# 289| &... +#-----| -> 5 -# 289| LoadExpr -#-----| -> IntegerLiteralExpr +# 289| b +#-----| -> &... -# 289| SubscriptExpr -#-----| -> LoadExpr +# 289| (Int) ... +#-----| -> 1 -# 289| BinaryExpr -#-----| -> AssignExpr +# 289| getter for ...[...] +#-----| -> (Int) ... -# 289| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 289| ... call to & ... +#-----| -> setter for ... = ... -# 289| DeclRefExpr -#-----| -> TypeExpr +# 289| 5 +#-----| -> getter for ...[...] -# 289| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 289| & +#-----| -> Int.Type -# 289| TypeExpr -#-----| -> DotSyntaxCallExpr +# 289| Int.Type +#-----| -> call to & -# 289| IntegerLiteralExpr -#-----| -> BinaryExpr +# 289| call to & +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> b -# 290| DeclRefExpr -#-----| -> InOutExpr +# 289| 1 +#-----| -> ... call to & ... -# 290| InOutExpr -#-----| -> IntegerLiteralExpr +# 290| &... +#-----| -> 7 -# 290| SubscriptExpr -#-----| -> DeclRefExpr +# 290| b +#-----| -> &... -# 290| AssignExpr -#-----| -> DeclRefExpr +# 290| ...[...] +#-----| -> | -# 290| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 290| setter for ... = ... +#-----| -> b -# 290| DeclRefExpr -#-----| -> InOutExpr +# 290| 7 +#-----| -> ...[...] -# 290| InOutExpr -#-----| -> IntegerLiteralExpr +# 290| &... +#-----| -> 6 -# 290| LoadExpr -#-----| -> IntegerLiteralExpr +# 290| b +#-----| -> &... -# 290| SubscriptExpr -#-----| -> LoadExpr +# 290| (Int) ... +#-----| -> 1 -# 290| BinaryExpr -#-----| -> AssignExpr +# 290| getter for ...[...] +#-----| -> (Int) ... -# 290| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 290| ... call to | ... +#-----| -> setter for ... = ... -# 290| DeclRefExpr -#-----| -> TypeExpr +# 290| 6 +#-----| -> getter for ...[...] -# 290| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 290| Int.Type +#-----| -> call to | -# 290| TypeExpr -#-----| -> DotSyntaxCallExpr +# 290| call to | +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> b -# 290| IntegerLiteralExpr -#-----| -> BinaryExpr +# 290| | +#-----| -> Int.Type -# 291| DeclRefExpr -#-----| -> InOutExpr +# 290| 1 +#-----| -> ... call to | ... -# 291| InOutExpr -#-----| -> IntegerLiteralExpr +# 291| &... +#-----| -> 8 -# 291| SubscriptExpr -#-----| -> DeclRefExpr +# 291| b +#-----| -> &... -# 291| AssignExpr -#-----| -> DeclRefExpr +# 291| ...[...] +#-----| -> ^ -# 291| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 291| setter for ... = ... +#-----| -> b -# 291| DeclRefExpr -#-----| -> InOutExpr +# 291| 8 +#-----| -> ...[...] -# 291| InOutExpr -#-----| -> IntegerLiteralExpr +# 291| &... +#-----| -> 7 -# 291| LoadExpr -#-----| -> IntegerLiteralExpr +# 291| b +#-----| -> &... -# 291| SubscriptExpr -#-----| -> LoadExpr +# 291| (Int) ... +#-----| -> 1 -# 291| BinaryExpr -#-----| -> AssignExpr +# 291| getter for ...[...] +#-----| -> (Int) ... -# 291| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 291| ... call to ^ ... +#-----| -> setter for ... = ... -# 291| DeclRefExpr -#-----| -> TypeExpr +# 291| 7 +#-----| -> getter for ...[...] -# 291| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 291| Int.Type +#-----| -> call to ^ -# 291| TypeExpr -#-----| -> DotSyntaxCallExpr +# 291| ^ +#-----| -> Int.Type -# 291| IntegerLiteralExpr -#-----| -> BinaryExpr +# 291| call to ^ +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> b -# 292| DeclRefExpr -#-----| -> InOutExpr +# 291| 1 +#-----| -> ... call to ^ ... -# 292| InOutExpr -#-----| -> IntegerLiteralExpr +# 292| &... +#-----| -> 9 -# 292| SubscriptExpr -#-----| -> DeclRefExpr +# 292| b +#-----| -> &... -# 292| AssignExpr -#-----| -> DeclRefExpr +# 292| ...[...] +#-----| -> << -# 292| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 292| setter for ... = ... +#-----| -> b -# 292| DeclRefExpr -#-----| -> InOutExpr +# 292| 9 +#-----| -> ...[...] -# 292| InOutExpr -#-----| -> IntegerLiteralExpr +# 292| &... +#-----| -> 8 -# 292| LoadExpr -#-----| -> IntegerLiteralExpr +# 292| b +#-----| -> &... -# 292| SubscriptExpr -#-----| -> LoadExpr +# 292| (Int) ... +#-----| -> 1 -# 292| BinaryExpr -#-----| -> AssignExpr +# 292| getter for ...[...] +#-----| -> (Int) ... -# 292| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 292| ... call to << ... +#-----| -> setter for ... = ... -# 292| DeclRefExpr -#-----| -> TypeExpr +# 292| 8 +#-----| -> getter for ...[...] -# 292| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 292| << +#-----| -> Int.Type -# 292| TypeExpr -#-----| -> DotSyntaxCallExpr +# 292| Int.Type +#-----| -> call to << -# 292| IntegerLiteralExpr -#-----| -> BinaryExpr +# 292| call to << +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> b -# 293| DeclRefExpr -#-----| -> InOutExpr +# 292| 1 +#-----| -> ... call to << ... -# 293| InOutExpr -#-----| -> IntegerLiteralExpr +# 293| &... +#-----| -> 10 -# 293| SubscriptExpr -#-----| -> DeclRefExpr +# 293| b +#-----| -> &... -# 293| AssignExpr -#-----| -> TuplePattern +# 293| ...[...] +#-----| -> >> -# 293| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 293| setter for ... = ... +#-----| -> (...) -# 293| DeclRefExpr -#-----| -> InOutExpr +# 293| 10 +#-----| -> ...[...] -# 293| InOutExpr -#-----| -> IntegerLiteralExpr +# 293| &... +#-----| -> 9 -# 293| LoadExpr -#-----| -> IntegerLiteralExpr +# 293| b +#-----| -> &... -# 293| SubscriptExpr -#-----| -> LoadExpr +# 293| (Int) ... +#-----| -> 1 -# 293| BinaryExpr -#-----| -> AssignExpr +# 293| getter for ...[...] +#-----| -> (Int) ... -# 293| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 293| ... call to >> ... +#-----| -> setter for ... = ... -# 293| DeclRefExpr -#-----| -> TypeExpr +# 293| 9 +#-----| -> getter for ...[...] -# 293| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 293| >> +#-----| -> Int.Type -# 293| TypeExpr -#-----| -> DotSyntaxCallExpr +# 293| Int.Type +#-----| -> call to >> -# 293| IntegerLiteralExpr -#-----| -> BinaryExpr +# 293| call to >> +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> b -# 295| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 293| 1 +#-----| -> ... call to >> ... -# 295| TuplePattern -#-----| -> NamedPattern +# 295| var ... = ... +#-----| -> a1 -# 295| ConcreteVarDecl -#-----| -> ConcreteVarDecl +# 295| (...) +#-----| -> a1 -# 295| NamedPattern -#-----| -> DeclRefExpr +# 295| a1 +#-----| -> tupleWithA -# 295| ConcreteVarDecl -#-----| -> ConcreteVarDecl +# 295| a1 +#-----| -> a2 -# 295| ConcreteVarDecl -#-----| -> ConcreteVarDecl +# 295| a2 +#-----| -> a3 -# 295| ConcreteVarDecl -#-----| -> ConcreteVarDecl +# 295| a3 +#-----| -> a4 -# 295| ConcreteVarDecl -#-----| -> DeclRefExpr +# 295| a4 +#-----| -> a5 -# 295| DeclRefExpr -#-----| -> LoadExpr +# 295| a5 +#-----| -> + -# 295| LoadExpr -#-----| -> PatternBindingDecl +# 295| ((Int, Int, Int, Int, Int)) ... +#-----| -> var ... = ... -# 296| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 295| tupleWithA +#-----| -> ((Int, Int, Int, Int, Int)) ... -# 296| TupleExpr -#-----| -> ReturnStmt +# 296| return ... +#-----| return -> exit testSubscriptExpr (normal) -# 296| DeclRefExpr -#-----| -> DeclRefExpr +# 296| (...) +#-----| -> return ... -# 296| BinaryExpr -#-----| -> DeclRefExpr +# 296| a1 +#-----| -> b -# 296| DeclRefExpr -#-----| -> TypeExpr +# 296| ... call to + ... +#-----| -> + -# 296| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 296| + +#-----| -> Int.Type -# 296| TypeExpr -#-----| -> DotSyntaxCallExpr +# 296| Int.Type +#-----| -> call to + -# 296| DeclRefExpr -#-----| -> InOutExpr +# 296| call to + +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a1 -# 296| InOutExpr -#-----| -> IntegerLiteralExpr +# 296| &... +#-----| -> 0 -# 296| LoadExpr -#-----| -> BinaryExpr +# 296| b +#-----| -> &... -# 296| SubscriptExpr -#-----| -> LoadExpr +# 296| (Int) ... +#-----| -> ... call to + ... -# 296| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 296| getter for ...[...] +#-----| -> (Int) ... -# 296| DeclRefExpr -#-----| -> DeclRefExpr +# 296| 0 +#-----| -> getter for ...[...] -# 296| BinaryExpr -#-----| -> DeclRefExpr +# 296| a2 +#-----| -> b -# 296| DeclRefExpr -#-----| -> TypeExpr +# 296| ... call to + ... +#-----| -> + -# 296| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 296| + +#-----| -> Int.Type -# 296| TypeExpr -#-----| -> DotSyntaxCallExpr +# 296| Int.Type +#-----| -> call to + -# 296| DeclRefExpr -#-----| -> InOutExpr +# 296| call to + +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a2 -# 296| InOutExpr -#-----| -> IntegerLiteralExpr +# 296| &... +#-----| -> 1 -# 296| LoadExpr -#-----| -> BinaryExpr +# 296| b +#-----| -> &... -# 296| SubscriptExpr -#-----| -> LoadExpr +# 296| (Int) ... +#-----| -> ... call to + ... -# 296| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 296| getter for ...[...] +#-----| -> (Int) ... -# 296| DeclRefExpr -#-----| -> DeclRefExpr +# 296| 1 +#-----| -> getter for ...[...] -# 296| BinaryExpr -#-----| -> DeclRefExpr +# 296| a3 +#-----| -> b -# 296| DeclRefExpr -#-----| -> TypeExpr +# 296| ... call to + ... +#-----| -> + -# 296| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 296| + +#-----| -> Int.Type -# 296| TypeExpr -#-----| -> DotSyntaxCallExpr +# 296| Int.Type +#-----| -> call to + -# 296| DeclRefExpr -#-----| -> InOutExpr +# 296| call to + +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a3 -# 296| InOutExpr -#-----| -> IntegerLiteralExpr +# 296| &... +#-----| -> 2 -# 296| LoadExpr -#-----| -> BinaryExpr +# 296| b +#-----| -> &... -# 296| SubscriptExpr -#-----| -> LoadExpr +# 296| (Int) ... +#-----| -> ... call to + ... -# 296| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 296| getter for ...[...] +#-----| -> (Int) ... -# 296| DeclRefExpr -#-----| -> DeclRefExpr +# 296| 2 +#-----| -> getter for ...[...] -# 296| BinaryExpr -#-----| -> DeclRefExpr +# 296| a4 +#-----| -> b -# 296| DeclRefExpr -#-----| -> TypeExpr +# 296| ... call to + ... +#-----| -> + -# 296| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 296| + +#-----| -> Int.Type -# 296| TypeExpr -#-----| -> DotSyntaxCallExpr +# 296| Int.Type +#-----| -> call to + -# 296| DeclRefExpr -#-----| -> InOutExpr +# 296| call to + +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a4 -# 296| InOutExpr -#-----| -> IntegerLiteralExpr +# 296| &... +#-----| -> 3 -# 296| LoadExpr -#-----| -> BinaryExpr +# 296| b +#-----| -> &... -# 296| SubscriptExpr -#-----| -> LoadExpr +# 296| (Int) ... +#-----| -> ... call to + ... -# 296| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 296| getter for ...[...] +#-----| -> (Int) ... -# 296| DeclRefExpr -#-----| -> DeclRefExpr +# 296| 3 +#-----| -> getter for ...[...] -# 296| BinaryExpr -#-----| -> TupleExpr +# 296| a5 +#-----| -> b -# 296| DeclRefExpr -#-----| -> TypeExpr +# 296| ... call to + ... +#-----| -> (...) -# 296| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 296| + +#-----| -> Int.Type -# 296| TypeExpr -#-----| -> DotSyntaxCallExpr +# 296| Int.Type +#-----| -> call to + -# 296| DeclRefExpr -#-----| -> InOutExpr +# 296| call to + +#-----| exception -> exit testSubscriptExpr (normal) +#-----| -> a5 -# 296| InOutExpr -#-----| -> IntegerLiteralExpr +# 296| &... +#-----| -> 4 -# 296| LoadExpr -#-----| -> BinaryExpr +# 296| b +#-----| -> &... -# 296| SubscriptExpr -#-----| -> LoadExpr +# 296| (Int) ... +#-----| -> ... call to + ... -# 296| IntegerLiteralExpr -#-----| -> SubscriptExpr +# 296| getter for ...[...] +#-----| -> (Int) ... -# 299| enter ConcreteFuncDecl -#-----| -> WhileStmt +# 296| 4 +#-----| -> getter for ...[...] -# 299| exit ConcreteFuncDecl +# 299| enter loop1 +#-----| -> while ... { ... } -# 299| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 299| exit loop1 -# 300| WhileStmt -#-----| -> DeclRefExpr +# 299| exit loop1 (normal) +#-----| -> exit loop1 -# 300| DeclRefExpr -#-----| -> LoadExpr +# 300| while ... { ... } +#-----| -> >= -# 300| LoadExpr -#-----| -> IntegerLiteralExpr +# 300| (Int) ... +#-----| -> 0 -# 300| BinaryExpr +# 300| x +#-----| -> (Int) ... + +# 300| ... call to >= ... #-----| -> StmtCondition # 300| StmtCondition -#-----| false -> exit ConcreteFuncDecl (normal) -#-----| true -> DeclRefExpr +#-----| false -> exit loop1 (normal) +#-----| true -> print -# 300| DeclRefExpr -#-----| -> TypeExpr +# 300| >= +#-----| -> Int.Type -# 300| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 300| Int.Type +#-----| -> call to >= -# 300| TypeExpr -#-----| -> DotSyntaxCallExpr +# 300| call to >= +#-----| exception -> exit loop1 (normal) +#-----| -> x -# 300| IntegerLiteralExpr -#-----| -> BinaryExpr +# 300| 0 +#-----| -> ... call to >= ... -# 301| DeclRefExpr -#-----| -> DeclRefExpr +# 301| print +#-----| -> x -# 301| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 301| call to print +#-----| exception -> exit loop1 (normal) +#-----| -> -= -# 301| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 301| default separator +#-----| -> default terminator -# 301| DefaultArgumentExpr -#-----| -> CallExpr +# 301| default terminator +#-----| -> call to print -# 301| ArrayExpr -#-----| -> VarargExpansionExpr +# 301| (Int) ... +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 301| DeclRefExpr -#-----| -> LoadExpr +# 301| (Any) ... +#-----| -> [...] -# 301| ErasureExpr -#-----| -> ArrayExpr +# 301| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 301| LoadExpr -#-----| -> ErasureExpr +# 301| [...] +#-----| -> default separator -# 301| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 301| [...] +#-----| -> [...] -# 302| DeclRefExpr -#-----| -> InOutExpr +# 301| x +#-----| -> (Int) ... -# 302| InOutExpr -#-----| -> IntegerLiteralExpr +# 302| &... +#-----| -> 1 -# 302| BinaryExpr -#-----| -> DeclRefExpr +# 302| x +#-----| -> &... -# 302| DeclRefExpr -#-----| -> TypeExpr +# 302| ... call to -= ... +#-----| -> >= -# 302| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 302| -= +#-----| -> Int.Type -# 302| TypeExpr -#-----| -> DotSyntaxCallExpr +# 302| Int.Type +#-----| -> call to -= -# 302| IntegerLiteralExpr -#-----| -> BinaryExpr +# 302| call to -= +#-----| exception -> exit loop1 (normal) +#-----| -> x -# 306| enter ConcreteFuncDecl -#-----| -> WhileStmt +# 302| 1 +#-----| -> ... call to -= ... -# 306| exit ConcreteFuncDecl +# 306| enter loop2 +#-----| -> while ... { ... } -# 306| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 306| exit loop2 -# 307| WhileStmt -#-----| -> DeclRefExpr +# 306| exit loop2 (normal) +#-----| -> exit loop2 -# 307| DeclRefExpr -#-----| -> LoadExpr +# 307| while ... { ... } +#-----| -> >= -# 307| LoadExpr -#-----| -> IntegerLiteralExpr +# 307| (Int) ... +#-----| -> 0 -# 307| BinaryExpr +# 307| x +#-----| -> (Int) ... + +# 307| ... call to >= ... #-----| -> StmtCondition # 307| StmtCondition -#-----| true -> DeclRefExpr -#-----| false -> DeclRefExpr +#-----| true -> print +#-----| false -> print -# 307| DeclRefExpr -#-----| -> TypeExpr +# 307| >= +#-----| -> Int.Type -# 307| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 307| Int.Type +#-----| -> call to >= -# 307| TypeExpr -#-----| -> DotSyntaxCallExpr +# 307| call to >= +#-----| exception -> exit loop2 (normal) +#-----| -> x -# 307| IntegerLiteralExpr -#-----| -> BinaryExpr +# 307| 0 +#-----| -> ... call to >= ... -# 308| DeclRefExpr -#-----| -> DeclRefExpr +# 308| print +#-----| -> x -# 308| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 308| call to print +#-----| exception -> exit loop2 (normal) +#-----| -> -= -# 308| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 308| default separator +#-----| -> default terminator -# 308| DefaultArgumentExpr -#-----| -> CallExpr +# 308| default terminator +#-----| -> call to print -# 308| ArrayExpr -#-----| -> VarargExpansionExpr +# 308| (Int) ... +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 308| DeclRefExpr -#-----| -> LoadExpr +# 308| (Any) ... +#-----| -> [...] -# 308| ErasureExpr -#-----| -> ArrayExpr +# 308| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 308| LoadExpr -#-----| -> ErasureExpr +# 308| [...] +#-----| -> default separator -# 308| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 308| [...] +#-----| -> [...] -# 309| DeclRefExpr -#-----| -> InOutExpr +# 308| x +#-----| -> (Int) ... -# 309| InOutExpr -#-----| -> IntegerLiteralExpr +# 309| &... +#-----| -> 1 -# 309| BinaryExpr -#-----| -> IfStmt +# 309| x +#-----| -> &... -# 309| DeclRefExpr -#-----| -> TypeExpr +# 309| ... call to -= ... +#-----| -> if ... then { ... } else { ... } -# 309| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 309| -= +#-----| -> Int.Type -# 309| TypeExpr -#-----| -> DotSyntaxCallExpr +# 309| Int.Type +#-----| -> call to -= -# 309| IntegerLiteralExpr -#-----| -> BinaryExpr +# 309| call to -= +#-----| exception -> exit loop2 (normal) +#-----| -> x -# 310| IfStmt -#-----| -> DeclRefExpr +# 309| 1 +#-----| -> ... call to -= ... -# 310| DeclRefExpr -#-----| -> LoadExpr +# 310| if ... then { ... } else { ... } +#-----| -> > -# 310| LoadExpr -#-----| -> IntegerLiteralExpr +# 310| (Int) ... +#-----| -> 100 -# 310| BinaryExpr +# 310| x +#-----| -> (Int) ... + +# 310| ... call to > ... #-----| -> StmtCondition # 310| StmtCondition -#-----| true -> BreakStmt -#-----| false -> IfStmt +#-----| true -> break +#-----| false -> if ... then { ... } -# 310| DeclRefExpr -#-----| -> TypeExpr +# 310| > +#-----| -> Int.Type -# 310| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 310| Int.Type +#-----| -> call to > -# 310| TypeExpr -#-----| -> DotSyntaxCallExpr +# 310| call to > +#-----| exception -> exit loop2 (normal) +#-----| -> x -# 310| IntegerLiteralExpr -#-----| -> BinaryExpr +# 310| 100 +#-----| -> ... call to > ... -# 311| BreakStmt -#-----| -> DeclRefExpr +# 311| break +#-----| -> print -# 313| IfStmt -#-----| -> DeclRefExpr +# 313| if ... then { ... } +#-----| -> > -# 313| DeclRefExpr -#-----| -> LoadExpr +# 313| (Int) ... +#-----| -> 50 -# 313| LoadExpr -#-----| -> IntegerLiteralExpr +# 313| x +#-----| -> (Int) ... -# 313| BinaryExpr +# 313| ... call to > ... #-----| -> StmtCondition # 313| StmtCondition -#-----| true -> ContinueStmt -#-----| false -> DeclRefExpr +#-----| true -> continue +#-----| false -> print -# 313| DeclRefExpr -#-----| -> TypeExpr +# 313| > +#-----| -> Int.Type -# 313| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 313| Int.Type +#-----| -> call to > -# 313| TypeExpr -#-----| -> DotSyntaxCallExpr +# 313| call to > +#-----| exception -> exit loop2 (normal) +#-----| -> x -# 313| IntegerLiteralExpr -#-----| -> BinaryExpr +# 313| 50 +#-----| -> ... call to > ... -# 314| ContinueStmt -#-----| continue -> DeclRefExpr +# 314| continue +#-----| continue -> >= -# 316| DeclRefExpr -#-----| -> StringLiteralExpr +# 316| print +#-----| -> Iter -# 316| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 316| call to print +#-----| exception -> exit loop2 (normal) +#-----| -> >= -# 316| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 316| default separator +#-----| -> default terminator -# 316| DefaultArgumentExpr -#-----| -> CallExpr +# 316| default terminator +#-----| -> call to print -# 316| ArrayExpr -#-----| -> VarargExpansionExpr +# 316| (Any) ... +#-----| -> [...] -# 316| ErasureExpr -#-----| -> ArrayExpr +# 316| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 316| StringLiteralExpr -#-----| -> ErasureExpr +# 316| Iter +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 316| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 316| [...] +#-----| -> default separator -# 318| DeclRefExpr -#-----| -> StringLiteralExpr +# 316| [...] +#-----| -> [...] -# 318| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) +# 318| print +#-----| -> Done -# 318| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 318| call to print +#-----| exception -> exit loop2 (normal) -# 318| DefaultArgumentExpr -#-----| -> CallExpr +# 318| default separator +#-----| -> default terminator -# 318| ArrayExpr -#-----| -> VarargExpansionExpr +# 318| default terminator +#-----| -> call to print -# 318| ErasureExpr -#-----| -> ArrayExpr +# 318| (Any) ... +#-----| -> [...] -# 318| StringLiteralExpr -#-----| -> ErasureExpr +# 318| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 318| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 318| Done +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 321| enter ConcreteFuncDecl -#-----| -> WhileStmt +# 318| [...] +#-----| -> default separator -# 321| exit ConcreteFuncDecl +# 318| [...] +#-----| -> [...] -# 321| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 321| enter labeledLoop +#-----| -> while ... { ... } -# 322| WhileStmt -#-----| -> DeclRefExpr +# 321| exit labeledLoop -# 322| DeclRefExpr -#-----| -> LoadExpr +# 321| exit labeledLoop (normal) +#-----| -> exit labeledLoop -# 322| LoadExpr -#-----| -> IntegerLiteralExpr +# 322| while ... { ... } +#-----| -> >= -# 322| BinaryExpr +# 322| (Int) ... +#-----| -> 0 + +# 322| x +#-----| -> (Int) ... + +# 322| ... call to >= ... #-----| -> StmtCondition # 322| StmtCondition -#-----| false -> exit ConcreteFuncDecl (normal) -#-----| true -> WhileStmt +#-----| false -> exit labeledLoop (normal) +#-----| true -> while ... { ... } -# 322| DeclRefExpr -#-----| -> TypeExpr +# 322| >= +#-----| -> Int.Type -# 322| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 322| Int.Type +#-----| -> call to >= -# 322| TypeExpr -#-----| -> DotSyntaxCallExpr +# 322| call to >= +#-----| exception -> exit labeledLoop (normal) +#-----| -> x -# 322| IntegerLiteralExpr -#-----| -> BinaryExpr +# 322| 0 +#-----| -> ... call to >= ... -# 323| WhileStmt -#-----| -> DeclRefExpr +# 323| while ... { ... } +#-----| -> >= -# 323| DeclRefExpr -#-----| -> LoadExpr +# 323| (Int) ... +#-----| -> 0 -# 323| LoadExpr -#-----| -> IntegerLiteralExpr +# 323| x +#-----| -> (Int) ... -# 323| BinaryExpr +# 323| ... call to >= ... #-----| -> StmtCondition # 323| StmtCondition -#-----| true -> DeclRefExpr -#-----| false -> DeclRefExpr +#-----| true -> print +#-----| false -> print -# 323| DeclRefExpr -#-----| -> TypeExpr +# 323| >= +#-----| -> Int.Type -# 323| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 323| Int.Type +#-----| -> call to >= -# 323| TypeExpr -#-----| -> DotSyntaxCallExpr +# 323| call to >= +#-----| exception -> exit labeledLoop (normal) +#-----| -> x -# 323| IntegerLiteralExpr -#-----| -> BinaryExpr +# 323| 0 +#-----| -> ... call to >= ... -# 324| DeclRefExpr -#-----| -> DeclRefExpr +# 324| print +#-----| -> x -# 324| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 324| call to print +#-----| exception -> exit labeledLoop (normal) +#-----| -> -= -# 324| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 324| default separator +#-----| -> default terminator -# 324| DefaultArgumentExpr -#-----| -> CallExpr +# 324| default terminator +#-----| -> call to print -# 324| ArrayExpr -#-----| -> VarargExpansionExpr +# 324| (Int) ... +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 324| DeclRefExpr -#-----| -> LoadExpr +# 324| (Any) ... +#-----| -> [...] -# 324| ErasureExpr -#-----| -> ArrayExpr +# 324| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 324| LoadExpr -#-----| -> ErasureExpr +# 324| [...] +#-----| -> default separator -# 324| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 324| [...] +#-----| -> [...] -# 325| DeclRefExpr -#-----| -> InOutExpr +# 324| x +#-----| -> (Int) ... -# 325| InOutExpr -#-----| -> IntegerLiteralExpr +# 325| &... +#-----| -> 1 -# 325| BinaryExpr -#-----| -> IfStmt +# 325| x +#-----| -> &... -# 325| DeclRefExpr -#-----| -> TypeExpr +# 325| ... call to -= ... +#-----| -> if ... then { ... } else { ... } -# 325| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 325| -= +#-----| -> Int.Type -# 325| TypeExpr -#-----| -> DotSyntaxCallExpr +# 325| Int.Type +#-----| -> call to -= -# 325| IntegerLiteralExpr -#-----| -> BinaryExpr +# 325| call to -= +#-----| exception -> exit labeledLoop (normal) +#-----| -> x -# 326| IfStmt -#-----| -> DeclRefExpr +# 325| 1 +#-----| -> ... call to -= ... -# 326| DeclRefExpr -#-----| -> LoadExpr +# 326| if ... then { ... } else { ... } +#-----| -> > -# 326| LoadExpr -#-----| -> IntegerLiteralExpr +# 326| (Int) ... +#-----| -> 100 -# 326| BinaryExpr +# 326| x +#-----| -> (Int) ... + +# 326| ... call to > ... #-----| -> StmtCondition # 326| StmtCondition -#-----| true -> BreakStmt -#-----| false -> IfStmt +#-----| true -> break outer +#-----| false -> if ... then { ... } -# 326| DeclRefExpr -#-----| -> TypeExpr +# 326| > +#-----| -> Int.Type -# 326| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 326| Int.Type +#-----| -> call to > -# 326| TypeExpr -#-----| -> DotSyntaxCallExpr +# 326| call to > +#-----| exception -> exit labeledLoop (normal) +#-----| -> x -# 326| IntegerLiteralExpr -#-----| -> BinaryExpr +# 326| 100 +#-----| -> ... call to > ... -# 327| BreakStmt -#-----| -> exit ConcreteFuncDecl (normal) +# 327| break outer +#-----| -> exit labeledLoop (normal) -# 329| IfStmt -#-----| -> DeclRefExpr +# 329| if ... then { ... } +#-----| -> > -# 329| DeclRefExpr -#-----| -> LoadExpr +# 329| (Int) ... +#-----| -> 50 -# 329| LoadExpr -#-----| -> IntegerLiteralExpr +# 329| x +#-----| -> (Int) ... -# 329| BinaryExpr +# 329| ... call to > ... #-----| -> StmtCondition # 329| StmtCondition -#-----| true -> ContinueStmt -#-----| false -> DeclRefExpr +#-----| true -> continue inner +#-----| false -> print -# 329| DeclRefExpr -#-----| -> TypeExpr +# 329| > +#-----| -> Int.Type -# 329| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 329| Int.Type +#-----| -> call to > -# 329| TypeExpr -#-----| -> DotSyntaxCallExpr +# 329| call to > +#-----| exception -> exit labeledLoop (normal) +#-----| -> x -# 329| IntegerLiteralExpr -#-----| -> BinaryExpr +# 329| 50 +#-----| -> ... call to > ... -# 330| ContinueStmt -#-----| continue -> DeclRefExpr +# 330| continue inner +#-----| continue -> >= -# 332| DeclRefExpr -#-----| -> StringLiteralExpr +# 332| print +#-----| -> Iter -# 332| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 332| call to print +#-----| exception -> exit labeledLoop (normal) +#-----| -> >= -# 332| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 332| default separator +#-----| -> default terminator -# 332| DefaultArgumentExpr -#-----| -> CallExpr +# 332| default terminator +#-----| -> call to print -# 332| ArrayExpr -#-----| -> VarargExpansionExpr +# 332| (Any) ... +#-----| -> [...] -# 332| ErasureExpr -#-----| -> ArrayExpr +# 332| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 332| StringLiteralExpr -#-----| -> ErasureExpr +# 332| Iter +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 332| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 332| [...] +#-----| -> default separator -# 334| DeclRefExpr -#-----| -> StringLiteralExpr +# 332| [...] +#-----| -> [...] -# 334| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 334| print +#-----| -> Done -# 334| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 334| call to print +#-----| exception -> exit labeledLoop (normal) +#-----| -> >= -# 334| DefaultArgumentExpr -#-----| -> CallExpr +# 334| default separator +#-----| -> default terminator -# 334| ArrayExpr -#-----| -> VarargExpansionExpr +# 334| default terminator +#-----| -> call to print -# 334| ErasureExpr -#-----| -> ArrayExpr +# 334| (Any) ... +#-----| -> [...] -# 334| StringLiteralExpr -#-----| -> ErasureExpr +# 334| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 334| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 334| Done +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 338| enter ConcreteFuncDecl -#-----| -> RepeatWhileStmt +# 334| [...] +#-----| -> default separator -# 338| exit ConcreteFuncDecl +# 334| [...] +#-----| -> [...] -# 338| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 338| enter testRepeat +#-----| -> repeat { ... } while ... -# 339| RepeatWhileStmt -#-----| -> DeclRefExpr +# 338| exit testRepeat -# 340| DeclRefExpr -#-----| -> DeclRefExpr +# 338| exit testRepeat (normal) +#-----| -> exit testRepeat -# 340| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 339| repeat { ... } while ... +#-----| -> print -# 340| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 340| print +#-----| -> x -# 340| DefaultArgumentExpr -#-----| -> CallExpr +# 340| call to print +#-----| exception -> exit testRepeat (normal) +#-----| -> -= -# 340| ArrayExpr -#-----| -> VarargExpansionExpr +# 340| default separator +#-----| -> default terminator -# 340| DeclRefExpr -#-----| -> LoadExpr +# 340| default terminator +#-----| -> call to print -# 340| ErasureExpr -#-----| -> ArrayExpr +# 340| (Int) ... +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 340| LoadExpr -#-----| -> ErasureExpr +# 340| (Any) ... +#-----| -> [...] -# 340| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 340| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 341| DeclRefExpr -#-----| -> InOutExpr +# 340| [...] +#-----| -> default separator -# 341| InOutExpr -#-----| -> IntegerLiteralExpr +# 340| [...] +#-----| -> [...] -# 341| BinaryExpr -#-----| -> DeclRefExpr +# 340| x +#-----| -> (Int) ... -# 341| DeclRefExpr -#-----| -> TypeExpr +# 341| &... +#-----| -> 1 -# 341| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 341| x +#-----| -> &... -# 341| TypeExpr -#-----| -> DotSyntaxCallExpr +# 341| ... call to -= ... +#-----| -> >= -# 341| IntegerLiteralExpr -#-----| -> BinaryExpr +# 341| -= +#-----| -> Int.Type -# 342| DeclRefExpr -#-----| -> LoadExpr +# 341| Int.Type +#-----| -> call to -= -# 342| LoadExpr -#-----| -> IntegerLiteralExpr +# 341| call to -= +#-----| exception -> exit testRepeat (normal) +#-----| -> x -# 342| BinaryExpr -#-----| false -> exit ConcreteFuncDecl (normal) -#-----| true -> DeclRefExpr +# 341| 1 +#-----| -> ... call to -= ... -# 342| DeclRefExpr -#-----| -> TypeExpr +# 342| (Int) ... +#-----| -> 0 -# 342| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 342| x +#-----| -> (Int) ... -# 342| TypeExpr -#-----| -> DotSyntaxCallExpr +# 342| ... call to >= ... +#-----| false -> exit testRepeat (normal) +#-----| true -> print -# 342| IntegerLiteralExpr -#-----| -> BinaryExpr +# 342| >= +#-----| -> Int.Type -# 345| enter ConcreteFuncDecl -#-----| -> NamedPattern +# 342| Int.Type +#-----| -> call to >= -# 345| exit ConcreteFuncDecl +# 342| call to >= +#-----| exception -> exit testRepeat (normal) +#-----| -> x -# 345| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 342| 0 +#-----| -> ... call to >= ... -# 346| PatternBindingDecl -#-----| -> ConcreteVarDecl +# 345| enter loop_with_identity_expr +#-----| -> x -# 346| ConcreteVarDecl -#-----| -> WhileStmt +# 345| exit loop_with_identity_expr -# 346| NamedPattern -#-----| -> IntegerLiteralExpr +# 345| exit loop_with_identity_expr (normal) +#-----| -> exit loop_with_identity_expr -# 346| IntegerLiteralExpr -#-----| -> PatternBindingDecl +# 346| var ... = ... +#-----| -> x -# 347| WhileStmt -#-----| -> DeclRefExpr +# 346| x +#-----| -> 0 -# 347| ParenExpr +# 346| x +#-----| -> while ... { ... } + +# 346| 0 +#-----| -> var ... = ... + +# 347| while ... { ... } +#-----| -> < + +# 347| (...) #-----| -> StmtCondition # 347| StmtCondition -#-----| false -> exit ConcreteFuncDecl (normal) -#-----| true -> DeclRefExpr +#-----| false -> exit loop_with_identity_expr (normal) +#-----| true -> += -# 347| DeclRefExpr -#-----| -> LoadExpr +# 347| (Int) ... +#-----| -> 10 -# 347| LoadExpr -#-----| -> IntegerLiteralExpr +# 347| x +#-----| -> (Int) ... -# 347| BinaryExpr -#-----| -> ParenExpr +# 347| ... call to < ... +#-----| -> (...) -# 347| DeclRefExpr -#-----| -> TypeExpr +# 347| < +#-----| -> Int.Type -# 347| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 347| Int.Type +#-----| -> call to < -# 347| TypeExpr -#-----| -> DotSyntaxCallExpr +# 347| call to < +#-----| exception -> exit loop_with_identity_expr (normal) +#-----| -> x -# 347| IntegerLiteralExpr -#-----| -> BinaryExpr +# 347| 10 +#-----| -> ... call to < ... -# 348| DeclRefExpr -#-----| -> InOutExpr +# 348| &... +#-----| -> 1 -# 348| InOutExpr -#-----| -> IntegerLiteralExpr +# 348| x +#-----| -> &... -# 348| BinaryExpr -#-----| -> DeclRefExpr +# 348| ... call to += ... +#-----| -> < -# 348| DeclRefExpr -#-----| -> TypeExpr +# 348| += +#-----| -> Int.Type -# 348| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 348| Int.Type +#-----| -> call to += -# 348| TypeExpr -#-----| -> DotSyntaxCallExpr +# 348| call to += +#-----| exception -> exit loop_with_identity_expr (normal) +#-----| -> x -# 348| IntegerLiteralExpr -#-----| -> BinaryExpr +# 348| 1 +#-----| -> ... call to += ... -# 353| enter AccessorDecl +# 353| enter get -# 353| exit AccessorDecl +# 353| exit get -# 353| exit AccessorDecl (normal) -#-----| -> exit AccessorDecl +# 353| exit get (normal) +#-----| -> exit get -# 354| enter ConstructorDecl -#-----| -> DeclRefExpr +# 354| enter deinit +#-----| -> self -# 354| exit ConstructorDecl +# 354| exit deinit -# 354| exit ConstructorDecl (normal) -#-----| -> exit ConstructorDecl +# 354| exit deinit (normal) +#-----| -> exit deinit -# 355| DeclRefExpr -#-----| -> MemberRefExpr +# 355| .c +#-----| -> arg -# 355| MemberRefExpr -#-----| -> DeclRefExpr +# 355| self +#-----| -> .c -# 355| AssignExpr -#-----| -> ReturnStmt +# 355| ... = ... +#-----| -> return -# 355| DeclRefExpr -#-----| -> AssignExpr +# 355| arg +#-----| -> ... = ... -# 356| ReturnStmt -#-----| return -> exit ConstructorDecl (normal) +# 356| return +#-----| return -> exit deinit (normal) -# 358| enter ConcreteFuncDecl -#-----| -> DeclRefExpr +# 358| enter getOptional +#-----| -> self -# 358| exit ConcreteFuncDecl +# 358| exit getOptional -# 358| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 358| exit getOptional (normal) +#-----| -> exit getOptional -# 359| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 359| return ... +#-----| return -> exit getOptional (normal) -# 359| DeclRefExpr -#-----| -> MemberRefExpr +# 359| getter for .c +#-----| -> return ... -# 359| MemberRefExpr -#-----| -> ReturnStmt +# 359| self +#-----| -> getter for .c -# 363| enter ConcreteFuncDecl -#-----| -> DeclRefExpr +# 363| enter testOptional +#-----| -> getMyInt -# 363| exit ConcreteFuncDecl +# 363| exit testOptional -# 363| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 363| exit testOptional (normal) +#-----| -> exit testOptional -# 364| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 364| return ... +#-----| return -> exit testOptional (normal) -# 364| DeclRefExpr -#-----| -> BindOptionalExpr +# 364| c +#-----| -> ...? -# 364| BindOptionalExpr -#-----| -> DotSyntaxCallExpr +# 364| ...? +#-----| -> call to getOptional -# 364| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 364| call to getOptional +#-----| exception -> exit testOptional (normal) +#-----| -> call to ... -# 364| CallExpr -#-----| -> BindOptionalExpr +# 364| call to ... +#-----| -> ...? -# 364| BindOptionalExpr -#-----| -> DotSyntaxCallExpr +# 364| ...? +#-----| -> call to getMyInt -# 364| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> CallExpr +# 364| call to getMyInt +#-----| exception -> exit testOptional (normal) +#-----| -> call to ... -# 364| CallExpr -#-----| -> InjectIntoOptionalExpr - -# 364| InjectIntoOptionalExpr +# 364| (Int?) ... #-----| -> OptionalEvaluationExpr # 364| OptionalEvaluationExpr -#-----| -> ReturnStmt +#-----| -> return ... -# 364| DeclRefExpr -#-----| -> DeclRefExpr +# 364| call to ... +#-----| -> (Int?) ... -# 364| DeclRefExpr -#-----| -> DeclRefExpr +# 364| getOptional +#-----| -> c -# 367| enter ConcreteFuncDecl -#-----| -> NamedPattern +# 364| getMyInt +#-----| -> getOptional -# 367| exit ConcreteFuncDecl +# 367| enter testCapture +#-----| -> z -# 367| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 367| exit testCapture -# 368| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 367| exit testCapture (normal) +#-----| -> exit testCapture -# 368| CaptureListExpr -#-----| -> ReturnStmt +# 368| return ... +#-----| return -> exit testCapture (normal) -# 368| ClosureExpr -#-----| -> CaptureListExpr +# 368| { ... } +#-----| -> return ... -# 368| NamedPattern -#-----| -> DeclRefExpr +# 368| { ... } +#-----| -> { ... } -# 368| PatternBindingDecl -#-----| -> NamedPattern +# 368| z +#-----| -> + -# 368| DeclRefExpr -#-----| -> DeclRefExpr +# 368| var ... = ... +#-----| -> t -# 368| BinaryExpr -#-----| -> PatternBindingDecl +# 368| x +#-----| -> y -# 368| DeclRefExpr -#-----| -> TypeExpr +# 368| ... call to + ... +#-----| -> var ... = ... -# 368| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 368| + +#-----| -> Int.Type -# 368| TypeExpr -#-----| -> DotSyntaxCallExpr +# 368| Int.Type +#-----| -> call to + -# 368| DeclRefExpr -#-----| -> BinaryExpr +# 368| call to + +#-----| exception -> exit testCapture (normal) +#-----| -> x -# 368| NamedPattern -#-----| -> StringLiteralExpr +# 368| y +#-----| -> ... call to + ... -# 368| PatternBindingDecl -#-----| -> ClosureExpr +# 368| t +#-----| -> literal -# 368| StringLiteralExpr -#-----| -> PatternBindingDecl +# 368| var ... = ... +#-----| -> { ... } -# 373| enter ConcreteFuncDecl -#-----| -> DeclRefExpr +# 368| literal +#-----| -> var ... = ... -# 373| exit ConcreteFuncDecl +# 373| enter testTupleElement +#-----| -> + -# 373| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 373| exit testTupleElement -# 374| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 373| exit testTupleElement (normal) +#-----| -> exit testTupleElement -# 374| DeclRefExpr -#-----| -> TupleElementExpr +# 374| return ... +#-----| return -> exit testTupleElement (normal) -# 374| TupleElementExpr -#-----| -> DeclRefExpr +# 374| t +#-----| -> .0 -# 374| BinaryExpr -#-----| -> DeclRefExpr +# 374| .0 +#-----| -> t -# 374| BinaryExpr -#-----| -> IntegerLiteralExpr +# 374| ... call to + ... +#-----| -> t -# 374| BinaryExpr -#-----| -> ReturnStmt +# 374| ... call to + ... +#-----| -> 1 -# 374| DeclRefExpr -#-----| -> TypeExpr +# 374| ... call to + ... +#-----| -> return ... -# 374| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 374| + +#-----| -> Int.Type -# 374| TypeExpr -#-----| -> DotSyntaxCallExpr +# 374| Int.Type +#-----| -> call to + -# 374| DeclRefExpr -#-----| -> TupleElementExpr +# 374| call to + +#-----| exception -> exit testTupleElement (normal) +#-----| -> t -# 374| TupleElementExpr -#-----| -> BinaryExpr +# 374| t +#-----| -> .1 -# 374| DeclRefExpr -#-----| -> TypeExpr +# 374| .1 +#-----| -> ... call to + ... -# 374| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 374| + +#-----| -> Int.Type -# 374| TypeExpr -#-----| -> DotSyntaxCallExpr +# 374| Int.Type +#-----| -> call to + -# 374| DeclRefExpr -#-----| -> TupleElementExpr +# 374| call to + +#-----| exception -> exit testTupleElement (normal) +#-----| -> + -# 374| TupleElementExpr -#-----| -> BinaryExpr +# 374| t +#-----| -> .2 -# 374| DeclRefExpr -#-----| -> TypeExpr +# 374| .2 +#-----| -> ... call to + ... -# 374| DotSyntaxCallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> DeclRefExpr +# 374| + +#-----| -> Int.Type -# 374| TypeExpr -#-----| -> DotSyntaxCallExpr +# 374| Int.Type +#-----| -> call to + -# 374| TupleExpr -#-----| -> TupleElementExpr +# 374| call to + +#-----| exception -> exit testTupleElement (normal) +#-----| -> + -# 374| TupleElementExpr -#-----| -> BinaryExpr +# 374| (...) +#-----| -> .0 -# 374| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 374| .0 +#-----| -> ... call to + ... -# 374| IntegerLiteralExpr -#-----| -> IntegerLiteralExpr +# 374| 1 +#-----| -> 2 -# 374| IntegerLiteralExpr -#-----| -> TupleExpr +# 374| 2 +#-----| -> 3 -# 377| CallExpr -#-----| exception -> exit ConstructorDecl (normal) +# 374| 3 +#-----| -> (...) -# 377| DeclRefExpr -#-----| -> StringLiteralExpr +# 377| #... +#-----| -> #... -# 377| MagicIdentifierLiteralExpr -#-----| -> MagicIdentifierLiteralExpr +# 377| #... +#-----| -> #... -# 377| MagicIdentifierLiteralExpr -#-----| -> MagicIdentifierLiteralExpr +# 377| #... +#-----| -> #... -# 377| MagicIdentifierLiteralExpr -#-----| -> MagicIdentifierLiteralExpr +# 377| #... +#-----| -> call to _unimplementedInitializer -# 377| MagicIdentifierLiteralExpr -#-----| -> CallExpr +# 377| _unimplementedInitializer +#-----| -> cfg.Derived -# 377| StringLiteralExpr -#-----| -> MagicIdentifierLiteralExpr +# 377| call to _unimplementedInitializer +#-----| exception -> exit deinit (normal) -# 377| enter ConstructorDecl -#-----| -> DeclRefExpr +# 377| cfg.Derived +#-----| -> #... -# 377| exit ConstructorDecl +# 377| enter deinit +#-----| -> _unimplementedInitializer -# 377| exit ConstructorDecl (normal) -#-----| -> exit ConstructorDecl +# 377| exit deinit -# 378| enter ConstructorDecl +# 377| exit deinit (normal) +#-----| -> exit deinit + +# 378| enter deinit +#-----| -> call to ... #-----| -> TBD (OtherConstructorDeclRefExpr) -# 378| exit ConstructorDecl +# 378| exit deinit -# 378| exit ConstructorDecl (normal) -#-----| -> exit ConstructorDecl +# 378| exit deinit (normal) +#-----| -> exit deinit -# 379| SuperRefExpr -#-----| -> DotSyntaxCallExpr +# 379| super +#-----| -> call to ... -# 379| DotSyntaxCallExpr -#-----| -> IntegerLiteralExpr +# 379| call to ... +#-----| -> 0 -# 379| CallExpr -#-----| -> RebindSelfInConstructorExpr +# 379| call to ... +#-----| -> self = ... -# 379| RebindSelfInConstructorExpr -#-----| -> ReturnStmt +# 379| self = ... +#-----| -> return + +# 379| call to ... +#-----| -> super # 379| TBD (OtherConstructorDeclRefExpr) -#-----| -> SuperRefExpr +#-----| -> super -# 379| IntegerLiteralExpr -#-----| -> CallExpr +# 379| 0 +#-----| -> call to ... -# 380| ReturnStmt -#-----| return -> exit ConstructorDecl (normal) +# 380| return +#-----| return -> exit deinit (normal) -# 383| enter ConcreteFuncDecl -#-----| -> DoStmt +# 383| enter doWithoutCatch +#-----| -> do { ... } -# 383| exit ConcreteFuncDecl +# 383| exit doWithoutCatch -# 383| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 383| exit doWithoutCatch (normal) +#-----| -> exit doWithoutCatch -# 384| DoStmt -#-----| -> DeclRefExpr +# 384| do { ... } +#-----| -> mightThrow -# 385| TryExpr -#-----| -> DeclRefExpr +# 385| try ... +#-----| -> print -# 385| DeclRefExpr -#-----| -> IntegerLiteralExpr +# 385| mightThrow +#-----| -> 0 -# 385| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) -#-----| -> TryExpr +# 385| call to mightThrow +#-----| exception -> exit doWithoutCatch (normal) +#-----| -> try ... -# 385| IntegerLiteralExpr -#-----| -> CallExpr +# 385| 0 +#-----| -> call to mightThrow -# 386| DeclRefExpr -#-----| -> StringLiteralExpr +# 386| print +#-----| -> Did not throw. -# 386| CallExpr -#-----| exception -> exit ConcreteFuncDecl (normal) +# 386| call to print +#-----| exception -> exit doWithoutCatch (normal) -# 386| DefaultArgumentExpr -#-----| -> DefaultArgumentExpr +# 386| default separator +#-----| -> default terminator -# 386| DefaultArgumentExpr -#-----| -> CallExpr +# 386| default terminator +#-----| -> call to print -# 386| ArrayExpr -#-----| -> VarargExpansionExpr +# 386| (Any) ... +#-----| -> [...] -# 386| ErasureExpr -#-----| -> ArrayExpr +# 386| (TBD (ProtocolCompositionType)) ... +#-----| -> [...] -# 386| StringLiteralExpr -#-----| -> ErasureExpr +# 386| Did not throw. +#-----| -> (Any) ... +#-----| -> (TBD (ProtocolCompositionType)) ... -# 386| VarargExpansionExpr -#-----| -> DefaultArgumentExpr +# 386| [...] +#-----| -> default separator -# 394| TBD (YieldStmt) -#-----| -> exit AccessorDecl (normal) +# 386| [...] +#-----| -> [...] -# 394| enter AccessorDecl - -# 394| enter AccessorDecl - -# 394| enter AccessorDecl +# 394| enter (unnamed function decl) +#-----| -> yield ... #-----| -> TBD (YieldStmt) -# 394| exit AccessorDecl +# 394| enter get -# 394| exit AccessorDecl +# 394| enter set -# 394| exit AccessorDecl +# 394| exit (unnamed function decl) -# 394| exit AccessorDecl (normal) -#-----| -> exit AccessorDecl +# 394| exit (unnamed function decl) (normal) +#-----| -> exit (unnamed function decl) -# 394| exit AccessorDecl (normal) -#-----| -> exit AccessorDecl +# 394| exit get -# 394| exit AccessorDecl (normal) -#-----| -> exit AccessorDecl +# 394| exit get (normal) +#-----| -> exit get -# 395| enter ConstructorDecl -#-----| -> DeclRefExpr +# 394| exit set -# 395| exit ConstructorDecl +# 394| exit set (normal) +#-----| -> exit set -# 395| exit ConstructorDecl (normal) -#-----| -> exit ConstructorDecl +# 394| yield ... +#-----| -> exit (unnamed function decl) (normal) -# 396| DeclRefExpr -#-----| -> MemberRefExpr +# 394| TBD (YieldStmt) +#-----| -> exit (unnamed function decl) (normal) -# 396| MemberRefExpr -#-----| -> IntegerLiteralExpr +# 395| enter deinit +#-----| -> self -# 396| AssignExpr -#-----| -> ReturnStmt +# 395| exit deinit -# 396| IntegerLiteralExpr -#-----| -> AssignExpr +# 395| exit deinit (normal) +#-----| -> exit deinit -# 397| ReturnStmt -#-----| return -> exit ConstructorDecl (normal) +# 396| .field +#-----| -> 10 -# 399| enter DestructorDecl -#-----| -> DeclRefExpr +# 396| self +#-----| -> .field -# 399| exit DestructorDecl +# 396| ... = ... +#-----| -> return -# 399| exit DestructorDecl (normal) -#-----| -> exit DestructorDecl +# 396| 10 +#-----| -> ... = ... -# 400| DeclRefExpr -#-----| -> MemberRefExpr +# 397| return +#-----| return -> exit deinit (normal) -# 400| MemberRefExpr -#-----| -> IntegerLiteralExpr +# 399| enter init +#-----| -> self -# 400| AssignExpr -#-----| -> exit DestructorDecl (normal) +# 399| exit init -# 400| IntegerLiteralExpr -#-----| -> AssignExpr +# 399| exit init (normal) +#-----| -> exit init -# 404| enter ConcreteFuncDecl -#-----| -> StringLiteralExpr +# 400| .field +#-----| -> 0 -# 404| exit ConcreteFuncDecl +# 400| self +#-----| -> .field -# 404| exit ConcreteFuncDecl (normal) -#-----| -> exit ConcreteFuncDecl +# 400| ... = ... +#-----| -> exit init (normal) -# 405| ReturnStmt -#-----| return -> exit ConcreteFuncDecl (normal) +# 400| 0 +#-----| -> ... = ... -# 405| DictionaryExpr -#-----| -> ReturnStmt +# 404| enter dictionaryLiteral +#-----| -> x -# 405| StringLiteralExpr -#-----| -> DeclRefExpr +# 404| exit dictionaryLiteral -# 405| TupleExpr -#-----| -> StringLiteralExpr +# 404| exit dictionaryLiteral (normal) +#-----| -> exit dictionaryLiteral -# 405| DeclRefExpr -#-----| -> TupleExpr +# 405| return ... +#-----| return -> exit dictionaryLiteral (normal) -# 405| StringLiteralExpr -#-----| -> DeclRefExpr +# 405| [...] +#-----| -> return ... -# 405| TupleExpr -#-----| -> DictionaryExpr +# 405| x +#-----| -> x -# 405| DeclRefExpr -#-----| -> TupleExpr +# 405| (...) +#-----| -> y + +# 405| x +#-----| -> (...) + +# 405| y +#-----| -> y + +# 405| (...) +#-----| -> [...] + +# 405| y +#-----| -> (...) diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected new file mode 100644 index 00000000000..92fe3d7565c --- /dev/null +++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected @@ -0,0 +1,14 @@ +| file://:0:0:0:0 | Phi | test.swift:15:15:15:15 | t2 | +| file://:0:0:0:0 | Phi | test.swift:21:15:21:15 | t1 | +| test.swift:6:9:6:13 | WriteDef | test.swift:7:15:7:15 | t1 | +| test.swift:7:15:7:15 | t1 | test.swift:8:10:8:10 | t1 | +| test.swift:8:5:8:10 | WriteDef | test.swift:10:15:10:15 | t2 | +| test.swift:8:10:8:10 | t1 | test.swift:8:5:8:10 | WriteDef | +| test.swift:8:10:8:10 | t1 | test.swift:9:15:9:15 | t1 | +| test.swift:9:15:9:15 | t1 | test.swift:11:8:11:8 | t1 | +| test.swift:12:9:12:14 | WriteDef | test.swift:13:19:13:19 | t2 | +| test.swift:12:14:12:14 | 0 | test.swift:12:9:12:14 | WriteDef | +| test.swift:15:15:15:15 | t2 | test.swift:19:14:19:14 | t2 | +| test.swift:17:10:17:10 | 0 | test.swift:17:5:17:10 | WriteDef | +| test.swift:19:14:19:14 | t2 | test.swift:19:9:19:14 | WriteDef | +| test.swift:19:14:19:14 | t2 | test.swift:19:14:19:14 | t2 | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.ql b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.ql new file mode 100644 index 00000000000..04a547b939d --- /dev/null +++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.ql @@ -0,0 +1,6 @@ +import swift +import codeql.swift.dataflow.DataFlow + +from DataFlow::Node pred, DataFlow::Node succ +where DataFlow::localFlowStep(pred, succ) +select pred, succ diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift new file mode 100644 index 00000000000..d20fecb54d7 --- /dev/null +++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift @@ -0,0 +1,22 @@ +func source() -> Int { return 0; } +func sink(arg: Int) {} + +func intraprocedural_with_local_flow() -> Void { + var t2: Int + var t1: Int = source() + sink(arg: t1) + t2 = t1 + sink(arg: t1) + sink(arg: t2) + if(t1 != 0) { + t2 = 0 + sink(arg: t2) + } + sink(arg: t2) + + t1 = 0; + while(false) { + t1 = t2 + } + sink(arg: t1) +}