Skip to content

Commit 7013663

Browse files
authored
Merge pull request github#10881 from tamasvajk/kotlin-constant-expr
Kotlin: Exclude constructs in serialization constructors from `java/evaluation-to-constant`
2 parents 6a7bcd3 + 80fa45f commit 7013663

File tree

9 files changed

+328
-6
lines changed

9 files changed

+328
-6
lines changed

java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/ConstantExpAppearsNonConstant.expected

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Likely Bugs/Arithmetic/ConstantExpAppearsNonConstant.ql

java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/PrintAst.expected

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,3 +478,296 @@ app/src/main/kotlin/testProject/App.kt:
478478
# 8| 16: [FieldDeclaration] int language;
479479
# 8| -1: [TypeAccess] int
480480
# 8| 0: [VarAccess] language
481+
# 10| 2: [Interface] Base
482+
# 11| 1: [Method] getId
483+
# 11| 3: [TypeAccess] String
484+
# 14| 3: [Class] X
485+
# 0| 1: [Constructor] X
486+
#-----| 4: (Parameters)
487+
# 0| 0: [Parameter] seen1
488+
# 0| 0: [TypeAccess] int
489+
# 0| 1: [Parameter] id
490+
# 0| 0: [TypeAccess] String
491+
# 0| 2: [Parameter] serializationConstructorMarker
492+
# 0| 0: [TypeAccess] SerializationConstructorMarker
493+
# 14| 5: [BlockStmt] { ... }
494+
# 14| 0: [ExprStmt] <Expr>;
495+
# 14| 0: [WhenExpr] when ...
496+
# 14| 0: [WhenBranch] ... -> ...
497+
# 14| 0: [ValueNEExpr] ... (value not-equals) ...
498+
# 14| 0: [IntegerLiteral] 0
499+
# 14| 1: [AndBitwiseExpr] ... & ...
500+
# 14| 0: [IntegerLiteral] 0
501+
# 14| 1: [VarAccess] seen1
502+
# 14| 1: [ExprStmt] <Expr>;
503+
# 14| 0: [MethodAccess] throwMissingFieldException(...)
504+
# 14| -1: [TypeAccess] PluginExceptionsKt
505+
# 14| 0: [VarAccess] seen1
506+
# 14| 1: [IntegerLiteral] 0
507+
# 14| 2: [MethodAccess] getDescriptor(...)
508+
# 14| -1: [VarAccess] INSTANCE
509+
# 14| 1: [SuperConstructorInvocationStmt] super(...)
510+
# 14| 2: [ExprStmt] <Expr>;
511+
# 14| 0: [WhenExpr] when ...
512+
# 14| 0: [WhenBranch] ... -> ...
513+
# 14| 0: [ValueEQExpr] ... (value equals) ...
514+
# 14| 0: [IntegerLiteral] 0
515+
# 14| 1: [AndBitwiseExpr] ... & ...
516+
# 14| 0: [VarAccess] seen1
517+
# 14| 1: [IntegerLiteral] 1
518+
# 14| 1: [ExprStmt] <Expr>;
519+
# 14| 0: [AssignExpr] ...=...
520+
# 14| 0: [VarAccess] X.this.id
521+
# 14| -1: [ThisAccess] X.this
522+
# 14| 0: [TypeAccess] X
523+
# 16| 1: [StringLiteral] X
524+
# 14| 1: [WhenBranch] ... -> ...
525+
# 14| 0: [BooleanLiteral] true
526+
# 14| 1: [ExprStmt] <Expr>;
527+
# 14| 0: [AssignExpr] ...=...
528+
# 14| 0: [VarAccess] X.this.id
529+
# 14| -1: [ThisAccess] X.this
530+
# 14| 0: [TypeAccess] X
531+
# 14| 1: [VarAccess] id
532+
# 0| 2: [Method] write$Self
533+
# 0| 3: [TypeAccess] Unit
534+
#-----| 4: (Parameters)
535+
# 0| 0: [Parameter] self
536+
# 0| 0: [TypeAccess] X
537+
# 0| 1: [Parameter] output
538+
# 0| 0: [TypeAccess] CompositeEncoder
539+
# 0| 2: [Parameter] serialDesc
540+
# 0| 0: [TypeAccess] SerialDescriptor
541+
# 14| 5: [BlockStmt] { ... }
542+
# 14| 0: [ExprStmt] <Expr>;
543+
# 14| 0: [WhenExpr] when ...
544+
# 14| 0: [WhenBranch] ... -> ...
545+
# 14| 0: [WhenExpr] when ...
546+
# 14| 0: [WhenBranch] ... -> ...
547+
# 14| 0: [MethodAccess] shouldEncodeElementDefault(...)
548+
# 14| -1: [VarAccess] output
549+
# 14| 0: [VarAccess] serialDesc
550+
# 14| 1: [IntegerLiteral] 0
551+
# 14| 1: [ExprStmt] <Expr>;
552+
# 14| 0: [BooleanLiteral] true
553+
# 14| 1: [WhenBranch] ... -> ...
554+
# 14| 0: [BooleanLiteral] true
555+
# 14| 1: [ExprStmt] <Expr>;
556+
# 14| 0: [ValueNEExpr] ... (value not-equals) ...
557+
# 14| 0: [MethodAccess] getId(...)
558+
# 14| -1: [VarAccess] self
559+
# 16| 1: [StringLiteral] X
560+
# 14| 1: [ExprStmt] <Expr>;
561+
# 14| 0: [MethodAccess] encodeStringElement(...)
562+
# 14| -1: [VarAccess] output
563+
# 14| 0: [VarAccess] serialDesc
564+
# 14| 1: [IntegerLiteral] 0
565+
# 14| 2: [MethodAccess] getId(...)
566+
# 14| -1: [VarAccess] self
567+
# 14| 3: [Class] $serializer
568+
# 0| 1: [FieldDeclaration] SerialDescriptor descriptor;
569+
# 0| -1: [TypeAccess] SerialDescriptor
570+
# 0| 2: [Method] childSerializers
571+
# 0| 3: [TypeAccess] KSerializer<?>[]
572+
# 0| 0: [TypeAccess] KSerializer<?>
573+
# 0| 0: [WildcardTypeAccess] ? ...
574+
# 14| 5: [BlockStmt] { ... }
575+
# 14| 0: [ReturnStmt] return ...
576+
# 14| 0: [ArrayCreationExpr] new KSerializer<?>[]
577+
# 14| -2: [ArrayInit] {...}
578+
# 14| -1: [TypeAccess] KSerializer<?>
579+
# 14| 0: [IntegerLiteral] 1
580+
# 0| 3: [Method] deserialize
581+
# 0| 3: [TypeAccess] X
582+
#-----| 4: (Parameters)
583+
# 0| 0: [Parameter] decoder
584+
# 0| 0: [TypeAccess] Decoder
585+
# 14| 5: [BlockStmt] { ... }
586+
# 14| 0: [LocalVariableDeclStmt] var ...;
587+
# 14| 1: [LocalVariableDeclExpr] tmp0_desc
588+
# 14| 0: [MethodAccess] getDescriptor(...)
589+
# 14| -1: [ThisAccess] this
590+
# 14| 1: [LocalVariableDeclStmt] var ...;
591+
# 14| 1: [LocalVariableDeclExpr] tmp1_flag
592+
# 14| 0: [BooleanLiteral] true
593+
# 14| 2: [LocalVariableDeclStmt] var ...;
594+
# 14| 1: [LocalVariableDeclExpr] tmp2_index
595+
# 14| 0: [IntegerLiteral] 0
596+
# 14| 3: [LocalVariableDeclStmt] var ...;
597+
# 14| 1: [LocalVariableDeclExpr] tmp3_bitMask0
598+
# 14| 0: [IntegerLiteral] 0
599+
# 14| 4: [LocalVariableDeclStmt] var ...;
600+
# 14| 1: [LocalVariableDeclExpr] tmp4_local0
601+
# 14| 0: [NullLiteral] null
602+
# 14| 5: [LocalVariableDeclStmt] var ...;
603+
# 14| 1: [LocalVariableDeclExpr] tmp5_input
604+
# 14| 0: [MethodAccess] beginStructure(...)
605+
# 14| -1: [VarAccess] decoder
606+
# 14| 0: [VarAccess] tmp0_desc
607+
# 14| 6: [ExprStmt] <Expr>;
608+
# 14| 0: [WhenExpr] when ...
609+
# 14| 0: [WhenBranch] ... -> ...
610+
# 14| 0: [MethodAccess] decodeSequentially(...)
611+
# 14| -1: [VarAccess] tmp5_input
612+
# 14| 1: [BlockStmt] { ... }
613+
# 14| 0: [BlockStmt] { ... }
614+
# 14| 0: [ExprStmt] <Expr>;
615+
# 14| 0: [AssignExpr] ...=...
616+
# 14| 0: [VarAccess] tmp4_local0
617+
# 14| 1: [MethodAccess] decodeStringElement(...)
618+
# 14| -1: [VarAccess] tmp5_input
619+
# 14| 0: [VarAccess] tmp0_desc
620+
# 14| 1: [IntegerLiteral] 0
621+
# 14| 1: [ExprStmt] <Expr>;
622+
# 14| 0: [AssignExpr] ...=...
623+
# 14| 0: [VarAccess] tmp3_bitMask0
624+
# 14| 1: [OrBitwiseExpr] ... | ...
625+
# 14| 0: [VarAccess] tmp3_bitMask0
626+
# 14| 1: [IntegerLiteral] 1
627+
# 14| 1: [WhenBranch] ... -> ...
628+
# 14| 0: [BooleanLiteral] true
629+
# 14| 1: [WhileStmt] while (...)
630+
# 14| 0: [VarAccess] tmp1_flag
631+
# 14| 1: [BlockStmt] { ... }
632+
# 14| 0: [ExprStmt] <Expr>;
633+
# 14| 0: [AssignExpr] ...=...
634+
# 14| 0: [VarAccess] tmp2_index
635+
# 14| 1: [MethodAccess] decodeElementIndex(...)
636+
# 14| -1: [VarAccess] tmp5_input
637+
# 14| 0: [VarAccess] tmp0_desc
638+
# 14| 1: [ExprStmt] <Expr>;
639+
# 14| 0: [WhenExpr] when ...
640+
# 14| 0: [WhenBranch] ... -> ...
641+
# 14| 0: [ValueEQExpr] ... (value equals) ...
642+
# 14| 0: [VarAccess] tmp2_index
643+
# 14| 1: [IntegerLiteral] -1
644+
# 14| 1: [ExprStmt] <Expr>;
645+
# 14| 0: [AssignExpr] ...=...
646+
# 14| 0: [VarAccess] tmp1_flag
647+
# 14| 1: [BooleanLiteral] false
648+
# 14| 1: [WhenBranch] ... -> ...
649+
# 14| 0: [ValueEQExpr] ... (value equals) ...
650+
# 14| 0: [VarAccess] tmp2_index
651+
# 14| 1: [IntegerLiteral] 0
652+
# 14| 1: [BlockStmt] { ... }
653+
# 14| 0: [ExprStmt] <Expr>;
654+
# 14| 0: [AssignExpr] ...=...
655+
# 14| 0: [VarAccess] tmp4_local0
656+
# 14| 1: [MethodAccess] decodeStringElement(...)
657+
# 14| -1: [VarAccess] tmp5_input
658+
# 14| 0: [VarAccess] tmp0_desc
659+
# 14| 1: [IntegerLiteral] 0
660+
# 14| 1: [ExprStmt] <Expr>;
661+
# 14| 0: [AssignExpr] ...=...
662+
# 14| 0: [VarAccess] tmp3_bitMask0
663+
# 14| 1: [OrBitwiseExpr] ... | ...
664+
# 14| 0: [VarAccess] tmp3_bitMask0
665+
# 14| 1: [IntegerLiteral] 1
666+
# 14| 2: [WhenBranch] ... -> ...
667+
# 14| 0: [BooleanLiteral] true
668+
# 14| 1: [ThrowStmt] throw ...
669+
# 14| 0: [ClassInstanceExpr] new UnknownFieldException(...)
670+
# 14| -3: [TypeAccess] UnknownFieldException
671+
# 14| 0: [VarAccess] tmp2_index
672+
# 14| 7: [ExprStmt] <Expr>;
673+
# 14| 0: [MethodAccess] endStructure(...)
674+
# 14| -1: [VarAccess] tmp5_input
675+
# 14| 0: [VarAccess] tmp0_desc
676+
# 14| 8: [ReturnStmt] return ...
677+
# 14| 0: [ClassInstanceExpr] new X(...)
678+
# 14| -3: [TypeAccess] X
679+
# 14| 0: [VarAccess] tmp3_bitMask0
680+
# 14| 1: [VarAccess] tmp4_local0
681+
# 14| 2: [NullLiteral] null
682+
# 0| 4: [Method] getDescriptor
683+
# 0| 3: [TypeAccess] SerialDescriptor
684+
# 0| 5: [BlockStmt] { ... }
685+
# 0| 0: [ReturnStmt] return ...
686+
# 0| 0: [VarAccess] this.descriptor
687+
# 0| -1: [ThisAccess] this
688+
# 0| 5: [Method] serialize
689+
# 0| 3: [TypeAccess] Unit
690+
#-----| 4: (Parameters)
691+
# 0| 0: [Parameter] encoder
692+
# 0| 0: [TypeAccess] Encoder
693+
# 0| 1: [Parameter] value
694+
# 0| 0: [TypeAccess] X
695+
# 14| 5: [BlockStmt] { ... }
696+
# 14| 0: [LocalVariableDeclStmt] var ...;
697+
# 14| 1: [LocalVariableDeclExpr] tmp0_desc
698+
# 14| 0: [MethodAccess] getDescriptor(...)
699+
# 14| -1: [ThisAccess] this
700+
# 14| 1: [LocalVariableDeclStmt] var ...;
701+
# 14| 1: [LocalVariableDeclExpr] tmp1_output
702+
# 14| 0: [MethodAccess] beginStructure(...)
703+
# 14| -1: [VarAccess] encoder
704+
# 14| 0: [VarAccess] tmp0_desc
705+
# 14| 2: [ExprStmt] <Expr>;
706+
# 14| 0: [MethodAccess] write$Self(...)
707+
# 14| -1: [TypeAccess] X
708+
# 14| 0: [VarAccess] value
709+
# 14| 1: [VarAccess] tmp1_output
710+
# 14| 2: [VarAccess] tmp0_desc
711+
# 14| 3: [ExprStmt] <Expr>;
712+
# 14| 0: [MethodAccess] endStructure(...)
713+
# 14| -1: [VarAccess] tmp1_output
714+
# 14| 0: [VarAccess] tmp0_desc
715+
# 14| 6: [Constructor] $serializer
716+
# 14| 5: [BlockStmt] { ... }
717+
# 14| 0: [SuperConstructorInvocationStmt] super(...)
718+
# 14| 1: [BlockStmt] { ... }
719+
# 14| 0: [LocalVariableDeclStmt] var ...;
720+
# 14| 1: [LocalVariableDeclExpr] tmp0_serialDesc
721+
# 14| 0: [ClassInstanceExpr] new PluginGeneratedSerialDescriptor(...)
722+
# 14| -3: [TypeAccess] PluginGeneratedSerialDescriptor
723+
# 14| 0: [StringLiteral] testProject.X
724+
# 14| 1: [ThisAccess] $serializer.this
725+
# 14| 0: [TypeAccess] $serializer
726+
# 14| 2: [IntegerLiteral] 1
727+
# 14| 1: [ExprStmt] <Expr>;
728+
# 14| 0: [MethodAccess] addElement(...)
729+
# 14| -1: [VarAccess] tmp0_serialDesc
730+
# 14| 0: [StringLiteral] id
731+
# 14| 1: [BooleanLiteral] true
732+
# 14| 2: [ExprStmt] <Expr>;
733+
# 14| 0: [AssignExpr] ...=...
734+
# 14| 0: [VarAccess] $serializer.this.descriptor
735+
# 14| -1: [ThisAccess] $serializer.this
736+
# 14| 0: [TypeAccess] $serializer
737+
# 14| 1: [VarAccess] tmp0_serialDesc
738+
# 14| 7: [Method] typeParametersSerializers
739+
# 14| 3: [TypeAccess] KSerializer<?>[]
740+
# 14| 0: [TypeAccess] KSerializer<?>
741+
# 14| 0: [WildcardTypeAccess] ? ...
742+
# 14| 5: [BlockStmt] { ... }
743+
# 14| 0: [ReturnStmt] return ...
744+
# 14| 0: [MethodAccess] typeParametersSerializers(...)
745+
# 14| -1: [SuperAccess] GeneratedSerializer.super
746+
# 14| 0: [TypeAccess] GeneratedSerializer
747+
# 14| 4: [Class] Companion
748+
# 0| 1: [Method] serializer
749+
# 0| 3: [TypeAccess] KSerializer<X>
750+
# 0| 0: [TypeAccess] X
751+
# 14| 5: [BlockStmt] { ... }
752+
# 14| 0: [ReturnStmt] return ...
753+
# 14| 0: [VarAccess] INSTANCE
754+
# 14| 2: [Constructor] Companion
755+
# 14| 5: [BlockStmt] { ... }
756+
# 14| 0: [SuperConstructorInvocationStmt] super(...)
757+
# 14| 1: [BlockStmt] { ... }
758+
# 15| 5: [Constructor] X
759+
# 14| 5: [BlockStmt] { ... }
760+
# 14| 0: [SuperConstructorInvocationStmt] super(...)
761+
# 15| 1: [BlockStmt] { ... }
762+
# 16| 0: [ExprStmt] <Expr>;
763+
# 16| 0: [KtInitializerAssignExpr] ...=...
764+
# 16| 0: [VarAccess] id
765+
# 16| 6: [FieldDeclaration] String id;
766+
# 16| -1: [TypeAccess] String
767+
# 16| 0: [StringLiteral] X
768+
# 16| 7: [Method] getId
769+
# 16| 3: [TypeAccess] String
770+
# 16| 5: [BlockStmt] { ... }
771+
# 16| 0: [ReturnStmt] return ...
772+
# 16| 0: [VarAccess] this.id
773+
# 16| -1: [ThisAccess] this

