Merge branch 'main' into jcogs33/update-externalapi-charpredicate

This commit is contained in:
Jami
2022-12-12 16:01:22 -05:00
committed by GitHub
329 changed files with 5786 additions and 3464 deletions

View File

@@ -119,7 +119,7 @@ class ExternalDeclExtractor(val logger: FileLogger, val invocationTrapFile: Stri
fileExtractor.extractClassSource(irDecl, extractDeclarations = !irDecl.isFileClass, extractStaticInitializer = false, extractPrivateMembers = false, extractFunctionBodies = false)
} else {
fileExtractor.extractDeclaration(irDecl, extractPrivateMembers = false, extractFunctionBodies = false)
fileExtractor.extractDeclaration(irDecl, extractPrivateMembers = false, extractFunctionBodies = false, extractAnnotations = true)
}
}
}

View File

@@ -207,6 +207,7 @@ class KotlinExtractorGlobalState {
val syntheticToRealClassMap = HashMap<IrClass, IrClass?>()
val syntheticToRealFunctionMap = HashMap<IrFunction, IrFunction?>()
val syntheticToRealFieldMap = HashMap<IrField, IrField?>()
val syntheticRepeatableAnnotationContainers = HashMap<IrClass, IrClass>()
}
/*

File diff suppressed because it is too large Load Diff

View File

@@ -40,11 +40,15 @@ open class KotlinUsesExtractor(
val pluginContext: IrPluginContext,
val globalExtensionState: KotlinExtractorGlobalState
) {
val javaLangObject by lazy {
val result = pluginContext.referenceClass(FqName("java.lang.Object"))?.owner
result?.let { extractExternalClassLater(it) }
result
}
fun referenceExternalClass(name: String) =
pluginContext.referenceClass(FqName(name))?.owner.also {
if (it == null)
logger.warn("Unable to resolve external class $name")
else
extractExternalClassLater(it)
}
val javaLangObject by lazy { referenceExternalClass("java.lang.Object") }
val javaLangObjectType by lazy {
javaLangObject?.typeWith()
@@ -885,11 +889,7 @@ open class KotlinUsesExtractor(
else -> null
}
val javaUtilCollection by lazy {
val result = pluginContext.referenceClass(FqName("java.util.Collection"))?.owner
result?.let { extractExternalClassLater(it) }
result
}
val javaUtilCollection by lazy { referenceExternalClass("java.util.Collection") }
val wildcardCollectionType by lazy {
javaUtilCollection?.let {
@@ -1152,11 +1152,7 @@ open class KotlinUsesExtractor(
return "@\"$prefix;{$parentId}.$name($paramTypeIds){$returnTypeId}${typeArgSuffix}\""
}
val javaLangClass by lazy {
val result = pluginContext.referenceClass(FqName("java.lang.Class"))?.owner
result?.let { extractExternalClassLater(it) }
result
}
val javaLangClass by lazy { referenceExternalClass("java.lang.Class") }
fun kClassToJavaClass(t: IrType): IrType {
when(t) {

View File

@@ -0,0 +1,396 @@
package com.github.codeql
import com.github.codeql.utils.versions.copyParameterToFunction
import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor
import com.github.codeql.utils.versions.getAnnotationType
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
import org.jetbrains.kotlin.ir.builders.declarations.addGetter
import org.jetbrains.kotlin.ir.builders.declarations.addProperty
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
import org.jetbrains.kotlin.ir.builders.declarations.buildField
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.IrClassReference
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrGetEnumValue
import org.jetbrains.kotlin.ir.expressions.IrVararg
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetEnumValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.getAnnotation
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.hasEqualFqName
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.primaryConstructor
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.lang.annotation.ElementType
import java.util.HashSet
class MetaAnnotationSupport(private val logger: FileLogger, private val pluginContext: IrPluginContext, private val extractor: KotlinFileExtractor) {
// Taken from AdditionalIrUtils.kt (not available in Kotlin < 1.6)
private val IrConstructorCall.annotationClass
get() = this.symbol.owner.constructedClass
// Taken from AdditionalIrUtils.kt (not available in Kotlin < 1.6)
private fun IrConstructorCall.isAnnotationWithEqualFqName(fqName: FqName): Boolean =
annotationClass.hasEqualFqName(fqName)
// Adapted from RepeatedAnnotationLowering.kt
fun groupRepeatableAnnotations(annotations: List<IrConstructorCall>): List<IrConstructorCall> {
if (annotations.size < 2) return annotations
val annotationsByClass = annotations.groupByTo(mutableMapOf()) { it.annotationClass }
if (annotationsByClass.values.none { it.size > 1 }) return annotations
val result = mutableListOf<IrConstructorCall>()
for (annotation in annotations) {
val annotationClass = annotation.annotationClass
val grouped = annotationsByClass.remove(annotationClass) ?: continue
if (grouped.size < 2) {
result.add(grouped.single())
continue
}
val containerClass = getOrCreateContainerClass(annotationClass)
if (containerClass != null)
wrapAnnotationEntriesInContainer(annotationClass, containerClass, grouped)?.let {
result.add(it)
}
else
logger.warnElement("Failed to find an annotation container class", annotationClass)
}
return result
}
// Adapted from RepeatedAnnotationLowering.kt
private fun getOrCreateContainerClass(annotationClass: IrClass): IrClass? {
val metaAnnotations = annotationClass.annotations
val jvmRepeatable = metaAnnotations.find { it.symbol.owner.parentAsClass.fqNameWhenAvailable == JvmAnnotationNames.REPEATABLE_ANNOTATION }
return if (jvmRepeatable != null) {
((jvmRepeatable.getValueArgument(0) as? IrClassReference)?.symbol as? IrClassSymbol)?.owner
} else {
getOrCreateSyntheticRepeatableAnnotationContainer(annotationClass)
}
}
// Adapted from RepeatedAnnotationLowering.kt
private fun wrapAnnotationEntriesInContainer(
annotationClass: IrClass,
containerClass: IrClass,
entries: List<IrConstructorCall>
): IrConstructorCall? {
val annotationType = annotationClass.typeWith()
val containerConstructor = containerClass.primaryConstructor
if (containerConstructor == null) {
logger.warnElement("Expected container class to have a primary constructor", containerClass)
return null
} else {
return IrConstructorCallImpl.fromSymbolOwner(containerClass.defaultType, containerConstructor.symbol).apply {
putValueArgument(
0,
IrVarargImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
pluginContext.irBuiltIns.arrayClass.typeWith(annotationType),
annotationType,
entries
)
)
}
}
}
// Taken from AdditionalClassAnnotationLowering.kt
private fun getApplicableTargetSet(c: IrClass): Set<KotlinTarget>? {
val targetEntry = c.getAnnotation(StandardNames.FqNames.target) ?: return null
return loadAnnotationTargets(targetEntry)
}
// Taken from AdditionalClassAnnotationLowering.kt
private fun loadAnnotationTargets(targetEntry: IrConstructorCall): Set<KotlinTarget>? {
val valueArgument = targetEntry.getValueArgument(0) as? IrVararg ?: return null
return valueArgument.elements.filterIsInstance<IrGetEnumValue>().mapNotNull {
KotlinTarget.valueOrNull(it.symbol.owner.name.asString())
}.toSet()
}
private val javaAnnotationTargetElementType by lazy { extractor.referenceExternalClass("java.lang.annotation.ElementType") }
private val javaAnnotationTarget by lazy { extractor.referenceExternalClass("java.lang.annotation.Target") }
private fun findEnumEntry(c: IrClass, name: String) =
c.declarations.filterIsInstance<IrEnumEntry>().find { it.name.asString() == name }
// Adapted from JvmSymbols.kt
private val jvm6TargetMap by lazy {
javaAnnotationTargetElementType?.let {
val etMethod = findEnumEntry(it, "METHOD")
mapOf(
KotlinTarget.CLASS to findEnumEntry(it, "TYPE"),
KotlinTarget.ANNOTATION_CLASS to findEnumEntry(it, "ANNOTATION_TYPE"),
KotlinTarget.CONSTRUCTOR to findEnumEntry(it, "CONSTRUCTOR"),
KotlinTarget.LOCAL_VARIABLE to findEnumEntry(it, "LOCAL_VARIABLE"),
KotlinTarget.FUNCTION to etMethod,
KotlinTarget.PROPERTY_GETTER to etMethod,
KotlinTarget.PROPERTY_SETTER to etMethod,
KotlinTarget.FIELD to findEnumEntry(it, "FIELD"),
KotlinTarget.VALUE_PARAMETER to findEnumEntry(it, "PARAMETER")
)
}
}
// Adapted from JvmSymbols.kt
private val jvm8TargetMap by lazy {
javaAnnotationTargetElementType?.let {
jvm6TargetMap?.let { j6Map ->
j6Map + mapOf(
KotlinTarget.TYPE_PARAMETER to findEnumEntry(it, "TYPE_PARAMETER"),
KotlinTarget.TYPE to findEnumEntry(it, "TYPE_USE")
)
}
}
}
private fun getAnnotationTargetMap() =
if (pluginContext.platform?.any { it.targetPlatformVersion == JvmTarget.JVM_1_6 } == true)
jvm6TargetMap
else
jvm8TargetMap
// Adapted from AdditionalClassAnnotationLowering.kt
private fun generateTargetAnnotation(c: IrClass): IrConstructorCall? {
if (c.hasAnnotation(JvmAnnotationNames.TARGET_ANNOTATION))
return null
val elementType = javaAnnotationTargetElementType ?: return null
val targetType = javaAnnotationTarget ?: return null
val targetConstructor = targetType.declarations.firstIsInstanceOrNull<IrConstructor>() ?: return null
val targets = getApplicableTargetSet(c) ?: return null
val annotationTargetMap = getAnnotationTargetMap() ?: return null
val javaTargets = targets.mapNotNullTo(HashSet()) { annotationTargetMap[it] }.sortedBy {
ElementType.valueOf(it.symbol.owner.name.asString())
}
val vararg = IrVarargImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
type = pluginContext.irBuiltIns.arrayClass.typeWith(elementType.defaultType),
varargElementType = elementType.defaultType
)
for (target in javaTargets) {
vararg.elements.add(
IrGetEnumValueImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, elementType.defaultType, target.symbol
)
)
}
return IrConstructorCallImpl.fromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, targetConstructor.returnType, targetConstructor.symbol, 0
).apply {
putValueArgument(0, vararg)
}
}
private val javaAnnotationRetention by lazy { extractor.referenceExternalClass("java.lang.annotation.Retention") }
private val javaAnnotationRetentionPolicy by lazy { extractor.referenceExternalClass("java.lang.annotation.RetentionPolicy") }
private val javaAnnotationRetentionPolicyRuntime by lazy { javaAnnotationRetentionPolicy?.let { findEnumEntry(it, "RUNTIME") } }
private val annotationRetentionMap by lazy {
javaAnnotationRetentionPolicy?.let {
mapOf(
KotlinRetention.SOURCE to findEnumEntry(it, "SOURCE"),
KotlinRetention.BINARY to findEnumEntry(it, "CLASS"),
KotlinRetention.RUNTIME to javaAnnotationRetentionPolicyRuntime
)
}
}
// Taken from AnnotationCodegen.kt (not available in Kotlin < 1.6.20)
private fun IrClass.getAnnotationRetention(): KotlinRetention? {
val retentionArgument =
getAnnotation(StandardNames.FqNames.retention)?.getValueArgument(0)
as? IrGetEnumValue ?: return null
val retentionArgumentValue = retentionArgument.symbol.owner
return KotlinRetention.valueOf(retentionArgumentValue.name.asString())
}
// Taken from AdditionalClassAnnotationLowering.kt
private fun generateRetentionAnnotation(irClass: IrClass): IrConstructorCall? {
if (irClass.hasAnnotation(JvmAnnotationNames.RETENTION_ANNOTATION))
return null
val retentionMap = annotationRetentionMap ?: return null
val kotlinRetentionPolicy = irClass.getAnnotationRetention()
val javaRetentionPolicy = kotlinRetentionPolicy?.let { retentionMap[it] } ?: javaAnnotationRetentionPolicyRuntime ?: return null
val retentionPolicyType = javaAnnotationRetentionPolicy ?: return null
val retentionType = javaAnnotationRetention ?: return null
val targetConstructor = retentionType.declarations.firstIsInstanceOrNull<IrConstructor>() ?: return null
return IrConstructorCallImpl.fromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, targetConstructor.returnType, targetConstructor.symbol, 0
).apply {
putValueArgument(
0,
IrGetEnumValueImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, retentionPolicyType.defaultType, javaRetentionPolicy.symbol
)
)
}
}
private val javaAnnotationRepeatable by lazy { extractor.referenceExternalClass("java.lang.annotation.Repeatable") }
private val kotlinAnnotationRepeatableContainer by lazy { extractor.referenceExternalClass("kotlin.jvm.internal.RepeatableContainer") }
// Taken from declarationBuilders.kt (not available in Kotlin < 1.6):
private fun addDefaultGetter(p: IrProperty, parentClass: IrClass) {
val field = p.backingField ?:
run { logger.warnElement("Expected property to have a backing field", p); return }
p.addGetter {
origin = IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
returnType = field.type
}.apply {
val thisReceiever = parentClass.thisReceiver ?:
run { logger.warnElement("Expected property's parent class to have a receiver parameter", parentClass); return }
val newParam = copyParameterToFunction(thisReceiever, this)
dispatchReceiverParameter = newParam
body = factory.createBlockBody(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf(
IrReturnImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
pluginContext.irBuiltIns.nothingType,
symbol,
IrGetFieldImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
field.symbol,
field.type,
IrGetValueImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
newParam.type,
newParam.symbol
)
)
)
)
)
}
}
// Taken from JvmCachedDeclarations.kt
private fun getOrCreateSyntheticRepeatableAnnotationContainer(annotationClass: IrClass) =
extractor.globalExtensionState.syntheticRepeatableAnnotationContainers.getOrPut(annotationClass) {
val containerClass = pluginContext.irFactory.buildClass {
kind = ClassKind.ANNOTATION_CLASS
name = Name.identifier("Container")
}.apply {
createImplicitParameterDeclarationWithWrappedDescriptor()
parent = annotationClass
superTypes = listOf(getAnnotationType(pluginContext))
}
val propertyName = Name.identifier("value")
val propertyType = pluginContext.irBuiltIns.arrayClass.typeWith(annotationClass.typeWith())
containerClass.addConstructor {
isPrimary = true
}.apply {
addValueParameter(propertyName.identifier, propertyType)
}
containerClass.addProperty {
name = propertyName
}.apply property@{
backingField = pluginContext.irFactory.buildField {
name = propertyName
type = propertyType
}.apply {
parent = containerClass
correspondingPropertySymbol = this@property.symbol
}
addDefaultGetter(this, containerClass)
}
val repeatableContainerAnnotation = kotlinAnnotationRepeatableContainer?.constructors?.single()
containerClass.annotations = annotationClass.annotations
.filter {
it.isAnnotationWithEqualFqName(StandardNames.FqNames.retention) ||
it.isAnnotationWithEqualFqName(StandardNames.FqNames.target)
}
.map { it.deepCopyWithSymbols(containerClass) } +
listOfNotNull(
repeatableContainerAnnotation?.let {
IrConstructorCallImpl.fromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.returnType, it.symbol, 0
)
}
)
containerClass
}
// Adapted from AdditionalClassAnnotationLowering.kt
private fun generateRepeatableAnnotation(irClass: IrClass, extractAnnotationTypeAccesses: Boolean): IrConstructorCall? {
if (!irClass.hasAnnotation(StandardNames.FqNames.repeatable) ||
irClass.hasAnnotation(JvmAnnotationNames.REPEATABLE_ANNOTATION)
) return null
val repeatableConstructor = javaAnnotationRepeatable?.declarations?.firstIsInstanceOrNull<IrConstructor>() ?: return null
val containerClass = getOrCreateSyntheticRepeatableAnnotationContainer(irClass)
// Whenever a repeatable annotation with a Kotlin-synthesised container is extracted, extract the synthetic container to the same trap file.
extractor.extractClassSource(containerClass, extractDeclarations = true, extractStaticInitializer = true, extractPrivateMembers = true, extractFunctionBodies = extractAnnotationTypeAccesses)
val containerReference = IrClassReferenceImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, pluginContext.irBuiltIns.kClassClass.typeWith(containerClass.defaultType),
containerClass.symbol, containerClass.defaultType
)
return IrConstructorCallImpl.fromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, repeatableConstructor.returnType, repeatableConstructor.symbol, 0
).apply {
putValueArgument(0, containerReference)
}
}
private val javaAnnotationDocumented by lazy { extractor.referenceExternalClass("java.lang.annotation.Documented") }
// Taken from AdditionalClassAnnotationLowering.kt
private fun generateDocumentedAnnotation(irClass: IrClass): IrConstructorCall? {
if (!irClass.hasAnnotation(StandardNames.FqNames.mustBeDocumented) ||
irClass.hasAnnotation(JvmAnnotationNames.DOCUMENTED_ANNOTATION)
) return null
val documentedConstructor = javaAnnotationDocumented?.declarations?.firstIsInstanceOrNull<IrConstructor>() ?: return null
return IrConstructorCallImpl.fromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, documentedConstructor.returnType, documentedConstructor.symbol, 0
)
}
fun generateJavaMetaAnnotations(c: IrClass, extractAnnotationTypeAccesses: Boolean) =
// This is essentially AdditionalClassAnnotationLowering adapted to run outside the backend.
listOfNotNull(generateTargetAnnotation(c), generateRetentionAnnotation(c), generateRepeatableAnnotation(c, extractAnnotationTypeAccesses), generateDocumentedAnnotation(c))
}

View File

@@ -10,7 +10,7 @@ import java.util.Stack
import org.jetbrains.kotlin.ir.IrElement
class LogCounter() {
public val diagnosticCounts = mutableMapOf<String, Int>()
public val diagnosticInfo = mutableMapOf<String, Pair<Severity, Int>>()
public val diagnosticLimit: Int
init {
diagnosticLimit = System.getenv("CODEQL_EXTRACTOR_KOTLIN_DIAGNOSTIC_LIMIT")?.toIntOrNull() ?: 100
@@ -114,12 +114,23 @@ open class LoggerBase(val logCounter: LogCounter) {
if(diagnosticLoc == null) {
" Missing caller information.\n"
} else {
val count = logCounter.diagnosticCounts.getOrDefault(diagnosticLoc, 0) + 1
logCounter.diagnosticCounts[diagnosticLoc] = count
val oldInfo = logCounter.diagnosticInfo.getOrDefault(diagnosticLoc, Pair(severity, 0))
if(severity != oldInfo.first) {
// We don't want to get in a loop, so just emit this
// directly without going through the diagnostic
// counting machinery
if (verbosity >= 1) {
val message = "Severity mismatch ($severity vs ${oldInfo.first}) at $diagnosticLoc"
emitDiagnostic(tw, Severity.Error, "Inconsistency", message, message)
}
}
val newCount = oldInfo.second + 1
val newInfo = Pair(severity, newCount)
logCounter.diagnosticInfo[diagnosticLoc] = newInfo
when {
logCounter.diagnosticLimit <= 0 -> ""
count == logCounter.diagnosticLimit -> " Limit reached for diagnostics from $diagnosticLoc.\n"
count > logCounter.diagnosticLimit -> return
newCount == logCounter.diagnosticLimit -> " Limit reached for diagnostics from $diagnosticLoc.\n"
newCount > logCounter.diagnosticLimit -> return
else -> ""
}
}
@@ -189,14 +200,16 @@ open class LoggerBase(val logCounter: LogCounter) {
}
fun printLimitedDiagnosticCounts(tw: TrapWriter) {
for((caller, count) in logCounter.diagnosticCounts) {
for((caller, info) in logCounter.diagnosticInfo) {
val severity = info.first
val count = info.second
if(count >= logCounter.diagnosticLimit) {
// We don't know if this location relates to an error
// or a warning, so we just declare hitting the limit
// to be an error regardless.
val message = "Total of $count diagnostics (reached limit of ${logCounter.diagnosticLimit}) from $caller."
if (verbosity >= 1) {
emitDiagnostic(tw, Severity.Error, "Limit", message, message)
emitDiagnostic(tw, severity, "Limit", message, message)
}
}
}

View File

@@ -0,0 +1,8 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
@OptIn(ObsoleteDescriptorBasedAPI::class)
fun getAnnotationType(context: IrPluginContext) =
context.typeTranslator.translateType(context.builtIns.annotationType)

View File

@@ -0,0 +1,7 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.backend.common.ir.copyTo
fun copyParameterToFunction(p: IrValueParameter, f: IrFunction) = p.copyTo(f)

View File

@@ -0,0 +1,6 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
fun getAnnotationType(context: IrPluginContext) =
context.irBuiltIns.annotationType

View File

@@ -0,0 +1,7 @@
package com.github.codeql.utils.versions
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.util.copyTo
fun copyParameterToFunction(p: IrValueParameter, f: IrFunction) = p.copyTo(f)

View File

@@ -53,6 +53,8 @@ predicate shouldBeDeadEnd(ControlFlowNode n) {
not exists(n.getFile().getRelativePath()) // TODO
or
n = any(ConstCase c).getValue(_) // TODO
or
n instanceof ErrorExpr // TODO
}
from ControlFlowNode n, string s

View File

@@ -41,7 +41,12 @@ predicate gapInChildren(Element e, int i) {
// -1 can be skipped (type arguments from -2 down, no qualifier at -1,
// then arguments from 0).
// Can we also skip arguments, e.g. due to defaults for parameters?
not (e instanceof MethodAccess and e.getFile().isKotlinSourceFile())
not (e instanceof MethodAccess and e.getFile().isKotlinSourceFile()) and
// Kotlin-extracted annotations can have missing children where a default
// value should be, because kotlinc doesn't load annotation defaults and we
// want to leave a space for another extractor to fill in the default if it
// is able.
not e instanceof Annotation
}
predicate lateFirstChild(Element e, int i) {
@@ -59,7 +64,12 @@ predicate lateFirstChild(Element e, int i) {
not (e instanceof LocalVariableDeclStmt and i = 1 and not exists(nthChildOf(e, 2))) and
// For statements may or may not declare a new variable (child 0), or
// have a condition (child 1).
not (e instanceof ForStmt and i = [1, 2])
not (e instanceof ForStmt and i = [1, 2]) and
// Kotlin-extracted annotations can have missing children where a default
// value should be, because kotlinc doesn't load annotation defaults and we
// want to leave a space for another extractor to fill in the default if it
// is able.
not e instanceof Annotation
}
from Element e, int i, string problem

View File

@@ -0,0 +1,301 @@
User.java:
# 0| [CompilationUnit] User
# 1| 1: [Class] User
# 3| 2: [Method] user
# 3| 3: [TypeAccess] void
#-----| 4: (Parameters)
# 3| 0: [Parameter] a1
# 3| 0: [TypeAccess] Ann1
# 3| 1: [Parameter] a2
# 3| 0: [TypeAccess] Ann2
# 3| 5: [BlockStmt] { ... }
# 4| 0: [ExprStmt] <Expr>;
# 4| 0: [MethodAccess] x(...)
# 4| -1: [VarAccess] a1
# 4| 1: [ExprStmt] <Expr>;
# 4| 0: [MethodAccess] z(...)
# 4| -1: [VarAccess] a2
# 4| 2: [ExprStmt] <Expr>;
# 4| 0: [ClassInstanceExpr] new Annotated(...)
# 4| -3: [TypeAccess] Annotated
# 4| 3: [ExprStmt] <Expr>;
# 4| 0: [ClassInstanceExpr] new HasJavaDeprecatedAnnotationUsedByJava(...)
# 4| -3: [TypeAccess] HasJavaDeprecatedAnnotationUsedByJava
# 4| 4: [ExprStmt] <Expr>;
# 4| 0: [ClassInstanceExpr] new HasKotlinDeprecatedAnnotationUsedByJava(...)
# 4| -3: [TypeAccess] HasKotlinDeprecatedAnnotationUsedByJava
ktUser.kt:
# 0| [CompilationUnit] ktUser
# 1| 1: [Class] KtUser
# 1| 1: [Constructor] KtUser
# 1| 5: [BlockStmt] { ... }
# 1| 0: [SuperConstructorInvocationStmt] super(...)
# 1| 1: [BlockStmt] { ... }
# 3| 2: [Method] user
# 3| 3: [TypeAccess] Unit
# 3| 5: [BlockStmt] { ... }
# 4| 0: [LocalVariableDeclStmt] var ...;
# 4| 1: [LocalVariableDeclExpr] a
# 4| 0: [ClassInstanceExpr] new AnnotatedUsedByKotlin(...)
# 4| -3: [TypeAccess] AnnotatedUsedByKotlin
# 5| 1: [LocalVariableDeclStmt] var ...;
# 5| 1: [LocalVariableDeclExpr] b
# 5| 0: [ClassInstanceExpr] new HasJavaDeprecatedAnnotationUsedByKotlin(...)
# 5| -3: [TypeAccess] HasJavaDeprecatedAnnotationUsedByKotlin
# 6| 2: [LocalVariableDeclStmt] var ...;
# 6| 1: [LocalVariableDeclExpr] c
# 6| 0: [ClassInstanceExpr] new HasKotlinDeprecatedAnnotationUsedByKotlin(...)
# 6| -3: [TypeAccess] HasKotlinDeprecatedAnnotationUsedByKotlin
# 8| 3: [ExprStmt] <Expr>;
# 8| 0: [ImplicitCoercionToUnitExpr] <implicit coercion to unit>
# 8| 0: [TypeAccess] Unit
# 8| 1: [MethodAccess] isJavaLetter(...)
# 8| -1: [TypeAccess] Character
# 8| 0: [CharacterLiteral] a
test.kt:
# 0| [CompilationUnit] test
# 4| 1: [Interface] Ann1
#-----| -3: (Annotations)
# 0| 1: [Annotation] Retention
# 0| 1: [VarAccess] RetentionPolicy.RUNTIME
# 0| -1: [TypeAccess] RetentionPolicy
# 4| 1: [Method] x
# 4| 3: [TypeAccess] int
# 4| 2: [Method] y
# 4| 3: [TypeAccess] Ann2
# 4| 3: [Method] z
# 4| 3: [TypeAccess] DayOfWeek
# 6| 2: [Interface] Ann2
#-----| -3: (Annotations)
# 0| 1: [Annotation] Retention
# 0| 1: [VarAccess] RetentionPolicy.RUNTIME
# 0| -1: [TypeAccess] RetentionPolicy
# 6| 1: [Method] z
# 6| 3: [TypeAccess] String
# 6| 2: [Method] w
# 6| 3: [TypeAccess] Class<?>
# 6| 0: [WildcardTypeAccess] ? ...
# 6| 3: [Method] v
# 6| 3: [TypeAccess] int[]
# 6| 4: [Method] u
# 6| 3: [TypeAccess] Ann3[]
# 6| 0: [TypeAccess] Ann3
# 6| 5: [Method] t
# 6| 3: [TypeAccess] Class<?>[]
# 6| 0: [TypeAccess] Class<?>
# 6| 0: [WildcardTypeAccess] ? ...
# 8| 3: [Interface] Ann3
#-----| -3: (Annotations)
# 0| 1: [Annotation] Retention
# 0| 1: [VarAccess] RetentionPolicy.RUNTIME
# 0| -1: [TypeAccess] RetentionPolicy
# 8| 1: [Method] a
# 8| 3: [TypeAccess] int
# 10| 4: [GenericType,Interface,ParameterizedType] GenericAnnotation
#-----| -3: (Annotations)
# 0| 1: [Annotation] Retention
# 0| 1: [VarAccess] RetentionPolicy.RUNTIME
# 0| -1: [TypeAccess] RetentionPolicy
#-----| -2: (Generic Parameters)
# 10| 0: [TypeVariable] T
# 10| 1: [Method] x
# 10| 3: [TypeAccess] Class<T>
# 10| 0: [TypeAccess] T
# 10| 2: [Method] y
# 10| 3: [TypeAccess] Class<T>[]
# 10| 0: [TypeAccess] Class<T>
# 10| 0: [TypeAccess] T
# 12| 6: [Interface] VarargAnnotation
#-----| -3: (Annotations)
# 0| 1: [Annotation] Repeatable
# 0| 1: [TypeLiteral] Container.class
# 0| 0: [TypeAccess] Container
# 0| 2: [Annotation] Retention
# 0| 1: [VarAccess] RetentionPolicy.RUNTIME
# 0| -1: [TypeAccess] RetentionPolicy
# 12| 3: [Annotation] Repeatable
# 0| 1: [Interface] Container
#-----| -3: (Annotations)
# 0| 1: [Annotation] RepeatableContainer
# 0| 2: [Annotation] Retention
# 0| 1: [VarAccess] RetentionPolicy.RUNTIME
# 0| -1: [TypeAccess] RetentionPolicy
# 0| 1: [Method] value
# 0| 3: [TypeAccess] VarargAnnotation[]
# 0| 0: [TypeAccess] VarargAnnotation
# 13| 2: [Method] x
# 13| 3: [TypeAccess] int[]
# 15| 7: [Interface] AnnWithDefaults
#-----| -3: (Annotations)
# 0| 1: [Annotation] Retention
# 0| 1: [VarAccess] RetentionPolicy.RUNTIME
# 0| -1: [TypeAccess] RetentionPolicy
# 15| 1: [Method] x
# 15| 3: [TypeAccess] int
# 15| 2: [Method] y
# 15| 3: [TypeAccess] String
# 15| 3: [Method] z
# 15| 3: [TypeAccess] DayOfWeek
# 15| 4: [Method] w
# 15| 3: [TypeAccess] Ann3[]
# 15| 0: [TypeAccess] Ann3
# 17| 8: [Class] Annotated
#-----| -3: (Annotations)
# 0| 1: [Annotation] Container
# 0| 1: [ArrayInit] {...}
# 19| 1: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 20| 2: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 0| 1: [IntegerLiteral] 1
# 21| 3: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 0| 1: [IntegerLiteral] 1
# 0| 2: [IntegerLiteral] 2
# 22| 4: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 0| 1: [IntegerLiteral] 1
# 0| 2: [IntegerLiteral] 2
# 0| 3: [IntegerLiteral] 3
# 23| 5: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 0| 1: [IntegerLiteral] 1
# 0| 2: [IntegerLiteral] 2
# 0| 3: [IntegerLiteral] 3
# 17| 2: [Annotation] Ann1
# 0| 1: [IntegerLiteral] 1
# 0| 2: [Annotation] Ann2
# 0| 1: [StringLiteral] "Hello"
# 0| 2: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
# 0| 3: [ArrayInit] {...}
# 0| 1: [IntegerLiteral] 1
# 0| 2: [IntegerLiteral] 2
# 0| 3: [IntegerLiteral] 3
# 0| 4: [ArrayInit] {...}
# 0| 1: [Annotation] Ann3
# 0| 1: [IntegerLiteral] 1
# 0| 2: [Annotation] Ann3
# 0| 1: [IntegerLiteral] 2
# 0| 5: [ArrayInit] {...}
# 0| 1: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
# 0| 2: [TypeLiteral] int.class
# 0| 0: [TypeAccess] int
# 0| 3: [VarAccess] DayOfWeek.MONDAY
# 0| -1: [TypeAccess] DayOfWeek
# 18| 3: [Annotation] GenericAnnotation
# 0| 1: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
# 0| 2: [ArrayInit] {...}
# 0| 1: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
# 0| 2: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
# 24| 4: [Annotation] AnnWithDefaults
# 0| 1: [IntegerLiteral] 1
# 0| 2: [StringLiteral] "hello"
# 0| 3: [VarAccess] DayOfWeek.TUESDAY
# 0| -1: [TypeAccess] DayOfWeek
# 0| 4: [ArrayInit] {...}
# 0| 1: [Annotation] Ann3
# 0| 1: [IntegerLiteral] 1
# 25| 1: [Constructor] Annotated
# 17| 5: [BlockStmt] { ... }
# 17| 0: [SuperConstructorInvocationStmt] super(...)
# 25| 1: [BlockStmt] { ... }
# 27| 9: [Class] AnnotatedUsedByKotlin
#-----| -3: (Annotations)
# 0| 1: [Annotation] Container
# 0| 1: [ArrayInit] {...}
# 29| 1: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 30| 2: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 0| 1: [IntegerLiteral] 1
# 31| 3: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 0| 1: [IntegerLiteral] 1
# 0| 2: [IntegerLiteral] 2
# 32| 4: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 0| 1: [IntegerLiteral] 1
# 0| 2: [IntegerLiteral] 2
# 0| 3: [IntegerLiteral] 3
# 33| 5: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 0| 1: [IntegerLiteral] 1
# 0| 2: [IntegerLiteral] 2
# 0| 3: [IntegerLiteral] 3
# 27| 2: [Annotation] Ann1
# 0| 1: [IntegerLiteral] 1
# 0| 2: [Annotation] Ann2
# 0| 1: [StringLiteral] "Hello"
# 0| 2: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
# 0| 3: [ArrayInit] {...}
# 0| 1: [IntegerLiteral] 1
# 0| 2: [IntegerLiteral] 2
# 0| 3: [IntegerLiteral] 3
# 0| 4: [ArrayInit] {...}
# 0| 1: [Annotation] Ann3
# 0| 1: [IntegerLiteral] 1
# 0| 2: [Annotation] Ann3
# 0| 1: [IntegerLiteral] 2
# 0| 5: [ArrayInit] {...}
# 0| 1: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
# 0| 2: [TypeLiteral] int.class
# 0| 0: [TypeAccess] int
# 0| 3: [VarAccess] DayOfWeek.MONDAY
# 0| -1: [TypeAccess] DayOfWeek
# 28| 3: [Annotation] GenericAnnotation
# 0| 1: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
# 0| 2: [ArrayInit] {...}
# 0| 1: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
# 0| 2: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
# 34| 4: [Annotation] AnnWithDefaults
# 0| 1: [IntegerLiteral] 1
# 0| 2: [StringLiteral] "hello"
# 0| 3: [VarAccess] DayOfWeek.TUESDAY
# 0| -1: [TypeAccess] DayOfWeek
# 0| 4: [ArrayInit] {...}
# 0| 1: [Annotation] Ann3
# 0| 1: [IntegerLiteral] 1
# 35| 1: [Constructor] AnnotatedUsedByKotlin
# 27| 5: [BlockStmt] { ... }
# 27| 0: [SuperConstructorInvocationStmt] super(...)
# 35| 1: [BlockStmt] { ... }
# 37| 10: [Class] HasJavaDeprecatedAnnotationUsedByJava
#-----| -3: (Annotations)
# 37| 1: [Annotation] Deprecated
# 38| 1: [Constructor] HasJavaDeprecatedAnnotationUsedByJava
# 37| 5: [BlockStmt] { ... }
# 37| 0: [SuperConstructorInvocationStmt] super(...)
# 38| 1: [BlockStmt] { ... }
# 40| 11: [Class] HasKotlinDeprecatedAnnotationUsedByJava
#-----| -3: (Annotations)
# 40| 1: [Annotation] Deprecated
# 0| 1: [StringLiteral] "Kotlin deprecation message 1"
# 41| 1: [Constructor] HasKotlinDeprecatedAnnotationUsedByJava
# 40| 5: [BlockStmt] { ... }
# 40| 0: [SuperConstructorInvocationStmt] super(...)
# 41| 1: [BlockStmt] { ... }
# 43| 12: [Class] HasJavaDeprecatedAnnotationUsedByKotlin
#-----| -3: (Annotations)
# 43| 1: [Annotation] Deprecated
# 44| 1: [Constructor] HasJavaDeprecatedAnnotationUsedByKotlin
# 43| 5: [BlockStmt] { ... }
# 43| 0: [SuperConstructorInvocationStmt] super(...)
# 44| 1: [BlockStmt] { ... }
# 46| 13: [Class] HasKotlinDeprecatedAnnotationUsedByKotlin
#-----| -3: (Annotations)
# 46| 1: [Annotation] Deprecated
# 0| 1: [StringLiteral] "Kotlin deprecation message 2"
# 47| 1: [Constructor] HasKotlinDeprecatedAnnotationUsedByKotlin
# 46| 5: [BlockStmt] { ... }
# 46| 0: [SuperConstructorInvocationStmt] super(...)
# 47| 1: [BlockStmt] { ... }

View File

@@ -0,0 +1 @@
semmle/code/java/PrintAst.ql

View File

@@ -0,0 +1,7 @@
public class User {
public static void user(Ann1 a1, Ann2 a2) {
a1.x(); a2.z(); new Annotated(); new HasJavaDeprecatedAnnotationUsedByJava(); new HasKotlinDeprecatedAnnotationUsedByJava();
}
}

View File

@@ -0,0 +1,5 @@
| HasJavaDeprecatedAnnotationUsedByJava | java.lang.Deprecated |
| HasJavaDeprecatedAnnotationUsedByKotlin | java.lang.Deprecated |
| HasKotlinDeprecatedAnnotationUsedByJava | kotlin.Deprecated |
| HasKotlinDeprecatedAnnotationUsedByKotlin | kotlin.Deprecated |
| isJavaLetter | java.lang.Deprecated |

View File

@@ -0,0 +1,11 @@
import java
from Annotatable a, Annotation ann
where
(
a.(Method).hasQualifiedName("java.lang", "Character", "isJavaLetter") or
a.(ClassOrInterface).fromSource()
) and
ann = a.getAnAnnotation() and
ann.getType().getName() = "Deprecated"
select a.toString(), a.getAnAnnotation().getType().getQualifiedName()

View File

@@ -0,0 +1,5 @@
extensions:
- addsTo:
pack: integrationtest-annotation-id-consistency
extensible: extNegativeSummaryModel
data: []

View File

@@ -0,0 +1,11 @@
public class KtUser {
fun user() {
val a = AnnotatedUsedByKotlin()
val b = HasJavaDeprecatedAnnotationUsedByKotlin()
val c = HasKotlinDeprecatedAnnotationUsedByKotlin()
// Use a Java-defined function carrying a java.lang.Deprecated annotation:
java.lang.Character.isJavaLetter('a')
}
}

View File

@@ -0,0 +1,8 @@
name: integrationtest-annotation-id-consistency
dependencies:
codeql/java-all: '*'
codeql/java-tests: '*'
codeql/java-queries: '*'
dataExtensions:
ext/*.model.yml

View File

@@ -0,0 +1,47 @@
import kotlin.reflect.KClass
import java.time.DayOfWeek
annotation class Ann1(val x: Int, val y: Ann2, val z: DayOfWeek) { }
annotation class Ann2(val z: String, val w: KClass<*>, val v: IntArray, val u: Array<Ann3>, val t: Array<KClass<*>>) { }
annotation class Ann3(val a: Int) { }
annotation class GenericAnnotation<T : Any>(val x: KClass<T>, val y: Array<KClass<T>>) { }
@Repeatable
annotation class VarargAnnotation(vararg val x: Int) { }
annotation class AnnWithDefaults(val x: Int = 1, val y: String = "hello", val z: DayOfWeek = DayOfWeek.TUESDAY, val w: Array<Ann3> = [Ann3(1)]) { }
@Ann1(1, Ann2("Hello", String::class, intArrayOf(1, 2, 3), arrayOf(Ann3(1), Ann3(2)), arrayOf(String::class, Int::class)), DayOfWeek.MONDAY)
@GenericAnnotation<String>(String::class, arrayOf(String::class, String::class))
@VarargAnnotation
@VarargAnnotation(1)
@VarargAnnotation(1, 2)
@VarargAnnotation(*[1, 2, 3])
@VarargAnnotation(*intArrayOf(1, 2, 3))
@AnnWithDefaults
class Annotated { }
@Ann1(1, Ann2("Hello", String::class, intArrayOf(1, 2, 3), arrayOf(Ann3(1), Ann3(2)), arrayOf(String::class, Int::class)), DayOfWeek.MONDAY)
@GenericAnnotation<String>(String::class, arrayOf(String::class, String::class))
@VarargAnnotation
@VarargAnnotation(1)
@VarargAnnotation(1, 2)
@VarargAnnotation(*[1, 2, 3])
@VarargAnnotation(*intArrayOf(1, 2, 3))
@AnnWithDefaults
class AnnotatedUsedByKotlin { }
@java.lang.Deprecated
class HasJavaDeprecatedAnnotationUsedByJava
@kotlin.Deprecated("Kotlin deprecation message 1")
class HasKotlinDeprecatedAnnotationUsedByJava
@java.lang.Deprecated
class HasJavaDeprecatedAnnotationUsedByKotlin
@kotlin.Deprecated("Kotlin deprecation message 2")
class HasKotlinDeprecatedAnnotationUsedByKotlin

View File

@@ -0,0 +1,5 @@
from create_database_utils import *
os.mkdir('out')
os.mkdir('out2')
run_codeql_database_create(["kotlinc test.kt -d out", "javac User.java -cp out -d out2", "kotlinc ktUser.kt -cp out -d out2"], lang="java")

View File

@@ -1,7 +1,17 @@
app/src/main/kotlin/testProject/App.kt:
# 0| [CompilationUnit] App
# 7| 1: [Class] Project
#-----| -3: (Annotations)
# 7| 1: [Annotation] Serializable
# 0| 1: [Constructor] Project
#-----| 1: (Annotations)
# 0| 1: [Annotation] Deprecated
# 0| 1: [StringLiteral] "This synthesized declaration should not be used directly"
# 0| 2: [Annotation] ReplaceWith
# 0| 1: [StringLiteral] ""
# 0| 2: [ArrayInit] {...}
# 0| 3: [VarAccess] DeprecationLevel.HIDDEN
# 0| -1: [TypeAccess] DeprecationLevel
#-----| 4: (Parameters)
# 0| 0: [Parameter] seen1
# 0| 0: [TypeAccess] int
@@ -41,6 +51,8 @@ app/src/main/kotlin/testProject/App.kt:
# 7| 0: [TypeAccess] Project
# 7| 1: [VarAccess] language
# 0| 2: [Method] component1
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 3: [TypeAccess] String
# 0| 5: [BlockStmt] { ... }
# 0| 0: [ReturnStmt] return ...
@@ -53,9 +65,13 @@ app/src/main/kotlin/testProject/App.kt:
# 0| 0: [VarAccess] this.language
# 0| -1: [ThisAccess] this
# 0| 4: [Method] copy
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 3: [TypeAccess] Project
#-----| 4: (Parameters)
# 8| 0: [Parameter] name
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 8| 0: [TypeAccess] String
# 8| 1: [Parameter] language
# 8| 0: [TypeAccess] int
@@ -176,6 +192,8 @@ app/src/main/kotlin/testProject/App.kt:
# 0| 2: [ReturnStmt] return ...
# 0| 0: [VarAccess] result
# 0| 8: [Method] toString
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 3: [TypeAccess] String
# 0| 5: [BlockStmt] { ... }
# 0| 0: [ReturnStmt] return ...
@@ -190,13 +208,21 @@ app/src/main/kotlin/testProject/App.kt:
# 0| -1: [ThisAccess] this
# 0| 6: [StringLiteral] ")"
# 0| 9: [Method] write$Self
#-----| 1: (Annotations)
# 0| 1: [Annotation] JvmStatic
# 0| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 0| 0: [Parameter] self
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] Project
# 0| 1: [Parameter] output
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] CompositeEncoder
# 0| 2: [Parameter] serialDesc
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] SerialDescriptor
# 7| 5: [BlockStmt] { ... }
# 7| 0: [ExprStmt] <Expr>;
@@ -214,9 +240,19 @@ app/src/main/kotlin/testProject/App.kt:
# 7| 2: [MethodAccess] getLanguage(...)
# 7| -1: [VarAccess] self
# 7| 10: [Class] $serializer
#-----| -3: (Annotations)
# 0| 1: [Annotation] Deprecated
# 0| 1: [StringLiteral] "This synthesized declaration should not be used directly"
# 0| 2: [Annotation] ReplaceWith
# 0| 1: [StringLiteral] ""
# 0| 2: [ArrayInit] {...}
# 0| 3: [VarAccess] DeprecationLevel.HIDDEN
# 0| -1: [TypeAccess] DeprecationLevel
# 0| 1: [FieldDeclaration] SerialDescriptor descriptor;
# 0| -1: [TypeAccess] SerialDescriptor
# 0| 2: [Method] childSerializers
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 3: [TypeAccess] KSerializer<?>[]
# 0| 0: [TypeAccess] KSerializer<?>
# 0| 0: [WildcardTypeAccess] ? ...
@@ -227,9 +263,13 @@ app/src/main/kotlin/testProject/App.kt:
# 7| -1: [TypeAccess] KSerializer<?>
# 7| 0: [IntegerLiteral] 2
# 0| 3: [Method] deserialize
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 3: [TypeAccess] Project
#-----| 4: (Parameters)
# 0| 0: [Parameter] decoder
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] Decoder
# 7| 5: [BlockStmt] { ... }
# 7| 0: [LocalVariableDeclStmt] var ...;
@@ -365,6 +405,8 @@ app/src/main/kotlin/testProject/App.kt:
# 7| 2: [VarAccess] tmp5_local1
# 7| 3: [NullLiteral] null
# 0| 4: [Method] getDescriptor
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 3: [TypeAccess] SerialDescriptor
# 0| 5: [BlockStmt] { ... }
# 0| 0: [ReturnStmt] return ...
@@ -374,8 +416,12 @@ app/src/main/kotlin/testProject/App.kt:
# 0| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 0| 0: [Parameter] encoder
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] Encoder
# 0| 1: [Parameter] value
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] Project
# 7| 5: [BlockStmt] { ... }
# 7| 0: [LocalVariableDeclStmt] var ...;
@@ -436,6 +482,8 @@ app/src/main/kotlin/testProject/App.kt:
# 7| 0: [TypeAccess] GeneratedSerializer
# 7| 11: [Class] Companion
# 0| 1: [Method] serializer
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 3: [TypeAccess] KSerializer<Project>
# 0| 0: [TypeAccess] Project
# 7| 5: [BlockStmt] { ... }
@@ -448,6 +496,8 @@ app/src/main/kotlin/testProject/App.kt:
# 8| 12: [Constructor] Project
#-----| 4: (Parameters)
# 8| 0: [Parameter] name
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 8| 0: [TypeAccess] String
# 8| 1: [Parameter] language
# 8| 0: [TypeAccess] int
@@ -464,6 +514,8 @@ app/src/main/kotlin/testProject/App.kt:
# 8| -1: [TypeAccess] String
# 8| 0: [VarAccess] name
# 8| 14: [Method] getName
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 8| 3: [TypeAccess] String
# 8| 5: [BlockStmt] { ... }
# 8| 0: [ReturnStmt] return ...
@@ -480,9 +532,21 @@ app/src/main/kotlin/testProject/App.kt:
# 8| 0: [VarAccess] language
# 10| 2: [Interface] Base
# 11| 1: [Method] getId
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 11| 3: [TypeAccess] String
# 14| 3: [Class] X
#-----| -3: (Annotations)
# 14| 1: [Annotation] Serializable
# 0| 1: [Constructor] X
#-----| 1: (Annotations)
# 0| 1: [Annotation] Deprecated
# 0| 1: [StringLiteral] "This synthesized declaration should not be used directly"
# 0| 2: [Annotation] ReplaceWith
# 0| 1: [StringLiteral] ""
# 0| 2: [ArrayInit] {...}
# 0| 3: [VarAccess] DeprecationLevel.HIDDEN
# 0| -1: [TypeAccess] DeprecationLevel
#-----| 4: (Parameters)
# 0| 0: [Parameter] seen1
# 0| 0: [TypeAccess] int
@@ -530,13 +594,21 @@ app/src/main/kotlin/testProject/App.kt:
# 14| 0: [TypeAccess] X
# 14| 1: [VarAccess] id
# 0| 2: [Method] write$Self
#-----| 1: (Annotations)
# 0| 1: [Annotation] JvmStatic
# 0| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 0| 0: [Parameter] self
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] X
# 0| 1: [Parameter] output
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] CompositeEncoder
# 0| 2: [Parameter] serialDesc
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] SerialDescriptor
# 14| 5: [BlockStmt] { ... }
# 14| 0: [ExprStmt] <Expr>;
@@ -565,9 +637,19 @@ app/src/main/kotlin/testProject/App.kt:
# 14| 2: [MethodAccess] getId(...)
# 14| -1: [VarAccess] self
# 14| 3: [Class] $serializer
#-----| -3: (Annotations)
# 0| 1: [Annotation] Deprecated
# 0| 1: [StringLiteral] "This synthesized declaration should not be used directly"
# 0| 2: [Annotation] ReplaceWith
# 0| 1: [StringLiteral] ""
# 0| 2: [ArrayInit] {...}
# 0| 3: [VarAccess] DeprecationLevel.HIDDEN
# 0| -1: [TypeAccess] DeprecationLevel
# 0| 1: [FieldDeclaration] SerialDescriptor descriptor;
# 0| -1: [TypeAccess] SerialDescriptor
# 0| 2: [Method] childSerializers
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 3: [TypeAccess] KSerializer<?>[]
# 0| 0: [TypeAccess] KSerializer<?>
# 0| 0: [WildcardTypeAccess] ? ...
@@ -578,9 +660,13 @@ app/src/main/kotlin/testProject/App.kt:
# 14| -1: [TypeAccess] KSerializer<?>
# 14| 0: [IntegerLiteral] 1
# 0| 3: [Method] deserialize
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 3: [TypeAccess] X
#-----| 4: (Parameters)
# 0| 0: [Parameter] decoder
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] Decoder
# 14| 5: [BlockStmt] { ... }
# 14| 0: [LocalVariableDeclStmt] var ...;
@@ -680,6 +766,8 @@ app/src/main/kotlin/testProject/App.kt:
# 14| 1: [VarAccess] tmp4_local0
# 14| 2: [NullLiteral] null
# 0| 4: [Method] getDescriptor
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 3: [TypeAccess] SerialDescriptor
# 0| 5: [BlockStmt] { ... }
# 0| 0: [ReturnStmt] return ...
@@ -689,8 +777,12 @@ app/src/main/kotlin/testProject/App.kt:
# 0| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 0| 0: [Parameter] encoder
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] Encoder
# 0| 1: [Parameter] value
#-----| -1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 0: [TypeAccess] X
# 14| 5: [BlockStmt] { ... }
# 14| 0: [LocalVariableDeclStmt] var ...;
@@ -746,6 +838,8 @@ app/src/main/kotlin/testProject/App.kt:
# 14| 0: [TypeAccess] GeneratedSerializer
# 14| 4: [Class] Companion
# 0| 1: [Method] serializer
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 0| 3: [TypeAccess] KSerializer<X>
# 0| 0: [TypeAccess] X
# 14| 5: [BlockStmt] { ... }
@@ -766,6 +860,8 @@ app/src/main/kotlin/testProject/App.kt:
# 16| -1: [TypeAccess] String
# 16| 0: [StringLiteral] "X"
# 16| 7: [Method] getId
#-----| 1: (Annotations)
# 0| 1: [Annotation] NotNull
# 16| 3: [TypeAccess] String
# 16| 5: [BlockStmt] { ... }
# 16| 0: [ReturnStmt] return ...

View File

@@ -0,0 +1,10 @@
import org.jetbrains.annotations.*;
import zpkg.A;
public interface AnnotatedInterface {
public @A @NotNull String notNullAnnotated(@A @NotNull String param);
public @A @Nullable String nullableAnnotated(@A @Nullable String param);
}

View File

@@ -0,0 +1,10 @@
import org.jetbrains.annotations.*;
import zpkg.A;
public class AnnotatedMethods implements AnnotatedInterface {
public @A @NotNull String notNullAnnotated(@A @NotNull String param) { return param; }
public @A @Nullable String nullableAnnotated(@A @Nullable String param) { return param; }
}

View File

@@ -0,0 +1,8 @@
public class JavaUser {
public static void test(KotlinAnnotatedMethods km, KotlinDelegate kd) {
km.f(null);
kd.notNullAnnotated("Hello world");
}
}

View File

@@ -0,0 +1,9 @@
import zpkg.A
class KotlinAnnotatedMethods {
@A fun f(@A m: AnnotatedMethods): String = m.notNullAnnotated("hello") + m.nullableAnnotated("world")!!
}
class KotlinDelegate(c: AnnotatedMethods) : AnnotatedInterface by c { }

View File

@@ -0,0 +1,6 @@
package org.jetbrains.annotations;
public @interface NotNull {
String value() default "";
Class<? extends Exception> exception() default Exception.class;
}

View File

@@ -0,0 +1,5 @@
package org.jetbrains.annotations;
public @interface Nullable {
String value() default "";
}

View File

@@ -0,0 +1,28 @@
| AnnotatedInterface.java:6:29:6:44 | notNullAnnotated | parameter | AnnotatedInterface.java:6:46:6:47 | A |
| AnnotatedInterface.java:6:29:6:44 | notNullAnnotated | parameter | AnnotatedInterface.java:6:49:6:56 | NotNull |
| AnnotatedInterface.java:6:29:6:44 | notNullAnnotated | return value | AnnotatedInterface.java:6:10:6:11 | A |
| AnnotatedInterface.java:6:29:6:44 | notNullAnnotated | return value | AnnotatedInterface.java:6:13:6:20 | NotNull |
| AnnotatedInterface.java:8:30:8:46 | nullableAnnotated | parameter | AnnotatedInterface.java:8:48:8:49 | A |
| AnnotatedInterface.java:8:30:8:46 | nullableAnnotated | parameter | AnnotatedInterface.java:8:51:8:59 | Nullable |
| AnnotatedInterface.java:8:30:8:46 | nullableAnnotated | return value | AnnotatedInterface.java:8:10:8:11 | A |
| AnnotatedInterface.java:8:30:8:46 | nullableAnnotated | return value | AnnotatedInterface.java:8:13:8:21 | Nullable |
| AnnotatedMethods.java:6:29:6:44 | notNullAnnotated | parameter | AnnotatedMethods.java:6:46:6:47 | A |
| AnnotatedMethods.java:6:29:6:44 | notNullAnnotated | parameter | AnnotatedMethods.java:6:49:6:56 | NotNull |
| AnnotatedMethods.java:6:29:6:44 | notNullAnnotated | return value | AnnotatedMethods.java:6:10:6:11 | A |
| AnnotatedMethods.java:6:29:6:44 | notNullAnnotated | return value | AnnotatedMethods.java:6:13:6:20 | NotNull |
| AnnotatedMethods.java:8:30:8:46 | nullableAnnotated | parameter | AnnotatedMethods.java:8:48:8:49 | A |
| AnnotatedMethods.java:8:30:8:46 | nullableAnnotated | parameter | AnnotatedMethods.java:8:51:8:59 | Nullable |
| AnnotatedMethods.java:8:30:8:46 | nullableAnnotated | return value | AnnotatedMethods.java:8:10:8:11 | A |
| AnnotatedMethods.java:8:30:8:46 | nullableAnnotated | return value | AnnotatedMethods.java:8:13:8:21 | Nullable |
| ktUser.kt:0:0:0:0 | notNullAnnotated | parameter | ktUser.kt:0:0:0:0 | A |
| ktUser.kt:0:0:0:0 | notNullAnnotated | parameter | ktUser.kt:0:0:0:0 | NotNull |
| ktUser.kt:0:0:0:0 | notNullAnnotated | return value | ktUser.kt:0:0:0:0 | A |
| ktUser.kt:0:0:0:0 | notNullAnnotated | return value | ktUser.kt:0:0:0:0 | NotNull |
| ktUser.kt:0:0:0:0 | nullableAnnotated | parameter | ktUser.kt:0:0:0:0 | A |
| ktUser.kt:0:0:0:0 | nullableAnnotated | parameter | ktUser.kt:0:0:0:0 | Nullable |
| ktUser.kt:0:0:0:0 | nullableAnnotated | return value | ktUser.kt:0:0:0:0 | A |
| ktUser.kt:0:0:0:0 | nullableAnnotated | return value | ktUser.kt:0:0:0:0 | Nullable |
| ktUser.kt:5:6:5:105 | f | parameter | ktUser.kt:0:0:0:0 | NotNull |
| ktUser.kt:5:6:5:105 | f | parameter | ktUser.kt:5:12:5:13 | A |
| ktUser.kt:5:6:5:105 | f | return value | ktUser.kt:0:0:0:0 | NotNull |
| ktUser.kt:5:6:5:105 | f | return value | ktUser.kt:5:3:5:4 | A |

View File

@@ -0,0 +1,7 @@
from create_database_utils import *
import os
os.mkdir('out')
os.mkdir('out2')
os.mkdir('out3')
run_codeql_database_create(["javac AnnotatedInterface.java AnnotatedMethods.java zpkg/A.java org/jetbrains/annotations/NotNull.java org/jetbrains/annotations/Nullable.java -d out", "kotlinc ktUser.kt -cp out -d out2", "javac JavaUser.java -cp out" + os.pathsep + "out2 -d out3"], lang="java")

View File

@@ -0,0 +1,11 @@
import java
from Method m, string origin, Annotation a
where
m.fromSource() and
(
origin = "return value" and a = m.getAnAnnotation()
or
origin = "parameter" and a = m.getAParameter().getAnAnnotation()
)
select m, origin, a

View File

@@ -0,0 +1,3 @@
package zpkg;
public @interface A { }

View File

@@ -0,0 +1,5 @@
public @interface JavaDefinedContainer {
public JavaDefinedRepeatable[] value();
}

View File

@@ -0,0 +1,3 @@
@java.lang.annotation.Repeatable(JavaDefinedContainer.class)
public @interface JavaDefinedRepeatable { }

View File

@@ -0,0 +1,9 @@
@LocalRepeatable
@LocalRepeatable
@LibRepeatable
@LibRepeatable
@ExplicitContainerRepeatable
@ExplicitContainerRepeatable
@JavaDefinedRepeatable
@JavaDefinedRepeatable
public class JavaUser { }

View File

@@ -0,0 +1,7 @@
@Repeatable
public annotation class LibRepeatable { }
annotation class KtDefinedContainer(val value: Array<ExplicitContainerRepeatable>) { }
@java.lang.annotation.Repeatable(KtDefinedContainer::class)
annotation class ExplicitContainerRepeatable() { }

View File

@@ -0,0 +1,16 @@
| JavaUser.java:9:14:9:21 | JavaUser | out2/JavaUser.class:0:0:0:0 | Container | value | out2/JavaUser.class:0:0:0:0 | {...} |
| JavaUser.java:9:14:9:21 | JavaUser | out2/JavaUser.class:0:0:0:0 | Container | value | out2/JavaUser.class:0:0:0:0 | {...} |
| JavaUser.java:9:14:9:21 | JavaUser | out2/JavaUser.class:0:0:0:0 | JavaDefinedContainer | value | out2/JavaUser.class:0:0:0:0 | {...} |
| JavaUser.java:9:14:9:21 | JavaUser | out2/JavaUser.class:0:0:0:0 | KtDefinedContainer | value | out2/JavaUser.class:0:0:0:0 | {...} |
| out/ExplicitContainerRepeatable.class:0:0:0:0 | ExplicitContainerRepeatable | out/ExplicitContainerRepeatable.class:0:0:0:0 | Repeatable | value | out/ExplicitContainerRepeatable.class:0:0:0:0 | KtDefinedContainer.class |
| out/ExplicitContainerRepeatable.class:0:0:0:0 | ExplicitContainerRepeatable | out/ExplicitContainerRepeatable.class:0:0:0:0 | Retention | value | out/ExplicitContainerRepeatable.class:0:0:0:0 | RUNTIME |
| out/JavaDefinedRepeatable.class:0:0:0:0 | JavaDefinedRepeatable | out/JavaDefinedRepeatable.class:0:0:0:0 | Repeatable | value | out/JavaDefinedRepeatable.class:0:0:0:0 | JavaDefinedContainer.class |
| out/KtDefinedContainer.class:0:0:0:0 | KtDefinedContainer | out/KtDefinedContainer.class:0:0:0:0 | Retention | value | out/KtDefinedContainer.class:0:0:0:0 | RUNTIME |
| out/LibRepeatable.class:0:0:0:0 | LibRepeatable | out/LibRepeatable.class:0:0:0:0 | Repeatable | value | out/LibRepeatable.class:0:0:0:0 | Container.class |
| out/LibRepeatable.class:0:0:0:0 | LibRepeatable | out/LibRepeatable.class:0:0:0:0 | Retention | value | out/LibRepeatable.class:0:0:0:0 | RUNTIME |
| test.kt:1:1:2:43 | LocalRepeatable | test.kt:0:0:0:0 | Repeatable | value | test.kt:0:0:0:0 | Container.class |
| test.kt:1:1:2:43 | LocalRepeatable | test.kt:0:0:0:0 | Retention | value | test.kt:0:0:0:0 | RetentionPolicy.RUNTIME |
| test.kt:4:1:12:21 | User | test.kt:0:0:0:0 | Container | value | test.kt:0:0:0:0 | {...} |
| test.kt:4:1:12:21 | User | test.kt:0:0:0:0 | Container | value | test.kt:0:0:0:0 | {...} |
| test.kt:4:1:12:21 | User | test.kt:0:0:0:0 | JavaDefinedContainer | value | test.kt:0:0:0:0 | {...} |
| test.kt:4:1:12:21 | User | test.kt:0:0:0:0 | KtDefinedContainer | value | test.kt:0:0:0:0 | {...} |

View File

@@ -0,0 +1,12 @@
@Repeatable
public annotation class LocalRepeatable { }
@LocalRepeatable
@LocalRepeatable
@LibRepeatable
@LibRepeatable
@ExplicitContainerRepeatable
@ExplicitContainerRepeatable
@JavaDefinedRepeatable
@JavaDefinedRepeatable
public class User { }

View File

@@ -0,0 +1,7 @@
from create_database_utils import *
os.mkdir('out')
os.mkdir('out2')
runSuccessfully([get_cmd("kotlinc"), "lib.kt", "-d", "out"])
runSuccessfully([get_cmd("javac"), "JavaDefinedContainer.java", "JavaDefinedRepeatable.java", "-d", "out"])
run_codeql_database_create(["kotlinc test.kt -cp out -d out", "javac JavaUser.java -cp out -d out2"], lang="java")

View File

@@ -0,0 +1,11 @@
import java
from ClassOrInterface annotated, Annotation a, string valName, Expr val
where
a.getValue(valName) = val and
annotated = a.getAnnotatedElement() and
annotated.getName() in [
"JavaDefinedRepeatable", "JavaDefinedContainer", "KtDefinedContainer", "LibRepeatable",
"ExplicitContainerRepeatable", "LocalRepeatable", "User", "JavaUser"
]
select a.getAnnotatedElement(), a, valName, val

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The extraction of Kotlin extension methods has been improved when default parameter values are present. The dispatch and extension receiver parameters are extracted in the correct order. The `ExtensionMethod::getExtensionReceiverParameterIndex` predicate has been introduced to facilitate getting the correct extension parameter index.

View File

@@ -14,5 +14,5 @@ extensions:
data: []
- addsTo:
pack: codeql/java-all
extensible: extNegativeSummaryModel
extensible: extNeutralModel
data: []

View File

@@ -1861,7 +1861,7 @@ extensions:
- addsTo:
pack: codeql/java-all
extensible: extNegativeSummaryModel
extensible: extNeutralModel
data:
- ["kotlin.annotation", "AnnotationRetention", "valueOf", "(String)", "generated"]
- ["kotlin.annotation", "AnnotationRetention", "values", "()", "generated"]

View File

@@ -676,7 +676,7 @@ extensions:
- addsTo:
pack: codeql/java-all
extensible: extNegativeSummaryModel
extensible: extNeutralModel
data:
- ["org.apache.commons.io.charset", "CharsetDecoders", "CharsetDecoders", "()", "generated"]
- ["org.apache.commons.io.charset", "CharsetEncoders", "CharsetEncoders", "()", "generated"]

View File

@@ -37,7 +37,9 @@ class Annotation extends @annotation, Expr {
}
/** Gets the annotation type declaration for this annotation. */
override AnnotationType getType() { result = Expr.super.getType() }
override AnnotationType getType() {
result = Expr.super.getType().(Interface).getSourceDeclaration()
}
/** Gets the annotation element with the specified `name`. */
AnnotationElement getAnnotationElement(string name) {
@@ -249,7 +251,7 @@ private predicate filteredAnnotValue(Annotation a, Method m, Expr val) {
private predicate sourceAnnotValue(Annotation a, Method m, Expr val) {
annotValue(a, m, val) and
val.getFile().getExtension() = "java"
val.getFile().isSourceFile()
}
/** An abstract representation of language elements that can be annotated. */

View File

@@ -91,7 +91,7 @@ predicate numDepends(RefType t, RefType dep, int value) {
elem = a and usesType(a.getType(), dep)
or
elem = [a.getValue(_), a.getAnArrayValue(_)] and
elem.getFile().getExtension() = "java" and
elem.getFile().isSourceFile() and
usesType(elem.(Expr).getType(), dep)
)
or

View File

@@ -1896,7 +1896,8 @@ class VarAccess extends Expr, @varaccess {
class ExtensionReceiverAccess extends VarAccess {
ExtensionReceiverAccess() {
exists(Parameter p |
this.getVariable() = p and p.getPosition() = 0 and p.getCallable() instanceof ExtensionMethod
this.getVariable() = p and
p.isExtensionParameter()
)
}

View File

@@ -327,18 +327,8 @@ class Callable extends StmtParent, Member, @callable {
this instanceof Method and
result instanceof Method and
this.getName() + "$default" = result.getName() and
extraLeadingParams <= 1 and
(
if ktExtensionFunctions(this, _, _)
then
// Both extension receivers are expected to occur at arg0, with any
// dispatch receiver inserted afterwards in the $default proxy's parameter list.
// Check the extension receiver matches here, and note regular args
// are bumped one position to the right.
regularParamsStartIdx = extraLeadingParams + 1 and
this.getParameterType(0).getErasure() = eraseRaw(result.getParameterType(0))
else regularParamsStartIdx = extraLeadingParams
) and
extraLeadingParams <= 1 and // 0 for static methods, 1 for instance methods
regularParamsStartIdx = extraLeadingParams and
lastParamType instanceof TypeObject
)
|
@@ -827,4 +817,19 @@ class ExtensionMethod extends Method {
KotlinType getExtendedKotlinType() { result = extendedKotlinType }
override string getAPrimaryQlClass() { result = "ExtensionMethod" }
/**
* Gets the index of the parameter that is the extension receiver. This is typically index 0. In case of `$default`
* extension methods that are defined as members, the index is 1. Index 0 is the dispatch receiver of the `$default`
* method.
*/
int getExtensionReceiverParameterIndex() {
if
exists(Method src |
this = src.getKotlinParameterDefaultsProxy() and
src.getNumberOfParameters() = this.getNumberOfParameters() - 3 // 2 extra parameters + 1 dispatch receiver
)
then result = 1
else result = 0
}
}

View File

@@ -120,7 +120,12 @@ private newtype TPrintAstNode =
shouldPrint(lvde, _) and lvde.getParent() instanceof SingleLocalVarDeclParent
} or
TAnnotationsNode(Annotatable ann) {
shouldPrint(ann, _) and ann.hasDeclaredAnnotation() and not partOfAnnotation(ann)
shouldPrint(ann, _) and
ann.hasDeclaredAnnotation() and
not partOfAnnotation(ann) and
// The Kotlin compiler might add annotations that are only present in byte code, although the annotatable element is
// present in source code.
exists(Annotation a | a.getAnnotatedElement() = ann and shouldPrint(a, _))
} or
TParametersNode(Callable c) { shouldPrint(c, _) and not c.hasNoParameters() } or
TBaseTypesNode(ClassOrInterface ty) { shouldPrint(ty, _) } or
@@ -293,19 +298,21 @@ final class AnnotationPartNode extends ExprStmtNode {
override ElementNode getChild(int childIndex) {
result.getElement() =
rank[childIndex](Element ch, string file, int line, int column |
ch = this.getAnAnnotationChild() and locationSortKeys(ch, file, line, column)
rank[childIndex](Element ch, string file, int line, int column, int idx |
ch = this.getAnnotationChild(idx) and locationSortKeys(ch, file, line, column)
|
ch order by file, line, column
ch order by file, line, column, idx
)
}
private Expr getAnAnnotationChild() {
result = element.(Annotation).getValue(_)
private Expr getAnnotationChild(int index) {
result = element.(Annotation).getValue(_) and
index >= 0 and
if exists(int x | x >= 0 | result.isNthChildOf(element, x))
then result.isNthChildOf(element, index)
else result.isNthChildOf(element, -(index + 1))
or
result = element.(ArrayInit).getAnInit()
or
result = element.(ArrayInit).(Annotatable).getAnAnnotation()
result = element.(ArrayInit).getInit(index)
}
}
@@ -672,10 +679,10 @@ final class AnnotationsNode extends PrintAstNode, TAnnotationsNode {
override ElementNode getChild(int childIndex) {
result.getElement() =
rank[childIndex](Element e, string file, int line, int column |
e = ann.getAnAnnotation() and locationSortKeys(e, file, line, column)
rank[childIndex](Element e, string file, int line, int column, string s |
e = ann.getAnAnnotation() and locationSortKeys(e, file, line, column) and s = e.toString()
|
e order by file, line, column
e order by file, line, column, s
)
}

View File

@@ -91,7 +91,7 @@ class Parameter extends Element, @param, LocalScopeVariable {
/** Holds if this formal parameter is a parameter representing the dispatch receiver in an extension method. */
predicate isExtensionParameter() {
this.getPosition() = 0 and this.getCallable() instanceof ExtensionMethod
this.getPosition() = this.getCallable().(ExtensionMethod).getExtensionReceiverParameterIndex()
}
/**

View File

@@ -11,9 +11,9 @@
* `package; type; subtypes; name; signature; ext; input; kind; provenance`
* - Summaries:
* `package; type; subtypes; name; signature; ext; input; output; kind; provenance`
* - Negative Summaries:
* - Neutrals:
* `package; type; name; signature; provenance`
* A negative summary is used to indicate that there is no flow via a callable.
* A neutral is used to indicate that there is no flow via a callable.
*
* The interpretation of a row is similar to API-graphs with a left-to-right
* reading.
@@ -122,30 +122,12 @@ private class SummaryModelCsvInternal extends Unit {
abstract predicate row(string row);
}
/**
* DEPRECATED: Define negative summary models as data extensions instead.
*
* A unit class for adding additional negative summary model rows.
*
* Extend this class to add additional negative summary definitions.
*/
deprecated class NegativeSummaryModelCsv = NegativeSummaryModelCsvInternal;
private class NegativeSummaryModelCsvInternal extends Unit {
/** Holds if `row` specifies a negative summary definition. */
abstract predicate row(string row);
}
private predicate sourceModelInternal(string row) { any(SourceModelCsvInternal s).row(row) }
private predicate summaryModelInternal(string row) { any(SummaryModelCsvInternal s).row(row) }
private predicate sinkModelInternal(string row) { any(SinkModelCsvInternal s).row(row) }
private predicate negativeSummaryModelInternal(string row) {
any(NegativeSummaryModelCsvInternal s).row(row)
}
/**
* Holds if an experimental source model exists for the given parameters.
* This is only for experimental queries.
@@ -313,25 +295,14 @@ predicate summaryModel(
.summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance)
}
/** Holds if a summary model exists indicating there is no flow for the given parameters. */
extensible predicate extNegativeSummaryModel(
/** Holds if a neutral model exists indicating there is no flow for the given parameters. */
extensible predicate extNeutralModel(
string package, string type, string name, string signature, string provenance
);
/** Holds if a summary model exists indicating there is no flow for the given parameters. */
predicate negativeSummaryModel(
string package, string type, string name, string signature, string provenance
) {
exists(string row |
negativeSummaryModelInternal(row) and
row.splitAt(";", 0) = package and
row.splitAt(";", 1) = type and
row.splitAt(";", 2) = name and
row.splitAt(";", 3) = signature and
row.splitAt(";", 4) = provenance
)
or
extNegativeSummaryModel(package, type, name, signature, provenance)
/** Holds if a neutral model exists indicating there is no flow for the given parameters. */
predicate neutralModel(string package, string type, string name, string signature, string provenance) {
extNeutralModel(package, type, name, signature, provenance)
}
private predicate relevantPackage(string package) {
@@ -472,8 +443,6 @@ module ModelValidation {
sinkModelInternal(row) and expect = 9 and pred = "sink"
or
summaryModelInternal(row) and expect = 10 and pred = "summary"
or
negativeSummaryModelInternal(row) and expect = 5 and pred = "negative summary"
|
exists(int cols |
cols = 1 + max(int n | exists(row.splitAt(";", n))) and
@@ -497,9 +466,9 @@ module ModelValidation {
summaryModel(package, type, _, name, signature, ext, _, _, _, provenance) and
pred = "summary"
or
negativeSummaryModel(package, type, name, signature, provenance) and
neutralModel(package, type, name, signature, provenance) and
ext = "" and
pred = "negative summary"
pred = "neutral"
|
not package.regexpMatch("[a-zA-Z0-9_\\.]*") and
result = "Dubious package \"" + package + "\" in " + pred + " model."
@@ -541,7 +510,7 @@ private predicate elementSpec(
or
summaryModel(package, type, subtypes, name, signature, ext, _, _, _, _)
or
negativeSummaryModel(package, type, name, signature, _) and ext = "" and subtypes = false
neutralModel(package, type, name, signature, _) and ext = "" and subtypes = false
}
private string paramsStringPart(Callable c, int i) {
@@ -590,7 +559,7 @@ private Element interpretElement0(
)
}
/** Gets the source/sink/summary/negativesummary element corresponding to the supplied parameters. */
/** Gets the source/sink/summary/neutral element corresponding to the supplied parameters. */
Element interpretElement(
string package, string type, boolean subtypes, string name, string signature, string ext
) {

View File

@@ -172,9 +172,7 @@ abstract class UserInput extends DataFlow::Node { }
/**
* Input that may be controlled by a remote user.
*/
private class RemoteUserInput extends UserInput {
RemoteUserInput() { this instanceof RemoteFlowSource }
}
private class RemoteUserInput extends UserInput instanceof RemoteFlowSource { }
/** A node with input that may be controlled by a local user. */
abstract class LocalUserInput extends UserInput { }

View File

@@ -246,14 +246,14 @@ module Public {
predicate isAutoGenerated() { none() }
}
/** A callable with a flow summary stating there is no flow via the callable. */
class NegativeSummarizedCallable extends SummarizedCallableBase {
NegativeSummarizedCallable() { negativeSummaryElement(this, _) }
/** A callable where there is no flow via the callable. */
class NeutralCallable extends SummarizedCallableBase {
NeutralCallable() { neutralElement(this, _) }
/**
* Holds if the negative summary is auto generated.
* Holds if the neutral is auto generated.
*/
predicate isAutoGenerated() { negativeSummaryElement(this, true) }
predicate isAutoGenerated() { neutralElement(this, true) }
}
}
@@ -1161,9 +1161,9 @@ module Private {
string toString() { result = super.toString() }
}
/** A flow summary to include in the `negativeSummary/1` query predicate. */
abstract class RelevantNegativeSummarizedCallable instanceof NegativeSummarizedCallable {
/** Gets the string representation of this callable used by `summary/1`. */
/** A model to include in the `neutral/1` query predicate. */
abstract class RelevantNeutralCallable instanceof NeutralCallable {
/** Gets the string representation of this callable used by `neutral/1`. */
abstract string getCallableCsv();
string toString() { result = super.toString() }
@@ -1180,13 +1180,13 @@ module Private {
if c.isAutoGenerated() then result = "generated" else result = "manual"
}
private string renderProvenanceNegative(NegativeSummarizedCallable c) {
private string renderProvenanceNeutral(NeutralCallable c) {
if c.isAutoGenerated() then result = "generated" else result = "manual"
}
/**
* A query predicate for outputting flow summaries in semi-colon separated format in QL tests.
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance"",
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance",
* ext is hardcoded to empty.
*/
query predicate summary(string csv) {
@@ -1205,14 +1205,14 @@ module Private {
}
/**
* Holds if a negative flow summary `csv` exists (semi-colon separated format). Used for testing purposes.
* Holds if a neutral model `csv` exists (semi-colon separated format). Used for testing purposes.
* The syntax is: "namespace;type;name;signature;provenance"",
*/
query predicate negativeSummary(string csv) {
exists(RelevantNegativeSummarizedCallable c |
query predicate neutral(string csv) {
exists(RelevantNeutralCallable c |
csv =
c.getCallableCsv() // Callable information
+ renderProvenanceNegative(c) // provenance
+ renderProvenanceNeutral(c) // provenance
)
}
}

View File

@@ -120,8 +120,11 @@ private predicate correspondingKotlinParameterDefaultsArgSpec(
exists(int oldArgParsed |
oldArgParsed = AccessPathSyntax::AccessPath::parseInt(oldArgNumber.splitAt(",").trim())
|
if ktExtensionFunctions(originalCallable, _, _) and oldArgParsed = 0
then defaultsArgSpec = "Argument[0]"
if
ktExtensionFunctions(originalCallable, _, _) and
ktExtensionFunctions(defaultsCallable, _, _) and
oldArgParsed = 0
then defaultsArgSpec = "Argument[" + paramOffset + "]" // 1 if dispatch receiver is present, 0 otherwise.
else defaultsArgSpec = "Argument[" + (oldArgParsed + paramOffset) + "]" + rest
)
)
@@ -160,12 +163,12 @@ predicate summaryElement(
}
/**
* Holds if a negative flow summary exists for `c`, which means that there is no
* flow through `c`. The flag `generated` states whether the summary is autogenerated.
* Holds if a neutral model exists for `c`, which means that there is no
* flow through `c`. The flag `generated` states whether the model is autogenerated.
*/
predicate negativeSummaryElement(SummarizedCallableBase c, boolean generated) {
predicate neutralElement(SummarizedCallableBase c, boolean generated) {
exists(string namespace, string type, string name, string signature, string provenance |
negativeSummaryModel(namespace, type, name, signature, provenance) and
neutralModel(namespace, type, name, signature, provenance) and
generated = isGenerated(provenance) and
c.asCallable() = interpretElement(namespace, type, false, name, signature, "")
)

View File

@@ -58,9 +58,7 @@ abstract class WhitelistedLiveCallable extends CallableEntryPoint { }
/**
* A `public static void main(String[] args)` method.
*/
class MainMethodEntry extends CallableEntryPoint {
MainMethodEntry() { this instanceof MainMethod }
}
class MainMethodEntry extends CallableEntryPoint instanceof MainMethod { }
/**
* A method that overrides a library method -- the result is
@@ -96,9 +94,7 @@ abstract class ReflectivelyConstructedClass extends EntryPoint, Class {
/**
* Classes that are deserialized by Jackson are reflectively constructed.
*/
library class JacksonReflectivelyConstructedClass extends ReflectivelyConstructedClass {
JacksonReflectivelyConstructedClass() { this instanceof JacksonDeserializableType }
library class JacksonReflectivelyConstructedClass extends ReflectivelyConstructedClass instanceof JacksonDeserializableType {
override Callable getALiveCallable() {
// Constructors may be called by Jackson, if they are a no-arg, they have a suitable annotation,
// or inherit a suitable annotation through a mixin.
@@ -312,8 +308,7 @@ class FacesAccessibleMethodEntryPoint extends CallableEntryPoint {
* A Java Server Faces custom component, that is reflectively constructed by the framework when
* used in a view (JSP or facelet).
*/
class FacesComponentReflectivelyConstructedClass extends ReflectivelyConstructedClass {
FacesComponentReflectivelyConstructedClass() { this instanceof FacesComponent }
class FacesComponentReflectivelyConstructedClass extends ReflectivelyConstructedClass instanceof FacesComponent {
}
/**
@@ -400,8 +395,7 @@ class JavaxManagedBeanReflectivelyConstructed extends ReflectivelyConstructedCla
* Classes marked as Java persistence entities can be reflectively constructed when the data is
* loaded.
*/
class PersistentEntityEntryPoint extends ReflectivelyConstructedClass {
PersistentEntityEntryPoint() { this instanceof PersistentEntity }
class PersistentEntityEntryPoint extends ReflectivelyConstructedClass instanceof PersistentEntity {
}
/**
@@ -465,6 +459,5 @@ class ArbitraryXmlEntryPoint extends ReflectivelyConstructedClass {
deprecated class ArbitraryXMLEntryPoint = ArbitraryXmlEntryPoint;
/** A Selenium PageObject, created by a call to PageFactory.initElements(..). */
class SeleniumPageObjectEntryPoint extends ReflectivelyConstructedClass {
SeleniumPageObjectEntryPoint() { this instanceof SeleniumPageObject }
class SeleniumPageObjectEntryPoint extends ReflectivelyConstructedClass instanceof SeleniumPageObject {
}

View File

@@ -50,9 +50,7 @@ class SpringBeanAnnotatedMethod extends CallableEntryPoint {
/**
* A live entry point within a Spring controller.
*/
class SpringControllerEntryPoint extends CallableEntryPoint {
SpringControllerEntryPoint() { this instanceof SpringControllerMethod }
}
class SpringControllerEntryPoint extends CallableEntryPoint instanceof SpringControllerMethod { }
/**
* A method that is accessible in a response, because it is part of the returned model,

View File

@@ -33,23 +33,18 @@ class Struts1ActionEntryPoint extends EntryPoint, Class {
/**
* A struts 2 action class that is reflectively constructed.
*/
class Struts2ReflectivelyConstructedAction extends ReflectivelyConstructedClass {
Struts2ReflectivelyConstructedAction() { this instanceof Struts2ActionClass }
class Struts2ReflectivelyConstructedAction extends ReflectivelyConstructedClass instanceof Struts2ActionClass {
}
/**
* A method called on a struts 2 action class when the action is activated.
*/
class Struts2ActionMethodEntryPoint extends CallableEntryPoint {
Struts2ActionMethodEntryPoint() { this instanceof Struts2ActionMethod }
}
class Struts2ActionMethodEntryPoint extends CallableEntryPoint instanceof Struts2ActionMethod { }
/**
* A method called on a struts 2 action class before an action is activated.
*/
class Struts2PrepareMethodEntryPoint extends CallableEntryPoint {
Struts2PrepareMethodEntryPoint() { this instanceof Struts2PrepareMethod }
}
class Struts2PrepareMethodEntryPoint extends CallableEntryPoint instanceof Struts2PrepareMethod { }
/**
* A class which is accessible - directly or indirectly - from a struts action.

View File

@@ -78,13 +78,10 @@ class JUnitCategory extends WhitelistedLiveClass {
/**
* A listener that will be reflectively constructed by TestNG.
*/
class TestNGReflectivelyConstructedListener extends ReflectivelyConstructedClass {
TestNGReflectivelyConstructedListener() {
// Consider any class that implements a TestNG listener interface to be live. Listeners can be
// specified on the command line, in `testng.xml` files and in Ant build files, so it is safest
// to assume that all such listeners are live.
this instanceof TestNGListenerImpl
}
class TestNGReflectivelyConstructedListener extends ReflectivelyConstructedClass instanceof TestNGListenerImpl {
// Consider any class that implements a TestNG listener interface to be live. Listeners can be
// specified on the command line, in `testng.xml` files and in Ant build files, so it is safest
// to assume that all such listeners are live.
}
/**
@@ -99,9 +96,7 @@ class TestNGDataProvidersEntryPoint extends CallableEntryPoint {
/**
* A `@Factory` TestNG method or constructor which is live.
*/
class TestNGFactoryEntryPoint extends CallableEntryPoint {
TestNGFactoryEntryPoint() { this instanceof TestNGFactoryCallable }
}
class TestNGFactoryEntryPoint extends CallableEntryPoint instanceof TestNGFactoryCallable { }
class TestRefectivelyConstructedClass extends ReflectivelyConstructedClass {
TestRefectivelyConstructedClass() {
@@ -159,6 +154,5 @@ class CucumberConstructedClass extends ReflectivelyConstructedClass {
/**
* A "step definition" that may be called by Cucumber when executing an acceptance test.
*/
class CucumberStepDefinitionEntryPoint extends CallableEntryPoint {
CucumberStepDefinitionEntryPoint() { this instanceof CucumberStepDefinition }
class CucumberStepDefinitionEntryPoint extends CallableEntryPoint instanceof CucumberStepDefinition {
}

View File

@@ -7,17 +7,12 @@ import semmle.code.java.frameworks.Servlets
* Any class which extends the `Servlet` interface is intended to be constructed reflectively by a
* servlet container.
*/
class ServletConstructedClass extends ReflectivelyConstructedClass {
class ServletConstructedClass extends ReflectivelyConstructedClass instanceof ServletClass {
ServletConstructedClass() {
this instanceof ServletClass and
// If we have seen any `web.xml` files, this servlet will be considered to be live only if it is
// referred to as a servlet-class in at least one. If no `web.xml` files are found, we assume
// that XML extraction was not enabled, and therefore consider all `Servlet` classes as live.
(
isWebXmlIncluded()
implies
exists(WebServletClass servletClass | this = servletClass.getClass())
)
isWebXmlIncluded() implies exists(WebServletClass servletClass | this = servletClass.getClass())
}
}
@@ -112,6 +107,4 @@ class GwtUiBinderEntryPoint extends CallableEntryPoint {
/**
* Fields that may be reflectively read or written to by the UiBinder framework.
*/
class GwtUiBinderReflectivelyReadField extends ReflectivelyReadField {
GwtUiBinderReflectivelyReadField() { this instanceof GwtUiField }
}
class GwtUiBinderReflectivelyReadField extends ReflectivelyReadField instanceof GwtUiField { }

View File

@@ -45,7 +45,10 @@ class WebViewGetUrlMethod extends Method {
class CrossOriginAccessMethod extends Method {
CrossOriginAccessMethod() {
this.getDeclaringType() instanceof TypeWebSettings and
this.hasName(["setAllowUniversalAccessFromFileURLs", "setAllowFileAccessFromFileURLs"])
this.hasName([
"setAllowFileAccess", "setAllowUniversalAccessFromFileURLs",
"setAllowFileAccessFromFileURLs"
])
}
}

View File

@@ -75,14 +75,11 @@ class ForbiddenSecurityConfigurationCallable extends ForbiddenCallable {
}
/** A method or constructor involving serialization that may not be called by an EJB. */
class ForbiddenSerializationCallable extends ForbiddenCallable {
ForbiddenSerializationCallable() { this instanceof ForbiddenSerializationMethod }
class ForbiddenSerializationCallable extends ForbiddenCallable instanceof ForbiddenSerializationMethod {
}
/** A method or constructor involving network factory operations that may not be called by an EJB. */
class ForbiddenSetFactoryCallable extends ForbiddenCallable {
ForbiddenSetFactoryCallable() { this instanceof ForbiddenSetFactoryMethod }
}
class ForbiddenSetFactoryCallable extends ForbiddenCallable instanceof ForbiddenSetFactoryMethod { }
/** A method or constructor involving server socket operations that may not be called by an EJB. */
class ForbiddenServerSocketCallable extends ForbiddenCallable {

View File

@@ -73,9 +73,8 @@ abstract class AlwaysEnabledSpringProfile extends string {
*
* Includes all `SpringProfile`s that are not specified as always enabled or never enabled.
*/
class SometimesEnabledSpringProfile extends string {
class SometimesEnabledSpringProfile extends string instanceof SpringProfile {
SometimesEnabledSpringProfile() {
this instanceof SpringProfile and
not (
this instanceof AlwaysEnabledSpringProfile or
this instanceof NeverEnabledSpringProfile

View File

@@ -290,9 +290,7 @@ string getSecureAlgorithmRegex() {
* algorithm. For example, methods returning ciphers, decryption methods,
* constructors of cipher classes, etc.
*/
abstract class CryptoAlgoSpec extends Top {
CryptoAlgoSpec() { this instanceof Call }
abstract class CryptoAlgoSpec extends Top instanceof Call {
abstract Expr getAlgoSpec();
}

View File

@@ -298,8 +298,9 @@ private class PathNormalizeSanitizer extends MethodAccess {
* what `getQualifier` actually gets in Java and Kotlin.
*/
private Expr getVisualQualifier(MethodAccess ma) {
if getSourceMethod(ma.getMethod()) instanceof ExtensionMethod
then result = ma.getArgument(0)
if ma.getMethod() instanceof ExtensionMethod
then
result = ma.getArgument(ma.getMethod().(ExtensionMethod).getExtensionReceiverParameterIndex())
else result = ma.getQualifier()
}
@@ -310,8 +311,11 @@ private Expr getVisualQualifier(MethodAccess ma) {
*/
bindingset[argPos]
private Argument getVisualArgument(MethodAccess ma, int argPos) {
if getSourceMethod(ma.getMethod()) instanceof ExtensionMethod
then result = ma.getArgument(argPos + 1)
if ma.getMethod() instanceof ExtensionMethod
then
result =
ma.getArgument(argPos + ma.getMethod().(ExtensionMethod).getExtensionReceiverParameterIndex() +
1)
else result = ma.getArgument(argPos)
}

View File

@@ -15,9 +15,7 @@ private class DefaultHeaderSplittingSink extends HeaderSplittingSink {
}
/** A source that introduces data considered safe to use by a header splitting source. */
abstract class SafeHeaderSplittingSource extends DataFlow::Node {
SafeHeaderSplittingSource() { this instanceof RemoteFlowSource }
}
abstract class SafeHeaderSplittingSource extends DataFlow::Node instanceof RemoteFlowSource { }
/** A default source that introduces data considered safe to use by a header splitting source. */
private class DefaultSafeHeaderSplittingSource extends SafeHeaderSplittingSource {

View File

@@ -53,9 +53,7 @@ class SuppressionComment extends Javadoc {
/**
* The scope of an alert suppression comment.
*/
class SuppressionScope extends @javadoc {
SuppressionScope() { this instanceof SuppressionComment }
class SuppressionScope extends @javadoc instanceof SuppressionComment {
/** Gets a suppression comment with this scope. */
SuppressionComment getSuppressionComment() { result = this }
@@ -69,7 +67,7 @@ class SuppressionScope extends @javadoc {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.(SuppressionComment).covers(filepath, startline, startcolumn, endline, endcolumn)
super.covers(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets a textual representation of this element. */

View File

@@ -69,9 +69,7 @@ class SuppressionAnnotation extends SuppressWarningsAnnotation {
/**
* The scope of an alert suppression annotation.
*/
class SuppressionScope extends @annotation {
SuppressionScope() { this instanceof SuppressionAnnotation }
class SuppressionScope extends @annotation instanceof SuppressionAnnotation {
/** Gets a suppression annotation with this scope. */
SuppressionAnnotation getSuppressionAnnotation() { result = this }
@@ -85,7 +83,7 @@ class SuppressionScope extends @annotation {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.(SuppressionAnnotation).covers(filepath, startline, startcolumn, endline, endcolumn)
super.covers(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets a textual representation of this element. */

View File

@@ -20,9 +20,7 @@ int leftWidth(ComparisonExpr e) { result = e.getLeftOperand().getType().(NumType
int rightWidth(ComparisonExpr e) { result = e.getRightOperand().getType().(NumType).getWidthRank() }
abstract class WideningComparison extends BinaryExpr {
WideningComparison() { this instanceof ComparisonExpr }
abstract class WideningComparison extends BinaryExpr instanceof ComparisonExpr {
abstract Expr getNarrower();
abstract Expr getWider();

View File

@@ -0,0 +1,65 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Allowing file access in an Android WebView can expose a device's file system to
the JavaScript running in that WebView. If the JavaScript contains
vulnerabilities or the WebView loads untrusted content, file access
allows an attacker to steal the user's data.
</p>
</overview>
<recommendation>
<p>When possible, do not allow file access. The file access settings
are disabled by default. You can explicitly disable file access by setting the
following settings to <code>false</code>:</p>
<ul>
<li><code>setAllowFileAccess</code></li>
<li><code>setAllowFileAccessFromFileURLs</code></li>
<li><code>setAllowUniversalAccessFromFileURLs</code></li>
</ul>
<p>If your application requires access to the file system, it is best to
avoid using <code>file://</code> URLs. Instead, use an alternative that
loads files via HTTPS, such
as <code>androidx.webkit.WebViewAssetLoader</code>.</p>
</recommendation>
<example>
<p>In the following (bad) example, the WebView is configured with settings
that allow local file access.</p>
<sample src="WebViewFileAccessUnsafe.java"/>
<p>In the following (good) example, the WebView is configured to disallow file access.</p>
<sample src="WebViewFileAccessSafe.java"/>
<p>
As mentioned previously, asset loaders can load files without file system
access. In the following (good) example, an asset loader is configured to
load assets over HTTPS.
</p>
<sample src="AssetLoaderExample.java"/>
</example>
<references>
<li>
Android documentation: <a href="https://developer.android.com/reference/android/webkit/WebSettings#setAllowFileAccess(boolean)">WebSettings.setAllowFileAccess</a>.
</li>
<li>
Android documentation: <a href="https://developer.android.com/reference/android/webkit/WebSettings#setAllowFileAccessFromFileURLs(boolean)">WebSettings.setAllowFileAccessFromFileURLs</a>.
</li>
<li>
Android documentation: <a href="https://developer.android.com/reference/android/webkit/WebSettings#setAllowUniversalAccessFromFileURLs(boolean)">WebSettings.setAllowUniversalAccessFromFileURLs</a>.
</li>
<li>
Android documentation: <a href="https://developer.android.com/reference/androidx/webkit/WebViewAssetLoader">WebViewAssetLoader</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,22 @@
/**
* @name Android WebSettings file access
* @kind problem
* @description Enabling access to the file system in a WebView allows attackers to view sensitive information.
* @id java/android-websettings-file-access
* @problem.severity warning
* @security-severity 6.5
* @precision medium
* @tags security
* external/cwe/cwe-200
*/
import java
import semmle.code.java.frameworks.android.WebView
from MethodAccess ma
where
ma.getMethod() instanceof CrossOriginAccessMethod and
ma.getArgument(0).(CompileTimeConstantExpr).getBooleanValue() = true
select ma,
"WebView setting " + ma.getMethod().getName() +
" may allow for unauthorized access of sensitive information."

View File

@@ -0,0 +1,15 @@
WebViewAssetLoader loader = new WebViewAssetLoader.Builder()
// Replace the domain with a domain you control, or use the default
// appassets.androidplatform.com
.setDomain("appassets.example.com")
.addPathHandler("/resources", new AssetsPathHandler(this))
.build();
webView.setWebViewClient(new WebViewClientCompat() {
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return assetLoader.shouldInterceptRequest(request.getUrl());
}
});
webView.loadUrl("https://appassets.example.com/resources/www/index.html");

View File

@@ -0,0 +1,5 @@
WebSettings settings = view.getSettings();
settings.setAllowFileAccess(false);
settings.setAllowFileAccessFromURLs(false);
settings.setAllowUniversalAccessFromURLs(false);

View File

@@ -0,0 +1,5 @@
WebSettings settings = view.getSettings();
settings.setAllowFileAccess(true);
settings.setAllowFileAccessFromURLs(true);
settings.setAllowUniversalAccessFromURLs(true);

View File

@@ -11,8 +11,8 @@ import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import ExternalApi
private predicate relevant(ExternalApi api) {
api.isSupported() or
api = any(FlowSummaryImpl::Public::NegativeSummarizedCallable nsc).asCallable()
api.isSupported() or
api = any(FlowSummaryImpl::Public::NeutralCallable nsc).asCallable()
}
from string apiName, int usages

View File

@@ -12,7 +12,7 @@ import ExternalApi
private predicate relevant(ExternalApi api) {
not api.isSupported() and
not api = any(FlowSummaryImpl::Public::NegativeSummarizedCallable nsc).asCallable()
not api = any(FlowSummaryImpl::Public::NeutralCallable nsc).asCallable()
}
from string apiName, int usages

View File

@@ -0,0 +1,5 @@
---
category: newQuery
---
* Added a new query `java/android-websettings-file-access` to detect configurations that enable file system access in Android WebViews.

View File

@@ -81,8 +81,7 @@ private class CompareSink extends ClientSuppliedIpUsedInSecurityCheckSink {
}
/** A data flow sink for sql operation. */
private class SqlOperationSink extends ClientSuppliedIpUsedInSecurityCheckSink {
SqlOperationSink() { this instanceof QueryInjectionSink }
private class SqlOperationSink extends ClientSuppliedIpUsedInSecurityCheckSink instanceof QueryInjectionSink {
}
/** A method that split string. */

View File

@@ -0,0 +1,48 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>The <code>Thread.sleep</code> method is used to pause the execution of current thread for
specified time. When the sleep time is user-controlled, especially in the web application context,
it can be abused to cause all of a server's threads to sleep, leading to denial of service.</p>
</overview>
<recommendation>
<p>To guard against this attack, consider specifying an upper range of allowed sleep time or adopting
the producer/consumer design pattern with <code>Object.wait</code> method to avoid performance
problems or even resource exhaustion. For more information, refer to the concurrency tutorial of Oracle
listed below or <code>java/ql/src/Likely Bugs/Concurrency</code> queries of CodeQL.</p>
</recommendation>
<example>
<p>The following example shows a bad situation and a good situation respectively. In the bad situation,
a thread sleep time comes directly from user input. In the good situation, an upper
range check on the maximum sleep time allowed is enforced.</p>
<sample src="ThreadResourceAbuse.java" />
</example>
<references>
<li>
Snyk:
<a href="https://snyk.io/vuln/SNYK-JAVA-COMGOOGLECODEGWTUPLOAD-569506">Denial of Service (DoS)
in com.googlecode.gwtupload:gwtupload</a>.
</li>
<li>
gwtupload:
<a href="https://github.com/manolo/gwtupload/issues/33">[Fix DOS issue] Updating the
AbstractUploadListener.java file</a>.
</li>
<li>
The blog of a gypsy engineer:
<a href="https://blog.gypsyengineer.com/en/security/cve-2019-17555-dos-via-retry-after-header-in-apache-olingo.html">
CVE-2019-17555: DoS via Retry-After header in Apache Olingo</a>.
</li>
<li>
Oracle:
<a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html">The Java Concurrency Tutorials</a>
</li>
</references>
</qhelp>

View File

@@ -3,7 +3,7 @@
* @description Using user input directly to control a thread's sleep time could lead to
* performance problems or even resource exhaustion.
* @kind path-problem
* @id java/thread-resource-abuse
* @id java/local-thread-resource-abuse
* @problem.severity recommendation
* @tags security
* external/cwe/cwe-400

View File

@@ -1,8 +1,8 @@
/**
* @name Capture negative summary models.
* @description Finds negative summary models to be used by other queries.
* @name Capture neutral models.
* @description Finds neutral models to be used by other queries.
* @kind diagnostic
* @id java/utils/model-generator/negative-summary-models
* @id java/utils/model-generator/neutral-models
* @tags model-generator
*/

View File

@@ -2,7 +2,6 @@
# Tool to regenerate existing framework CSV models.
from pathlib import Path
import json
import os
import shutil
@@ -37,7 +36,7 @@ def regenerateModel(lgtmSlug, extractedDb):
modelFile = lgtmSlugToModelFile[lgtmSlug]
codeQlRoot = findGitRoot()
subprocess.check_call([codeQlRoot + "/java/ql/src/utils/model-generator/GenerateFlowModel.py",
"--with-summaries", "--with-sinks", "--with-negative-summaries",
"--with-summaries", "--with-sinks", "--with-neutrals",
extractedDb, modelFile])
print("Regenerated " + modelFile)
shutil.rmtree(tmpDir)

View File

@@ -1,7 +1,7 @@
/**
* @name Extract MaD negative summary model rows.
* @description This extracts the Models as data negative summary model rows.
* @id java/utils/modelconverter/generate-data-extensions-negative-summary
* @name Extract MaD neutral model rows.
* @description This extracts the Models as data neutral model rows.
* @id java/utils/modelconverter/generate-data-extensions-neutral
*/
import java
@@ -9,6 +9,6 @@ import semmle.code.java.dataflow.ExternalFlow
from string package, string type, string name, string signature, string provenance
where
negativeSummaryModel(package, type, name, signature, provenance) and
neutralModel(package, type, name, signature, provenance) and
provenance != "generated"
select package, type, name, signature, provenance order by package, type, name, signature

View File

@@ -58,9 +58,7 @@ private string asSummaryModel(TargetApiSpecific api, string input, string output
+ "generated"
}
string asNegativeSummaryModel(TargetApiSpecific api) {
result = asPartialNegativeModel(api) + "generated"
}
string asNeutralModel(TargetApiSpecific api) { result = asPartialNeutralModel(api) + "generated" }
/**
* Gets the value summary model for `api` with `input` and `output`.

View File

@@ -131,9 +131,9 @@ string asPartialModel(TargetApiSpecific api) {
}
/**
* Computes the first 4 columns for negative CSV rows.
* Computes the first 4 columns for neutral CSV rows.
*/
string asPartialNegativeModel(TargetApiSpecific api) {
string asPartialNeutralModel(TargetApiSpecific api) {
exists(string type, string name, string parameters |
partialModel(api, type, name, parameters) and
result =

View File

@@ -77,10 +77,10 @@ string captureFlow(DataFlowTargetApi api) {
}
/**
* Gets the negative summary for `api`, if any.
* A negative summary is generated, if there does not exist any positive flow.
* Gets the neutral summary for `api`, if any.
* A neutral model is generated, if there does not exist any summary model.
*/
string captureNoFlow(DataFlowTargetApi api) {
not exists(captureFlow(api)) and
result = asNegativeSummaryModel(api)
result = asNeutralModel(api)
}

View File

@@ -499,11 +499,8 @@ private RefType getAReferencedType(RefType t) {
}
/** A top level type whose file should be stubbed */
class GeneratedTopLevel extends TopLevelType {
GeneratedTopLevel() {
this = this.getSourceDeclaration() and
this instanceof GeneratedType
}
class GeneratedTopLevel extends TopLevelType instanceof GeneratedType {
GeneratedTopLevel() { this = this.getSourceDeclaration() }
private TopLevelType getAnImportedType() {
result = getAReferencedType(this).getSourceDeclaration()
@@ -536,8 +533,6 @@ class GeneratedTopLevel extends TopLevelType {
/** Creates a full stub for the file containing this type. */
string stubFile() {
result =
this.stubComment() + this.stubPackage() + this.stubImports() + this.(GeneratedType).getStub() +
"\n"
result = this.stubComment() + this.stubPackage() + this.stubImports() + super.getStub() + "\n"
}
}

View File

@@ -1,82 +1,21 @@
test.kt:
# 0| [CompilationUnit] test
# 3| 1: [Interface] A
# 3| 1: [Constructor] A
#-----| 4: (Parameters)
# 3| 0: [Parameter] c1
# 3| 0: [TypeAccess] Class<?>
# 3| 0: [WildcardTypeAccess] ? ...
# 3| 1: [Parameter] c2
# 3| 0: [TypeAccess] Class<? extends CharSequence>
# 3| 0: [WildcardTypeAccess] ? ...
# 3| 0: [TypeAccess] CharSequence
# 3| 2: [Parameter] c3
# 3| 0: [TypeAccess] Class<String>
# 3| 0: [TypeAccess] String
# 3| 3: [Parameter] c4
# 3| 0: [TypeAccess] Class<?>[]
# 3| 0: [TypeAccess] Class<?>
# 3| 0: [WildcardTypeAccess] ? ...
# 3| 5: [BlockStmt] { ... }
# 3| 0: [SuperConstructorInvocationStmt] super(...)
# 3| 1: [BlockStmt] { ... }
# 3| 0: [ExprStmt] <Expr>;
# 3| 0: [KtInitializerAssignExpr] ...=...
# 3| 0: [VarAccess] c1
# 3| 1: [ExprStmt] <Expr>;
# 3| 0: [KtInitializerAssignExpr] ...=...
# 3| 0: [VarAccess] c2
# 3| 2: [ExprStmt] <Expr>;
# 3| 0: [KtInitializerAssignExpr] ...=...
# 3| 0: [VarAccess] c3
# 3| 3: [ExprStmt] <Expr>;
# 3| 0: [KtInitializerAssignExpr] ...=...
# 3| 0: [VarAccess] c4
# 3| 2: [FieldDeclaration] Class<?> c1;
# 3| -1: [TypeAccess] Class<?>
# 3| 0: [WildcardTypeAccess] ? ...
# 3| 0: [VarAccess] c1
# 3| 3: [Method] c1
#-----| -3: (Annotations)
# 0| 1: [Annotation] Retention
# 0| 1: [VarAccess] RetentionPolicy.RUNTIME
# 0| -1: [TypeAccess] RetentionPolicy
# 3| 1: [Method] c1
# 3| 3: [TypeAccess] Class<?>
# 3| 0: [WildcardTypeAccess] ? ...
# 3| 5: [BlockStmt] { ... }
# 3| 0: [ReturnStmt] return ...
# 3| 0: [VarAccess] this.c1
# 3| -1: [ThisAccess] this
# 3| 4: [FieldDeclaration] Class<? extends CharSequence> c2;
# 3| -1: [TypeAccess] Class<? extends CharSequence>
# 3| 0: [WildcardTypeAccess] ? ...
# 3| 0: [TypeAccess] CharSequence
# 3| 0: [VarAccess] c2
# 3| 5: [Method] c2
# 3| 2: [Method] c2
# 3| 3: [TypeAccess] Class<? extends CharSequence>
# 3| 0: [WildcardTypeAccess] ? ...
# 3| 0: [TypeAccess] CharSequence
# 3| 5: [BlockStmt] { ... }
# 3| 0: [ReturnStmt] return ...
# 3| 0: [VarAccess] this.c2
# 3| -1: [ThisAccess] this
# 3| 6: [FieldDeclaration] Class<String> c3;
# 3| -1: [TypeAccess] Class<String>
# 3| 0: [TypeAccess] String
# 3| 0: [VarAccess] c3
# 3| 7: [Method] c3
# 3| 3: [Method] c3
# 3| 3: [TypeAccess] Class<String>
# 3| 0: [TypeAccess] String
# 3| 5: [BlockStmt] { ... }
# 3| 0: [ReturnStmt] return ...
# 3| 0: [VarAccess] this.c3
# 3| -1: [ThisAccess] this
# 3| 8: [FieldDeclaration] Class<?>[] c4;
# 3| -1: [TypeAccess] Class<?>[]
# 3| 0: [TypeAccess] Class<?>
# 3| 0: [WildcardTypeAccess] ? ...
# 3| 0: [VarAccess] c4
# 3| 9: [Method] c4
# 3| 4: [Method] c4
# 3| 3: [TypeAccess] Class<?>[]
# 3| 0: [TypeAccess] Class<?>
# 3| 0: [WildcardTypeAccess] ? ...
# 3| 5: [BlockStmt] { ... }
# 3| 0: [ReturnStmt] return ...
# 3| 0: [VarAccess] this.c4
# 3| -1: [ThisAccess] this

View File

@@ -1,35 +1,9 @@
classExprs
| test.kt:3:20:3:36 | ...=... | Class<?> |
| test.kt:3:20:3:36 | Class<?> | Class<?> |
| test.kt:3:20:3:36 | Class<?> | Class<?> |
| test.kt:3:20:3:36 | Class<?> | Class<?> |
| test.kt:3:20:3:36 | c1 | Class<?> |
| test.kt:3:20:3:36 | c1 | Class<?> |
| test.kt:3:20:3:36 | this.c1 | Class<?> |
| test.kt:3:39:3:70 | ...=... | Class<? extends CharSequence> |
| test.kt:3:39:3:70 | Class<? extends CharSequence> | Class<? extends CharSequence> |
| test.kt:3:39:3:70 | Class<? extends CharSequence> | Class<? extends CharSequence> |
| test.kt:3:39:3:70 | Class<? extends CharSequence> | Class<? extends CharSequence> |
| test.kt:3:39:3:70 | c2 | Class<? extends CharSequence> |
| test.kt:3:39:3:70 | c2 | Class<? extends CharSequence> |
| test.kt:3:39:3:70 | this.c2 | Class<? extends CharSequence> |
| test.kt:3:73:3:94 | ...=... | Class<String> |
| test.kt:3:73:3:94 | Class<String> | Class<String> |
| test.kt:3:73:3:94 | Class<String> | Class<String> |
| test.kt:3:73:3:94 | Class<String> | Class<String> |
| test.kt:3:73:3:94 | c3 | Class<String> |
| test.kt:3:73:3:94 | c3 | Class<String> |
| test.kt:3:73:3:94 | this.c3 | Class<String> |
| test.kt:3:97:3:120 | ...=... | Class<?>[] |
| test.kt:3:97:3:120 | Class<?> | Class<?> |
| test.kt:3:97:3:120 | Class<?> | Class<?> |
| test.kt:3:97:3:120 | Class<?> | Class<?> |
| test.kt:3:97:3:120 | Class<?>[] | Class<?>[] |
| test.kt:3:97:3:120 | Class<?>[] | Class<?>[] |
| test.kt:3:97:3:120 | Class<?>[] | Class<?>[] |
| test.kt:3:97:3:120 | c4 | Class<?>[] |
| test.kt:3:97:3:120 | c4 | Class<?>[] |
| test.kt:3:97:3:120 | this.c4 | Class<?>[] |
#select
| test.kt:3:20:3:36 | c1 | Class<?> |
| test.kt:3:39:3:70 | c2 | Class<? extends CharSequence> |

View File

@@ -0,0 +1,3 @@
public @interface Annot0j {
int abc() default 0;
}

View File

@@ -0,0 +1,15 @@
public @interface Annot1j {
int a() default 2;
String b() default "ab";
Class c() default X.class;
Y d() default Y.A;
Y[] e() default { Y.A, Y.B };
Annot0j f() default @Annot0j(
abc = 1
);
}

View File

@@ -0,0 +1,280 @@
Annot0j.java:
# 0| [CompilationUnit] Annot0j
# 1| 1: [Interface] Annot0j
# 2| 1: [Method] abc
# 2| 3: [TypeAccess] int
Annot1j.java:
# 0| [CompilationUnit] Annot1j
# 1| 1: [Interface] Annot1j
# 2| 1: [Method] a
# 2| 3: [TypeAccess] int
# 4| 2: [Method] b
# 4| 3: [TypeAccess] String
# 6| 3: [Method] c
# 6| 3: [TypeAccess] Class<>
# 8| 4: [Method] d
# 8| 3: [TypeAccess] Y
# 10| 5: [Method] e
# 10| 3: [ArrayTypeAccess] ...[]
# 10| 0: [TypeAccess] Y
# 12| 6: [Method] f
# 12| 3: [TypeAccess] Annot0j
def.kt:
# 0| [CompilationUnit] def
# 0| 1: [Class] DefKt
# 46| 2: [Method] fn
#-----| 1: (Annotations)
# 45| 1: [Annotation] Annot0k
# 0| 1: [IntegerLiteral] 0
#-----| 2: (Generic Parameters)
# 46| 0: [TypeVariable] T
# 46| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 46| 0: [Parameter] a
#-----| -1: (Annotations)
# 46| 1: [Annotation] Annot0k
# 0| 1: [IntegerLiteral] 0
# 46| 0: [TypeAccess] Annot0k
# 46| 5: [BlockStmt] { ... }
# 47| 0: [ExprStmt] <Expr>;
# 47| 0: [MethodAccess] println(...)
# 47| -1: [TypeAccess] ConsoleKt
# 47| 0: [MethodAccess] a(...)
# 47| -1: [VarAccess] a
# 50| 1: [LocalVariableDeclStmt] var ...;
# 50| 1: [LocalVariableDeclExpr] x
# 50| 0: [IntegerLiteral] 10
# 53| 3: [FieldDeclaration] int p;
#-----| -2: (Annotations)
# 56| 1: [Annotation] Annot0k
# 0| 1: [IntegerLiteral] 0
# 53| -1: [TypeAccess] int
# 57| 0: [IntegerLiteral] 5
# 57| 4: [Method] getP
#-----| 1: (Annotations)
# 54| 1: [Annotation] Annot0k
# 0| 1: [IntegerLiteral] 0
# 57| 3: [TypeAccess] int
# 57| 5: [BlockStmt] { ... }
# 57| 0: [ReturnStmt] return ...
# 57| 0: [VarAccess] DefKt.p
# 57| -1: [TypeAccess] DefKt
# 57| 5: [Method] setP
#-----| 1: (Annotations)
# 55| 1: [Annotation] Annot0k
# 0| 1: [IntegerLiteral] 0
# 57| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 57| 0: [Parameter] <set-?>
# 57| 0: [TypeAccess] int
# 57| 5: [BlockStmt] { ... }
# 57| 0: [ExprStmt] <Expr>;
# 57| 0: [AssignExpr] ...=...
# 57| 0: [VarAccess] DefKt.p
# 57| -1: [TypeAccess] DefKt
# 57| 1: [VarAccess] <set-?>
# 59| 6: [ExtensionMethod] myExtension
# 59| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 59| 0: [Parameter] <this>
#-----| -1: (Annotations)
# 59| 1: [Annotation] Annot0k
# 0| 1: [IntegerLiteral] 0
# 59| 0: [TypeAccess] String
# 59| 5: [BlockStmt] { ... }
# 5| 2: [Interface] Annot0k
#-----| -3: (Annotations)
# 0| 1: [Annotation] Retention
# 0| 1: [VarAccess] RetentionPolicy.RUNTIME
# 0| -1: [TypeAccess] RetentionPolicy
# 0| 2: [Annotation] Target
# 0| 1: [ArrayInit] {...}
# 0| 1: [VarAccess] ElementType.TYPE
# 0| -1: [TypeAccess] ElementType
# 0| 2: [VarAccess] ElementType.FIELD
# 0| -1: [TypeAccess] ElementType
# 0| 3: [VarAccess] ElementType.METHOD
# 0| -1: [TypeAccess] ElementType
# 0| 4: [VarAccess] ElementType.PARAMETER
# 0| -1: [TypeAccess] ElementType
# 0| 5: [VarAccess] ElementType.CONSTRUCTOR
# 0| -1: [TypeAccess] ElementType
# 0| 6: [VarAccess] ElementType.LOCAL_VARIABLE
# 0| -1: [TypeAccess] ElementType
# 0| 7: [VarAccess] ElementType.ANNOTATION_TYPE
# 0| -1: [TypeAccess] ElementType
# 0| 8: [VarAccess] ElementType.TYPE_PARAMETER
# 0| -1: [TypeAccess] ElementType
# 0| 9: [VarAccess] ElementType.TYPE_USE
# 0| -1: [TypeAccess] ElementType
# 5| 3: [Annotation] Target
# 0| 1: [ArrayInit] {...}
# 0| 1: [VarAccess] AnnotationTarget.CLASS
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 2: [VarAccess] AnnotationTarget.ANNOTATION_CLASS
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 3: [VarAccess] AnnotationTarget.TYPE_PARAMETER
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 4: [VarAccess] AnnotationTarget.PROPERTY
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 5: [VarAccess] AnnotationTarget.FIELD
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 6: [VarAccess] AnnotationTarget.LOCAL_VARIABLE
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 7: [VarAccess] AnnotationTarget.VALUE_PARAMETER
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 8: [VarAccess] AnnotationTarget.CONSTRUCTOR
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 9: [VarAccess] AnnotationTarget.FUNCTION
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 10: [VarAccess] AnnotationTarget.PROPERTY_GETTER
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 11: [VarAccess] AnnotationTarget.PROPERTY_SETTER
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 12: [VarAccess] AnnotationTarget.TYPE
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 13: [VarAccess] AnnotationTarget.FILE
# 0| -1: [TypeAccess] AnnotationTarget
# 0| 14: [VarAccess] AnnotationTarget.TYPEALIAS
# 0| -1: [TypeAccess] AnnotationTarget
# 21| 1: [Method] a
#-----| 1: (Annotations)
# 21| 1: [Annotation] JvmName
# 0| 1: [StringLiteral] "a"
# 21| 3: [TypeAccess] int
# 23| 3: [Interface] Annot1k
#-----| -3: (Annotations)
# 0| 1: [Annotation] Retention
# 0| 1: [VarAccess] RetentionPolicy.RUNTIME
# 0| -1: [TypeAccess] RetentionPolicy
# 23| 2: [Annotation] Annot0k
# 0| 1: [IntegerLiteral] 0
# 25| 1: [Method] a
# 25| 3: [TypeAccess] int
# 26| 2: [Method] b
# 26| 3: [TypeAccess] String
# 27| 3: [Method] c
# 27| 3: [TypeAccess] Class<?>
# 27| 0: [WildcardTypeAccess] ? ...
# 28| 4: [Method] d
# 28| 3: [TypeAccess] Y
# 29| 5: [Method] e
# 29| 3: [TypeAccess] Y[]
# 29| 0: [TypeAccess] Y
# 30| 6: [Method] f
# 30| 3: [TypeAccess] Annot0k
# 33| 4: [Class] X
# 33| 1: [Constructor] X
# 33| 5: [BlockStmt] { ... }
# 33| 0: [SuperConstructorInvocationStmt] super(...)
# 33| 1: [BlockStmt] { ... }
# 34| 5: [Class] Y
# 0| 2: [Method] valueOf
# 0| 3: [TypeAccess] Y
#-----| 4: (Parameters)
# 0| 0: [Parameter] value
# 0| 0: [TypeAccess] String
# 0| 3: [Method] values
# 0| 3: [TypeAccess] Y[]
# 0| 0: [TypeAccess] Y
# 34| 4: [Constructor] Y
# 34| 5: [BlockStmt] { ... }
# 34| 0: [ExprStmt] <Expr>;
# 34| 0: [ClassInstanceExpr] new Enum(...)
# 34| -3: [TypeAccess] Enum<Y>
# 34| 0: [TypeAccess] Y
# 34| 0: [NullLiteral] null
# 34| 1: [IntegerLiteral] 0
# 34| 1: [BlockStmt] { ... }
# 35| 5: [FieldDeclaration] Y A;
# 35| -1: [TypeAccess] Y
# 35| 0: [ClassInstanceExpr] new Y(...)
# 35| -3: [TypeAccess] Y
# 35| 6: [FieldDeclaration] Y B;
# 35| -1: [TypeAccess] Y
# 35| 0: [ClassInstanceExpr] new Y(...)
# 35| -3: [TypeAccess] Y
# 35| 7: [FieldDeclaration] Y C;
# 35| -1: [TypeAccess] Y
# 35| 0: [ClassInstanceExpr] new Y(...)
# 35| -3: [TypeAccess] Y
# 38| 6: [Class] Z
#-----| -3: (Annotations)
# 38| 1: [Annotation] Annot0k
# 0| 1: [IntegerLiteral] 1
# 39| 2: [Annotation] Annot1k
# 0| 1: [IntegerLiteral] 2
# 0| 2: [StringLiteral] "ab"
# 0| 3: [TypeLiteral] X.class
# 0| 0: [TypeAccess] X
# 0| 4: [VarAccess] Y.B
# 0| -1: [TypeAccess] Y
# 0| 5: [ArrayInit] {...}
# 0| 1: [VarAccess] Y.C
# 0| -1: [TypeAccess] Y
# 0| 2: [VarAccess] Y.A
# 0| -1: [TypeAccess] Y
# 0| 6: [Annotation] Annot0k
# 0| 1: [IntegerLiteral] 1
# 42| 1: [Constructor] Z
#-----| 1: (Annotations)
# 41| 1: [Annotation] Annot0k
# 0| 1: [IntegerLiteral] 0
# 41| 5: [BlockStmt] { ... }
# 42| 0: [SuperConstructorInvocationStmt] super(...)
# 42| 1: [BlockStmt] { ... }
use.java:
# 0| [CompilationUnit] use
# 1| 1: [Class] use
#-----| -1: (Base Types)
# 1| 0: [TypeAccess] Annot0k
# 3| 2: [Method] a
#-----| 1: (Annotations)
# 2| 1: [Annotation] Override
# 3| 3: [TypeAccess] int
# 3| 5: [BlockStmt] { ... }
# 3| 0: [ReturnStmt] return ...
# 3| 0: [IntegerLiteral] 1
# 6| 3: [Method] annotationType
#-----| 1: (Annotations)
# 5| 1: [Annotation] Override
# 6| 3: [TypeAccess] Class<? extends Annotation>
# 6| 0: [WildcardTypeAccess] ? ...
# 6| 0: [TypeAccess] Annotation
# 6| 5: [BlockStmt] { ... }
# 7| 0: [ReturnStmt] return ...
# 7| 0: [NullLiteral] null
# 14| 4: [Class] Z
#-----| -3: (Annotations)
# 10| 1: [Annotation] Annot0j
# 10| 1: [IntegerLiteral] 1
# 11| 2: [Annotation] Annot1j
# 11| 1: [IntegerLiteral] 1
# 11| 2: [StringLiteral] "ac"
# 11| 3: [TypeLiteral] X.class
# 11| 0: [TypeAccess] X
# 11| 4: [VarAccess] Y.B
# 11| -1: [TypeAccess] Y
# 11| 5: [ArrayInit] {...}
# 11| 3: [VarAccess] Y.C
# 11| -1: [TypeAccess] Y
# 11| 4: [VarAccess] Y.A
# 11| -1: [TypeAccess] Y
# 11| 6: [Annotation] Annot0j
# 11| 1: [IntegerLiteral] 2
# 12| 3: [Annotation] Annot0k
# 12| 1: [IntegerLiteral] 1
# 13| 4: [Annotation] Annot1k
# 13| 1: [IntegerLiteral] 1
# 13| 2: [StringLiteral] "ac"
# 13| 3: [TypeLiteral] X.class
# 13| 0: [TypeAccess] X
# 13| 4: [VarAccess] Y.B
# 13| -1: [TypeAccess] Y
# 13| 5: [ArrayInit] {...}
# 13| 3: [VarAccess] Y.C
# 13| -1: [TypeAccess] Y
# 13| 4: [VarAccess] Y.A
# 13| -1: [TypeAccess] Y
# 13| 6: [Annotation] Annot0k
# 13| 1: [IntegerLiteral] 2

View File

@@ -0,0 +1 @@
semmle/code/java/PrintAst.ql

View File

@@ -1,2 +1,82 @@
| def.kt:2:1:2:31 | SomeAnnotation | Interface |
| use.java:2:23:2:25 | use | Class |
annotationDeclarations
| Annot0j.java:1:19:1:25 | Annot0j | Annot0j.java:2:9:2:11 | abc |
| Annot1j.java:1:19:1:25 | Annot1j | Annot1j.java:2:9:2:9 | a |
| Annot1j.java:1:19:1:25 | Annot1j | Annot1j.java:4:12:4:12 | b |
| Annot1j.java:1:19:1:25 | Annot1j | Annot1j.java:6:11:6:11 | c |
| Annot1j.java:1:19:1:25 | Annot1j | Annot1j.java:8:7:8:7 | d |
| Annot1j.java:1:19:1:25 | Annot1j | Annot1j.java:10:9:10:9 | e |
| Annot1j.java:1:19:1:25 | Annot1j | Annot1j.java:12:13:12:13 | f |
| def.kt:5:1:21:60 | Annot0k | def.kt:21:44:21:59 | a |
| def.kt:23:1:31:1 | Annot1k | def.kt:25:5:25:18 | a |
| def.kt:23:1:31:1 | Annot1k | def.kt:26:5:26:24 | b |
| def.kt:23:1:31:1 | Annot1k | def.kt:27:5:27:31 | c |
| def.kt:23:1:31:1 | Annot1k | def.kt:28:5:28:18 | d |
| def.kt:23:1:31:1 | Annot1k | def.kt:29:5:29:32 | e |
| def.kt:23:1:31:1 | Annot1k | def.kt:30:5:30:31 | f |
annotations
| def.kt:0:0:0:0 | Annot0k | def.kt:39:1:39:40 | Annot1k | def.kt:5:1:21:60 | Annot0k |
| def.kt:23:1:23:8 | Annot0k | def.kt:23:1:31:1 | Annot1k | def.kt:5:1:21:60 | Annot0k |
| def.kt:38:1:38:17 | Annot0k | def.kt:38:1:43:1 | Z | def.kt:5:1:21:60 | Annot0k |
| def.kt:39:1:39:40 | Annot1k | def.kt:38:1:43:1 | Z | def.kt:23:1:31:1 | Annot1k |
| def.kt:41:5:41:12 | Annot0k | def.kt:42:5:42:19 | Z | def.kt:5:1:21:60 | Annot0k |
| def.kt:45:1:45:8 | Annot0k | def.kt:46:1:51:1 | fn | def.kt:5:1:21:60 | Annot0k |
| def.kt:46:21:46:28 | Annot0k | def.kt:46:21:46:39 | a | def.kt:5:1:21:60 | Annot0k |
| def.kt:54:1:54:12 | Annot0k | def.kt:57:1:57:23 | getP | def.kt:5:1:21:60 | Annot0k |
| def.kt:55:1:55:12 | Annot0k | def.kt:57:1:57:23 | setP | def.kt:5:1:21:60 | Annot0k |
| def.kt:56:1:56:14 | Annot0k | def.kt:53:1:57:23 | p | def.kt:5:1:21:60 | Annot0k |
| def.kt:59:5:59:21 | Annot0k | def.kt:59:5:59:28 | <this> | def.kt:5:1:21:60 | Annot0k |
| use.java:10:5:10:21 | Annot0j | use.java:14:18:14:18 | Z | Annot0j.java:1:19:1:25 | Annot0j |
| use.java:11:5:11:90 | Annot1j | use.java:14:18:14:18 | Z | Annot1j.java:1:19:1:25 | Annot1j |
| use.java:11:73:11:89 | Annot0j | use.java:11:5:11:90 | Annot1j | Annot0j.java:1:19:1:25 | Annot0j |
| use.java:12:5:12:19 | Annot0k | use.java:14:18:14:18 | Z | def.kt:5:1:21:60 | Annot0k |
| use.java:13:5:13:88 | Annot1k | use.java:14:18:14:18 | Z | def.kt:23:1:31:1 | Annot1k |
| use.java:13:73:13:87 | Annot0k | use.java:13:5:13:88 | Annot1k | def.kt:5:1:21:60 | Annot0k |
annotationValues
| def.kt:0:0:0:0 | Annot0k | def.kt:0:0:0:0 | 1 |
| def.kt:0:0:0:0 | Retention | def.kt:0:0:0:0 | RetentionPolicy.RUNTIME |
| def.kt:0:0:0:0 | Retention | def.kt:0:0:0:0 | RetentionPolicy.RUNTIME |
| def.kt:0:0:0:0 | Target | def.kt:0:0:0:0 | {...} |
| def.kt:5:1:20:1 | Target | def.kt:0:0:0:0 | {...} |
| def.kt:21:26:21:42 | JvmName | def.kt:0:0:0:0 | "a" |
| def.kt:23:1:23:8 | Annot0k | def.kt:0:0:0:0 | 0 |
| def.kt:38:1:38:17 | Annot0k | def.kt:0:0:0:0 | 1 |
| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | 2 |
| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | "ab" |
| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | Annot0k |
| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | X.class |
| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | Y.B |
| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | {...} |
| def.kt:41:5:41:12 | Annot0k | def.kt:0:0:0:0 | 0 |
| def.kt:45:1:45:8 | Annot0k | def.kt:0:0:0:0 | 0 |
| def.kt:46:21:46:28 | Annot0k | def.kt:0:0:0:0 | 0 |
| def.kt:54:1:54:12 | Annot0k | def.kt:0:0:0:0 | 0 |
| def.kt:55:1:55:12 | Annot0k | def.kt:0:0:0:0 | 0 |
| def.kt:56:1:56:14 | Annot0k | def.kt:0:0:0:0 | 0 |
| def.kt:59:5:59:21 | Annot0k | def.kt:0:0:0:0 | 0 |
| use.java:10:5:10:21 | Annot0j | use.java:10:20:10:20 | 1 |
| use.java:11:5:11:90 | Annot1j | use.java:11:18:11:18 | 1 |
| use.java:11:5:11:90 | Annot1j | use.java:11:25:11:28 | "ac" |
| use.java:11:5:11:90 | Annot1j | use.java:11:35:11:41 | X.class |
| use.java:11:5:11:90 | Annot1j | use.java:11:48:11:50 | Y.B |
| use.java:11:5:11:90 | Annot1j | use.java:11:57:11:66 | {...} |
| use.java:11:5:11:90 | Annot1j | use.java:11:73:11:89 | Annot0j |
| use.java:11:73:11:89 | Annot0j | use.java:11:88:11:88 | 2 |
| use.java:12:5:12:19 | Annot0k | use.java:12:18:12:18 | 1 |
| use.java:13:5:13:88 | Annot1k | use.java:13:18:13:18 | 1 |
| use.java:13:5:13:88 | Annot1k | use.java:13:25:13:28 | "ac" |
| use.java:13:5:13:88 | Annot1k | use.java:13:35:13:41 | X.class |
| use.java:13:5:13:88 | Annot1k | use.java:13:48:13:50 | Y.B |
| use.java:13:5:13:88 | Annot1k | use.java:13:57:13:66 | {...} |
| use.java:13:5:13:88 | Annot1k | use.java:13:73:13:87 | Annot0k |
| use.java:13:73:13:87 | Annot0k | use.java:13:86:13:86 | 2 |
#select
| Annot0j.java:1:19:1:25 | Annot0j | Interface |
| Annot1j.java:1:19:1:25 | Annot1j | Interface |
| def.kt:0:0:0:0 | DefKt | Class |
| def.kt:5:1:21:60 | Annot0k | Interface |
| def.kt:23:1:31:1 | Annot1k | Interface |
| def.kt:33:1:33:10 | X | Class |
| def.kt:34:1:36:1 | Y | Class |
| def.kt:38:1:43:1 | Z | Class |
| use.java:1:14:1:16 | use | Class |
| use.java:14:18:14:18 | Z | Class |

View File

@@ -3,3 +3,18 @@ import java
from ClassOrInterface x
where x.fromSource()
select x, x.getPrimaryQlClasses()
query predicate annotationDeclarations(AnnotationType at, AnnotationElement ae) {
at.fromSource() and
at.getAnAnnotationElement() = ae
}
query predicate annotations(Annotation a, Element e, AnnotationType at) {
at.fromSource() and
a.getAnnotatedElement() = e and
at = a.getType()
}
query predicate annotationValues(Annotation a, Expr v) {
a.getValue(_) = v and v.getFile().isSourceFile()
}

View File

@@ -1,3 +1,62 @@
@file:Annot0k
annotation class SomeAnnotation
import kotlin.reflect.KClass
@Target(AnnotationTarget.CLASS,
AnnotationTarget.ANNOTATION_CLASS,
AnnotationTarget.TYPE_PARAMETER,
AnnotationTarget.PROPERTY,
AnnotationTarget.FIELD,
AnnotationTarget.LOCAL_VARIABLE, // TODO
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.CONSTRUCTOR,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.TYPE, // TODO
//AnnotationTarget.EXPRESSION, // TODO
AnnotationTarget.FILE, // TODO
AnnotationTarget.TYPEALIAS // TODO
)
annotation class Annot0k(@get:JvmName("a") val abc: Int = 0)
@Annot0k
annotation class Annot1k(
val a: Int = 2,
val b: String = "ab",
val c: KClass<*> = X::class,
val d: Y = Y.A,
val e: Array<Y> = [Y.A, Y.B],
val f: Annot0k = Annot0k(1)
)
class X {}
enum class Y {
A,B,C
}
@Annot0k(abc = 1)
@Annot1k(d = Y.B, e = arrayOf(Y.C, Y.A))
class Z {
@Annot0k
constructor(){}
}
@Annot0k
fun <@Annot0k T> fn(@Annot0k a: Annot0k) {
println(a.abc)
@Annot0k
var x = 10
}
@Annot0k
@get:Annot0k
@set:Annot0k
@field:Annot0k
var p: @Annot0k Int = 5
fun @receiver:Annot0k String.myExtension() { }
@Annot0k
typealias AAA = Z

View File

@@ -1,3 +1,15 @@
public class use implements Annot0k {
@Override
public int a() { return 1; }
public abstract class use implements SomeAnnotation {}
@Override
public Class<? extends java.lang.annotation.Annotation> annotationType() {
return null;
}
@Annot0j(abc = 1)
@Annot1j(a = 1, b = "ac", c = X.class, d = Y.B, e = {Y.C, Y.A}, f = @Annot0j(abc = 2))
@Annot0k(a = 1)
@Annot1k(a = 1, b = "ac", c = X.class, d = Y.B, e = {Y.C, Y.A}, f = @Annot0k(a = 2))
public class Z { }
}

View File

@@ -1,84 +1,12 @@
test.kt:
# 0| [CompilationUnit] test
# 1| 1: [Interface] Ann
# 1| 1: [Constructor] Ann
#-----| 4: (Parameters)
# 1| 0: [Parameter] arr1
# 1| 0: [TypeAccess] String[]
# 1| 0: [TypeAccess] String
# 1| 1: [Parameter] arr2
# 1| 0: [TypeAccess] int[]
# 1| 5: [BlockStmt] { ... }
# 1| 0: [SuperConstructorInvocationStmt] super(...)
# 1| 1: [BlockStmt] { ... }
# 1| 0: [ExprStmt] <Expr>;
# 1| 0: [KtInitializerAssignExpr] ...=...
# 1| 0: [VarAccess] arr1
# 1| 1: [ExprStmt] <Expr>;
# 1| 0: [KtInitializerAssignExpr] ...=...
# 1| 0: [VarAccess] arr2
# 1| 2: [Constructor] Ann
#-----| 4: (Parameters)
# 1| 0: [Parameter] p0
# 1| 0: [TypeAccess] String[]
# 1| 1: [Parameter] p1
# 1| 0: [TypeAccess] int[]
# 1| 2: [Parameter] p2
# 1| 0: [TypeAccess] int
# 1| 3: [Parameter] p3
# 1| 0: [TypeAccess] DefaultConstructorMarker
# 1| 5: [BlockStmt] { ... }
# 1| 0: [IfStmt] if (...)
# 1| 0: [EQExpr] ... == ...
# 1| 0: [AndBitwiseExpr] ... & ...
# 1| 0: [IntegerLiteral] 1
# 1| 1: [VarAccess] p2
# 1| 1: [IntegerLiteral] 0
# 1| 1: [ExprStmt] <Expr>;
# 1| 0: [AssignExpr] ...=...
# 1| 0: [VarAccess] p0
# 0| 1: [ArrayCreationExpr] new String[]
# 0| -2: [ArrayInit] {...}
# 0| 0: [StringLiteral] "hello"
# 0| 1: [StringLiteral] "world"
# 0| -1: [TypeAccess] String
# 0| 0: [IntegerLiteral] 2
# 1| 1: [IfStmt] if (...)
# 1| 0: [EQExpr] ... == ...
# 1| 0: [AndBitwiseExpr] ... & ...
# 1| 0: [IntegerLiteral] 2
# 1| 1: [VarAccess] p2
# 1| 1: [IntegerLiteral] 0
# 1| 1: [ExprStmt] <Expr>;
# 1| 0: [AssignExpr] ...=...
# 1| 0: [VarAccess] p1
# 0| 1: [ArrayCreationExpr] new int[]
# 0| -2: [ArrayInit] {...}
# 0| 0: [IntegerLiteral] 1
# 0| 1: [IntegerLiteral] 2
# 0| 2: [IntegerLiteral] 3
# 0| -1: [TypeAccess] int
# 0| 0: [IntegerLiteral] 3
# 1| 2: [ThisConstructorInvocationStmt] this(...)
# 1| 0: [VarAccess] p0
# 1| 1: [VarAccess] p1
# 1| 3: [FieldDeclaration] String[] arr1;
# 1| -1: [TypeAccess] String[]
# 1| 0: [TypeAccess] String
# 1| 0: [VarAccess] arr1
# 1| 4: [Method] arr1
#-----| -3: (Annotations)
# 0| 1: [Annotation] Retention
# 0| 1: [VarAccess] RetentionPolicy.RUNTIME
# 0| -1: [TypeAccess] RetentionPolicy
# 1| 1: [Method] arr1
# 1| 3: [TypeAccess] String[]
# 1| 0: [TypeAccess] String
# 1| 5: [BlockStmt] { ... }
# 1| 0: [ReturnStmt] return ...
# 1| 0: [VarAccess] this.arr1
# 1| -1: [ThisAccess] this
# 1| 5: [Method] arr2
# 1| 2: [Method] arr2
# 1| 3: [TypeAccess] int[]
# 1| 5: [BlockStmt] { ... }
# 1| 0: [ReturnStmt] return ...
# 1| 0: [VarAccess] this.arr2
# 1| -1: [ThisAccess] this
# 1| 6: [FieldDeclaration] int[] arr2;
# 1| -1: [TypeAccess] int[]
# 1| 0: [VarAccess] arr2

View File

@@ -1,2 +1 @@
| exprs.kt:278:52:278:66 | <error expr> | ErrorExpr | unexpected dead end |
| exprs.kt:278:52:278:66 | { ... } | BlockStmt | unexpected dead end |

View File

@@ -35,4 +35,5 @@ MaybeElement enclosingCallable(Expr e) {
}
from Expr e
where e.getFile().isSourceFile()
select e, enclosingCallable(e), e.getPrimaryQlClasses()

Some files were not shown because too many files have changed in this diff Show More