mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Swift: extract opaque types and their decls
This commit is contained in:
@@ -390,4 +390,15 @@ codeql::IfConfigDecl DeclTranslator::translateIfConfigDecl(const swift::IfConfig
|
||||
return entry;
|
||||
}
|
||||
|
||||
std::optional<codeql::OpaqueTypeDecl> DeclTranslator::translateOpaqueTypeDecl(
|
||||
const swift::OpaqueTypeDecl& decl) {
|
||||
if (auto entry = createNamedEntry(decl)) {
|
||||
fillTypeDecl(decl, *entry);
|
||||
entry->naming_declaration = dispatcher.fetchLabel(decl.getNamingDecl());
|
||||
entry->opaque_generic_params = dispatcher.fetchRepeatedLabels(decl.getOpaqueGenericParams());
|
||||
return entry;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace codeql
|
||||
|
||||
@@ -45,6 +45,7 @@ class DeclTranslator : public AstTranslatorBase<DeclTranslator> {
|
||||
codeql::ImportDecl translateImportDecl(const swift::ImportDecl& decl);
|
||||
std::optional<codeql::ModuleDecl> translateModuleDecl(const swift::ModuleDecl& decl);
|
||||
codeql::IfConfigDecl translateIfConfigDecl(const swift::IfConfigDecl& decl);
|
||||
std::optional<codeql::OpaqueTypeDecl> translateOpaqueTypeDecl(const swift::OpaqueTypeDecl& decl);
|
||||
|
||||
private:
|
||||
std::string mangledName(const swift::ValueDecl& decl);
|
||||
|
||||
@@ -250,4 +250,12 @@ codeql::ModuleType TypeTranslator::translateModuleType(const swift::ModuleType&
|
||||
entry.module = dispatcher.fetchLabel(type.getModule());
|
||||
return entry;
|
||||
}
|
||||
|
||||
codeql::OpaqueTypeArchetypeType TypeTranslator::translateOpaqueTypeArchetypeType(
|
||||
const swift::OpaqueTypeArchetypeType& type) {
|
||||
auto entry = createTypeEntry(type);
|
||||
fillArchetypeType(type, entry);
|
||||
entry.declaration = dispatcher.fetchLabel(type.getDecl());
|
||||
return entry;
|
||||
}
|
||||
} // namespace codeql
|
||||
|
||||
@@ -69,6 +69,8 @@ class TypeTranslator : public TypeTranslatorBase<TypeTranslator> {
|
||||
codeql::BuiltinIntegerType translateBuiltinIntegerType(const swift::BuiltinIntegerType& type);
|
||||
codeql::OpenedArchetypeType translateOpenedArchetypeType(const swift::OpenedArchetypeType& type);
|
||||
codeql::ModuleType translateModuleType(const swift::ModuleType& type);
|
||||
codeql::OpaqueTypeArchetypeType translateOpaqueTypeArchetypeType(
|
||||
const swift::OpaqueTypeArchetypeType& type);
|
||||
|
||||
private:
|
||||
void fillType(const swift::TypeBase& type, codeql::Type& entry);
|
||||
|
||||
@@ -259,6 +259,12 @@ module Raw {
|
||||
|
||||
class OpaqueTypeDecl extends @opaque_type_decl, GenericTypeDecl {
|
||||
override string toString() { result = "OpaqueTypeDecl" }
|
||||
|
||||
ValueDecl getNamingDeclaration() { opaque_type_decls(this, result) }
|
||||
|
||||
GenericTypeParamType getOpaqueGenericParam(int index) {
|
||||
opaque_type_decl_opaque_generic_params(this, index, result)
|
||||
}
|
||||
}
|
||||
|
||||
class ParamDecl extends @param_decl, VarDecl {
|
||||
@@ -1477,6 +1483,8 @@ module Raw {
|
||||
|
||||
class OpaqueTypeArchetypeType extends @opaque_type_archetype_type, ArchetypeType {
|
||||
override string toString() { result = "OpaqueTypeArchetypeType" }
|
||||
|
||||
OpaqueTypeDecl getDeclaration() { opaque_type_archetype_types(this, result) }
|
||||
}
|
||||
|
||||
class OpenedArchetypeType extends @opened_archetype_type, ArchetypeType {
|
||||
|
||||
@@ -2,9 +2,70 @@
|
||||
private import codeql.swift.generated.Synth
|
||||
private import codeql.swift.generated.Raw
|
||||
import codeql.swift.elements.decl.GenericTypeDecl
|
||||
import codeql.swift.elements.type.GenericTypeParamType
|
||||
import codeql.swift.elements.decl.ValueDecl
|
||||
|
||||
module Generated {
|
||||
/**
|
||||
* A declaration of an opaque type, that is formally equivalent to a given type but abstracts it
|
||||
* away.
|
||||
*
|
||||
* Such a declaration is implicitly given when a declaration is written with an opaque result type,
|
||||
* for example
|
||||
* ```
|
||||
* func opaque() -> some SignedInteger { return 1 }
|
||||
* ```
|
||||
* See https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html.
|
||||
*/
|
||||
class OpaqueTypeDecl extends Synth::TOpaqueTypeDecl, GenericTypeDecl {
|
||||
override string getAPrimaryQlClass() { result = "OpaqueTypeDecl" }
|
||||
|
||||
/**
|
||||
* Gets the naming declaration of this opaque type declaration.
|
||||
*
|
||||
* This includes nodes from the "hidden" AST. It can be overridden in subclasses to change the
|
||||
* behavior of both the `Immediate` and non-`Immediate` versions.
|
||||
*/
|
||||
ValueDecl getImmediateNamingDeclaration() {
|
||||
result =
|
||||
Synth::convertValueDeclFromRaw(Synth::convertOpaqueTypeDeclToRaw(this)
|
||||
.(Raw::OpaqueTypeDecl)
|
||||
.getNamingDeclaration())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the naming declaration of this opaque type declaration.
|
||||
*/
|
||||
final ValueDecl getNamingDeclaration() { result = getImmediateNamingDeclaration().resolve() }
|
||||
|
||||
/**
|
||||
* Gets the `index`th opaque generic parameter of this opaque type declaration (0-based).
|
||||
*
|
||||
* This includes nodes from the "hidden" AST. It can be overridden in subclasses to change the
|
||||
* behavior of both the `Immediate` and non-`Immediate` versions.
|
||||
*/
|
||||
GenericTypeParamType getImmediateOpaqueGenericParam(int index) {
|
||||
result =
|
||||
Synth::convertGenericTypeParamTypeFromRaw(Synth::convertOpaqueTypeDeclToRaw(this)
|
||||
.(Raw::OpaqueTypeDecl)
|
||||
.getOpaqueGenericParam(index))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `index`th opaque generic parameter of this opaque type declaration (0-based).
|
||||
*/
|
||||
final GenericTypeParamType getOpaqueGenericParam(int index) {
|
||||
result = getImmediateOpaqueGenericParam(index).resolve()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets any of the opaque generic parameters of this opaque type declaration.
|
||||
*/
|
||||
final GenericTypeParamType getAnOpaqueGenericParam() { result = getOpaqueGenericParam(_) }
|
||||
|
||||
/**
|
||||
* Gets the number of opaque generic parameters of this opaque type declaration.
|
||||
*/
|
||||
final int getNumberOfOpaqueGenericParams() { result = count(getAnOpaqueGenericParam()) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,33 @@
|
||||
private import codeql.swift.generated.Synth
|
||||
private import codeql.swift.generated.Raw
|
||||
import codeql.swift.elements.type.ArchetypeType
|
||||
import codeql.swift.elements.decl.OpaqueTypeDecl
|
||||
|
||||
module Generated {
|
||||
/**
|
||||
* An opaque type, that is a type formally equivalent to an underlying type but abstracting it away.
|
||||
*
|
||||
* See https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html.
|
||||
*/
|
||||
class OpaqueTypeArchetypeType extends Synth::TOpaqueTypeArchetypeType, ArchetypeType {
|
||||
override string getAPrimaryQlClass() { result = "OpaqueTypeArchetypeType" }
|
||||
|
||||
/**
|
||||
* Gets the declaration of this opaque type archetype type.
|
||||
*
|
||||
* This includes nodes from the "hidden" AST. It can be overridden in subclasses to change the
|
||||
* behavior of both the `Immediate` and non-`Immediate` versions.
|
||||
*/
|
||||
OpaqueTypeDecl getImmediateDeclaration() {
|
||||
result =
|
||||
Synth::convertOpaqueTypeDeclFromRaw(Synth::convertOpaqueTypeArchetypeTypeToRaw(this)
|
||||
.(Raw::OpaqueTypeArchetypeType)
|
||||
.getDeclaration())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the declaration of this opaque type archetype type.
|
||||
*/
|
||||
final OpaqueTypeDecl getDeclaration() { result = getImmediateDeclaration().resolve() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,7 +528,15 @@ nominal_type_decls( //dir=decl
|
||||
);
|
||||
|
||||
opaque_type_decls( //dir=decl
|
||||
unique int id: @opaque_type_decl
|
||||
unique int id: @opaque_type_decl,
|
||||
int naming_declaration: @value_decl_or_none ref
|
||||
);
|
||||
|
||||
#keyset[id, index]
|
||||
opaque_type_decl_opaque_generic_params( //dir=decl
|
||||
int id: @opaque_type_decl ref,
|
||||
int index: int ref,
|
||||
int opaque_generic_param: @generic_type_param_type_or_none ref
|
||||
);
|
||||
|
||||
param_decls( //dir=decl
|
||||
@@ -2222,7 +2230,8 @@ dictionary_types( //dir=type
|
||||
;
|
||||
|
||||
opaque_type_archetype_types( //dir=type
|
||||
unique int id: @opaque_type_archetype_type
|
||||
unique int id: @opaque_type_archetype_type,
|
||||
int declaration: @opaque_type_decl_or_none ref
|
||||
);
|
||||
|
||||
opened_archetype_types( //dir=type
|
||||
@@ -2389,6 +2398,11 @@ variadic_sequence_types( //dir=type
|
||||
| @unspecified_element
|
||||
;
|
||||
|
||||
@opaque_type_decl_or_none =
|
||||
@opaque_type_decl
|
||||
| @unspecified_element
|
||||
;
|
||||
|
||||
@opaque_value_expr_or_none =
|
||||
@opaque_value_expr
|
||||
| @unspecified_element
|
||||
|
||||
@@ -5,30 +5,31 @@ predicate toBeTested(Element e) {
|
||||
e instanceof File
|
||||
or
|
||||
exists(ModuleDecl m |
|
||||
m = e and
|
||||
not m.isBuiltinModule() and
|
||||
not m.isSystemModule() and
|
||||
(m = e or m.getInterfaceType() = e)
|
||||
not m.isSystemModule()
|
||||
)
|
||||
or
|
||||
exists(Locatable loc |
|
||||
loc.getLocation().getFile().getName().matches("%swift/ql/test%") and
|
||||
e.(Locatable).getLocation().getFile().getName().matches("%swift/ql/test%")
|
||||
or
|
||||
exists(Element tested |
|
||||
toBeTested(tested) and
|
||||
(
|
||||
e = loc
|
||||
e = tested.(ValueDecl).getInterfaceType()
|
||||
or
|
||||
exists(Type t |
|
||||
(e = t or e = t.(ExistentialType).getConstraint() or e = t.getCanonicalType()) and
|
||||
(
|
||||
t = loc.(ValueDecl).getInterfaceType()
|
||||
or
|
||||
t = loc.(NominalTypeDecl).getType()
|
||||
or
|
||||
t = loc.(VarDecl).getType()
|
||||
or
|
||||
t = loc.(Expr).getType()
|
||||
)
|
||||
)
|
||||
e = tested.(NominalTypeDecl).getType()
|
||||
or
|
||||
e = tested.(VarDecl).getType()
|
||||
or
|
||||
e = tested.(Expr).getType()
|
||||
or
|
||||
e = tested.(Type).getCanonicalType()
|
||||
or
|
||||
e = tested.(ExistentialType).getConstraint()
|
||||
or
|
||||
e.(UnspecifiedElement).getParent() = tested
|
||||
or
|
||||
e.(OpaqueTypeDecl).getNamingDeclaration() = tested
|
||||
)
|
||||
)
|
||||
or
|
||||
toBeTested(e.(UnspecifiedElement).getParent())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
| file://:0:0:0:0 | _ | getModule: | file://:0:0:0:0 | opaque_types | getInterfaceType: | (some Base).Type | getName: | _ | getNamingDeclaration: | opaque_types.swift:9:1:9:51 | baz(_:) |
|
||||
| file://:0:0:0:0 | _ | getModule: | file://:0:0:0:0 | opaque_types | getInterfaceType: | (some P).Type | getName: | _ | getNamingDeclaration: | opaque_types.swift:5:1:5:45 | bar(_:) |
|
||||
| file://:0:0:0:0 | _ | getModule: | file://:0:0:0:0 | opaque_types | getInterfaceType: | (some P).Type | getName: | _ | getNamingDeclaration: | opaque_types.swift:13:1:13:59 | bazz() |
|
||||
| file://:0:0:0:0 | _ | getModule: | file://:0:0:0:0 | opaque_types | getInterfaceType: | (some SignedInteger).Type | getName: | _ | getNamingDeclaration: | opaque_types.swift:1:1:1:45 | foo() |
|
||||
@@ -0,0 +1,16 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from
|
||||
OpaqueTypeDecl x, ModuleDecl getModule, Type getInterfaceType, string getName,
|
||||
ValueDecl getNamingDeclaration
|
||||
where
|
||||
toBeTested(x) and
|
||||
not x.isUnknown() and
|
||||
getModule = x.getModule() and
|
||||
getInterfaceType = x.getInterfaceType() and
|
||||
getName = x.getName() and
|
||||
getNamingDeclaration = x.getNamingDeclaration()
|
||||
select x, "getModule:", getModule, "getInterfaceType:", getInterfaceType, "getName:", getName,
|
||||
"getNamingDeclaration:", getNamingDeclaration
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from OpaqueTypeDecl x, int index
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, index, x.getBaseType(index)
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from OpaqueTypeDecl x, int index
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, index, x.getGenericTypeParam(index)
|
||||
@@ -0,0 +1,4 @@
|
||||
| file://:0:0:0:0 | _ | 0 | \u03c4_0_0 |
|
||||
| file://:0:0:0:0 | _ | 0 | \u03c4_1_0 |
|
||||
| file://:0:0:0:0 | _ | 0 | \u03c4_1_0 |
|
||||
| file://:0:0:0:0 | _ | 0 | \u03c4_1_0 |
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from OpaqueTypeDecl x, int index
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, index, x.getOpaqueGenericParam(index)
|
||||
@@ -0,0 +1,13 @@
|
||||
func foo() -> some SignedInteger { return 1 }
|
||||
|
||||
protocol P {}
|
||||
|
||||
func bar<T: P>(_ x: T) -> some P { return x }
|
||||
|
||||
class Base {}
|
||||
|
||||
func baz<T: Base>(_ x: T) -> some Base { return x }
|
||||
|
||||
class Generic<T: Equatable>: P {}
|
||||
|
||||
func bazz<T: Equatable>() -> some P { return Generic<T>() }
|
||||
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
| some Base | getName: | some Base | getCanonicalType: | some Base | getInterfaceType: | \u03c4_1_0 | getDeclaration: | file://:0:0:0:0 | _ |
|
||||
| some P | getName: | some P | getCanonicalType: | some P | getInterfaceType: | \u03c4_1_0 | getDeclaration: | file://:0:0:0:0 | _ |
|
||||
| some P | getName: | some P | getCanonicalType: | some P | getInterfaceType: | \u03c4_1_0 | getDeclaration: | file://:0:0:0:0 | _ |
|
||||
| some SignedInteger | getName: | some SignedInteger | getCanonicalType: | some SignedInteger | getInterfaceType: | \u03c4_0_0 | getDeclaration: | file://:0:0:0:0 | _ |
|
||||
@@ -0,0 +1,16 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from
|
||||
OpaqueTypeArchetypeType x, string getName, Type getCanonicalType, Type getInterfaceType,
|
||||
OpaqueTypeDecl getDeclaration
|
||||
where
|
||||
toBeTested(x) and
|
||||
not x.isUnknown() and
|
||||
getName = x.getName() and
|
||||
getCanonicalType = x.getCanonicalType() and
|
||||
getInterfaceType = x.getInterfaceType() and
|
||||
getDeclaration = x.getDeclaration()
|
||||
select x, "getName:", getName, "getCanonicalType:", getCanonicalType, "getInterfaceType:",
|
||||
getInterfaceType, "getDeclaration:", getDeclaration
|
||||
@@ -0,0 +1,13 @@
|
||||
| some P | 0 | opaque_types.swift:3:1:3:13 | P |
|
||||
| some P | 0 | opaque_types.swift:3:1:3:13 | P |
|
||||
| some SignedInteger | 0 | file://:0:0:0:0 | SignedInteger |
|
||||
| some SignedInteger | 1 | file://:0:0:0:0 | BinaryInteger |
|
||||
| some SignedInteger | 2 | file://:0:0:0:0 | SignedNumeric |
|
||||
| some SignedInteger | 3 | file://:0:0:0:0 | CustomStringConvertible |
|
||||
| some SignedInteger | 4 | file://:0:0:0:0 | Hashable |
|
||||
| some SignedInteger | 5 | file://:0:0:0:0 | Numeric |
|
||||
| some SignedInteger | 6 | file://:0:0:0:0 | Strideable |
|
||||
| some SignedInteger | 7 | file://:0:0:0:0 | Equatable |
|
||||
| some SignedInteger | 8 | file://:0:0:0:0 | AdditiveArithmetic |
|
||||
| some SignedInteger | 9 | file://:0:0:0:0 | ExpressibleByIntegerLiteral |
|
||||
| some SignedInteger | 10 | file://:0:0:0:0 | Comparable |
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from OpaqueTypeArchetypeType x, int index
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, index, x.getProtocol(index)
|
||||
@@ -0,0 +1 @@
|
||||
| some Base | Base |
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from OpaqueTypeArchetypeType x
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, x.getSuperclass()
|
||||
@@ -0,0 +1,13 @@
|
||||
func foo() -> some SignedInteger { return 1 }
|
||||
|
||||
protocol P {}
|
||||
|
||||
func bar<T: P>(_ x: T) -> some P { return x }
|
||||
|
||||
class Base {}
|
||||
|
||||
func baz<T: Base>(_ x: T) -> some Base { return x }
|
||||
|
||||
class Generic<T: Equatable>: P {}
|
||||
|
||||
func bazz<T: Equatable>() -> some P { return Generic<T>() }
|
||||
@@ -218,7 +218,20 @@ class NominalTypeDecl(GenericTypeDecl, IterableDeclContext):
|
||||
type: Type
|
||||
|
||||
class OpaqueTypeDecl(GenericTypeDecl):
|
||||
pass
|
||||
"""
|
||||
A declaration of an opaque type, that is formally equivalent to a given type but abstracts it
|
||||
away.
|
||||
|
||||
Such a declaration is implicitly given when a declaration is written with an opaque result type,
|
||||
for example
|
||||
```
|
||||
func opaque() -> some SignedInteger { return 1 }
|
||||
```
|
||||
See https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html.
|
||||
"""
|
||||
naming_declaration: ValueDecl
|
||||
opaque_generic_params: list["GenericTypeParamType"]
|
||||
opaque_generic_params: list["GenericTypeParamType"]
|
||||
|
||||
class TypeAliasDecl(GenericTypeDecl):
|
||||
pass
|
||||
@@ -966,7 +979,10 @@ class NominalType(NominalOrBoundGenericNominalType):
|
||||
pass
|
||||
|
||||
class OpaqueTypeArchetypeType(ArchetypeType):
|
||||
pass
|
||||
"""An opaque type, that is a type formally equivalent to an underlying type but abstracting it away.
|
||||
|
||||
See https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html."""
|
||||
declaration: OpaqueTypeDecl
|
||||
|
||||
class OpenedArchetypeType(ArchetypeType):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user