Compare commits

...

45 Commits

Author SHA1 Message Date
Nick Rolfe
e287e4b316 Ruby: compress TRAP with Brotli 2022-07-29 19:52:10 +01:00
Jeroen Ketema
b50f4bc1a8 Merge pull request #9903 from jketema/builtin
C++: Support additional compiler builtin operations
2022-07-29 17:20:19 +02:00
Paolo Tranquilli
13f2cf9003 Merge pull request #9922 from github/redsun82/swift-precompiled-modules-are-not-extracted
Swift: extract precompiled swiftmodule files
2022-07-29 16:43:34 +02:00
Paolo Tranquilli
daf1fa3c31 Swift: lock built swiftmodule traps in main
This should cover `-merge-modules` mode.

Dumping of the configuration to the target files was moved to a
separate pair of header/source files, as now it is also done in
`SwiftOutputRewrite.cpp`.
2022-07-29 16:27:55 +02:00
Paolo Tranquilli
405d0fcd54 Merge branch 'main' into redsun82/swift-precompiled-modules-are-not-extracted 2022-07-29 15:57:52 +02:00
Tony Torralba
593ce01362 Merge pull request #9908 from atorralba/atorralba/xml-inline-exp-test
Java: Add support for XML InlineExpectationsTest
2022-07-29 14:49:19 +02:00
AlexDenisov
48e93b3654 Merge pull request #9925 from github/alexdenisov/pcm-var-dedup
Swift: do not deduplicate PCM variables (as the mangler crashes there sometimes)
2022-07-29 14:30:41 +02:00
AlexDenisov
22c5b7af4f Merge pull request #9921 from github/alexdenisov/type-alias-mangling
Swift: mangle TypeAliasDecls differently
2022-07-29 14:30:28 +02:00
Alex Denisov
34edb2537f Swift: mangle TypeAliasDecls differently 2022-07-29 14:12:02 +02:00
Alex Denisov
5b1fe56d5f Swift: do not deduplicate PCM variables (as the mangler crashes there sometimes) 2022-07-29 14:06:18 +02:00
Tony Torralba
ec03ebbbfc Add spurious and missing test cases 2022-07-29 13:44:25 +02:00
Tony Torralba
6091f0dbce Use camelCase for XML acronym 2022-07-29 13:44:11 +02:00
Paolo Tranquilli
099ab0e0c2 Swift: readd .trap suffix to swiftmodule trap files 2022-07-29 12:26:33 +02:00
Paolo Tranquilli
604328ea5f Swift: strip suffix from swiftmodule trap files 2022-07-29 12:25:11 +02:00
Paolo Tranquilli
652230d021 Merge branch 'main' into redsun82/swift-precompiled-modules-are-not-extracted 2022-07-29 12:21:15 +02:00
Paolo Tranquilli
69633948ce Merge pull request #9920 from github/alexdenisov/colocate-pcms
Swift: put all the PCM traps into the same place
2022-07-29 12:20:58 +02:00
Paolo Tranquilli
065fecc57e Swift: extract precompiled swiftmodule files
Previously we were not extracting any `swiftmodule` file that was not
a system or a built-in one. This was done to avoid re-extracting
`swiftmodule` files that were built previously in the same build, but it
turned out to be too eager, as there are legitimate cases where a
non-system, non-built-in precompiled swift module can be used. An
example of that is the `PackageDescription` module used in Swift
Package Manager manifest files (`Package.swift`).

We now relax the test and trigger module extraction on all loaded
modules that do not have source files (we trigger source file extraction
for those). The catch, is that we also create empty trap files for
current output `swiftmodule` files (including possible alias locations
set up by XCode).

This means that if a following extractor run loads a previously built
`swiftmodule` file, although it will trigger module extraction, this
will however be skipped as it will find its target file already present
(this is done via the `TargetFile` semantics).
2022-07-29 11:10:03 +02:00
Alex Denisov
50e1ffda64 Swift: put all the PCM traps into the same place 2022-07-29 10:19:13 +02:00
Jeroen Ketema
a27b1ee33a C++: Improve ErrorExpr documentation to match current practise 2022-07-29 09:08:56 +02:00
Jeroen Ketema
5a59354d73 C++: Minor clean up of the builtin operations qldoc 2022-07-29 09:08:56 +02:00
Jeroen Ketema
bce253920c C++: Fix __builtin_shuffle qldoc 2022-07-29 09:08:56 +02:00
Jeroen Ketema
afdd21eab7 C++: Update DB scheme stats file 2022-07-29 09:08:56 +02:00
Jeroen Ketema
295ecbb401 C++: Add upgrade and downgrade scripts for new builtins 2022-07-29 09:08:56 +02:00
Jeroen Ketema
1806b8933f C++: Add change note for newly added builtins 2022-07-29 09:08:56 +02:00
Jeroen Ketema
20b66eaf34 C++: Support __builtin_shuffle builtin
While here write gcc instead of GNU, which is more accurate.
2022-07-29 09:08:56 +02:00
Jeroen Ketema
81e687ea98 C++: Support __builtin_bit_cast builtin 2022-07-29 09:08:56 +02:00
Jeroen Ketema
a85d3f9b7f C++: Support __has_unique_object_representations builtin 2022-07-29 09:08:56 +02:00
Jeroen Ketema
0c03935437 C++: Support __is_aggregate builtin
Fix some whitespace issues while here.
2022-07-29 09:08:56 +02:00
Jeroen Ketema
c4283dd23f C++: Support __is_assignable builtin
While here fix the documentation of `__is_trivially_assignable` and
`__is_nothrow_assignable`.
2022-07-29 09:08:56 +02:00
AlexDenisov
9876c391fa Merge pull request #9915 from github/redsun82/swift-fixes
Swift: small dispatcher fixes
2022-07-29 08:22:54 +02:00
Chris Smowton
e140d2ab4f Merge pull request #9824 from smowton/smowton/admin/wildcard-substitution-test
Add test for Java wildcard substitution
2022-07-28 17:07:41 +01:00
Paolo Tranquilli
985237ab2d Swift: small dispatcher fixes
File extraction was not using named trap keys, and `emitDebugInfo` was
using `std::forward` when it should not.
2022-07-28 17:05:52 +02:00
Chris Smowton
1737ed50ba Add test cases for wildcard lowering of array types 2022-07-28 15:52:00 +01:00
Chris Smowton
8cd2aeb65d Accept test changes 2022-07-28 15:52:00 +01:00
Chris Smowton
7475f84ea5 Fix type-parameter-out-of-scope test 2022-07-28 15:51:59 +01:00
Chris Smowton
e7f275382e Add test for Java wildcard substitution 2022-07-28 15:51:59 +01:00
Paolo Tranquilli
8a36a2b563 Merge pull request #9912 from github/redsun82/swift-human-readable-trap-prefixes
Swift: make trap key prefixes readable
2022-07-28 14:34:57 +02:00
Paolo Tranquilli
ddf715e6a9 Merge pull request #9911 from github/redsun82/swift-deduplicate-vardecls
Swift: deduplicate `VarDecl`
2022-07-28 14:31:59 +02:00
Paolo Tranquilli
d547a417c9 Swift: accept new test results 2022-07-28 12:57:12 +02:00
Paolo Tranquilli
cb006900cd Merge branch 'main' into redsun82/swift-deduplicate-vardecls 2022-07-28 12:55:31 +02:00
Paolo Tranquilli
7d7966e711 Swift: make trap key prefixes readable
This replaces numeric tag-based prefixes with the actual tag name.
While this means in general slightly larger trap files, it aids
debugging them for a human.

In the future we can make this conditional on some kind of trap debug
option, but for the moment it does not seem detrimental.
2022-07-28 12:43:30 +02:00
Paolo Tranquilli
b491884996 Merge pull request #9910 from github/redsun82/swift-no-cleanup-on-integration-tests
Swift: add `--no-cleanup` to integration tests
2022-07-28 12:41:53 +02:00
Paolo Tranquilli
76ea63ffbe Swift: deduplicate VarDecl
Deduplication of `ConcreteVarDecl` is triggered only if its
`DeclContext` is not local. This avoids a mangled name conflict.

Also added more thourough tests for `ConcreteVarDecl` and `ParamDecl`.
2022-07-28 12:28:52 +02:00
Paolo Tranquilli
ab1370cc8f Swift: add --no-cleanup to integration tests 2022-07-28 11:19:45 +02:00
Tony Torralba
7ca955a0e6 Add support for XML InlineExpectationsTest 2022-07-27 17:23:10 +02:00
77 changed files with 11888 additions and 3049 deletions

View File

@@ -0,0 +1,17 @@
class Expr extends @expr {
string toString() { none() }
}
class Location extends @location_expr {
string toString() { none() }
}
predicate isExprWithNewBuiltin(Expr expr) {
exists(int kind | exprs(expr, kind, _) | 330 <= kind and kind <= 334)
}
from Expr expr, int kind, int kind_new, Location location
where
exprs(expr, kind, location) and
if isExprWithNewBuiltin(expr) then kind_new = 0 else kind_new = kind
select expr, kind_new, location

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Add new builtin operations
compatibility: partial
exprs.rel: run exprs.qlo

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Added subclasses of `BuiltInOperations` for `__builtin_bit_cast`, `__builtin_shuffle`, `__has_unique_object_representations`, `__is_aggregate`, and `__is_assignable`.

View File

