Skip to content

Commit 6dc1244

Browse files
authored
Merge pull request #4064 from hvitved/csharp/gvn-speedup
C#: Speed up `Implements.qll` and `Unification.qll`
2 parents aa522b5 + acb0828 commit 6dc1244

File tree

2 files changed

+117
-60
lines changed

2 files changed

+117
-60
lines changed

csharp/ql/src/semmle/code/csharp/Implements.qll

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ private module Gvn {
259259
private newtype TGvnType =
260260
TLeafGvnType(LeafType t) or
261261
TMethodTypeParameterGvnType(int i) { i = any(MethodTypeParameter p).getIndex() } or
262-
TConstructedGvnType(ConstructedGvnTypeList l)
262+
TConstructedGvnType(ConstructedGvnTypeList l) { l.isFullyConstructed() }
263263

264264
private newtype TConstructedGvnTypeList =
265265
TConstructedGvnTypeNil(Unification::CompoundTypeKind k) or
@@ -334,6 +334,10 @@ private module Gvn {
334334
)
335335
}
336336

337+
predicate isFullyConstructed() {
338+
this.getKind().getNumberOfTypeParameters() - 1 = this.length()
339+
}
340+
337341
private GvnType getArg(int i) {
338342
exists(GvnType head, ConstructedGvnTypeList tail |
339343
this = TConstructedGvnTypeCons(head, tail)
@@ -345,47 +349,71 @@ private module Gvn {
345349
)
346350
}
347351

352+
private Unification::GenericType getConstructedGenericDeclaringTypeAt(int i) {
353+
i = 0 and
354+
result = this.getKind().getConstructedSourceDeclaration()
355+
or
356+
result = this.getConstructedGenericDeclaringTypeAt(i - 1).getGenericDeclaringType()
357+
}
358+
359+
private predicate isDeclaringTypeAt(int i) {
360+
exists(this.getConstructedGenericDeclaringTypeAt(i - 1))
361+
}
362+
348363
/**
349-
* Gets a textual representation of this constructed type, restricted
350-
* to the prefix `t` of the underlying source declaration type.
351-
*
352-
* The `toString()` calculation needs to be split up into prefixes, in
353-
* order to apply the type arguments correctly. For example, a source
354-
* declaration type `A<>.B.C<,>` applied to types `int, string, bool`
355-
* needs to be printed as `A<int>.B.C<string,bool>`.
364+
* Gets the `j`th `toString()` part of the `i`th nested component of this
365+
* constructed type, if any. The nested components are sorted in reverse
366+
* order, while the individual parts are sorted in normal order.
356367
*/
357368
language[monotonicAggregates]
358-
private string toStringConstructed(Unification::GenericType t) {
359-
t = this.getKind().getConstructedSourceDeclaration().getGenericDeclaringType*() and
360-
exists(int offset, int children, string name, string nameArgs |
361-
offset = t.getNumberOfDeclaringArguments() and
362-
children = t.getNumberOfArgumentsSelf() and
363-
name = Unification::getNameNested(t) and
364-
if children = 0
365-
then nameArgs = name
366-
else
367-
exists(string offsetArgs |
368-
offsetArgs =
369-
concat(int i |
370-
i in [offset .. offset + children - 1]
371-
|
372-
this.getArg(i).toString(), "," order by i
373-
) and
374-
nameArgs = name.prefix(name.length() - children - 1) + "<" + offsetArgs + ">"
369+
private string toStringConstructedPart(int i, int j) {
370+
this.isFullyConstructed() and
371+
exists(Unification::GenericType t |
372+
t = this.getConstructedGenericDeclaringTypeAt(i) and
373+
exists(int offset, int children, string name |
374+
offset = t.getNumberOfDeclaringArguments() and
375+
children = t.getNumberOfArgumentsSelf() and
376+
name = Unification::getNameNested(t) and
377+
if children = 0
378+
then
379+
j = 0 and result = name
380+
or
381+
this.isDeclaringTypeAt(i) and j = 1 and result = "."
382+
else (
383+
j = 0 and result = name.prefix(name.length() - children - 1) + "<"
384+
or
385+
j in [1 .. 2 * children - 1] and
386+
if j % 2 = 0
387+
then result = ","
388+
else result = this.getArg((j + 1) / 2 + offset - 1).toString()
389+
or
390+
j = 2 * children and
391+
result = ">"
392+
or
393+
this.isDeclaringTypeAt(i) and
394+
j = 2 * children + 1 and
395+
result = "."
375396
)
376-
|
377-
offset = 0 and result = nameArgs
378-
or
379-
result = this.toStringConstructed(t.getGenericDeclaringType()) + "." + nameArgs
397+
)
380398
)
381399
}
382400

383401
language[monotonicAggregates]
384402
string toString() {
403+
this.isFullyConstructed() and
385404
exists(Unification::CompoundTypeKind k | k = this.getKind() |
386405
result = k.toStringBuiltin(this.getArg(0).toString())
387406
or
388-
result = this.toStringConstructed(k.getConstructedSourceDeclaration())
407+
result =
408+
strictconcat(int i, int j |
409+
exists(Unification::GenericType t, int children |
410+
t = this.getConstructedGenericDeclaringTypeAt(i) and
411+
children = t.getNumberOfArgumentsSelf() and
412+
if children = 0 then j = 0 else j in [0 .. 2 * children]
413+
)
414+
|
415+
this.toStringConstructedPart(i, j) order by i desc, j
416+
)
389417
)
390418
}
391419

csharp/ql/src/semmle/code/csharp/Unification.qll

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ module Gvn {
213213
)
214214
}
215215

216+
predicate isFullyConstructed() {
217+
this.getKind().getNumberOfTypeParameters() - 1 = this.length()
218+
}
219+
216220
GvnType getArg(int i) {
217221
exists(GvnType head, ConstructedGvnTypeList tail |
218222
this = TConstructedGvnTypeCons(head, tail)
@@ -224,47 +228,72 @@ module Gvn {
224228
)
225229
}
226230

231+
private GenericType getConstructedGenericDeclaringTypeAt(int i) {
232+
i = 0 and
233+
result = this.getKind().getConstructedSourceDeclaration()
234+
or
235+
result = this.getConstructedGenericDeclaringTypeAt(i - 1).getGenericDeclaringType()
236+
}
237+
238+
private predicate isDeclaringTypeAt(int i) {
239+
exists(this.getConstructedGenericDeclaringTypeAt(i - 1))
240+
}
241+
227242
/**
228-
* Gets a textual representation of this constructed type, restricted
229-
* to the prefix `t` of the underlying source declaration type.
230-
*
231-
* The `toString()` calculation needs to be split up into prefixes, in
232-
* order to apply the type arguments correctly. For example, a source
233-
* declaration type `A<>.B.C<,>` applied to types `int, string, bool`
234-
* needs to be printed as `A<int>.B.C<string,bool>`.
243+
* Gets the `j`th `toString()` part of the `i`th nested component of this
244+
* constructed type, if any. The nested components are sorted in reverse
245+
* order, while the individual parts are sorted in normal order.
235246
*/
236247
language[monotonicAggregates]
237-
private string toStringConstructed(GenericType t) {
238-
t = this.getKind().getConstructedSourceDeclaration().getGenericDeclaringType*() and
239-
exists(int offset, int children, string name, string nameArgs |
240-
offset = t.getNumberOfDeclaringArguments() and
241-
children = t.getNumberOfArgumentsSelf() and
242-
name = getNameNested(t) and
243-
if children = 0
244-
then nameArgs = name
245-
else
246-
exists(string offsetArgs |
247-
offsetArgs =
248-
concat(int i |
249-
i in [offset .. offset + children - 1]
250-
|
251-
this.getArg(i).toString(), "," order by i
252-
) and
253-
nameArgs = name.prefix(name.length() - children - 1) + "<" + offsetArgs + ">"
248+
private string toStringConstructedPart(int i, int j) {
249+
this.isFullyConstructed() and
250+
exists(GenericType t |
251+
t = this.getConstructedGenericDeclaringTypeAt(i) and
252+
exists(int offset, int children, string name |
253+
offset = t.getNumberOfDeclaringArguments() and
254+
children = t.getNumberOfArgumentsSelf() and
255+
name = getNameNested(t) and
256+
if children = 0
257+
then
258+
j = 0 and result = name
259+
or
260+
this.isDeclaringTypeAt(i) and j = 1 and result = "."
261+
else (
262+
j = 0 and result = name.prefix(name.length() - children - 1) + "<"
263+
or
264+
j in [1 .. 2 * children - 1] and
265+
if j % 2 = 0
266+
then result = ","
267+
else result = this.getArg((j + 1) / 2 + offset - 1).toString()
268+
or
269+
j = 2 * children and
270+
result = ">"
271+
or
272+
this.isDeclaringTypeAt(i) and
273+
j = 2 * children + 1 and
274+
result = "."
254275
)
255-
|
256-
offset = 0 and result = nameArgs
257-
or
258-
result = this.toStringConstructed(t.getGenericDeclaringType()) + "." + nameArgs
276+
)
259277
)
260278
}
261279

262280
language[monotonicAggregates]
263281
string toString() {
282+
this.isFullyConstructed() and
264283
exists(CompoundTypeKind k | k = this.getKind() |
265284
result = k.toStringBuiltin(this.getArg(0).toString())
266285
or
267-
result = this.toStringConstructed(k.getConstructedSourceDeclaration())
286+
result =
287+
strictconcat(int i, int j, int offset |
288+
exists(GenericType t, int children |
289+
t = this.getConstructedGenericDeclaringTypeAt(i) and
290+
children = t.getNumberOfArgumentsSelf() and
291+
(if this.isDeclaringTypeAt(i) then offset = 1 else offset = 0) and
292+
if children = 0 then j in [0 .. offset] else j in [0 .. 2 * children + offset]
293+
)
294+
|
295+
this.toStringConstructedPart(i, j) order by i desc, j
296+
)
268297
)
269298
}
270299

@@ -482,7 +511,7 @@ module Gvn {
482511
newtype TGvnType =
483512
TLeafGvnType(LeafType t) or
484513
TTypeParameterGvnType() or
485-
TConstructedGvnType(ConstructedGvnTypeList l)
514+
TConstructedGvnType(ConstructedGvnTypeList l) { l.isFullyConstructed() }
486515

487516
cached
488517
newtype TConstructedGvnTypeList =

0 commit comments

Comments
 (0)