Skip to content

Commit

Permalink
Further scoping cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
oxisto committed Sep 24, 2023
1 parent d7b2e95 commit 536ba9e
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 69 deletions.
51 changes: 29 additions & 22 deletions cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,8 @@ class ScopeManager : ScopeProvider {
*/
@JvmOverloads
fun resolveReference(ref: Reference, scope: Scope? = currentScope): ValueDeclaration? {
return resolve<ValueDeclaration>(scope) {
val s = extractScope(ref) ?: scope
return resolve<ValueDeclaration>(s) {
if (
it.name.lastPartsMatch(ref.name)
) { // TODO: This place is likely to make things fail
Expand Down Expand Up @@ -638,45 +639,51 @@ class ScopeManager : ScopeProvider {
call: CallExpression,
scope: Scope? = currentScope
): List<FunctionDeclaration> {
val s = extractScope(call, scope)
val s = extractScope(call) ?: scope

return resolve(s) { it.name.lastPartsMatch(call.name) && it.hasSignature(call.signature) }
}

fun extractScope(node: Node, scope: Scope? = currentScope): Scope? {
var s = scope

/**
* This function extracts scope information out of the [Node.name] of the given [Node]. It will
* return null, if the node does not contain any scope information (e.g. is not qualified).
* Otherwise, the scope pointing to the [Name.parent] of the [Node.name] will be returned.
*
* 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`.
*/
fun extractScope(node: Node): Scope? {
// First, we need to check, whether we have some kind of scoping.
if (node.name.parent != null) {
if (node.name.isQualified()) {
// extract the scope name, it is usually a name space, but could probably be something
// else as well in other languages
val scopeName = node.name.parent

// TODO: proper scope selection

// this is a scoped call. we need to explicitly jump to that particular scope
// lookup the appropriate scope by name
// TODO(oxisto): We do not yet support relative scopes, e.g. "A" inside "B" should point
// to "A::B", not "A"
val scopes = filterScopes { (it is NameScope && it.name == scopeName) }
s =
if (scopes.isEmpty()) {
Util.errorWithFileLocation(
node,
LOGGER,
"Could not find the scope $scopeName needed to resolve the call ${node.name}. Falling back to the default (current) scope"
)
s
} else {
scopes[0]
}
return if (scopes.isEmpty()) {
Util.errorWithFileLocation(
node,
LOGGER,
"Could not find the scope $scopeName needed to resolve the call ${node.name}"
)
null
} else {
scopes[0]
}
}

return s
return null
}

/**
* Directly jumps to a given scope. Returns the previous scope. Do not forget to set the scope
* back to the old scope after performing the actions inside this scope.
*
* Handle with care, here be dragons. Should not be exposed outside of the cpg-core module.
* Handle with care, here be dragons. Should not be exposed outside the cpg-core module.
*/
@PleaseBeCareful
internal fun jumpTo(scope: Scope?): Scope? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import de.fraunhofer.aisec.cpg.passes.inference.inferMethod
import de.fraunhofer.aisec.cpg.passes.inference.startInference
import de.fraunhofer.aisec.cpg.passes.order.DependsOn
import de.fraunhofer.aisec.cpg.processing.strategy.Strategy
import java.util.*
import org.slf4j.Logger
import org.slf4j.LoggerFactory

Expand Down Expand Up @@ -167,17 +166,26 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
reference: Reference,
type: FunctionPointerType
): ValueDeclaration {
val parent = reference.name.parent
var target = scopeManager.resolveReference(reference)

return handleUnknownFunction(
if (parent != null) {
reference.objectType(parent).recordDeclaration
} else {
null
},
reference.name,
type
)
// If we didn't find anything, we create a new function or method declaration
if (target == null) {
// Determine the scope where we want to start our inference
val scope = scopeManager.extractScope(reference)

target =
(scope?.astNode ?: currentTU)
.startInference(ctx)
.createInferredFunctionDeclaration(
reference.name,
null,
false,
type.parameters,
type.returnType
)
}

return target
}

protected fun resolveReference(currentClass: RecordDeclaration?, current: Node?) {
Expand Down Expand Up @@ -435,41 +443,6 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
}
}

/**
* Generates a [MethodDeclaration] if the [declarationHolder] is a [RecordDeclaration] or a
* [FunctionDeclaration] if the [declarationHolder] is a [TranslationUnitDeclaration]. The
* resulting function/method has the signature and return type specified in [fctPtrType] and the
* specified [name].
*/
protected fun handleUnknownFunction(
declarationHolder: RecordDeclaration?,
name: Name,
fctPtrType: FunctionPointerType
): FunctionDeclaration {
// Try to find the function or method in the list of existing functions.
val target =
if (declarationHolder != null) {
declarationHolder.methods.firstOrNull { f ->
f.matches(name, fctPtrType.returnType, fctPtrType.parameters)
}
} else {
currentTU.functions.firstOrNull { f ->
f.matches(name, fctPtrType.returnType, fctPtrType.parameters)
}
}
// If we didn't find anything, we create a new function or method declaration
return target
?: (declarationHolder ?: currentTU)
.startInference(ctx)
.createInferredFunctionDeclaration(
name,
null,
false,
fctPtrType.parameters,
fctPtrType.returnType
)
}

protected fun resolve(node: Node?, currClass: RecordDeclaration?) {
when (node) {
is MemberExpression -> resolveMemberExpression(currClass, node)
Expand Down Expand Up @@ -520,7 +493,7 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
// the TU. It is also a little bit redundant, since ScopeManager.resolveFunction
// (which gets called before) already extracts the scope, but this information
// gets lost.
val scope = scopeManager.extractScope(call, scopeManager.globalScope)
val scope = scopeManager.extractScope(call) ?: scopeManager.globalScope

// We have two possible start points, a namespace declaration or a translation
// unit. Nothing else is allowed (fow now)
Expand Down

0 comments on commit 536ba9e

Please sign in to comment.