Skip to content

Commit

Permalink
Symbol resolver with EOG power
Browse files Browse the repository at this point in the history
Co-Authored-By: KuechA <31155350+KuechA@users.noreply.github.com>
  • Loading branch information
oxisto and KuechA committed Sep 28, 2023
1 parent 6da9562 commit c2cea18
Show file tree
Hide file tree
Showing 61 changed files with 1,227 additions and 1,055 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
package de.fraunhofer.aisec.cpg.analysis.fsm

import de.fraunhofer.aisec.cpg.graph.Node
import de.fraunhofer.aisec.cpg.graph.declarations.Declaration
import de.fraunhofer.aisec.cpg.graph.declarations.ParameterDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.VariableDeclaration
import de.fraunhofer.aisec.cpg.graph.edge.Properties
Expand Down Expand Up @@ -291,7 +290,8 @@ open class DFAOrderEvaluator(
if (
node is MemberCallExpression &&
node.base is Reference &&
consideredBases.contains((node.base as Reference).refersTo as Declaration)
(node.base as Reference).refersTo != null &&
consideredBases.contains((node.base as Reference).refersTo!!)
) {
allUsedBases.add((node.base as Reference).refersTo)
}
Expand Down
32 changes: 12 additions & 20 deletions cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -615,20 +615,7 @@ class ScopeManager : ScopeProvider {
*/
@JvmOverloads
fun resolveReference(ref: Reference, startScope: Scope? = currentScope): ValueDeclaration? {
// Unfortunately, we still have an issue about duplicate declarations because header files
// are included multiple times, so we need to exclude the C++ frontend (for now).
val language = ref.language
val (scope, name) =
if (
language?.name?.localName != "CLanguage" &&
(language?.name?.localName != "CPPLanguage")
) {
// For all other languages, we can extract the scope information out of the name and
// start our search at the dedicated scope.
extractScope(ref, startScope)
} else {
Pair(scope, ref.name)
}
val (scope, name) = extractScope(ref, startScope)

// Try to resolve value declarations according to our criteria
return resolve<ValueDeclaration>(scope) {
Expand Down Expand Up @@ -686,13 +673,17 @@ class ScopeManager : ScopeProvider {
* This function extracts a possible scope out of a [Name], e.g. if the name is fully qualified.
* This also resolves possible name aliases (e.g. because of imports). It returns a pair of a
* scope (if found) as well as the name, which is possibly adjusted for the aliases.
*
* 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: Scope? = currentScope): Pair<Scope?, Name> {
var name: Name = node.name
var s = 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
var scopeName = node.name.parent
Expand All @@ -714,9 +705,9 @@ class ScopeManager : ScopeProvider {
Util.errorWithFileLocation(
node,
LOGGER,
"Could not find the scope $scopeName needed to resolve the call ${node.name}. Falling back to the default (current) scope"
"Could not find the scope $scopeName needed to resolve the call ${node.name}"
)
s
scope
} else {
scopes[0]
}
Expand All @@ -729,7 +720,7 @@ class ScopeManager : ScopeProvider {
* 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 Expand Up @@ -832,11 +823,12 @@ class ScopeManager : ScopeProvider {
/**
* Retrieves the [RecordDeclaration] for the given name in the given scope.
*
* @param scope the scope
* @param name the name
* * @param scope the scope. Default is [currentScope]
*
* @return the declaration, or null if it does not exist
*/
fun getRecordForName(scope: Scope, name: Name): RecordDeclaration? {
fun getRecordForName(name: Name, scope: Scope? = currentScope): RecordDeclaration? {
return resolve<RecordDeclaration>(scope, true) { it.name.lastPartsMatch(name) }
.firstOrNull()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,7 @@ private constructor(
* This will register
* - [TypeHierarchyResolver]
* - [ImportResolver]
* - [VariableUsageResolver]
* - [CallResolver]
* - [SymbolResolver]
* - [DFGPass]
* - [EvaluationOrderGraphPass]
* - [TypeResolver]
Expand All @@ -457,8 +456,7 @@ private constructor(
fun defaultPasses(): Builder {
registerPass<TypeHierarchyResolver>()
registerPass<ImportResolver>()
registerPass<VariableUsageResolver>()
registerPass<CallResolver>() // creates CG
registerPass<SymbolResolver>()
registerPass<DFGPass>()
registerPass<EvaluationOrderGraphPass>() // creates EOG
registerPass<TypeResolver>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,13 @@ package de.fraunhofer.aisec.cpg.frontends

import de.fraunhofer.aisec.cpg.ScopeManager
import de.fraunhofer.aisec.cpg.TranslationContext
import de.fraunhofer.aisec.cpg.graph.Name
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.MemberExpression
import de.fraunhofer.aisec.cpg.graph.types.Type
import de.fraunhofer.aisec.cpg.passes.CallResolver
import java.util.regex.Pattern
import de.fraunhofer.aisec.cpg.passes.SymbolResolver

/**
* A language trait is a feature or trait that is common to a group of programming languages. Any
Expand Down Expand Up @@ -116,7 +114,7 @@ interface HasComplexCallResolution : LanguageTrait {
call: CallExpression,
ctx: TranslationContext,
currentTU: TranslationUnitDeclaration,
callResolver: CallResolver
callResolver: SymbolResolver
): List<FunctionDeclaration>

/**
Expand All @@ -131,7 +129,7 @@ interface HasComplexCallResolution : LanguageTrait {
fun refineInvocationCandidatesFromRecord(
recordDeclaration: RecordDeclaration,
call: CallExpression,
namePattern: Pattern,
name: String,
ctx: TranslationContext
): List<FunctionDeclaration>
}
Expand Down Expand Up @@ -170,7 +168,6 @@ interface HasSuperClasses : LanguageTrait {
callee: MemberExpression,
curClass: RecordDeclaration,
scopeManager: ScopeManager,
recordMap: Map<Name, RecordDeclaration>
): Boolean
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ fun MetadataProvider.newCallExpression(
val node = CallExpression()
node.applyMetadata(this, fqn, rawNode, code, true)

// Set the call expression as resolution helper for the callee
if (callee is Reference) {
callee.resolutionHelper = node
}

node.callee = callee
node.template = template

Expand Down Expand Up @@ -331,6 +336,11 @@ fun MetadataProvider.newMemberCallExpression(
code,
)

// Set the call expression as resolution helper for the callee
if (callee is Reference) {
callee.resolutionHelper = node
}

node.callee = callee
node.isStatic = isStatic

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,12 @@ open class Node : IVisitable<Node>, Persistable, LanguageProvider, ScopeProvider
code == other.code &&
comment == other.comment &&
location == other.location &&
file == other.file &&
// We need to exclude "file" here, because in C++ the same header node can be
// imported in two different files and in this case, the "file" property will be
// different. Since want to squash those equal nodes, we will only consider all the
// other attributes, including "location" (which contains the *original* file
// location in the header file), but not "file".
// file == other.file &&
isImplicit == other.isImplicit
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,12 +438,12 @@ context(Holder<out Statement>)

fun LanguageFrontend<*, *>.memberCall(
localName: CharSequence,
member: Expression,
base: Expression,
isStatic: Boolean = false,
init: (MemberCallExpression.() -> Unit)? = null
): MemberCallExpression {
// Try to parse the name
val node = newMemberCallExpression(newMemberExpression(localName, member), isStatic)
val node = newMemberCallExpression(newMemberExpression(localName, base), isStatic)
if (init != null) {
init(node)
}
Expand Down Expand Up @@ -684,9 +684,9 @@ fun LanguageFrontend<*, *>.whileCondition(init: WhileStatement.() -> Expression)
}

/**
* <<<<<<< HEAD Configures the [DoStatement.condition] in the Fluent Node DSL of the nearest
* enclosing [DoStatement]. The [init] block can be used to create further sub-nodes as well as
* configuring the created node itself.
* Configures the [DoStatement.condition] in the Fluent Node DSL of the nearest enclosing
* [DoStatement]. The [init] block can be used to create further sub-nodes as well as configuring
* the created node itself.
*/
context(DoStatement)

Expand All @@ -695,13 +695,9 @@ fun LanguageFrontend<*, *>.whileCondition(init: DoStatement.() -> Expression): E
}

/**
* Creates a new [CompoundStatement] in the Fluent Node DSL and sets it to the
* [IfStatement.thenStatement] of the nearest enclosing [IfStatement]. The [init] block can be used
* to create further sub-nodes as well as configuring the created node itself.
* =======
* Creates a new [Block] in the Fluent Node DSL and sets it to the [IfStatement.thenStatement] of
* the nearest enclosing [IfStatement]. The [init] block can be used to create further sub-nodes as
* well as configuring the created node itself. >>>>>>> main
* well as configuring the created node itself.
*/
context(IfStatement)

Expand Down Expand Up @@ -748,9 +744,9 @@ fun LanguageFrontend<*, *>.loopBody(init: Block.() -> Unit): Block {
}

/**
* Creates a new [CompoundStatement] in the Fluent Node DSL and sets it to the
* [DoStatement.statement] of the nearest enclosing [DoStatement]. The [init] block can be used to
* create further sub-nodes as well as configuring the created node itself.
* Creates a new [Block] in the Fluent Node DSL and sets it to the [DoStatement.statement] of the
* nearest enclosing [WhileStatement]. The [init] block can be used to create further sub-nodes as
* well as configuring the created node itself.
*/
context(DoStatement)

Expand Down Expand Up @@ -1439,3 +1435,14 @@ private fun <T : Node> LanguageFrontend<*, *>.scopeIfNecessary(
scopeManager.leaveScope(node)
}
}

context(MethodDeclaration)

fun LanguageFrontend<*, *>.receiver(name: String, type: Type): VariableDeclaration {
val node = newVariableDeclaration(name, type)

this@MethodDeclaration.receiver = node
scopeManager.addDeclaration(node)

return node
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,16 @@ package de.fraunhofer.aisec.cpg.graph.declarations
import de.fraunhofer.aisec.cpg.graph.AST
import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge
import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdgeDelegate
import de.fraunhofer.aisec.cpg.graph.types.Type
import org.apache.commons.lang3.builder.ToStringBuilder
import org.neo4j.ogm.annotation.Relationship

class EnumDeclaration : Declaration() {
class EnumDeclaration : RecordDeclaration() {
@Relationship(value = "ENTRIES", direction = Relationship.Direction.OUTGOING)
@AST
var entryEdges: MutableList<PropertyEdge<EnumConstantDeclaration>> = ArrayList()

@Relationship(value = "SUPER_TYPES", direction = Relationship.Direction.OUTGOING)
var superTypeEdges: MutableList<PropertyEdge<Type>> = ArrayList()

@Relationship var superTypeDeclarations: Set<RecordDeclaration> = HashSet()

var entries by PropertyEdgeDelegate(EnumDeclaration::entryEdges)

var superTypes by PropertyEdgeDelegate(EnumDeclaration::superTypeEdges)

override fun toString(): String {
return ToStringBuilder(this, TO_STRING_STYLE)
.appendSuper(super.toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ import de.fraunhofer.aisec.cpg.graph.statements.expressions.Block
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression
import de.fraunhofer.aisec.cpg.graph.types.Type
import de.fraunhofer.aisec.cpg.isDerivedFrom
import de.fraunhofer.aisec.cpg.passes.ResolutionStartHolder
import java.util.*
import java.util.stream.Collectors
import org.apache.commons.lang3.builder.ToStringBuilder
import org.neo4j.ogm.annotation.Relationship

/** Represents the declaration or definition of a function. */
open class FunctionDeclaration : ValueDeclaration(), DeclarationHolder {
open class FunctionDeclaration : ValueDeclaration(), DeclarationHolder, ResolutionStartHolder {
/** The function body. Usually a [Block]. */
@AST var body: Statement? = null

Expand Down Expand Up @@ -111,27 +111,25 @@ open class FunctionDeclaration : ValueDeclaration(), DeclarationHolder {
targetFunctionDeclaration.signatureTypes == signatureTypes
}

// TODO: Documentation required. It's not completely clear what this method is supposed to do.
fun hasSignature(targetSignature: List<Type>): Boolean {
val signature =
parameters
.stream()
.sorted(Comparator.comparingInt(ParameterDeclaration::argumentIndex))
.collect(Collectors.toList())
return if (signature.all { !it.isVariadic } && targetSignature.size < signature.size) {
val signature = parameters.sortedBy { it.argumentIndex }
// TODO: Why do we have to sort it here while we don't sort the list in signatureTypes?
return if (targetSignature.size < signature.size) {
// TODO: So we don't consider arguments with default values (among others) but then, the
// SymbolResolver (or CXXCallResolverHelper) has a bunch of functions to consider it.
false
} else {
// signature is a collection of positional arguments, so the order must be preserved
for (i in signature.indices) {
val declared = signature[i]
if (declared.isVariadic) {
for ((i, declared) in signature.withIndex()) {
if (declared.isVariadic && targetSignature.size >= signature.size) {
// Everything that follows is collected by this param, so the signature is
// fulfilled no matter what comes now (potential FIXME: in Java, we could have
// overloading with different vararg types, in C++ we can't, as vararg types are
// not defined here anyways)
return true
}
val provided = targetSignature[i]
if (!provided.isDerivedFrom(declared.type)) {
if (!targetSignature[i].isDerivedFrom(declared.type)) {
return false
}
}
Expand Down Expand Up @@ -189,18 +187,15 @@ open class FunctionDeclaration : ValueDeclaration(), DeclarationHolder {
return parameters.map { it.default }
}

val defaultParameterSignature: List<Type>
get() {
val signature: MutableList<Type> = ArrayList()
for (paramVariableDeclaration in parameters) {
if (paramVariableDeclaration.default != null) {
signature.add(paramVariableDeclaration.type)
val defaultParameterSignature: List<Type> // TODO: What's this property?
get() =
parameters.map {
if (it.default != null) {
it.type
} else {
signature.add(unknownType())
unknownType()
}
}
return signature
}

val signatureTypes: List<Type>
get() = parameters.map { it.type }
Expand All @@ -222,6 +217,9 @@ open class FunctionDeclaration : ValueDeclaration(), DeclarationHolder {
.toString()
}

override val resolutionStartNodes: List<Node>
get() = listOfNotNull(this)

override fun equals(other: Any?): Boolean {
if (this === other) {
return true
Expand Down
Loading

0 comments on commit c2cea18

Please sign in to comment.