@@ -1,5 +1,5 @@
/** /**
* Provides classes for modeling built-in operations. Built-in operations are * Provides classes for modeling built-in operations. Built-in operations are
* typically compiler specific and are used by libraries and generated code. * typically compiler specific and are used by libraries and generated code.
*/ */
@@ -120,8 +120,8 @@ class BuiltInNoOp extends BuiltInOperation, @noopexpr {
/** /**
* A C/C++ `__builtin_offsetof` built-in operation (used by some implementations * A C/C++ `__builtin_offsetof` built-in operation (used by some implementations
* of `offsetof`). The operation retains its semantics even in the presence * of `offsetof`). The operation retains its semantics even in the presence
* of an overloaded `operator &`). This is a GNU/Clang extension. * of an overloaded `operator &`). This is a gcc/clang extension.
* ``` * ```
* struct S { * struct S {
* int a, b; * int a, b;
@@ -137,8 +137,8 @@ class BuiltInOperationBuiltInOffsetOf extends BuiltInOperation, @offsetofexpr {
/** /**
* A C/C++ `__INTADDR__` built-in operation (used by some implementations * A C/C++ `__INTADDR__` built-in operation (used by some implementations
* of `offsetof`). The operation retains its semantics even in the presence * of `offsetof`). The operation retains its semantics even in the presence
* of an overloaded `operator &`). This is an EDG extension. * of an overloaded `operator &`). This is an EDG extension.
* ``` * ```
* struct S { * struct S {
* int a, b; * int a, b;
@@ -173,7 +173,7 @@ class BuiltInOperationHasAssign extends BuiltInOperation, @hasassignexpr {
* *
* Returns `true` if the type has a copy constructor. * Returns `true` if the type has a copy constructor.
* ``` * ```
* std::integral_constant< bool, __has_copy(_Tp)> hc; * std::integral_constant<bool, __has_copy(_Tp)> hc;
* ``` * ```
*/ */
class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr { class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr {
@@ -189,7 +189,7 @@ class BuiltInOperationHasCopy extends BuiltInOperation, @hascopyexpr {
* Returns `true` if a copy assignment operator has an empty exception * Returns `true` if a copy assignment operator has an empty exception
* specification. * specification.
* ``` * ```
* std::integral_constant< bool, __has_nothrow_assign(_Tp)> hnta; * std::integral_constant<bool, __has_nothrow_assign(_Tp)> hnta;
* ``` * ```
*/ */
class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassign { class BuiltInOperationHasNoThrowAssign extends BuiltInOperation, @hasnothrowassign {
@@ -220,7 +220,7 @@ class BuiltInOperationHasNoThrowConstructor extends BuiltInOperation, @hasnothro
* *
* Returns `true` if the copy constructor has an empty exception specification. * Returns `true` if the copy constructor has an empty exception specification.
* ``` * ```
* std::integral_constant< bool, __has_nothrow_copy(MyType) >; * std::integral_constant<bool, __has_nothrow_copy(MyType) >;
* ``` * ```
*/ */
class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy { class BuiltInOperationHasNoThrowCopy extends BuiltInOperation, @hasnothrowcopy {
@@ -266,7 +266,7 @@ class BuiltInOperationHasTrivialConstructor extends BuiltInOperation, @hastrivia
* *
* Returns true if the type has a trivial copy constructor. * Returns true if the type has a trivial copy constructor.
* ``` * ```
* std::integral_constant< bool, __has_trivial_copy(MyType) > htc; * std::integral_constant<bool, __has_trivial_copy(MyType)> htc;
* ``` * ```
*/ */
class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy { class BuiltInOperationHasTrivialCopy extends BuiltInOperation, @hastrivialcopy {
@@ -468,7 +468,7 @@ class BuiltInOperationIsUnion extends BuiltInOperation, @isunionexpr {
* ``` * ```
* template<typename _Tp1, typename _Tp2> * template<typename _Tp1, typename _Tp2>
* struct types_compatible * struct types_compatible
* : public integral_constant<bool, __builtin_types_compatible_p(_Tp1, _Tp2) > * : public integral_constant<bool, __builtin_types_compatible_p(_Tp1, _Tp2)>
* { }; * { };
* ``` * ```
*/ */
@@ -479,8 +479,7 @@ class BuiltInOperationBuiltInTypesCompatibleP extends BuiltInOperation, @typesco
/** /**
* A clang `__builtin_shufflevector` expression. * A clang `__builtin_shufflevector` expression.
* *
* It outputs a permutation of elements from one or two input vectors. * It outputs a permutation of elements from one or two input vectors. See
* Please see
* https://releases.llvm.org/3.7.0/tools/clang/docs/LanguageExtensions.html#langext-builtin-shufflevector * https://releases.llvm.org/3.7.0/tools/clang/docs/LanguageExtensions.html#langext-builtin-shufflevector
* for more information. * for more information.
* ``` * ```
@@ -494,11 +493,29 @@ class BuiltInOperationBuiltInShuffleVector extends BuiltInOperation, @builtinshu
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInShuffleVector" } override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInShuffleVector" }
} }
/**
* A gcc `__builtin_shuffle` expression.
*
* It outputs a permutation of elements from one or two input vectors.
* See https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html
* for more information.
* ```
* // Concatenate every other element of 4-element vectors V1 and V2.
* M = {0, 2, 4, 6};
* V3 = __builtin_shuffle(V1, V2, M);
* ```
*/
class BuiltInOperationBuiltInShuffle extends BuiltInOperation, @builtinshuffle {
override string toString() { result = "__builtin_shuffle" }
override string getAPrimaryQlClass() { result = "BuiltInOperationBuiltInShuffle" }
}
/** /**
* A clang `__builtin_convertvector` expression. * A clang `__builtin_convertvector` expression.
* *
* Allows for conversion of vectors of equal element count and compatible * Allows for conversion of vectors of equal element count and compatible
* element types. Please see * element types. See
* https://releases.llvm.org/3.7.0/tools/clang/docs/LanguageExtensions.html#builtin-convertvector * https://releases.llvm.org/3.7.0/tools/clang/docs/LanguageExtensions.html#builtin-convertvector
* for more information. * for more information.
* ``` * ```
@@ -547,7 +564,7 @@ class BuiltInOperationBuiltInAddressOf extends UnaryOperation, BuiltInOperation,
* ``` * ```
* template<typename T, typename... Args> * template<typename T, typename... Args>
* struct is_trivially_constructible * struct is_trivially_constructible
* : public integral_constant<bool, __is_trivially_constructible(T, Args...) > * : public integral_constant<bool, __is_trivially_constructible(T, Args...)>
* { }; * { };
* ``` * ```
*/ */
@@ -612,13 +629,10 @@ class BuiltInOperationIsTriviallyDestructible extends BuiltInOperation, @istrivi
* The `__is_trivially_assignable` built-in operation (used by some * The `__is_trivially_assignable` built-in operation (used by some
* implementations of the `<type_traits>` header). * implementations of the `<type_traits>` header).
* *
* Returns `true` if the assignment operator `C::operator =(const C& c)` is * Returns `true` if the assignment operator `C::operator =(const D& d)` is
* trivial. * trivial (i.e., it will not call any operation that is non-trivial).
* ``` * ```
* template<typename T> * bool v = __is_trivially_assignable(MyType1, MyType2);
* struct is_trivially_assignable
* : public integral_constant<bool, __is_trivially_assignable(T) >
* { };
* ``` * ```
*/ */
class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istriviallyassignableexpr { class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istriviallyassignableexpr {
@@ -631,10 +645,10 @@ class BuiltInOperationIsTriviallyAssignable extends BuiltInOperation, @istrivial
* The `__is_nothrow_assignable` built-in operation (used by some * The `__is_nothrow_assignable` built-in operation (used by some
* implementations of the `<type_traits>` header). * implementations of the `<type_traits>` header).
* *
* Returns true if there exists a `C::operator =(const C& c) nothrow` * Returns true if there exists a `C::operator =(const D& d) nothrow`
* assignment operator (i.e, with an empty exception specification). * assignment operator (i.e, with an empty exception specification).
* ``` * ```
* bool v = __is_nothrow_assignable(MyType); * bool v = __is_nothrow_assignable(MyType1, MyType2);
* ``` * ```
*/ */
class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowassignableexpr { class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowassignableexpr {
@@ -643,15 +657,30 @@ class BuiltInOperationIsNothrowAssignable extends BuiltInOperation, @isnothrowas
override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowAssignable" } override string getAPrimaryQlClass() { result = "BuiltInOperationIsNothrowAssignable" }
} }
/**
* The `__is_assignable` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns true if there exists a `C::operator =(const D& d)` assignment
* operator.
* ```
* bool v = __is_assignable(MyType1, MyType2);
* ```
*/
class BuiltInOperationIsAssignable extends BuiltInOperation, @isassignable {
override string toString() { result = "__is_assignable" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsAssignable" }
}
/** /**
* The `__is_standard_layout` built-in operation (used by some implementations * The `__is_standard_layout` built-in operation (used by some implementations
* of the `<type_traits>` header). * of the `<type_traits>` header).
* *
* Returns `true` if the type is a primitive type, or a `class`, `struct` or * Returns `true` if the type is a primitive type, or a `class`, `struct` or
* `union` WITHOUT (1) virtual functions or base classes, (2) reference member * `union` without (1) virtual functions or base classes, (2) reference member
* variable or (3) multiple occurrences of base `class` objects, among other * variable, or (3) multiple occurrences of base `class` objects, among other
* restrictions. Please see * restrictions. See https://en.cppreference.com/w/cpp/named_req/StandardLayoutType
* https://en.cppreference.com/w/cpp/named_req/StandardLayoutType
* for more information. * for more information.
* ``` * ```
* bool v = __is_standard_layout(MyType); * bool v = __is_standard_layout(MyType);
@@ -668,7 +697,7 @@ class BuiltInOperationIsStandardLayout extends BuiltInOperation, @isstandardlayo
* implementations of the `<type_traits>` header). * implementations of the `<type_traits>` header).
* *
* Returns `true` if instances of this type can be copied by trivial * Returns `true` if instances of this type can be copied by trivial
* means. The copying is done in a manner similar to the `memcpy` * means. The copying is done in a manner similar to the `memcpy`
* function. * function.
*/ */
class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istriviallycopyableexpr { class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istriviallycopyableexpr {
@@ -682,13 +711,13 @@ class BuiltInOperationIsTriviallyCopyable extends BuiltInOperation, @istrivially
* the `<type_traits>` header). * the `<type_traits>` header).
* *
* Returns `true` if the type is a scalar type, a reference type or an array of * Returns `true` if the type is a scalar type, a reference type or an array of
* literal types, among others. Please see * literal types, among others. See
* https://en.cppreference.com/w/cpp/named_req/LiteralType * https://en.cppreference.com/w/cpp/named_req/LiteralType
* for more information. * for more information.
* *
* ``` * ```
* template <typename _Tp> * template <typename _Tp>
* std::integral_constant< bool, __is_literal_type(_Tp)> ilt; * std::integral_constant<bool, __is_literal_type(_Tp)> ilt;
* ``` * ```
*/ */
class BuiltInOperationIsLiteralType extends BuiltInOperation, @isliteraltypeexpr { class BuiltInOperationIsLiteralType extends BuiltInOperation, @isliteraltypeexpr {
@@ -705,7 +734,7 @@ class BuiltInOperationIsLiteralType extends BuiltInOperation, @isliteraltypeexpr
* compiler, with semantics of the `memcpy` operation. * compiler, with semantics of the `memcpy` operation.
* ``` * ```
* template <typename _Tp> * template <typename _Tp>
* std::integral_constant< bool, __has_trivial_move_constructor(_Tp)> htmc; * std::integral_constant<bool, __has_trivial_move_constructor(_Tp)> htmc;
* ``` * ```
*/ */
class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation, class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation,
@@ -723,7 +752,7 @@ class BuiltInOperationHasTrivialMoveConstructor extends BuiltInOperation,
* ``` * ```
* template<typename T> * template<typename T>
* struct has_trivial_move_assign * struct has_trivial_move_assign
* : public integral_constant<bool, __has_trivial_move_assign(T) > * : public integral_constant<bool, __has_trivial_move_assign(T)>
* { }; * { };
* ``` * ```
*/ */
@@ -758,7 +787,7 @@ class BuiltInOperationHasNothrowMoveAssign extends BuiltInOperation, @hasnothrow
* ``` * ```
* template<typename T, typename... Args> * template<typename T, typename... Args>
* struct is_constructible * struct is_constructible
* : public integral_constant<bool, __is_constructible(T, Args...) > * : public integral_constant<bool, __is_constructible(T, Args...)>
* { }; * { };
* ``` * ```
*/ */
@@ -785,7 +814,7 @@ class BuiltInOperationIsNothrowConstructible extends BuiltInOperation, @isnothro
} }
/** /**
* The `__has_finalizer` built-in operation. This is a Microsoft extension. * The `__has_finalizer` built-in operation. This is a Microsoft extension.
* *
* Returns `true` if the type defines a _finalizer_ `C::!C(void)`, to be called * Returns `true` if the type defines a _finalizer_ `C::!C(void)`, to be called
* from either the regular destructor or the garbage collector. * from either the regular destructor or the garbage collector.
@@ -800,10 +829,10 @@ class BuiltInOperationHasFinalizer extends BuiltInOperation, @hasfinalizerexpr {
} }
/** /**
* The `__is_delegate` built-in operation. This is a Microsoft extension. * The `__is_delegate` built-in operation. This is a Microsoft extension.
* *
* Returns `true` if the function has been declared as a `delegate`, used in * Returns `true` if the function has been declared as a `delegate`, used in
* message forwarding. Please see * message forwarding. See
* https://docs.microsoft.com/en-us/cpp/extensions/delegate-cpp-component-extensions * https://docs.microsoft.com/en-us/cpp/extensions/delegate-cpp-component-extensions
* for more information. * for more information.
*/ */
@@ -814,9 +843,9 @@ class BuiltInOperationIsDelegate extends BuiltInOperation, @isdelegateexpr {
} }
/** /**
* The `__is_interface_class` built-in operation. This is a Microsoft extension. * The `__is_interface_class` built-in operation. This is a Microsoft extension.
* *
* Returns `true` if the type has been declared as an `interface`. Please see * Returns `true` if the type has been declared as an `interface`. See
* https://docs.microsoft.com/en-us/cpp/extensions/interface-class-cpp-component-extensions * https://docs.microsoft.com/en-us/cpp/extensions/interface-class-cpp-component-extensions
* for more information. * for more information.
*/ */
@@ -827,9 +856,9 @@ class BuiltInOperationIsInterfaceClass extends BuiltInOperation, @isinterfacecla
} }
/** /**
* The `__is_ref_array` built-in operation. This is a Microsoft extension. * The `__is_ref_array` built-in operation. This is a Microsoft extension.
* *
* Returns `true` if the object passed in is a _platform array_. Please see * Returns `true` if the object passed in is a _platform array_. See
* https://docs.microsoft.com/en-us/cpp/extensions/arrays-cpp-component-extensions * https://docs.microsoft.com/en-us/cpp/extensions/arrays-cpp-component-extensions
* for more information. * for more information.
* ``` * ```
@@ -844,9 +873,9 @@ class BuiltInOperationIsRefArray extends BuiltInOperation, @isrefarrayexpr {
} }
/** /**
* The `__is_ref_class` built-in operation. This is a Microsoft extension. * The `__is_ref_class` built-in operation. This is a Microsoft extension.
* *
* Returns `true` if the type is a _reference class_. Please see * Returns `true` if the type is a _reference class_. See
* https://docs.microsoft.com/en-us/cpp/extensions/classes-and-structs-cpp-component-extensions * https://docs.microsoft.com/en-us/cpp/extensions/classes-and-structs-cpp-component-extensions
* for more information. * for more information.
* ``` * ```
@@ -861,10 +890,10 @@ class BuiltInOperationIsRefClass extends BuiltInOperation, @isrefclassexpr {
} }
/** /**
* The `__is_sealed` built-in operation. This is a Microsoft extension. * The `__is_sealed` built-in operation. This is a Microsoft extension.
* *
* Returns `true` if a given class or virtual function is marked as `sealed`, * Returns `true` if a given class or virtual function is marked as `sealed`,
* meaning that it cannot be extended or overridden. The `sealed` keyword * meaning that it cannot be extended or overridden. The `sealed` keyword
* is similar to the C++11 `final` keyword. * is similar to the C++11 `final` keyword.
* ``` * ```
* ref class X sealed { * ref class X sealed {
@@ -879,7 +908,7 @@ class BuiltInOperationIsSealed extends BuiltInOperation, @issealedexpr {
} }
/** /**
* The `__is_simple_value_class` built-in operation. This is a Microsoft extension. * The `__is_simple_value_class` built-in operation. This is a Microsoft extension.
* *
* Returns `true` if passed a value type that contains no references to the * Returns `true` if passed a value type that contains no references to the
* garbage-collected heap. * garbage-collected heap.
@@ -898,9 +927,9 @@ class BuiltInOperationIsSimpleValueClass extends BuiltInOperation, @issimplevalu
} }
/** /**
* The `__is_value_class` built-in operation. This is a Microsoft extension. * The `__is_value_class` built-in operation. This is a Microsoft extension.
* *
* Returns `true` if passed a value type. Please see * Returns `true` if passed a value type. See
* https://docs.microsoft.com/en-us/cpp/extensions/classes-and-structs-cpp-component-extensions * https://docs.microsoft.com/en-us/cpp/extensions/classes-and-structs-cpp-component-extensions
* For more information. * For more information.
* ``` * ```
@@ -922,7 +951,7 @@ class BuiltInOperationIsValueClass extends BuiltInOperation, @isvalueclassexpr {
* ``` * ```
* template<typename T> * template<typename T>
* struct is_final * struct is_final
* : public integral_constant<bool, __is_final(T) > * : public integral_constant<bool, __is_final(T)>
* { }; * { };
* ``` * ```
*/ */
@@ -933,7 +962,7 @@ class BuiltInOperationIsFinal extends BuiltInOperation, @isfinalexpr {
} }
/** /**
* The `__builtin_choose_expr` expression. This is a GNU/Clang extension. * The `__builtin_choose_expr` expression. This is a gcc/clang extension.
* *
* The expression functions similarly to the ternary `?:` operator, except * The expression functions similarly to the ternary `?:` operator, except
* that it is evaluated at compile-time. * that it is evaluated at compile-time.
@@ -978,3 +1007,50 @@ class BuiltInComplexOperation extends BuiltInOperation, @builtincomplex {
/** Gets the operand corresponding to the imaginary part of the complex number. */ /** Gets the operand corresponding to the imaginary part of the complex number. */
Expr getImaginaryOperand() { this.hasChild(result, 1) } Expr getImaginaryOperand() { this.hasChild(result, 1) }
} }
/**
* A C++ `__is_aggregate` built-in operation (used by some implementations of the
* `<type_traits>` header).
*
* Returns `true` if the type has is an aggregate type.
* ```
* std::integral_constant<bool, __is_aggregate(_Tp)> ia;
* ```
*/
class BuiltInOperationIsAggregate extends BuiltInOperation, @isaggregate {
override string toString() { result = "__is_aggregate" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsAggregate" }
}
/**
* A C++ `__has_unique_object_representations` built-in operation (used by some
* implementations of the `<type_traits>` header).
*
* Returns `true` if the type is trivially copyable and if the object representation
* is unique for two objects with the same value.
* ```
* bool v = __has_unique_object_representations(MyType);
* ```
*/
class BuiltInOperationHasUniqueObjectRepresentations extends BuiltInOperation,
@hasuniqueobjectrepresentations {
override string toString() { result = "__has_unique_object_representations" }
override string getAPrimaryQlClass() { result = "BuiltInOperationHasUniqueObjectRepresentations" }
}
/**
* A C/C++ `__builtin_bit_cast` built-in operation (used by some implementations
* of `std::bit_cast`).
*
* Performs a bit cast from a value to a type.
* ```
* __builtin_bit_cast(Type, value);
* ```
*/
class BuiltInBitCast extends BuiltInOperation, @builtinbitcast {
override string toString() { result = "__builtin_bit_cast" }
override string getAPrimaryQlClass() { result = "BuiltInBitCast" }
}

View File

@@ -596,9 +596,12 @@ class ParenthesisExpr extends Conversion, @parexpr {
} }
/** /**
* A C/C++ expression that has not been resolved. * A C/C++ expression that could not be resolved, or that can no longer be
* represented due to a database upgrade or downgrade.
* *
* It is assigned `ErroneousType` as its type. * If the expression could not be resolved, it has type `ErroneousType`. In the
* case of a database upgrade or downgrade, the original type from before the
* upgrade or downgrade is kept if that type can be represented.
*/ */
class ErrorExpr extends Expr, @errorexpr { class ErrorExpr extends Expr, @errorexpr {
override string toString() { result = "<error expr>" } override string toString() { result = "<error expr>" }

View File

@@ -1650,6 +1650,11 @@ case @expr.kind of
| 327 = @co_await | 327 = @co_await
| 328 = @co_yield | 328 = @co_yield
| 329 = @temp_init | 329 = @temp_init
| 330 = @isassignable
| 331 = @isaggregate
| 332 = @hasuniqueobjectrepresentations
| 333 = @builtinbitcast
| 334 = @builtinshuffle
; ;
@var_args_expr = @vastartexpr @var_args_expr = @vastartexpr
@@ -1711,6 +1716,11 @@ case @expr.kind of
| @isfinalexpr | @isfinalexpr
| @builtinchooseexpr | @builtinchooseexpr
| @builtincomplex | @builtincomplex
| @isassignable
| @isaggregate
| @hasuniqueobjectrepresentations
| @builtinbitcast
| @builtinshuffle
; ;
new_allocated_type( new_allocated_type(

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add new builtin operations
compatibility: backwards

View File

@@ -1,4 +1,4 @@
// semmle-extractor-options: --clang
struct mystruct { struct mystruct {
int f1; int f1;
int f2; int f2;
@@ -13,3 +13,6 @@ void f(void) {
int i2 = edg_offsetof(struct mystruct,f2); int i2 = edg_offsetof(struct mystruct,f2);
} }
void g(void) {
double f = __builtin_bit_cast(double,42l);
}

View File

@@ -13,3 +13,6 @@
| edg.c:13:14:13:45 | (size_t)... | 0 | 0 | | edg.c:13:14:13:45 | (size_t)... | 0 | 0 |
| edg.c:13:14:13:45 | __INTADDR__ | 1 | 1 | | edg.c:13:14:13:45 | __INTADDR__ | 1 | 1 |
| edg.c:13:43:13:44 | f2 | 0 | 0 | | edg.c:13:43:13:44 | f2 | 0 | 0 |
| edg.c:17:16:17:45 | __builtin_bit_cast | 1 | 1 |
| edg.c:17:16:17:45 | double | 0 | 0 |
| edg.c:17:42:17:44 | 42 | 1 | 1 |

View File

@@ -296,3 +296,20 @@
| ms.cpp:255:24:255:43 | a_struct | | <none> | | ms.cpp:255:24:255:43 | a_struct | | <none> |
| ms.cpp:256:24:256:49 | __is_final | a_final_struct | 1 | | ms.cpp:256:24:256:49 | __is_final | a_final_struct | 1 |
| ms.cpp:256:24:256:49 | a_final_struct | | <none> | | ms.cpp:256:24:256:49 | a_final_struct | | <none> |
| ms.cpp:258:29:258:62 | __is_assignable | a_struct,a_struct | 1 |
| ms.cpp:258:29:258:62 | a_struct | | <none> |
| ms.cpp:258:29:258:62 | a_struct | | <none> |
| ms.cpp:259:29:259:59 | __is_assignable | a_struct,empty | 0 |
| ms.cpp:259:29:259:59 | a_struct | | <none> |
| ms.cpp:259:29:259:59 | empty | | <none> |
| ms.cpp:260:29:260:57 | __is_assignable | a_struct,int | 0 |
| ms.cpp:260:29:260:57 | a_struct | | <none> |
| ms.cpp:260:29:260:57 | int | | <none> |
| ms.cpp:262:28:262:51 | __is_aggregate | a_struct | 1 |
| ms.cpp:262:28:262:51 | a_struct | | <none> |
| ms.cpp:263:28:263:46 | __is_aggregate | int | 0 |
| ms.cpp:263:28:263:46 | int | | <none> |
| ms.cpp:265:49:265:88 | __has_unique_object_representations | int | 1 |
| ms.cpp:265:49:265:88 | int | | <none> |
| ms.cpp:266:49:266:90 | __has_unique_object_representations | float | 0 |
| ms.cpp:266:49:266:90 | float | | <none> |

View File

@@ -254,5 +254,14 @@ void f(void) {
bool b_is_final1 = __is_final(a_struct); bool b_is_final1 = __is_final(a_struct);
bool b_is_final2 = __is_final(a_final_struct); bool b_is_final2 = __is_final(a_final_struct);
}
bool b_is_assignable1 = __is_assignable(a_struct,a_struct);
bool b_is_assignable2 = __is_assignable(a_struct,empty);
bool b_is_assignable3 = __is_assignable(a_struct,int);
bool b_is_aggregate1 = __is_aggregate(a_struct);
bool b_is_aggregate2 = __is_aggregate(int);
bool b_has_unique_object_representations1 = __has_unique_object_representations(int);
bool b_has_unique_object_representations2 = __has_unique_object_representations(float);
}

View File

@@ -1,2 +1,4 @@
| vector_types2.cpp:10:15:10:42 | __builtin_shuffle |
| vector_types2.cpp:11:15:11:45 | __builtin_shuffle |
| vector_types.cpp:31:13:31:49 | __builtin_shufflevector | | vector_types.cpp:31:13:31:49 | __builtin_shufflevector |
| vector_types.cpp:58:10:58:52 | __builtin_convertvector | | vector_types.cpp:58:10:58:52 | __builtin_convertvector |

View File

@@ -13,6 +13,12 @@
| file://:0:0:0:0 | gp_offset | gp_offset | file://:0:0:0:0 | unsigned int | 4 | | file://:0:0:0:0 | gp_offset | gp_offset | file://:0:0:0:0 | unsigned int | 4 |
| file://:0:0:0:0 | overflow_arg_area | overflow_arg_area | file://:0:0:0:0 | void * | 8 | | file://:0:0:0:0 | overflow_arg_area | overflow_arg_area | file://:0:0:0:0 | void * | 8 |
| file://:0:0:0:0 | reg_save_area | reg_save_area | file://:0:0:0:0 | void * | 8 | | file://:0:0:0:0 | reg_save_area | reg_save_area | file://:0:0:0:0 | void * | 8 |
| vector_types2.cpp:5:7:5:7 | a | a | vector_types2.cpp:2:13:2:15 | v4i | 16 |
| vector_types2.cpp:6:7:6:7 | b | b | vector_types2.cpp:2:13:2:15 | v4i | 16 |
| vector_types2.cpp:7:7:7:12 | mask_1 | mask_1 | vector_types2.cpp:2:13:2:15 | v4i | 16 |
| vector_types2.cpp:8:7:8:12 | mask_2 | mask_2 | vector_types2.cpp:2:13:2:15 | v4i | 16 |
| vector_types2.cpp:10:7:10:11 | res_1 | res_1 | vector_types2.cpp:2:13:2:15 | v4i | 16 |
| vector_types2.cpp:11:7:11:11 | res_2 | res_2 | vector_types2.cpp:2:13:2:15 | v4i | 16 |
| vector_types.cpp:9:21:9:21 | x | x | vector_types.cpp:6:15:6:17 | v4f | 16 | | vector_types.cpp:9:21:9:21 | x | x | vector_types.cpp:6:15:6:17 | v4f | 16 |
| vector_types.cpp:14:18:14:20 | lhs | lhs | vector_types.cpp:6:15:6:17 | v4f | 16 | | vector_types.cpp:14:18:14:20 | lhs | lhs | vector_types.cpp:6:15:6:17 | v4f | 16 |
| vector_types.cpp:14:27:14:29 | rhs | rhs | vector_types.cpp:6:15:6:17 | v4f | 16 | | vector_types.cpp:14:27:14:29 | rhs | rhs | vector_types.cpp:6:15:6:17 | v4f | 16 |

View File

@@ -0,0 +1,12 @@
// semmle-extractor-options: --gnu --gnu_version 80000
typedef int v4i __attribute__((vector_size (16)));
void f() {
v4i a = {1,2,3,4};
v4i b = {5,6,7,8};
v4i mask_1 = {3,0,1,2};
v4i mask_2 = {3,5,4,2};
v4i res_1 = __builtin_shuffle(a, mask_1);
v4i res_2 = __builtin_shuffle(a, b, mask_2);
}

View File

@@ -12,6 +12,8 @@ Type getAMentionedType(RefType type) {
result = getAMentionedType(type).(InstantiatedType).getATypeArgument() result = getAMentionedType(type).(InstantiatedType).getATypeArgument()
or or
result = getAMentionedType(type).(NestedType).getEnclosingType() result = getAMentionedType(type).(NestedType).getEnclosingType()
or
result = getAMentionedType(type).(Wildcard).getATypeBound().getType()
} }
Type getATypeUsedInClass(RefType type) { Type getATypeUsedInClass(RefType type) {

View File

@@ -20,3 +20,15 @@ private class KtExpectationComment extends KtComment, ExpectationComment {
override string getContents() { result = this.getText().suffix(2).trim() } override string getContents() { result = this.getText().suffix(2).trim() }
} }
private class XmlExpectationComment extends ExpectationComment instanceof XMLComment {
override string getContents() { result = this.(XMLComment).getText().trim() }
override Location getLocation() { result = this.(XMLComment).getLocation() }
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
this.(XMLComment).hasLocationInfo(path, sl, sc, el, ec)
}
override string toString() { result = this.(XMLComment).toString() }
}

View File

@@ -14,8 +14,8 @@ calls
| test.kt:22:15:22:33 | setter(...) | test.kt:12:1:25:1 | user | test.kt:0:0:0:0 | TestKt | file:///!unknown-binary-location/Generic.class:0:0:0:0 | setter | file:///!unknown-binary-location/Generic.class:0:0:0:0 | Generic<? super String> | | test.kt:22:15:22:33 | setter(...) | test.kt:12:1:25:1 | user | test.kt:0:0:0:0 | TestKt | file:///!unknown-binary-location/Generic.class:0:0:0:0 | setter | file:///!unknown-binary-location/Generic.class:0:0:0:0 | Generic<? super String> |
| test.kt:23:15:23:22 | getter(...) | test.kt:12:1:25:1 | user | test.kt:0:0:0:0 | TestKt | file:///!unknown-binary-location/Generic.class:0:0:0:0 | getter | file:///!unknown-binary-location/Generic.class:0:0:0:0 | Generic<? super String> | | test.kt:23:15:23:22 | getter(...) | test.kt:12:1:25:1 | user | test.kt:0:0:0:0 | TestKt | file:///!unknown-binary-location/Generic.class:0:0:0:0 | getter | file:///!unknown-binary-location/Generic.class:0:0:0:0 | Generic<? super String> |
constructors constructors
| Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2<? extends String>(java.lang.String) | ? extends String | void | Test.java:1:7:1:14 | Generic2 | Test.java:3:10:3:17 | Generic2 | | Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2<? extends String>(<nulltype>) | <nulltype> | void | Test.java:1:7:1:14 | Generic2 | Test.java:3:10:3:17 | Generic2 |
| Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2<? super String>(java.lang.Object) | ? super String | void | Test.java:1:7:1:14 | Generic2 | Test.java:3:10:3:17 | Generic2 | | Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2<? super String>(java.lang.String) | String | void | Test.java:1:7:1:14 | Generic2 | Test.java:3:10:3:17 | Generic2 |
| Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | Generic2<String> | Generic2<String>(java.lang.String) | String | void | Test.java:1:7:1:14 | Generic2 | Test.java:3:10:3:17 | Generic2 | | Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | Generic2<String> | Generic2<String>(java.lang.String) | String | void | Test.java:1:7:1:14 | Generic2 | Test.java:3:10:3:17 | Generic2 |
| Test.java:1:7:1:14 | Generic2 | Test.java:3:10:3:17 | Generic2 | Generic2(java.lang.Object) | T | void | Test.java:1:7:1:14 | Generic2 | Test.java:3:10:3:17 | Generic2 | | Test.java:1:7:1:14 | Generic2 | Test.java:3:10:3:17 | Generic2 | Generic2(java.lang.Object) | T | void | Test.java:1:7:1:14 | Generic2 | Test.java:3:10:3:17 | Generic2 |
| Test.java:14:14:14:17 | Test | Test.java:14:14:14:17 | Test | Test() | No parameters | void | Test.java:14:14:14:17 | Test | Test.java:14:14:14:17 | Test | | Test.java:14:14:14:17 | Test | Test.java:14:14:14:17 | Test | Test() | No parameters | void | Test.java:14:14:14:17 | Test | Test.java:14:14:14:17 | Test |
@@ -34,14 +34,14 @@ refTypes
| test.kt:1:1:10:1 | Generic | | test.kt:1:1:10:1 | Generic |
| test.kt:1:15:1:15 | T | | test.kt:1:15:1:15 | T |
#select #select
| Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | getter | getter() | No parameters | ? extends String | Test.java:1:7:1:14 | Generic2 | Test.java:9:5:9:10 | getter | | Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | getter | getter() | No parameters | String | Test.java:1:7:1:14 | Generic2 | Test.java:9:5:9:10 | getter |
| Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | identity | identity(java.lang.String) | ? extends String | ? extends String | Test.java:1:7:1:14 | Generic2 | Test.java:8:5:8:12 | identity | | Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | identity | identity(<nulltype>) | <nulltype> | String | Test.java:1:7:1:14 | Generic2 | Test.java:8:5:8:12 | identity |
| Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | identity2 | identity2(java.lang.String) | ? extends String | ? extends String | Test.java:1:7:1:14 | Generic2 | Test.java:7:5:7:13 | identity2 | | Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | identity2 | identity2(<nulltype>) | <nulltype> | String | Test.java:1:7:1:14 | Generic2 | Test.java:7:5:7:13 | identity2 |
| Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | setter | setter(java.lang.String) | ? extends String | void | Test.java:1:7:1:14 | Generic2 | Test.java:10:8:10:13 | setter | | Generic2.class:0:0:0:0 | Generic2<? extends String> | Generic2.class:0:0:0:0 | setter | setter(<nulltype>) | <nulltype> | void | Test.java:1:7:1:14 | Generic2 | Test.java:10:8:10:13 | setter |
| Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | getter | getter() | No parameters | ? super String | Test.java:1:7:1:14 | Generic2 | Test.java:9:5:9:10 | getter | | Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | getter | getter() | No parameters | Object | Test.java:1:7:1:14 | Generic2 | Test.java:9:5:9:10 | getter |
| Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | identity | identity(java.lang.Object) | ? super String | ? super String | Test.java:1:7:1:14 | Generic2 | Test.java:8:5:8:12 | identity | | Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | identity | identity(java.lang.String) | String | Object | Test.java:1:7:1:14 | Generic2 | Test.java:8:5:8:12 | identity |
| Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | identity2 | identity2(java.lang.Object) | ? super String | ? super String | Test.java:1:7:1:14 | Generic2 | Test.java:7:5:7:13 | identity2 | | Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | identity2 | identity2(java.lang.String) | String | Object | Test.java:1:7:1:14 | Generic2 | Test.java:7:5:7:13 | identity2 |
| Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | setter | setter(java.lang.Object) | ? super String | void | Test.java:1:7:1:14 | Generic2 | Test.java:10:8:10:13 | setter | | Generic2.class:0:0:0:0 | Generic2<? super String> | Generic2.class:0:0:0:0 | setter | setter(java.lang.String) | String | void | Test.java:1:7:1:14 | Generic2 | Test.java:10:8:10:13 | setter |
| Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | getter | getter() | No parameters | String | Test.java:1:7:1:14 | Generic2 | Test.java:9:5:9:10 | getter | | Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | getter | getter() | No parameters | String | Test.java:1:7:1:14 | Generic2 | Test.java:9:5:9:10 | getter |
| Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | identity | identity(java.lang.String) | String | String | Test.java:1:7:1:14 | Generic2 | Test.java:8:5:8:12 | identity | | Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | identity | identity(java.lang.String) | String | String | Test.java:1:7:1:14 | Generic2 | Test.java:8:5:8:12 | identity |
| Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | identity2 | identity2(java.lang.String) | String | String | Test.java:1:7:1:14 | Generic2 | Test.java:7:5:7:13 | identity2 | | Generic2.class:0:0:0:0 | Generic2<String> | Generic2.class:0:0:0:0 | identity2 | identity2(java.lang.String) | String | String | Test.java:1:7:1:14 | Generic2 | Test.java:7:5:7:13 | identity2 |

View File

@@ -0,0 +1,20 @@
import java.util.List;
public class Lib<T> {
public void takesVar(T t) { }
public void takesInvar(List<T> lt) { }
public void takesUnbound(List<?> lt) { }
public void takesExtends(List<? extends T> lt) { }
public void takesSuper(List<? super T> lt) { }
public T returnsVar() { return null; }
public List<T> returnsInvar() { return null; }
public List<?> returnsUnbound() { return null; }
public List<? extends T> returnsExtends() { return null; }
public List<? super T> returnsSuper() { return null; }
public void takesArray(T[] ts) { }
public T[] returnsArray() { return null; }
}

View File

@@ -0,0 +1,12 @@
public class User {
public static void test(Lib<CharSequence> invarLib, Lib<? extends CharSequence> extendsLib, Lib<? super CharSequence> superLib, Lib<?> unboundLib) {
invarLib.takesVar(null);
extendsLib.takesVar(null);
superLib.takesVar(null);
unboundLib.takesVar(null);
}
}

View File

@@ -0,0 +1,64 @@
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | returnsArray | CharSequence[] |
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | returnsExtends | List<? extends CharSequence> |
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | returnsInvar | List<? extends CharSequence> |
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | returnsSuper | List<?> |
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | returnsUnbound | List<?> |
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | returnsVar | CharSequence |
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | takesArray | <nulltype>[] |
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | takesExtends | List<? extends CharSequence> |
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | takesInvar | List<? extends CharSequence> |
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | takesSuper | List<?> |
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | takesUnbound | List<?> |
| Lib.class:0:0:0:0 | Lib<? extends CharSequence> | Lib.class:0:0:0:0 | takesVar | <nulltype> |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | returnsArray | Object[] |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | returnsExtends | List<?> |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | returnsInvar | List<? super CharSequence> |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | returnsSuper | List<? super CharSequence> |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | returnsUnbound | List<?> |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | returnsVar | Object |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | takesArray | CharSequence[] |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | takesExtends | List<?> |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | takesInvar | List<? super CharSequence> |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | takesSuper | List<? super CharSequence> |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | takesUnbound | List<?> |
| Lib.class:0:0:0:0 | Lib<? super CharSequence> | Lib.class:0:0:0:0 | takesVar | CharSequence |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | returnsArray | Object[] |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | returnsExtends | List<? extends Object> |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | returnsInvar | List<?> |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | returnsSuper | List<?> |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | returnsUnbound | List<?> |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | returnsVar | Object |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | takesArray | <nulltype>[] |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | takesExtends | List<? extends Object> |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | takesInvar | List<?> |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | takesSuper | List<?> |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | takesUnbound | List<?> |
| Lib.class:0:0:0:0 | Lib<?> | Lib.class:0:0:0:0 | takesVar | <nulltype> |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | returnsArray | CharSequence[] |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | returnsExtends | List<? extends CharSequence> |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | returnsInvar | List<CharSequence> |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | returnsSuper | List<? super CharSequence> |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | returnsUnbound | List<?> |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | returnsVar | CharSequence |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | takesArray | CharSequence[] |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | takesExtends | List<? extends CharSequence> |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | takesInvar | List<CharSequence> |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | takesSuper | List<? super CharSequence> |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | takesUnbound | List<?> |
| Lib.class:0:0:0:0 | Lib<CharSequence> | Lib.class:0:0:0:0 | takesVar | CharSequence |
| Lib.java:3:14:3:16 | Lib | Lib.java:5:15:5:22 | takesVar | T |
| Lib.java:3:14:3:16 | Lib | Lib.java:6:15:6:24 | takesInvar | List<T> |
| Lib.java:3:14:3:16 | Lib | Lib.java:7:15:7:26 | takesUnbound | List<?> |
| Lib.java:3:14:3:16 | Lib | Lib.java:8:15:8:26 | takesExtends | List<? extends T> |
| Lib.java:3:14:3:16 | Lib | Lib.java:9:15:9:24 | takesSuper | List<? super T> |
| Lib.java:3:14:3:16 | Lib | Lib.java:11:12:11:21 | returnsVar | T |
| Lib.java:3:14:3:16 | Lib | Lib.java:12:18:12:29 | returnsInvar | List<T> |
| Lib.java:3:14:3:16 | Lib | Lib.java:13:18:13:31 | returnsUnbound | List<?> |
| Lib.java:3:14:3:16 | Lib | Lib.java:14:28:14:41 | returnsExtends | List<? extends T> |
| Lib.java:3:14:3:16 | Lib | Lib.java:15:26:15:37 | returnsSuper | List<? super T> |
| Lib.java:3:14:3:16 | Lib | Lib.java:17:15:17:24 | takesArray | T[] |
| Lib.java:3:14:3:16 | Lib | Lib.java:18:14:18:25 | returnsArray | T[] |
| User.java:1:14:1:17 | User | User.java:3:22:3:25 | test | Lib<? extends CharSequence> |
| User.java:1:14:1:17 | User | User.java:3:22:3:25 | test | Lib<? super CharSequence> |
| User.java:1:14:1:17 | User | User.java:3:22:3:25 | test | Lib<?> |
| User.java:1:14:1:17 | User | User.java:3:22:3:25 | test | Lib<CharSequence> |

View File

@@ -0,0 +1,7 @@
import java
Type notVoid(Type t) { result = t and not result instanceof VoidType }
from Callable c
where c.getSourceDeclaration().fromSource()
select c.getDeclaringType(), c, notVoid([c.getAParamType(), c.getReturnType()]).toString()

View File

@@ -0,0 +1,3 @@
public class Test {
}

View File

@@ -0,0 +1,2 @@
| test.xml:4:5:4:32 | attribute=value | Unexpected result: hasXmlResult= |
| test.xml:5:29:5:52 | $ hasXmlResult | Missing result:hasXmlResult= |

View File

@@ -0,0 +1,17 @@
import semmle.code.xml.XML
import TestUtilities.InlineExpectationsTest
class XmlTest extends InlineExpectationsTest {
XmlTest() { this = "XmlTest" }
override string getARelevantTag() { result = "hasXmlResult" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "hasXmlResult" and
exists(XMLAttribute a |
a.getLocation() = location and
element = a.toString() and
value = ""
)
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<document>
<element attribute="value">Text</element> <!-- $ hasXmlResult -->
<element attribute="value">Text</element> <!-- Missing -->
<element>Text</element> <!-- $ hasXmlResult --> <!-- Spurious -->
</document>

BIN
ruby/Cargo.lock generated

Binary file not shown.

View File

@@ -20,3 +20,4 @@ num_cpus = "1.13.0"
regex = "1.5.5" regex = "1.5.5"
encoding = "0.2" encoding = "0.2"
lazy_static = "1.4.0" lazy_static = "1.4.0"
brotli = "3.3.4"

View File

@@ -71,6 +71,15 @@ impl Writer {
let mut trap_file = BufWriter::new(trap_file); let mut trap_file = BufWriter::new(trap_file);
self.write_trap_entries(&mut trap_file) self.write_trap_entries(&mut trap_file)
} }
Compression::Brotli => {
let params = brotli::enc::BrotliEncoderParams {
quality: 3,
..Default::default()
};
let trap_file = brotli::CompressorWriter::with_params(trap_file, 4096, &params);
let mut trap_file = BufWriter::new(trap_file);
self.write_trap_entries(&mut trap_file)
}
} }
} }
@@ -221,6 +230,7 @@ fn limit_string(string: &str, max_size: usize) -> &str {
pub enum Compression { pub enum Compression {
None, None,
Gzip, Gzip,
Brotli,
} }
impl Compression { impl Compression {
@@ -229,12 +239,12 @@ impl Compression {
Ok(method) => match Compression::from_string(&method) { Ok(method) => match Compression::from_string(&method) {
Some(c) => c, Some(c) => c,
None => { None => {
tracing::error!("Unknown compression method '{}'; using gzip.", &method); tracing::error!("Unknown compression method '{}'; using brotli.", &method);
Compression::Gzip Compression::Brotli
} }
}, },
// Default compression method if the env var isn't set: // Default compression method if the env var isn't set:
Err(_) => Compression::Gzip, Err(_) => Compression::Brotli,
} }
} }
@@ -242,6 +252,7 @@ impl Compression {
match s.to_lowercase().as_ref() { match s.to_lowercase().as_ref() {
"none" => Some(Compression::None), "none" => Some(Compression::None),
"gzip" => Some(Compression::Gzip), "gzip" => Some(Compression::Gzip),
"brotli" => Some(Compression::Brotli),
_ => None, _ => None,
} }
} }
@@ -250,6 +261,7 @@ impl Compression {
match self { match self {
Compression::None => "trap", Compression::None => "trap",
Compression::Gzip => "trap.gz", Compression::Gzip => "trap.gz",
Compression::Brotli => "trap.br",
} }
} }
} }

View File

@@ -86,11 +86,10 @@ def generate(opts, renderer):
renderer.render(cpp.TrapList(entries, opts.dbscheme), out / dir / "TrapEntries") renderer.render(cpp.TrapList(entries, opts.dbscheme), out / dir / "TrapEntries")
tags = [] tags = []
for index, tag in enumerate(toposort_flatten(tag_graph)): for tag in toposort_flatten(tag_graph):
tags.append(cpp.Tag( tags.append(cpp.Tag(
name=get_tag_name(tag), name=get_tag_name(tag),
bases=[get_tag_name(b) for b in sorted(tag_graph[tag])], bases=[get_tag_name(b) for b in sorted(tag_graph[tag])],
index=index,
id=tag, id=tag,
)) ))
renderer.render(cpp.TagList(tags, opts.dbscheme), out / "TrapTags") renderer.render(cpp.TagList(tags, opts.dbscheme), out / "TrapTags")

View File

@@ -83,7 +83,6 @@ class TagBase:
class Tag: class Tag:
name: str name: str
bases: List[TagBase] bases: List[TagBase]
index: int
id: str id: str
def __post_init__(self): def __post_init__(self):

View File

@@ -7,7 +7,7 @@ namespace codeql {
// {{id}} // {{id}}
struct {{name}}Tag {{#has_bases}}: {{#bases}}{{^first}}, {{/first}}{{base}}Tag{{/bases}} {{/has_bases}}{ struct {{name}}Tag {{#has_bases}}: {{#bases}}{{^first}}, {{/first}}{{base}}Tag{{/bases}} {{/has_bases}}{
static constexpr const char* prefix = "{{index}}"; static constexpr const char* prefix = "{{name}}";
}; };
{{/tags}} {{/tags}}
} }

View File

@@ -65,7 +65,7 @@ def test_trap_has_first_field_marked():
def test_tag_has_first_base_marked(): def test_tag_has_first_base_marked():
bases = ["a", "b", "c"] bases = ["a", "b", "c"]
expected = [cpp.TagBase("a", first=True), cpp.TagBase("b"), cpp.TagBase("c")] expected = [cpp.TagBase("a", first=True), cpp.TagBase("b"), cpp.TagBase("c")]
t = cpp.Tag("name", bases, 0, "id") t = cpp.Tag("name", bases, "id")
assert t.bases == expected assert t.bases == expected
@@ -75,7 +75,7 @@ def test_tag_has_first_base_marked():
(["a", "b"], True) (["a", "b"], True)
]) ])
def test_tag_has_bases(bases, expected): def test_tag_has_bases(bases, expected):
t = cpp.Tag("name", bases, 0, "id") t = cpp.Tag("name", bases, "id")
assert t.has_bases is expected assert t.has_bases is expected

