Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a function for languages to influence reference resolution out of candidates #1909

Merged
merged 2 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize
import de.fraunhofer.aisec.cpg.*
import de.fraunhofer.aisec.cpg.graph.Name
import de.fraunhofer.aisec.cpg.graph.Node
import de.fraunhofer.aisec.cpg.graph.declarations.Declaration
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration
import de.fraunhofer.aisec.cpg.graph.edges.ast.TemplateArguments
import de.fraunhofer.aisec.cpg.graph.statements.expressions.BinaryOperator
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Reference
import de.fraunhofer.aisec.cpg.graph.types.*
import de.fraunhofer.aisec.cpg.graph.unknownType
import de.fraunhofer.aisec.cpg.helpers.Util
import de.fraunhofer.aisec.cpg.passes.SymbolResolver
import java.io.File
import kotlin.reflect.KClass
Expand Down Expand Up @@ -361,6 +364,30 @@ abstract class Language<T : LanguageFrontend<*, *>> : Node() {
Pair(list.toSet(), CallResolutionResult.SuccessKind.SUCCESSFUL)
}
}

/**
* This function returns the best viable declaration when resolving a [Reference]. The
* candidates to chose from are stored in [Reference.candidates] In most cases the languages can
* keep the default implementation, which only returns a declaration, if the list contains one
* single item. Otherwise, we have an ambiguous result and cannot determine the result with
* certainty.
*
* If we encounter an ambiguous result, a warning is issued.
*/
open fun bestViableReferenceCandidate(ref: Reference): Declaration? {
return if (ref.candidates.size > 1) {
Util.warnWithFileLocation(
ref,
log,
"Resolution of reference {} was ambiguous, cannot set refersTo correctly, " +
"will be set to null.",
ref.name
)
null
} else {
ref.candidates.singleOrNull()
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,16 @@
protected fun handleReference(currentClass: RecordDeclaration?, ref: Reference) {
val language = ref.language

if (language == null) {
Util.warnWithFileLocation(

Check warning on line 197 in cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt

View check run for this annotation

Codecov / codecov/patch

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt#L197

Added line #L197 was not covered by tests
ref,
log,
"Language for reference {} is empty, we cannot resolve this reference correctly.",
ref.name

Check warning on line 201 in cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt

View check run for this annotation

Codecov / codecov/patch

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt#L199-L201

Added lines #L199 - L201 were not covered by tests
)
return
}

// Ignore references to anonymous identifiers, if the language supports it (e.g., the _
// identifier in Go)
if (
Expand All @@ -211,10 +221,11 @@
// resolution, but in future this will also be used in resolving regular references.
ref.candidates = scopeManager.lookupSymbolByNameOfNode(ref).toSet()

// Preparation for a future without legacy call resolving. Taking the first candidate is not
// ideal since we are running into an issue with function pointers here (see workaround
// below).
var wouldResolveTo = ref.candidates.singleOrNull()
// We need to choose the best viable candidate out of the ones we have for our reference.
// Hopefully we have only one, but there might be instances where more than one is a valid
// candidate. We let the language have a chance at overriding the default behaviour (which
// takes only a single one).
var wouldResolveTo = language.bestViableReferenceCandidate(ref)

// For now, we need to ignore reference expressions that are directly embedded into call
// expressions, because they are the "callee" property. In the future, we will use this
Expand Down
Loading