From 92d330ad75fc663b6552154e7b3384476f6b5fad Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Thu, 12 Dec 2024 22:38:36 +0100 Subject: [PATCH] Handle some explicit null cases --- .../de/fraunhofer/aisec/cpg/ScopeManager.kt | 33 ++++++++++--------- .../aisec/cpg/passes/SymbolResolver.kt | 23 +++++++++---- .../aisec/cpg/passes/inference/PassHelper.kt | 3 +- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt index aefbd603c7..05d0200c5a 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt @@ -510,16 +510,13 @@ class ScopeManager : ScopeProvider { } val extractedScope = extractScope(ref, startScope) - var scope: Scope? - val name: Name + // If the scope extraction fails, we can only return here directly without any result if (extractedScope == null) { - // the scope does not exist at all - scope = startScope - name = ref.name - } else { - scope = extractedScope.scope - name = extractedScope.adjustedName + return null } + + var scope = extractedScope.scope + val name = extractedScope.adjustedName if (scope == null) { scope = startScope } @@ -564,16 +561,22 @@ class ScopeManager : ScopeProvider { return decl } + /** + * This class represents the result of the [extractScope] operation. It contains a [scope] + * object, if a scope was found and the [adjustedName] that is normalized if any aliases were + * found during scope extraction. + */ data class ScopeExtraction(val scope: Scope?, val adjustedName: Name) /** - * This function extracts a scope for the [Name], e.g. if the name is fully qualified. `null` is - * returned, if no scope can be extracted. + * This function extracts a scope for the [Name], e.g. if the name is fully qualified (wrapped + * in a [ScopeExtraction] object. `null` is returned if a scope was specified, but does not + * exist as a [Scope] object. * - * The pair returns the extracted scope and a name that is adjusted by possible import aliases. - * The extracted scope is "responsible" for the name (e.g. declares the parent namespace) and - * the returned name only differs from the provided name if aliasing was involved at the node - * location (e.g. because of imports). + * The returned object contains the extracted scope and a name that is adjusted by possible + * import aliases. The extracted scope is "responsible" for the name (e.g. declares the parent + * namespace) and the returned name only differs from the provided name if aliasing was involved + * at the node location (e.g. because of imports). * * Note: Currently only *fully* qualified names are properly resolved. This function will * probably return imprecise results for partially qualified names, e.g. if a name `A` inside @@ -581,7 +584,7 @@ class ScopeManager : ScopeProvider { * * @param node the nodes name references a namespace constituted by a scope * @param scope the current scope relevant for the name resolution, e.g. parent of node - * @return a pair with the scope of node.name and the alias-adjusted name + * @return a [ScopeExtraction] object with the scope of node.name and the alias-adjusted name */ fun extractScope(node: HasNameAndLocation, scope: Scope? = currentScope): ScopeExtraction? { return extractScope(node.name, node.location, scope) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt index 95d50d387f..d463d64090 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt @@ -106,7 +106,7 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) { // Gather all resolution EOG starters; and make sure they really do not have a // predecessor, otherwise we might analyze a node multiple times - val nodes = it.allEOGStarters.filter { it.prevEOGEdges.isEmpty() } + val nodes = it.allEOGStarters.filter { it.prevEOGEdges.isEmpty } for (node in nodes) { walker.iterate(node) @@ -144,7 +144,11 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) { if (target == null) { // Determine the scope where we want to start our inference val extractedScope = scopeManager.extractScope(reference) - var scope = extractedScope?.scope + if (extractedScope == null) { + return null + } + + var scope = extractedScope.scope if (scope !is NameScope) { scope = null } @@ -529,19 +533,26 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) { setOf(), mapOf(), setOf(), - CallResolutionResult.SuccessKind.UNRESOLVED, + UNRESOLVED, source.scope, ) val language = source.language if (language == null) { - result.success = CallResolutionResult.SuccessKind.PROBLEMATIC + result.success = PROBLEMATIC return result } // Set the start scope. This can either be the call's scope or a scope specified in an FQN val extractedScope = ctx.scopeManager.extractScope(source, source.scope) - val scope = extractedScope?.scope + + // If we could not extract the scope (even though one was specified), we can only return an + // empty result + if (extractedScope == null) { + return result + } + + val scope = extractedScope.scope result.actualStartScope = scope ?: source.scope // If the function does not allow function overloading, and we have multiple candidate @@ -571,7 +582,7 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) { // If we have a "problematic" result, we can stop here. In this case we cannot really // determine anything more. - if (result.success == CallResolutionResult.SuccessKind.PROBLEMATIC) { + if (result.success == PROBLEMATIC) { result.bestViable = result.viableFunctions return result } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/PassHelper.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/PassHelper.kt index 8c2319a897..37014c17c0 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/PassHelper.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/PassHelper.kt @@ -100,7 +100,8 @@ internal fun Pass<*>.tryRecordInference( "class" } // Determine the scope where we want to start our inference - val extractedScope = scopeManager.extractScope(type, scope = type.scope) + val extractedScope = + scopeManager.extractScope(type.name, location = locationHint?.location, scope = type.scope) var scope = extractedScope?.scope if (scope !is NameScope) {