View File

@@ -162,10 +162,10 @@ def test_one_union_tags(generate_tags):
assert generate_tags([ assert generate_tags([
dbscheme.Union(lhs="@left_hand_side", rhs=["@b", "@a", "@c"]), dbscheme.Union(lhs="@left_hand_side", rhs=["@b", "@a", "@c"]),
]) == [ ]) == [
cpp.Tag(name="LeftHandSide", bases=[], index=0, id="@left_hand_side"), cpp.Tag(name="LeftHandSide", bases=[], id="@left_hand_side"),
cpp.Tag(name="A", bases=["LeftHandSide"], index=1, id="@a"), cpp.Tag(name="A", bases=["LeftHandSide"], id="@a"),
cpp.Tag(name="B", bases=["LeftHandSide"], index=2, id="@b"), cpp.Tag(name="B", bases=["LeftHandSide"], id="@b"),
cpp.Tag(name="C", bases=["LeftHandSide"], index=3, id="@c"), cpp.Tag(name="C", bases=["LeftHandSide"], id="@c"),
] ]
@@ -175,12 +175,12 @@ def test_multiple_union_tags(generate_tags):
dbscheme.Union(lhs="@a", rhs=["@b", "@c"]), dbscheme.Union(lhs="@a", rhs=["@b", "@c"]),
dbscheme.Union(lhs="@e", rhs=["@c", "@f"]), dbscheme.Union(lhs="@e", rhs=["@c", "@f"]),
]) == [ ]) == [
cpp.Tag(name="D", bases=[], index=0, id="@d"), cpp.Tag(name="D", bases=[], id="@d"),
cpp.Tag(name="E", bases=[], index=1, id="@e"), cpp.Tag(name="E", bases=[], id="@e"),
cpp.Tag(name="A", bases=["D"], index=2, id="@a"), cpp.Tag(name="A", bases=["D"], id="@a"),
cpp.Tag(name="F", bases=["E"], index=3, id="@f"), cpp.Tag(name="F", bases=["E"], id="@f"),
cpp.Tag(name="B", bases=["A"], index=4, id="@b"), cpp.Tag(name="B", bases=["A"], id="@b"),
cpp.Tag(name="C", bases=["A", "E"], index=5, id="@c"), cpp.Tag(name="C", bases=["A", "E"], id="@c"),
] ]

