C#: Speed up Implements.qll and Unification.qll

Restrict constructed GVN types to those that are complete, and reduce
intermediate string construction in `toString()` computations.
This commit is contained in:
Tom Hvitved
2020-08-12 21:10:05 +02:00
parent 1f432dc45f
commit dcccdee227
2 changed files with 113 additions and 60 deletions

View File

@@ -259,7 +259,7 @@ private module Gvn {
private newtype TGvnType =
TLeafGvnType(LeafType t) or
TMethodTypeParameterGvnType(int i) { i = any(MethodTypeParameter p).getIndex() } or
TConstructedGvnType(ConstructedGvnTypeList l)
TConstructedGvnType(ConstructedGvnTypeList l) { l.isComplete() }
private newtype TConstructedGvnTypeList =
TConstructedGvnTypeNil(Unification::CompoundTypeKind k) or
@@ -334,6 +334,8 @@ private module Gvn {
)
}
predicate isComplete() { this.getKind().getNumberOfTypeParameters() - 1 = this.length() }
private GvnType getArg(int i) {
exists(GvnType head, ConstructedGvnTypeList tail |
this = TConstructedGvnTypeCons(head, tail)
@@ -345,47 +347,71 @@ private module Gvn {
)
}
private Unification::GenericType getConstructedGenericDeclaringTypeAt(int i) {
i = 0 and
result = this.getKind().getConstructedSourceDeclaration()
or
result = this.getConstructedGenericDeclaringTypeAt(i - 1).getGenericDeclaringType()
}
private predicate isDeclaringTypeAt(int i) {
exists(this.getConstructedGenericDeclaringTypeAt(i - 1))
}
/**
* Gets a textual representation of this constructed type, restricted
* to the prefix `t` of the underlying source declaration type.
*
* The `toString()` calculation needs to be split up into prefixes, in
* order to apply the type arguments correctly. For example, a source
* declaration type `A<>.B.C<,>` applied to types `int, string, bool`
* needs to be printed as `A<int>.B.C<string,bool>`.
* Gets the `j`th `toString()` part of the `i`th nested component of this
* constructed type, if any. The nested components are sorted in reverse
* order, while the individual parts are sorted in normal order.
*/
language[monotonicAggregates]
private string toStringConstructed(Unification::GenericType t) {
t = this.getKind().getConstructedSourceDeclaration().getGenericDeclaringType*() and
exists(int offset, int children, string name, string nameArgs |
offset = t.getNumberOfDeclaringArguments() and
children = t.getNumberOfArgumentsSelf() and
name = Unification::getNameNested(t) and
if children = 0
then nameArgs = name
else
exists(string offsetArgs |
offsetArgs =
concat(int i |
i in [offset .. offset + children - 1]
|
this.getArg(i).toString(), "," order by i
) and
nameArgs = name.prefix(name.length() - children - 1) + "<" + offsetArgs + ">"
private string toStringConstructedPart(int i, int j) {
this.isComplete() and
exists(Unification::GenericType t |
t = this.getConstructedGenericDeclaringTypeAt(i) and
exists(int offset, int children, string name |
offset = t.getNumberOfDeclaringArguments() and
children = t.getNumberOfArgumentsSelf() and
name = Unification::getNameNested(t) and
if children = 0
then
j = 0 and result = name
or
this.isDeclaringTypeAt(i) and j = 1 and result = "."
else (
j = 0 and result = name.prefix(name.length() - children - 1) + "<"
or
j in [1 .. 2 * children - 1] and
if j % 2 = 0
then result = ","
else result = this.getArg((j + 1) / 2 + offset - 1).toString()
or
j = 2 * children and
result = ">"
or
this.isDeclaringTypeAt(i) and
j = 2 * children + 1 and
result = "."
)
|
offset = 0 and result = nameArgs
or
result = this.toStringConstructed(t.getGenericDeclaringType()) + "." + nameArgs
)
)
}
language[monotonicAggregates]
string toString() {
this.isComplete() and
exists(Unification::CompoundTypeKind k | k = this.getKind() |
result = k.toStringBuiltin(this.getArg(0).toString())
or
result = this.toStringConstructed(k.getConstructedSourceDeclaration())
result =
strictconcat(int i, int j |
exists(Unification::GenericType t, int children |
t = this.getConstructedGenericDeclaringTypeAt(i) and
children = t.getNumberOfArgumentsSelf() and
if children = 0 then j = 0 else j in [0 .. 2 * children]
)
|
this.toStringConstructedPart(i, j) order by i desc, j
)
)
}

View File

@@ -213,6 +213,8 @@ module Gvn {
)
}
predicate isComplete() { this.getKind().getNumberOfTypeParameters() - 1 = this.length() }
GvnType getArg(int i) {
exists(GvnType head, ConstructedGvnTypeList tail |
this = TConstructedGvnTypeCons(head, tail)
@@ -224,47 +226,72 @@ module Gvn {
)
}
private GenericType getConstructedGenericDeclaringTypeAt(int i) {
i = 0 and
result = this.getKind().getConstructedSourceDeclaration()
or
result = this.getConstructedGenericDeclaringTypeAt(i - 1).getGenericDeclaringType()
}
private predicate isDeclaringTypeAt(int i) {
exists(this.getConstructedGenericDeclaringTypeAt(i - 1))
}
/**
* Gets a textual representation of this constructed type, restricted
* to the prefix `t` of the underlying source declaration type.
*
* The `toString()` calculation needs to be split up into prefixes, in
* order to apply the type arguments correctly. For example, a source
* declaration type `A<>.B.C<,>` applied to types `int, string, bool`
* needs to be printed as `A<int>.B.C<string,bool>`.
* Gets the `j`th `toString()` part of the `i`th nested component of this
* constructed type, if any. The nested components are sorted in reverse
* order, while the individual parts are sorted in normal order.
*/
language[monotonicAggregates]
private string toStringConstructed(GenericType t) {
t = this.getKind().getConstructedSourceDeclaration().getGenericDeclaringType*() and
exists(int offset, int children, string name, string nameArgs |
offset = t.getNumberOfDeclaringArguments() and
children = t.getNumberOfArgumentsSelf() and
name = getNameNested(t) and
if children = 0
then nameArgs = name
else
exists(string offsetArgs |
offsetArgs =
concat(int i |
i in [offset .. offset + children - 1]
|
this.getArg(i).toString(), "," order by i
) and
nameArgs = name.prefix(name.length() - children - 1) + "<" + offsetArgs + ">"
private string toStringConstructedPart(int i, int j) {
this.isComplete() and
exists(GenericType t |
t = this.getConstructedGenericDeclaringTypeAt(i) and
exists(int offset, int children, string name |
offset = t.getNumberOfDeclaringArguments() and
children = t.getNumberOfArgumentsSelf() and
name = getNameNested(t) and
if children = 0
then
j = 0 and result = name
or
this.isDeclaringTypeAt(i) and j = 1 and result = "."
else (
j = 0 and result = name.prefix(name.length() - children - 1) + "<"
or
j in [1 .. 2 * children - 1] and
if j % 2 = 0
then result = ","
else result = this.getArg((j + 1) / 2 + offset - 1).toString()
or
j = 2 * children and
result = ">"
or
this.isDeclaringTypeAt(i) and
j = 2 * children + 1 and
result = "."
)
|
offset = 0 and result = nameArgs
or
result = this.toStringConstructed(t.getGenericDeclaringType()) + "." + nameArgs
)
)
}
language[monotonicAggregates]
string toString() {
this.isComplete() and
exists(CompoundTypeKind k | k = this.getKind() |
result = k.toStringBuiltin(this.getArg(0).toString())
or
result = this.toStringConstructed(k.getConstructedSourceDeclaration())
result =
strictconcat(int i, int j, int offset |
exists(GenericType t, int children |
t = this.getConstructedGenericDeclaringTypeAt(i) and
children = t.getNumberOfArgumentsSelf() and
(if this.isDeclaringTypeAt(i) then offset = 1 else offset = 0) and
if children = 0 then j in [0 .. offset] else j in [0 .. 2 * children + offset]
)
|
this.toStringConstructedPart(i, j) order by i desc, j
)
)
}
@@ -482,7 +509,7 @@ module Gvn {
newtype TGvnType =
TLeafGvnType(LeafType t) or
TTypeParameterGvnType() or
TConstructedGvnType(ConstructedGvnTypeList l)
TConstructedGvnType(ConstructedGvnTypeList l) { l.isComplete() }
cached
newtype TConstructedGvnTypeList =