java/ql/integration-tests/posix-only/kotlin/gradle_kotlinx_serialization/app/src/main/kotlin/testProject/App.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,13 @@ import kotlinx.serialization.json.*
55
import kotlinx.serialization.Serializable
66

77
@Serializable
8-
data class Project(val name: String, val language: Int)
8+
data class Project(val name: String, val language: Int)
9+
10+
interface Base {
11+
val id: String
12+
}
13+
14+
@Serializable
15+
class X private constructor() : Base {
16+
override val id: String = "X"
17+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
| CodeQL Kotlin extractor | 5 | | Unbound symbol found, skipping extraction of expression | app/src/main/kotlin/testProject/App.kt:7:1:8:55 | app/src/main/kotlin/testProject/App.kt:7:1:8:55 |
2+
| CodeQL Kotlin extractor | 5 | | Unbound symbol found, skipping extraction of expression | app/src/main/kotlin/testProject/App.kt:14:1:17:1 | app/src/main/kotlin/testProject/App.kt:14:1:17:1 |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
libraryPathDependencies:
22
- codeql-java
33
- codeql/java-tests
4+
- codeql/java-queries

java/ql/lib/semmle/code/java/deadcode/DeadCode.qll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import semmle.code.java.deadcode.DeadEnumConstant
33
import semmle.code.java.deadcode.DeadCodeCustomizations
44
import semmle.code.java.deadcode.DeadField
55
import semmle.code.java.deadcode.EntryPoints
6+
private import semmle.code.java.frameworks.kotlin.Serialization
67

78
/**
89
* Holds if the given callable has any liveness causes.
@@ -309,10 +310,7 @@ class RootdefCallable extends Callable {
309310
this.isCompilerGenerated()
310311
or
311312
// Exclude Kotlin serialization constructors.
312-
this.(Constructor)
313-
.getParameterType(this.getNumberOfParameters() - 1)
314-
.(RefType)
315-
.hasQualifiedName("kotlinx.serialization.internal", "SerializationConstructorMarker")
313+
this instanceof SerializationConstructor
316314
}
317315
}
318316

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Provides classes and predicates for working with the `kotlinx.serialization` plugin.
3+
*/
4+
5+
import java
6+
7+
/**
8+
* A constructor with a `SerializationConstructorMarker` parameter.
9+
*/
10+
class SerializationConstructor extends Constructor {
11+
SerializationConstructor() {
12+
this.getParameterType(this.getNumberOfParameters() - 1)
13+
.(RefType)
14+
.hasQualifiedName("kotlinx.serialization.internal", "SerializationConstructorMarker")
15+
}
16+
}

java/ql/src/Likely Bugs/Arithmetic/ConstantExpAppearsNonConstant.ql

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*/
1111

1212
import java
13+
import semmle.code.java.frameworks.kotlin.Serialization
1314

1415
int eval(Expr e) { result = e.(CompileTimeConstantExpr).getIntValue() }
1516

@@ -59,5 +60,7 @@ where
5960
// Exclude explicit zero multiplication.
6061
not e.(MulExpr).getAnOperand().(IntegerLiteral).getIntValue() = 0 and
6162
// Exclude expressions that appear to be disabled deliberately (e.g. `false && ...`).
62-
not e.(AndLogicalExpr).getAnOperand().(BooleanLiteral).getBooleanValue() = false
63+
not e.(AndLogicalExpr).getAnOperand().(BooleanLiteral).getBooleanValue() = false and
64+
// Exclude expressions that are in serialization constructors, which are auto-generated.
65+
not e.getEnclosingCallable() instanceof SerializationConstructor
6366
select e, "Expression always evaluates to the same value."

0 commit comments

Comments
 (0)