View File

@@ -2,14 +2,10 @@ load("//swift:rules.bzl", "swift_cc_binary")
swift_cc_binary( swift_cc_binary(
name = "extractor", name = "extractor",
srcs = [ srcs = glob([
"SwiftOutputRewrite.cpp", "*.h",
"SwiftOutputRewrite.h", "*.cpp",
"SwiftExtractor.cpp", ]),
"SwiftExtractor.h",
"SwiftExtractorConfiguration.h",
"main.cpp",
],
visibility = ["//swift:__pkg__"], visibility = ["//swift:__pkg__"],
deps = [ deps = [
"//swift/extractor/infra", "//swift/extractor/infra",

View File

@@ -14,9 +14,10 @@
#include "swift/extractor/trap/generated/TrapClasses.h" #include "swift/extractor/trap/generated/TrapClasses.h"
#include "swift/extractor/trap/TrapDomain.h" #include "swift/extractor/trap/TrapDomain.h"
#include "swift/extractor/visitors/SwiftVisitor.h" #include "swift/extractor/visitors/SwiftVisitor.h"
#include "swift/extractor/infra/TargetFile.h" #include "swift/extractor/TargetTrapFile.h"
using namespace codeql; using namespace codeql;
using namespace std::string_literals;
static void archiveFile(const SwiftExtractorConfiguration& config, swift::SourceFile& file) { static void archiveFile(const SwiftExtractorConfiguration& config, swift::SourceFile& file) {
if (std::error_code ec = llvm::sys::fs::create_directories(config.trapDir)) { if (std::error_code ec = llvm::sys::fs::create_directories(config.trapDir)) {
@@ -53,12 +54,18 @@ static std::string getFilename(swift::ModuleDecl& module, swift::SourceFile* pri
if (primaryFile) { if (primaryFile) {
return primaryFile->getFilename().str(); return primaryFile->getFilename().str();
} }
// Several modules with different name might come from .pcm (clang module) files // PCM clang module
// In this case we want to differentiate them if (module.isNonSwiftModule()) {
std::string filename = module.getModuleFilename().str(); // Several modules with different names might come from .pcm (clang module) files
filename += "-"; // In this case we want to differentiate them
filename += module.getName().str(); // Moreover, pcm files may come from caches located in different directories, but are
return filename; // unambiguously identified by the base file name, so we can discard the absolute directory
std::string filename = "/pcms/"s + llvm::sys::path::filename(module.getModuleFilename()).str();
filename += "-";
filename += module.getName().str();
return filename;
}
return module.getModuleFilename().str();
} }
static llvm::SmallVector<swift::Decl*> getTopLevelDecls(swift::ModuleDecl& module, static llvm::SmallVector<swift::Decl*> getTopLevelDecls(swift::ModuleDecl& module,
@@ -73,20 +80,6 @@ static llvm::SmallVector<swift::Decl*> getTopLevelDecls(swift::ModuleDecl& modul
return ret; return ret;
} }
static void dumpArgs(TargetFile& out, const SwiftExtractorConfiguration& config) {
out << "/* extractor-args:\n";
for (const auto& opt : config.frontendOptions) {
out << " " << std::quoted(opt) << " \\\n";
}
out << "\n*/\n";
out << "/* swift-frontend-args:\n";
for (const auto& opt : config.patchedFrontendOptions) {
out << " " << std::quoted(opt) << " \\\n";
}
out << "\n*/\n";
}
static void extractDeclarations(const SwiftExtractorConfiguration& config, static void extractDeclarations(const SwiftExtractorConfiguration& config,
swift::CompilerInstance& compiler, swift::CompilerInstance& compiler,
swift::ModuleDecl& module, swift::ModuleDecl& module,
@@ -96,12 +89,11 @@ static void extractDeclarations(const SwiftExtractorConfiguration& config,
// The extractor can be called several times from different processes with // The extractor can be called several times from different processes with
// the same input file(s). Using `TargetFile` the first process will win, and the following // the same input file(s). Using `TargetFile` the first process will win, and the following
// will just skip the work // will just skip the work
auto trapTarget = TargetFile::create(filename + ".trap", config.trapDir, config.getTempTrapDir()); auto trapTarget = createTargetTrapFile(config, filename);
if (!trapTarget) { if (!trapTarget) {
// another process arrived first, nothing to do for us // another process arrived first, nothing to do for us
return; return;
} }
dumpArgs(*trapTarget, config);
TrapDomain trap{*trapTarget}; TrapDomain trap{*trapTarget};
// TODO: remove this and recreate it with IPA when we have that // TODO: remove this and recreate it with IPA when we have that
@@ -166,21 +158,21 @@ void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config,
auto modules = collectModules(compiler); auto modules = collectModules(compiler);
for (auto& module : modules) { for (auto& module : modules) {
// We only extract system and builtin modules here as the other "user" modules can be built bool isFromSourceFile = false;
// during the build process and then re-used at a later stage. In this case, we extract the for (auto file : module->getFiles()) {
// user code twice: once during the module build in a form of a source file, and then as auto sourceFile = llvm::dyn_cast<swift::SourceFile>(file);
// a pre-built module during building of the dependent source files. if (!sourceFile) {
if (module->isSystemModule() || module->isBuiltinModule()) { continue;
extractDeclarations(config, compiler, *module);
} else {
for (auto file : module->getFiles()) {
auto sourceFile = llvm::dyn_cast<swift::SourceFile>(file);
if (!sourceFile || inputFiles.count(sourceFile->getFilename().str()) == 0) {
continue;
}
archiveFile(config, *sourceFile);
extractDeclarations(config, compiler, *module, sourceFile);
} }
isFromSourceFile = true;
if (inputFiles.count(sourceFile->getFilename().str()) == 0) {
continue;
}
archiveFile(config, *sourceFile);
extractDeclarations(config, compiler, *module, sourceFile);
}
if (!isFromSourceFile) {
extractDeclarations(config, compiler, *module);
} }
} }
} }

View File

@@ -3,6 +3,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "swift/extractor/infra/TargetFile.h"
namespace codeql { namespace codeql {
struct SwiftExtractorConfiguration { struct SwiftExtractorConfiguration {
// The location for storing TRAP files to be imported by CodeQL engine. // The location for storing TRAP files to be imported by CodeQL engine.
@@ -33,4 +35,5 @@ struct SwiftExtractorConfiguration {
// overall extraction process. // overall extraction process.
std::string getTempArtifactDir() const { return scratchDir + "/swift-extraction-artifacts"; } std::string getTempArtifactDir() const { return scratchDir + "/swift-extraction-artifacts"; }
}; };
} // namespace codeql } // namespace codeql

View File

@@ -1,5 +1,6 @@
#include "SwiftOutputRewrite.h" #include "SwiftOutputRewrite.h"
#include "swift/extractor/SwiftExtractorConfiguration.h" #include "swift/extractor/SwiftExtractorConfiguration.h"
#include "swift/extractor/TargetTrapFile.h"
#include <llvm/ADT/SmallString.h> #include <llvm/ADT/SmallString.h>
#include <llvm/Support/FileSystem.h> #include <llvm/Support/FileSystem.h>
@@ -163,7 +164,7 @@ static std::vector<std::string> computeModuleAliases(llvm::StringRef modulePath,
namespace codeql { namespace codeql {
std::unordered_map<std::string, std::string> rewriteOutputsInPlace( std::unordered_map<std::string, std::string> rewriteOutputsInPlace(
SwiftExtractorConfiguration& config, const SwiftExtractorConfiguration& config,
std::vector<std::string>& CLIArgs) { std::vector<std::string>& CLIArgs) {
std::unordered_map<std::string, std::string> remapping; std::unordered_map<std::string, std::string> remapping;
@@ -324,4 +325,17 @@ std::vector<std::string> collectVFSFiles(const SwiftExtractorConfiguration& conf
return overlays; return overlays;
} }
void lockOutputSwiftModuleTraps(const SwiftExtractorConfiguration& config,
const std::unordered_map<std::string, std::string>& remapping) {
for (const auto& [oldPath, newPath] : remapping) {
if (llvm::StringRef(oldPath).endswith(".swiftmodule")) {
if (auto target = createTargetTrapFile(config, oldPath)) {
*target << "// trap file deliberately empty\n"
"// this swiftmodule was created during the build, so its entities must have"
" been extracted directly from source files";
}
}
}
}
} // namespace codeql } // namespace codeql

View File

@@ -13,7 +13,7 @@ struct SwiftExtractorConfiguration;
// artifacts produced by the actual Swift compiler. // artifacts produced by the actual Swift compiler.
// Returns the map containing remapping oldpath -> newPath. // Returns the map containing remapping oldpath -> newPath.
std::unordered_map<std::string, std::string> rewriteOutputsInPlace( std::unordered_map<std::string, std::string> rewriteOutputsInPlace(
SwiftExtractorConfiguration& config, const SwiftExtractorConfiguration& config,
std::vector<std::string>& CLIArgs); std::vector<std::string>& CLIArgs);
// Create directories for all the redirected new paths as the Swift compiler expects them to exist. // Create directories for all the redirected new paths as the Swift compiler expects them to exist.
@@ -29,4 +29,7 @@ void storeRemappingForVFS(const SwiftExtractorConfiguration& config,
// This is separate from storeRemappingForVFS as we also collect files produced by other processes. // This is separate from storeRemappingForVFS as we also collect files produced by other processes.
std::vector<std::string> collectVFSFiles(const SwiftExtractorConfiguration& config); std::vector<std::string> collectVFSFiles(const SwiftExtractorConfiguration& config);
// Creates empty trap files for output swiftmodule files
void lockOutputSwiftModuleTraps(const SwiftExtractorConfiguration& config,
const std::unordered_map<std::string, std::string>& remapping);
} // namespace codeql } // namespace codeql

View File

@@ -0,0 +1,23 @@
#include "swift/extractor/TargetTrapFile.h"
#include <iomanip>
namespace codeql {
std::optional<TargetFile> createTargetTrapFile(const SwiftExtractorConfiguration& configuration,
std::string_view target) {
std::string trap{target};
trap += ".trap";
auto ret = TargetFile::create(trap, configuration.trapDir, configuration.getTempTrapDir());
if (ret) {
*ret << "/* extractor-args:\n";
for (const auto& opt : configuration.frontendOptions) {
*ret << " " << std::quoted(opt) << " \\\n";
}
*ret << "\n*/\n"
"/* swift-frontend-args:\n";
for (const auto& opt : configuration.patchedFrontendOptions) {
*ret << " " << std::quoted(opt) << " \\\n";
}
*ret << "\n*/\n";
}
return ret;
}
} // namespace codeql

View File

@@ -0,0 +1,11 @@
#pragma once
#include "swift/extractor/infra/TargetFile.h"
#include "swift/extractor/SwiftExtractorConfiguration.h"
namespace codeql {
std::optional<TargetFile> createTargetTrapFile(const SwiftExtractorConfiguration& configuration,
std::string_view target);
} // namespace codeql

View File

@@ -215,7 +215,7 @@ class SwiftDispatcher {
template <typename... Args> template <typename... Args>
void emitDebugInfo(const Args&... args) { void emitDebugInfo(const Args&... args) {
trap.debug(std::forward<Args>(args)...); trap.debug(args...);
} }
// In order to not emit duplicated entries for declarations, we restrict emission to only // In order to not emit duplicated entries for declarations, we restrict emission to only
@@ -315,7 +315,7 @@ class SwiftDispatcher {
virtual void visit(swift::TypeBase* type) = 0; virtual void visit(swift::TypeBase* type) = 0;
void visit(const FilePath& file) { void visit(const FilePath& file) {
auto entry = createEntry(file); auto entry = createEntry(file, file.path);
entry.name = file.path; entry.name = file.path;
emit(entry); emit(entry);
} }

View File

@@ -68,6 +68,7 @@ int main(int argc, char** argv) {
codeql::rewriteOutputsInPlace(configuration, configuration.patchedFrontendOptions); codeql::rewriteOutputsInPlace(configuration, configuration.patchedFrontendOptions);
codeql::ensureDirectoriesForNewPathsExist(remapping); codeql::ensureDirectoriesForNewPathsExist(remapping);
codeql::storeRemappingForVFS(configuration, remapping); codeql::storeRemappingForVFS(configuration, remapping);
codeql::lockOutputSwiftModuleTraps(configuration, remapping);
std::vector<const char*> args; std::vector<const char*> args;
for (auto& arg : configuration.patchedFrontendOptions) { for (auto& arg : configuration.patchedFrontendOptions) {

View File

@@ -83,11 +83,13 @@ codeql::PrecedenceGroupDecl DeclVisitor::translatePrecedenceGroupDecl(
return entry; return entry;
} }
codeql::ParamDecl DeclVisitor::translateParamDecl(const swift::ParamDecl& decl) { std::optional<codeql::ParamDecl> DeclVisitor::translateParamDecl(const swift::ParamDecl& decl) {
// TODO: deduplicate auto entry = createNamedEntry(decl);
ParamDecl entry{dispatcher_.assignNewLabel(decl)}; if (!entry) {
fillVarDecl(decl, entry); return std::nullopt;
entry.is_inout = decl.isInOut(); }
fillVarDecl(decl, *entry);
entry->is_inout = decl.isInOut();
return entry; return entry;
} }
@@ -111,11 +113,20 @@ codeql::PatternBindingDecl DeclVisitor::translatePatternBindingDecl(
return entry; return entry;
} }
codeql::ConcreteVarDecl DeclVisitor::translateVarDecl(const swift::VarDecl& decl) { std::optional<codeql::ConcreteVarDecl> DeclVisitor::translateVarDecl(const swift::VarDecl& decl) {
// TODO: deduplicate all non-local variables std::optional<codeql::ConcreteVarDecl> entry;
ConcreteVarDecl entry{dispatcher_.assignNewLabel(decl)}; // We do not deduplicate variables from non-swift (PCM, clang modules) modules as the mangler
entry.introducer_int = static_cast<uint8_t>(decl.getIntroducer()); // crashes sometimes
fillVarDecl(decl, entry); if (decl.getDeclContext()->isLocalContext() || decl.getModuleContext()->isNonSwiftModule()) {
entry.emplace(dispatcher_.assignNewLabel(decl));
} else {
entry = createNamedEntry(decl);
if (!entry) {
return std::nullopt;
}
}
entry->introducer_int = static_cast<uint8_t>(decl.getIntroducer());
fillVarDecl(decl, *entry);
return entry; return entry;
} }
@@ -287,6 +298,14 @@ std::string DeclVisitor::mangledName(const swift::ValueDecl& decl) {
if (decl.getKind() == swift::DeclKind::Module) { if (decl.getKind() == swift::DeclKind::Module) {
return static_cast<const swift::ModuleDecl&>(decl).getRealName().str().str(); return static_cast<const swift::ModuleDecl&>(decl).getRealName().str().str();
} }
// In cases like this (when coming from PCM)
// typealias CFXMLTree = CFTree
// typealias CFXMLTreeRef = CFXMLTree
// mangleAnyDecl mangles both CFXMLTree and CFXMLTreeRef into 'So12CFXMLTreeRefa'
// which is not correct and causes inconsistencies. mangleEntity makes these two distinct
if (decl.getKind() == swift::DeclKind::TypeAlias) {
return mangler.mangleEntity(&decl);
}
// prefix adds a couple of special symbols, we don't necessary need them // prefix adds a couple of special symbols, we don't necessary need them
return mangler.mangleAnyDecl(&decl, /* prefix = */ false); return mangler.mangleAnyDecl(&decl, /* prefix = */ false);
} }

View File

@@ -30,10 +30,10 @@ class DeclVisitor : public AstVisitorBase<DeclVisitor> {
codeql::PostfixOperatorDecl translatePostfixOperatorDecl(const swift::PostfixOperatorDecl& decl); codeql::PostfixOperatorDecl translatePostfixOperatorDecl(const swift::PostfixOperatorDecl& decl);
codeql::InfixOperatorDecl translateInfixOperatorDecl(const swift::InfixOperatorDecl& decl); codeql::InfixOperatorDecl translateInfixOperatorDecl(const swift::InfixOperatorDecl& decl);
codeql::PrecedenceGroupDecl translatePrecedenceGroupDecl(const swift::PrecedenceGroupDecl& decl); codeql::PrecedenceGroupDecl translatePrecedenceGroupDecl(const swift::PrecedenceGroupDecl& decl);
codeql::ParamDecl translateParamDecl(const swift::ParamDecl& decl); std::optional<codeql::ParamDecl> translateParamDecl(const swift::ParamDecl& decl);
codeql::TopLevelCodeDecl translateTopLevelCodeDecl(const swift::TopLevelCodeDecl& decl); codeql::TopLevelCodeDecl translateTopLevelCodeDecl(const swift::TopLevelCodeDecl& decl);
codeql::PatternBindingDecl translatePatternBindingDecl(const swift::PatternBindingDecl& decl); codeql::PatternBindingDecl translatePatternBindingDecl(const swift::PatternBindingDecl& decl);
codeql::ConcreteVarDecl translateVarDecl(const swift::VarDecl& decl); std::optional<codeql::ConcreteVarDecl> translateVarDecl(const swift::VarDecl& decl);
std::variant<codeql::StructDecl, codeql::StructDeclsTrap> translateStructDecl( std::variant<codeql::StructDecl, codeql::StructDeclsTrap> translateStructDecl(
const swift::StructDecl& decl); const swift::StructDecl& decl);
std::variant<codeql::ClassDecl, codeql::ClassDeclsTrap> translateClassDecl( std::variant<codeql::ClassDecl, codeql::ClassDeclsTrap> translateClassDecl(

View File

@@ -12,7 +12,7 @@ def run_codeql_database_create(cmds, lang, keep_trap=True):
codeql_root = pathlib.Path(__file__).parents[2] codeql_root = pathlib.Path(__file__).parents[2]
cmd = [ cmd = [
"codeql", "database", "create", "codeql", "database", "create",
"-s", ".", "-l", "swift", "--internal-use-lua-tracing", f"--search-path={codeql_root}", "-s", ".", "-l", "swift", "--internal-use-lua-tracing", f"--search-path={codeql_root}", "--no-cleanup",
] ]
if keep_trap: if keep_trap:
cmd.append("--keep-trap") cmd.append("--keep-trap")

View File

@@ -1,5 +1,4 @@
| Sources/cross-references/lib.swift:10:5:10:5 | X | | Sources/cross-references/lib.swift:10:5:10:5 | X |
| Sources/cross-references/lib.swift:10:5:10:5 | X |
| Sources/cross-references/lib.swift:17:16:17:19 | v | | Sources/cross-references/lib.swift:17:16:17:19 | v |
| Sources/cross-references/lib.swift:22:16:22:19 | v | | Sources/cross-references/lib.swift:22:16:22:19 | v |
| Sources/cross-references/lib.swift:27:8:27:13 | lhs | | Sources/cross-references/lib.swift:27:8:27:13 | lhs |

View File

@@ -1,4 +1,5 @@
| file://:0:0:0:0 | A | | file://:0:0:0:0 | A |
| file://:0:0:0:0 | B | | file://:0:0:0:0 | B |
| file://:0:0:0:0 | PackageDescription |
| file://:0:0:0:0 | main | | file://:0:0:0:0 | main |
| file://:0:0:0:0 | partial_modules | | file://:0:0:0:0 | partial_modules |

View File

@@ -62,6 +62,8 @@ def main(opts):
] ]
if opts.check_databases: if opts.check_databases:
cmd.append("--check-databases") cmd.append("--check-databases")
else:
cmd.append("--no-check-databases")
if opts.learn: if opts.learn:
cmd.append("--learn") cmd.append("--learn")
cmd.extend(str(t.parent) for t in succesful_db_creation) cmd.extend(str(t.parent) for t in succesful_db_creation)

View File

@@ -0,0 +1,7 @@
| var_decls.swift:4:7:4:7 | i | getInterfaceType: | Int | getName: | i | getType: | Int | getIntroducerInt: | 1 |
| var_decls.swift:7:5:7:5 | numbers | getInterfaceType: | [Int] | getName: | numbers | getType: | [Int] | getIntroducerInt: | 1 |
| var_decls.swift:10:12:10:12 | numbers | getInterfaceType: | [Int] | getName: | numbers | getType: | [Int] | getIntroducerInt: | 0 |
| var_decls.swift:15:7:15:7 | wrappedValue | getInterfaceType: | T | getName: | wrappedValue | getType: | T | getIntroducerInt: | 1 |
| var_decls.swift:20:7:20:7 | wrappedValue | getInterfaceType: | Int | getName: | wrappedValue | getType: | Int | getIntroducerInt: | 1 |
| var_decls.swift:24:15:24:15 | _wrapped | getInterfaceType: | X<Y> | getName: | _wrapped | getType: | X<Y> | getIntroducerInt: | 1 |
| var_decls.swift:24:15:24:15 | wrapped | getInterfaceType: | Int | getName: | wrapped | getType: | Int | getIntroducerInt: | 1 |

View File

@@ -0,0 +1,14 @@
// generated by codegen/codegen.py
import codeql.swift.elements
import TestUtils
from ConcreteVarDecl x, Type getInterfaceType, string getName, Type getType, int getIntroducerInt
where
toBeTested(x) and
not x.isUnknown() and
getInterfaceType = x.getInterfaceType() and
getName = x.getName() and
getType = x.getType() and
getIntroducerInt = x.getIntroducerInt()
select x, "getInterfaceType:", getInterfaceType, "getName:", getName, "getType:", getType,
"getIntroducerInt:", getIntroducerInt

View File

@@ -0,0 +1,13 @@
| var_decls.swift:10:12:10:12 | numbers | 0 | var_decls.swift:10:12:10:12 | get |
| var_decls.swift:15:7:15:7 | wrappedValue | 0 | var_decls.swift:15:7:15:7 | get |
| var_decls.swift:15:7:15:7 | wrappedValue | 1 | var_decls.swift:15:7:15:7 | set |
| var_decls.swift:15:7:15:7 | wrappedValue | 2 | var_decls.swift:15:7:15:7 | (unnamed function decl) |
| var_decls.swift:20:7:20:7 | wrappedValue | 0 | var_decls.swift:20:7:20:7 | get |
| var_decls.swift:20:7:20:7 | wrappedValue | 1 | var_decls.swift:20:7:20:7 | set |
| var_decls.swift:20:7:20:7 | wrappedValue | 2 | var_decls.swift:20:7:20:7 | (unnamed function decl) |
| var_decls.swift:24:15:24:15 | _wrapped | 0 | var_decls.swift:24:15:24:15 | get |
| var_decls.swift:24:15:24:15 | _wrapped | 1 | var_decls.swift:24:15:24:15 | set |
| var_decls.swift:24:15:24:15 | _wrapped | 2 | var_decls.swift:24:15:24:15 | (unnamed function decl) |
| var_decls.swift:24:15:24:15 | wrapped | 0 | var_decls.swift:24:15:24:15 | get |
| var_decls.swift:24:15:24:15 | wrapped | 1 | var_decls.swift:24:15:24:15 | set |
| var_decls.swift:24:15:24:15 | wrapped | 2 | var_decls.swift:24:15:24:15 | (unnamed function decl) |

View File

@@ -0,0 +1,7 @@
// generated by codegen/codegen.py
import codeql.swift.elements
import TestUtils
from ConcreteVarDecl x, int index
where toBeTested(x) and not x.isUnknown()
select x, index, x.getAccessorDecl(index)

View File

@@ -0,0 +1 @@
| var_decls.swift:24:15:24:15 | wrapped | X<Y> |

View File

@@ -0,0 +1,7 @@
// generated by codegen/codegen.py
import codeql.swift.elements
import TestUtils
from ConcreteVarDecl x
where toBeTested(x) and not x.isUnknown()
select x, x.getAttachedPropertyWrapperType()

View File

@@ -0,0 +1,3 @@
| var_decls.swift:4:7:4:7 | i | var_decls.swift:4:11:4:11 | 0 |
| var_decls.swift:7:5:7:5 | numbers | var_decls.swift:7:15:7:18 | [...] |
| var_decls.swift:10:12:10:12 | numbers | var_decls.swift:10:22:10:35 | [...] |

View File

@@ -0,0 +1,7 @@
// generated by codegen/codegen.py
import codeql.swift.elements
import TestUtils
from ConcreteVarDecl x
where toBeTested(x) and not x.isUnknown()
select x, x.getParentInitializer()

View File

@@ -0,0 +1,7 @@
| var_decls.swift:4:7:4:7 | i | var_decls.swift:4:7:4:7 | i |
| var_decls.swift:7:5:7:5 | numbers | var_decls.swift:7:5:7:5 | numbers |
| var_decls.swift:10:12:10:12 | numbers | var_decls.swift:10:12:10:12 | numbers |
| var_decls.swift:15:7:15:7 | wrappedValue | var_decls.swift:15:7:15:21 | ... as ... |
| var_decls.swift:20:7:20:7 | wrappedValue | var_decls.swift:20:7:20:21 | ... as ... |
| var_decls.swift:24:15:24:15 | _wrapped | var_decls.swift:24:15:24:15 | ... as ... |
| var_decls.swift:24:15:24:15 | wrapped | var_decls.swift:24:15:24:25 | ... as ... |

View File

@@ -0,0 +1,7 @@
// generated by codegen/codegen.py
import codeql.swift.elements
import TestUtils
from ConcreteVarDecl x
where toBeTested(x) and not x.isUnknown()
select x, x.getParentPattern()

View File

@@ -1,4 +0,0 @@
// generated by codegen/codegen.py
After a swift source file is added in this directory and codegen/codegen.py is run again, test queries
will appear and this file will be deleted

View File

@@ -0,0 +1,25 @@
func loop() {
for i in 1...5 {
}
var i = 0
}
var numbers = [42]
struct S {
static let numbers = [42, 404, 101]
}
@propertyWrapper
struct X<T> {
var wrappedValue: T
}
@propertyWrapper
struct Y {
var wrappedValue: Int
}
struct Wrapped {
@X @Y var wrapped : Int
}

View File

@@ -1,4 +0,0 @@
// generated by codegen/codegen.py
After a swift source file is added in this directory and codegen/codegen.py is run again, test queries
will appear and this file will be deleted

View File

@@ -0,0 +1,15 @@
| param_decls.swift:1:10:1:13 | _ | getInterfaceType: | Int | getName: | _ | getType: | Int | isInout: | no |
| param_decls.swift:1:18:1:29 | y | getInterfaceType: | Double | getName: | y | getType: | Double | isInout: | yes |
| param_decls.swift:2:10:2:13 | _ | getInterfaceType: | Int | getName: | _ | getType: | Int | isInout: | no |
| param_decls.swift:2:18:2:29 | y | getInterfaceType: | Double | getName: | y | getType: | Double | isInout: | yes |
| param_decls.swift:5:5:5:5 | self | getInterfaceType: | S | getName: | self | getType: | S | isInout: | yes |
| param_decls.swift:5:15:5:15 | x | getInterfaceType: | Int | getName: | x | getType: | Int | isInout: | no |
| param_decls.swift:5:15:5:15 | x | getInterfaceType: | Int | getName: | x | getType: | Int | isInout: | no |
| param_decls.swift:5:15:5:18 | x | getInterfaceType: | Int | getName: | x | getType: | Int | isInout: | no |
| param_decls.swift:5:23:5:23 | y | getInterfaceType: | Int | getName: | y | getType: | Int | isInout: | no |
| param_decls.swift:5:23:5:23 | y | getInterfaceType: | Int | getName: | y | getType: | Int | isInout: | no |
| param_decls.swift:5:23:5:26 | y | getInterfaceType: | Int | getName: | y | getType: | Int | isInout: | no |
| param_decls.swift:7:9:7:9 | newValue | getInterfaceType: | Int? | getName: | newValue | getType: | Int? | isInout: | no |
| param_decls.swift:12:13:12:22 | s | getInterfaceType: | String | getName: | s | getType: | String | isInout: | yes |
| param_decls.swift:13:13:13:22 | s | getInterfaceType: | String | getName: | s | getType: | String | isInout: | yes |
| param_decls.swift:14:26:14:26 | $0 | getInterfaceType: | Int | getName: | $0 | getType: | Int | isInout: | no |

View File

@@ -0,0 +1,14 @@
// generated by codegen/codegen.py
import codeql.swift.elements
import TestUtils
from ParamDecl x, Type getInterfaceType, string getName, Type getType, string isInout
where
toBeTested(x) and
not x.isUnknown() and
getInterfaceType = x.getInterfaceType() and
getName = x.getName() and
getType = x.getType() and
if x.isInout() then isInout = "yes" else isInout = "no"
select x, "getInterfaceType:", getInterfaceType, "getName:", getName, "getType:", getType,
"isInout:", isInout

View File

@@ -0,0 +1,7 @@
// generated by codegen/codegen.py
import codeql.swift.elements
import TestUtils
from ParamDecl x, int index
where toBeTested(x) and not x.isUnknown()
select x, index, x.getAccessorDecl(index)

View File

@@ -0,0 +1,7 @@
// generated by codegen/codegen.py
import codeql.swift.elements
import TestUtils
from ParamDecl x
where toBeTested(x) and not x.isUnknown()
select x, x.getAttachedPropertyWrapperType()

View File

@@ -0,0 +1,7 @@
// generated by codegen/codegen.py
import codeql.swift.elements
import TestUtils
from ParamDecl x
where toBeTested(x) and not x.isUnknown()
select x, x.getParentInitializer()

View File

@@ -0,0 +1,7 @@
// generated by codegen/codegen.py
import codeql.swift.elements
import TestUtils
from ParamDecl x
where toBeTested(x) and not x.isUnknown()
select x, x.getParentPattern()

View File

@@ -0,0 +1,15 @@
func foo(_: Int, x y: inout Double) {}
func bar(_: Int, x y: inout Double) {}
struct S {
subscript(x: Int, y: Int) -> Int? {
get { nil }
set {}
}
}
func closures() {
let x = {(s: inout String) -> String in s}
let y = {(s: inout String) -> String in ""}
let z : (Int) -> Int = { $0 + 1 }
}