Skip to content

Commit

Permalink
Restricting lookupScopeByName to a specific language (#2056)
Browse files Browse the repository at this point in the history
  • Loading branch information
oxisto authored Feb 19, 2025
1 parent adaa2fb commit 400d3dd
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 33 deletions.
26 changes: 14 additions & 12 deletions cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,6 @@ class ScopeManager : ScopeProvider {
var currentScope: Scope? = null
private set

/** Represents an alias with the name [to] for the particular name [from]. */
data class Alias(var from: Name, var to: Name)

/** True, if the scope manager is currently in a [FunctionScope]. */
val isInFunction: Boolean
get() = this.firstScopeOrNull { it is FunctionScope } != null
Expand Down Expand Up @@ -519,8 +516,12 @@ class ScopeManager : ScopeProvider {
* @param scope the current scope relevant for the name resolution, e.g. parent of node
* @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)
fun extractScope(
node: HasNameAndLocation,
language: Language<*> = node.language,
scope: Scope? = currentScope,
): ScopeExtraction? {
return extractScope(node.name, language, node.location, scope)
}

/**
Expand All @@ -542,6 +543,7 @@ class ScopeManager : ScopeProvider {
*/
fun extractScope(
name: Name,
language: Language<*>,
location: PhysicalLocation? = null,
scope: Scope? = currentScope,
): ScopeExtraction? {
Expand All @@ -552,7 +554,7 @@ class ScopeManager : ScopeProvider {
// First, we need to check, whether we have some kind of scoping.
if (scopeName != null) {
// We need to check, whether we have an alias for the name's parent in this file
val scope = lookupScopeByName(scopeName, scope)
val scope = lookupScopeByName(scopeName, language, scope)

if (scope == null) {
Util.warnWithFileLocation(
Expand Down Expand Up @@ -584,7 +586,7 @@ class ScopeManager : ScopeProvider {
* @param name the name to look up
* @param startScope the scope to start the lookup in
*/
fun lookupScopeByName(name: Name, startScope: Scope?): Scope? {
fun lookupScopeByName(name: Name, language: Language<*>?, startScope: Scope?): Scope? {
val parts = name.splitTo(mutableListOf())
var part: Name? = name
var scope = startScope
Expand All @@ -601,7 +603,7 @@ class ScopeManager : ScopeProvider {
// namespace (in different files), but they all (should) point to the same scope.
scope =
scope
.lookupSymbol(part.localName) {
.lookupSymbol(part.localName, languageOnly = language) {
it is NamespaceDeclaration ||
it is RecordDeclaration ||
it is TypedefDeclaration
Expand Down Expand Up @@ -670,7 +672,7 @@ class ScopeManager : ScopeProvider {
*
* @return the declaration, or null if it does not exist
*/
fun getRecordForName(name: Name, language: Language<*>?): RecordDeclaration? {
fun getRecordForName(name: Name, language: Language<*>): RecordDeclaration? {
return lookupSymbolByName(name, language)
.filterIsInstance<RecordDeclaration>()
.singleOrNull()
Expand Down Expand Up @@ -780,12 +782,12 @@ class ScopeManager : ScopeProvider {
*/
fun lookupSymbolByName(
name: Name,
language: Language<*>?,
language: Language<*>,
location: PhysicalLocation? = null,
startScope: Scope? = currentScope,
predicate: ((Declaration) -> Boolean)? = null,
): List<Declaration> {
val extractedScope = extractScope(name, location, startScope)
val extractedScope = extractScope(name, language, location, startScope)
val scope: Scope?
val n: Name
if (extractedScope == null) {
Expand Down Expand Up @@ -844,7 +846,7 @@ class ScopeManager : ScopeProvider {
*/
fun lookupTypeSymbolByName(
name: Name,
language: Language<*>?,
language: Language<*>,
startScope: Scope?,
): DeclaresType? {
var symbols =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
val language = source.language

// 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 extractedScope = ctx.scopeManager.extractScope(source, language, source.scope)

// If we could not extract the scope (even though one was specified), we can only return an
// empty result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ open class TypeResolver(ctx: TranslationContext) : ComponentPass(ctx) {

// If we did not find any declaration, we can try to infer a record declaration for it
if (declares == null) {
declares = tryRecordInference(type, locationHint = type)
declares = tryRecordInference(type, source = type)
}

// If we found the "real" declared type, we can normalize the name of our scoped type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ import kotlin.collections.forEach
* Tries to infer a [NamespaceDeclaration] from a [Name]. This will return `null`, if inference was
* not possible, or if it was turned off in the [InferenceConfiguration].
*/
fun Pass<*>.tryNamespaceInference(name: Name, locationHint: Node?): NamespaceDeclaration? {
fun Pass<*>.tryNamespaceInference(name: Name, source: Node): NamespaceDeclaration? {
// Determine the scope where we want to start our inference
val extractedScope = scopeManager.extractScope(name, location = locationHint?.location)
val extractedScope =
scopeManager.extractScope(name, language = source.language, location = source.location)
var scope = extractedScope?.scope

if (scope !is NameScope) {
Expand All @@ -79,22 +80,19 @@ fun Pass<*>.tryNamespaceInference(name: Name, locationHint: Node?): NamespaceDec
// parent record)
var parentName = name.parent
if (scope == null && parentName != null) {
holder = tryScopeInference(parentName, locationHint)
holder = tryScopeInference(parentName, source)
}

return (holder ?: scopeManager.globalScope?.astNode)
?.startInference(ctx)
?.inferNamespaceDeclaration(name, null, locationHint)
?.inferNamespaceDeclaration(name, null, source)
}

/**
* Tries to infer a [RecordDeclaration] from an unresolved [Type]. This will return `null`, if
* inference was not possible, or if it was turned off in the [InferenceConfiguration].
*/
internal fun Pass<*>.tryRecordInference(
type: Type,
locationHint: Node? = null,
): RecordDeclaration? {
internal fun Pass<*>.tryRecordInference(type: Type, source: Node): RecordDeclaration? {
val kind =
if (type.language is HasStructs) {
"struct"
Expand All @@ -103,7 +101,12 @@ internal fun Pass<*>.tryRecordInference(
}
// Determine the scope where we want to start our inference
val extractedScope =
scopeManager.extractScope(type.name, location = locationHint?.location, scope = type.scope)
scopeManager.extractScope(
type.name,
language = source.language,
location = source.location,
scope = type.scope,
)
var scope = extractedScope?.scope

if (scope !is NameScope) {
Expand All @@ -126,13 +129,13 @@ internal fun Pass<*>.tryRecordInference(
// parent record)
var parentName = type.name.parent
if (scope == null && parentName != null) {
holder = tryScopeInference(parentName, locationHint)
holder = tryScopeInference(parentName, source)
}

val record =
(holder ?: scopeManager.globalScope?.astNode)
?.startInference(ctx)
?.inferRecordDeclaration(type, kind, locationHint)
?.inferRecordDeclaration(type, kind, source)

// Update the type's record. Because types are only unique per scope, we potentially need to
// update multiple type nodes, i.e., all type nodes whose FQN match the inferred record. We only
Expand Down Expand Up @@ -176,7 +179,7 @@ internal fun Pass<*>.tryVariableInference(ref: Reference): VariableDeclaration?
} else if (ref.name.isQualified()) {
// For now, we only infer globals at the top-most global level, i.e., no globals in
// namespaces
val extractedScope = scopeManager.extractScope(ref, null)
val extractedScope = scopeManager.extractScope(ref, ref.language, null)
when (val scope = extractedScope?.scope) {
is NameScope -> {
log.warn(
Expand Down Expand Up @@ -231,7 +234,7 @@ internal fun Pass<*>.tryFieldInference(
// We access an unknown field of an unknown record. so we need to handle that along the
// way as well.
if (record == null) {
record = tryRecordInference(targetType, locationHint = ref)
record = tryRecordInference(targetType, source = ref)
}

if (record == null) {
Expand Down Expand Up @@ -410,9 +413,7 @@ internal fun Pass<*>.tryMethodInference(
// other type declarations are already inferred by the type resolver at this stage.
if (records.isEmpty()) {
records =
listOfNotNull(
tryRecordInference(bestGuess?.root ?: call.unknownType(), locationHint = call)
)
listOfNotNull(tryRecordInference(bestGuess?.root ?: call.unknownType(), source = call))
}
records = records.distinct()

Expand All @@ -428,15 +429,15 @@ internal fun Pass<*>.tryMethodInference(
* check will be repeated for `java.lang`, until we are finally ready to infer the
* [RecordDeclaration] `java.lang.System`.
*/
internal fun Pass<*>.tryScopeInference(scopeName: Name, locationHint: Node?): Declaration? {
internal fun Pass<*>.tryScopeInference(scopeName: Name, source: Node): Declaration? {
// At this point, we need to check whether we have any type reference to our scope
// name. If we have (e.g. it is used in a function parameter, variable, etc.), then we
// have a high chance that this is actually a parent record and not a namespace
var parentType = typeManager.lookupResolvedType(scopeName)
return if (parentType != null) {
tryRecordInference(parentType, locationHint = locationHint)
tryRecordInference(parentType, source = source)
} else {
tryNamespaceInference(scopeName, locationHint = locationHint)
tryNamespaceInference(scopeName, source = source)
}
}

Expand Down

0 comments on commit 400d3dd

Please sign in to comment.