Skip to content

Commit

Permalink
Handle some explicit null cases
Browse files Browse the repository at this point in the history
  • Loading branch information
oxisto committed Dec 12, 2024
1 parent 403cc3d commit 92d330a
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 22 deletions.
33 changes: 18 additions & 15 deletions cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -564,24 +561,30 @@ 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
* `B` points to `A::B`, rather than to `A`.
*
* @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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 92d330a

Please sign in to comment.