From 96849dfa376e349e740446bf7dc3f25d37df41cb Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Thu, 25 Jul 2024 15:12:52 +0200 Subject: [PATCH] Added more basic interfaces (#1607) --- .../aisec/cpg/analysis/ValueEvaluator.kt | 2 +- .../fraunhofer/aisec/cpg/query/QueryTest.kt | 4 +- .../aisec/cpg/graph/ExpressionBuilder.kt | 8 +- .../de/fraunhofer/aisec/cpg/graph/HasBase.kt | 49 ------ .../fraunhofer/aisec/cpg/graph/HasDefault.kt | 35 ---- .../aisec/cpg/graph/HasInitializer.kt | 65 -------- .../aisec/cpg/graph/HasOperatorCode.kt | 33 ---- .../fraunhofer/aisec/cpg/graph/Interfaces.kt | 151 ++++++++++++++++++ .../de/fraunhofer/aisec/cpg/graph/Node.kt | 20 ++- .../statements/expressions/BinaryOperator.kt | 10 +- .../statements/expressions/CallExpression.kt | 34 ++-- .../expressions/MemberCallExpression.kt | 2 +- .../expressions/MemberExpression.kt | 6 + .../statements/expressions/UnaryOperator.kt | 11 +- .../cpg/passes/ControlDependenceGraphPass.kt | 22 ++- .../cpg/passes/EvaluationOrderGraphPass.kt | 4 +- .../aisec/cpg/graph/InterfacesTest.kt} | 23 ++- 17 files changed, 246 insertions(+), 233 deletions(-) delete mode 100644 cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasBase.kt delete mode 100644 cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasDefault.kt delete mode 100644 cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasInitializer.kt delete mode 100644 cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasOperatorCode.kt create mode 100644 cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Interfaces.kt rename cpg-core/src/{main/kotlin/de/fraunhofer/aisec/cpg/graph/HasAliases.kt => test/kotlin/de/fraunhofer/aisec/cpg/graph/InterfacesTest.kt} (68%) diff --git a/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluator.kt b/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluator.kt index 83ec63be30..4e807603a7 100644 --- a/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluator.kt +++ b/cpg-analysis/src/main/kotlin/de/fraunhofer/aisec/cpg/analysis/ValueEvaluator.kt @@ -180,7 +180,7 @@ open class ValueEvaluator( "<=" -> handleLEq(lhsValue, rhsValue, expr) "==" -> handleEq(lhsValue, rhsValue, expr) "!=" -> handleNEq(lhsValue, rhsValue, expr) - else -> cannotEvaluate(expr as Node, this) + else -> cannotEvaluate(expr, this) } } diff --git a/cpg-analysis/src/test/kotlin/de/fraunhofer/aisec/cpg/query/QueryTest.kt b/cpg-analysis/src/test/kotlin/de/fraunhofer/aisec/cpg/query/QueryTest.kt index 7753272530..e8630c6f84 100644 --- a/cpg-analysis/src/test/kotlin/de/fraunhofer/aisec/cpg/query/QueryTest.kt +++ b/cpg-analysis/src/test/kotlin/de/fraunhofer/aisec/cpg/query/QueryTest.kt @@ -598,7 +598,7 @@ class QueryTest { result .all( { it.name.localName == "print" }, - { n2 -> dataFlow(n1 as Node, n2.parameters[0]).value } + { n2 -> dataFlow(n1, n2.parameters[0]).value } ) .first } @@ -613,7 +613,7 @@ class QueryTest { { n1 -> result.allExtended( { it.name.localName == "print" }, - { n2 -> dataFlow(n1 as Node, n2.parameters[0]) } + { n2 -> dataFlow(n1, n2.parameters[0]) } ) } ) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/ExpressionBuilder.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/ExpressionBuilder.kt index 260e45f135..c5f956a757 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/ExpressionBuilder.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/ExpressionBuilder.kt @@ -273,7 +273,9 @@ fun MetadataProvider.newCallExpression( callee.resolutionHelper = node } - node.callee = callee + if (callee != null) { + node.callee = callee + } node.template = template log(node) @@ -304,7 +306,9 @@ fun MetadataProvider.newMemberCallExpression( callee.resolutionHelper = node } - node.callee = callee + if (callee != null) { + node.callee = callee + } node.isStatic = isStatic log(node) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasBase.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasBase.kt deleted file mode 100644 index 84e8a22fea..0000000000 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasBase.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2021, Fraunhofer AISEC. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * $$$$$$\ $$$$$$$\ $$$$$$\ - * $$ __$$\ $$ __$$\ $$ __$$\ - * $$ / \__|$$ | $$ |$$ / \__| - * $$ | $$$$$$$ |$$ |$$$$\ - * $$ | $$ ____/ $$ |\_$$ | - * $$ | $$\ $$ | $$ | $$ | - * \$$$$$ |$$ | \$$$$$ | - * \______/ \__| \______/ - * - */ -package de.fraunhofer.aisec.cpg.graph - -import de.fraunhofer.aisec.cpg.graph.declarations.OperatorDeclaration -import de.fraunhofer.aisec.cpg.graph.statements.expressions.BinaryOperator -import de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression - -/** Specifies that a certain node has a base on which it executes an operation. */ -interface HasBase : HasOperatorCode { - - /** The base. */ - val base: Expression? - - /** - * The operator that is used to access the base. Usually either `.` or `->`, but some languages - * offer additional operator codes. - */ - override val operatorCode: String? -} - -/** - * Specifies that this node (e.g. a [BinaryOperator] contains an operation that can be overloaded by - * an [OperatorDeclaration]. - */ -interface HasOverloadedOperation : HasBase diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasDefault.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasDefault.kt deleted file mode 100644 index 88139e7388..0000000000 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasDefault.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2021, Fraunhofer AISEC. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * $$$$$$\ $$$$$$$\ $$$$$$\ - * $$ __$$\ $$ __$$\ $$ __$$\ - * $$ / \__|$$ | $$ |$$ / \__| - * $$ | $$$$$$$ |$$ |$$$$\ - * $$ | $$ ____/ $$ |\_$$ | - * $$ | $$\ $$ | $$ | $$ | - * \$$$$$ |$$ | \$$$$$ | - * \______/ \__| \______/ - * - */ -package de.fraunhofer.aisec.cpg.graph - -/** - * Interface that allows us to mark nodes that contain a default value - * - * @param type of the default node - */ -interface HasDefault { - var default: T -} diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasInitializer.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasInitializer.kt deleted file mode 100644 index f1b2800e5d..0000000000 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasInitializer.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2021, Fraunhofer AISEC. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * $$$$$$\ $$$$$$$\ $$$$$$\ - * $$ __$$\ $$ __$$\ $$ __$$\ - * $$ / \__|$$ | $$ |$$ / \__| - * $$ | $$$$$$$ |$$ |$$$$\ - * $$ | $$ ____/ $$ |\_$$ | - * $$ | $$\ $$ | $$ | $$ | - * \$$$$$ |$$ | \$$$$$ | - * \______/ \__| \______/ - * - */ -package de.fraunhofer.aisec.cpg.graph - -import de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression -import de.fraunhofer.aisec.cpg.graph.types.HasType - -/** - * Specifies that a certain node has an initializer. It is a special case of [ArgumentHolder], in - * which the initializer is treated as the first (and only) argument. - */ -interface HasInitializer : HasType, ArgumentHolder, AssignmentHolder { - - var initializer: Expression? - - override fun addArgument(expression: Expression) { - this.initializer = expression - } - - override fun removeArgument(expression: Expression): Boolean { - return if (this.initializer == expression) { - this.initializer = null - true - } else { - false - } - } - - override fun replaceArgument(old: Expression, new: Expression): Boolean { - this.initializer = new - return true - } - - override fun hasArgument(expression: Expression): Boolean { - return initializer == expression - } - - override val assignments: List - get() { - return initializer?.let { listOf(Assignment(it, this, this)) } ?: listOf() - } -} diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasOperatorCode.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasOperatorCode.kt deleted file mode 100644 index f226b9c010..0000000000 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasOperatorCode.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2023, Fraunhofer AISEC. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * $$$$$$\ $$$$$$$\ $$$$$$\ - * $$ __$$\ $$ __$$\ $$ __$$\ - * $$ / \__|$$ | $$ |$$ / \__| - * $$ | $$$$$$$ |$$ |$$$$\ - * $$ | $$ ____/ $$ |\_$$ | - * $$ | $$\ $$ | $$ | $$ | - * \$$$$$ |$$ | \$$$$$ | - * \______/ \__| \______/ - * - */ -package de.fraunhofer.aisec.cpg.graph - -/** A simple interface to denote that the implementing class has some kind of [operatorCode]. */ -interface HasOperatorCode { - - /** The operator code, identifying an operation executed on one or more [Expression]s */ - val operatorCode: String? -} diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Interfaces.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Interfaces.kt new file mode 100644 index 0000000000..3d5971bbf4 --- /dev/null +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Interfaces.kt @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2021, Fraunhofer AISEC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $$$$$$\ $$$$$$$\ $$$$$$\ + * $$ __$$\ $$ __$$\ $$ __$$\ + * $$ / \__|$$ | $$ |$$ / \__| + * $$ | $$$$$$$ |$$ |$$$$\ + * $$ | $$ ____/ $$ |\_$$ | + * $$ | $$\ $$ | $$ | $$ | + * \$$$$$ |$$ | \$$$$$ | + * \______/ \__| \______/ + * + */ +package de.fraunhofer.aisec.cpg.graph + +import de.fraunhofer.aisec.cpg.frontends.Language +import de.fraunhofer.aisec.cpg.graph.declarations.OperatorDeclaration +import de.fraunhofer.aisec.cpg.graph.scopes.Scope +import de.fraunhofer.aisec.cpg.graph.statements.expressions.* +import de.fraunhofer.aisec.cpg.graph.types.HasType +import de.fraunhofer.aisec.cpg.graph.types.Type +import de.fraunhofer.aisec.cpg.passes.SymbolResolver +import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation + +/** A simple interface that a node has [language]. */ +interface HasLanguage { + + var language: Language<*>? +} + +/** A simple interface that a node has [name] and [location]. */ +interface HasNameAndLocation : HasLanguage { + + val name: Name + + /** Location of the finding in source code. */ + val location: PhysicalLocation? +} + +/** A simple interface that a node has [scope]. */ +interface HasScope : HasNameAndLocation { + + /** The scope this node lives in. */ + val scope: Scope? +} + +/** A simple interface to denote that the implementing class has some kind of [operatorCode]. */ +interface HasOperatorCode : HasScope { + + /** The operator code, identifying an operation executed on one or more [Expression]s */ + val operatorCode: String? +} + +/** Specifies that a certain node has a base on which it executes an operation. */ +interface HasBase : HasOperatorCode { + + /** The base. If there is no actual base, it can be null. */ + val base: Expression? + + /** + * The operator that is used to access the [base]. Usually either `.` or `->`, but some + * languages offer additional operator codes. If the [base] is null, the [operatorCode] should + * also be null. + */ + override val operatorCode: String? +} + +/** + * Interface that allows us to mark nodes that contain a default value + * + * @param type of the default node + */ +interface HasDefault : HasScope { + var default: T +} + +/** + * Specifies that a certain node has an initializer. It is a special case of [ArgumentHolder], in + * which the initializer is treated as the first (and only) argument. + */ +interface HasInitializer : HasScope, HasType, ArgumentHolder, AssignmentHolder { + + var initializer: Expression? + + override fun addArgument(expression: Expression) { + this.initializer = expression + } + + override fun removeArgument(expression: Expression): Boolean { + return if (this.initializer == expression) { + this.initializer = null + true + } else { + false + } + } + + override fun replaceArgument(old: Expression, new: Expression): Boolean { + this.initializer = new + return true + } + + override fun hasArgument(expression: Expression): Boolean { + return initializer == expression + } + + override val assignments: List + get() { + return initializer?.let { listOf(Assignment(it, this, this)) } ?: listOf() + } +} + +/** + * Some nodes have aliases, i.e., it potentially references another variable. This means that + * writing to this node, also writes to its [aliases] and vice-versa. + */ +interface HasAliases : HasScope { + /** The aliases which this node has. */ + var aliases: MutableSet +} + +/** + * Specifies that this node (e.g. a [BinaryOperator] contains an operation that can be overloaded by + * an [OperatorDeclaration]. + */ +interface HasOverloadedOperation : HasOperatorCode { + + /** + * Arguments forwarded to the operator. This might not necessarily be all of the regular + * "arguments", since often the the first argument is part of the [operatorBase]. + */ + val operatorArguments: List + + /** + * The base expression this operator works on. The [Type] of this is also the source where the + * [SymbolResolver] is looking for an overloaded [OperatorDeclaration]. + */ + val operatorBase: HasType +} diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt index 073c837764..d9eca8716d 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt @@ -29,6 +29,7 @@ import com.fasterxml.jackson.annotation.JsonBackReference import com.fasterxml.jackson.annotation.JsonIgnore import de.fraunhofer.aisec.cpg.PopulatedByPass import de.fraunhofer.aisec.cpg.TranslationContext +import de.fraunhofer.aisec.cpg.TypeManager import de.fraunhofer.aisec.cpg.frontends.Handler import de.fraunhofer.aisec.cpg.frontends.Language import de.fraunhofer.aisec.cpg.graph.declarations.* @@ -52,7 +53,14 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory /** The base class for all graph objects that are going to be persisted in the database. */ -open class Node : IVisitable, Persistable, LanguageProvider, ScopeProvider, ContextProvider { +open class Node : + IVisitable, + Persistable, + LanguageProvider, + ScopeProvider, + ContextProvider, + HasNameAndLocation, + HasScope { /** * Because we are updating type information in the properties of the node, we need a reference * to managers such as the [TypeManager] instance which is responsible for this particular node. @@ -61,11 +69,8 @@ open class Node : IVisitable, Persistable, LanguageProvider, ScopeProvider */ @get:JsonIgnore @Transient override var ctx: TranslationContext? = null - /** - * This property holds the full name using our new [Name] class. It is currently not persisted - * in the graph database. - */ - @Convert(NameConverter::class) open var name: Name = Name(EMPTY_NAME) + /** This property holds the full name using our new [Name] class. */ + @Convert(NameConverter::class) override var name: Name = Name(EMPTY_NAME) /** * Original code snippet of this node. Most nodes will have a corresponding "code", but in cases @@ -97,8 +102,7 @@ open class Node : IVisitable, Persistable, LanguageProvider, ScopeProvider /** Optional comment of this node. */ var comment: String? = null - /** Location of the finding in source code. */ - @Convert(LocationConverter::class) var location: PhysicalLocation? = null + @Convert(LocationConverter::class) override var location: PhysicalLocation? = null /** * Name of the containing file. It can be null for artificially created nodes or if just diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/BinaryOperator.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/BinaryOperator.kt index 7624ab0c5f..f37f34be63 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/BinaryOperator.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/BinaryOperator.kt @@ -129,6 +129,14 @@ open class BinaryOperator : // TODO: replicate something similar like propagateTypeOfBinaryOperation for assigned types } + /** The binary operator operators on the [lhs]. [rhs] is part of the [operatorArguments]. */ + override val operatorArguments: List + get() = listOf(rhs) + + /** The binary operator operators on the [lhs]. [rhs] is part of the [operatorArguments]. */ + override val operatorBase: HasType + get() = lhs + override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -168,7 +176,7 @@ open class BinaryOperator : return lhs == expression || rhs == expression } - override val base: Expression? + val base: Expression? get() { return if (operatorCode == ".*" || operatorCode == "->*") { lhs diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/CallExpression.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/CallExpression.kt index 973983e638..717ed8a6fd 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/CallExpression.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/CallExpression.kt @@ -27,8 +27,7 @@ package de.fraunhofer.aisec.cpg.graph.statements.expressions import de.fraunhofer.aisec.cpg.PopulatedByPass import de.fraunhofer.aisec.cpg.graph.* -import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration -import de.fraunhofer.aisec.cpg.graph.declarations.TemplateDeclaration +import de.fraunhofer.aisec.cpg.graph.declarations.* import de.fraunhofer.aisec.cpg.graph.declarations.TemplateDeclaration.TemplateInitialization import de.fraunhofer.aisec.cpg.graph.edge.* import de.fraunhofer.aisec.cpg.graph.edge.Properties @@ -45,7 +44,8 @@ import org.neo4j.ogm.annotation.Relationship * An expression, which calls another function. It has a list of arguments (list of [Expression]s) * and is connected via the INVOKES edge to its [FunctionDeclaration]. */ -open class CallExpression : Expression(), HasType.TypeObserver, ArgumentHolder { +open class CallExpression : + Expression(), HasOverloadedOperation, HasType.TypeObserver, ArgumentHolder { /** * Connection to its [FunctionDeclaration]. This will be populated by the [SymbolResolver]. This * will have an effect on the [type] @@ -87,12 +87,18 @@ open class CallExpression : Expression(), HasType.TypeObserver, ArgumentHolder { */ var arguments by PropertyEdgeDelegate(CallExpression::argumentEdges) + /** The list of argument types (aka the signature). */ + val signature: List + get() { + return argumentEdges.map { it.end.type } + } + /** * The expression that is being "called". This is currently not yet used in the [SymbolResolver] * but will be in the future. In most cases, this is a [Reference] and its [Reference.refersTo] * is intentionally left empty. It is not filled by the [SymbolResolver]. */ - @AST var callee: Expression? = null + @AST var callee: Expression = ProblemExpression("could not parse callee") /** * The [Name] of this call expression, based on its [callee]. @@ -108,7 +114,7 @@ open class CallExpression : Expression(), HasType.TypeObserver, ArgumentHolder { } else if (value is BinaryOperator && value.rhs.type is FunctionPointerType) { value.lhs.type.name.fqn("*" + value.rhs.name.localName) } else { - value?.name ?: Name(EMPTY_NAME) + value.name } } set(_) { @@ -155,10 +161,6 @@ open class CallExpression : Expression(), HasType.TypeObserver, ArgumentHolder { return true } - /** Returns the function signature as list of types of the call arguments. */ - val signature: List - get() = argumentEdges.map { it.end.type } - /** Specifies, whether this call has any template arguments. */ var template = false @@ -273,6 +275,20 @@ open class CallExpression : Expression(), HasType.TypeObserver, ArgumentHolder { return ToStringBuilder(this, TO_STRING_STYLE).appendSuper(super.toString()).toString() } + override val operatorCode: String? + get() = "()" + + override val operatorArguments: List + get() = arguments + + /** + * Some languages allow to even overload "()", meaning that basically a normal call to [callee] + * is overloaded. In this case we want the [operatorBase] to point to [callee], so we can take + * its type to lookup the necessary [OperatorDeclaration]. + */ + override val operatorBase: HasType + get() = callee + override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is CallExpression) return false diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/MemberCallExpression.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/MemberCallExpression.kt index 140c5aa09c..588be27338 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/MemberCallExpression.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/MemberCallExpression.kt @@ -38,7 +38,7 @@ import java.util.* * While this node implements [HasBase], this is basically just a shortcut to access the base of the * underlying [callee] property, if appropriate. */ -class MemberCallExpression : CallExpression(), HasOverloadedOperation, HasBase, HasOperatorCode { +class MemberCallExpression : CallExpression(), HasBase, HasOperatorCode { /** * The base object. This is basically a shortcut to accessing the base of the [callee], if it * has one (i.e., if it implements [HasBase]). This is the case for example, if it is a diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/MemberExpression.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/MemberExpression.kt index 9315f056e2..d6ae489025 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/MemberExpression.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/MemberExpression.kt @@ -53,6 +53,12 @@ class MemberExpression : Reference(), HasOverloadedOperation, ArgumentHolder, Ha override var operatorCode: String? = null + override val operatorArguments: List + get() = listOf() + + override val operatorBase: HasType + get() = base + override fun toString(): String { return ToStringBuilder(this, TO_STRING_STYLE) .appendSuper(super.toString()) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/UnaryOperator.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/UnaryOperator.kt index ac0885ffdf..6e92af65dd 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/UnaryOperator.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/statements/expressions/UnaryOperator.kt @@ -46,9 +46,14 @@ class UnaryOperator : Expression(), HasOverloadedOperation, ArgumentHolder, HasT changeExpressionAccess() } - /** The unary operator operates on itself. */ - override val base: Expression? - get() = this + /** + * The unary operator does not have any arguments, since [input] is already the [operatorBase]. + */ + override val operatorArguments: List + get() = listOf() + + /** The unary operator operates on [input]. */ + override val operatorBase = input /** The operator code. */ override var operatorCode: String? = null diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/ControlDependenceGraphPass.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/ControlDependenceGraphPass.kt index d64e7a134a..dedc6d4229 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/ControlDependenceGraphPass.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/ControlDependenceGraphPass.kt @@ -60,7 +60,7 @@ open class ControlDependenceGraphPass(ctx: TranslationContext) : EOGStarterPass( } /** - * Computes the CDG for the given [functionDeclaration]. It performs the following steps: + * Computes the CDG for the given [startNode]. It performs the following steps: * 1) Compute the "parent branching node" for each node and through which path the node is * reached * 2) Find out which branch of a [BranchingNode] is actually conditional. The other ones aren't. @@ -226,27 +226,23 @@ open class ControlDependenceGraphPass(ctx: TranslationContext) : EOGStarterPass( Pair(functionDeclaration, setOf(functionDeclaration)), *functionDeclaration .allChildren() + .filterIsInstance() .map { branchingNode -> val mergingPoints = - if ( - (branchingNode as? Node)?.nextEOGEdges?.any { - !it.isConditionalBranch() - } == true - ) { + if (branchingNode.nextEOGEdges.any { !it.isConditionalBranch() }) { // There's an unconditional path (case 1), so when reaching this branch, // we're done. Collect all (=1) unconditional branches. - (branchingNode as? Node) - ?.nextEOGEdges - ?.filter { !it.isConditionalBranch() } - ?.map { it.end } - ?.toSet() + branchingNode.nextEOGEdges + .filter { !it.isConditionalBranch() } + .map { it.end } + .toSet() } else { // All branches are executed based on some condition (case 2), so we // collect all these branches. - (branchingNode as Node).nextEOGEdges.map { it.end }.toSet() + branchingNode.nextEOGEdges.map { it.end }.toSet() } // Map this branching node to its merging points - Pair(branchingNode as Node, mergingPoints) + Pair(branchingNode, mergingPoints) } .toTypedArray() ) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt index 8541fd17f3..6aa0f7a39c 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt @@ -690,9 +690,7 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa protected fun handleGotoStatement(node: GotoStatement) { pushToEOG(node) node.targetLabel?.let { - processedListener.registerObjectListener(it) { _: Any?, to: Any? -> - addEOGEdge(node, to as Node) - } + processedListener.registerObjectListener(it) { _, to -> addEOGEdge(node, to) } } currentPredecessors.clear() } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasAliases.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/InterfacesTest.kt similarity index 68% rename from cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasAliases.kt rename to cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/InterfacesTest.kt index afb92e0a50..ececbb06d3 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/HasAliases.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/InterfacesTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Fraunhofer AISEC. All rights reserved. + * Copyright (c) 2024, Fraunhofer AISEC. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,11 +25,18 @@ */ package de.fraunhofer.aisec.cpg.graph -/** - * Some nodes have aliases, i.e., it potentially references another variable. This means that - * writing to this node, also writes to its [aliases] and vice-versa. - */ -interface HasAliases { - /** The aliases which this node has. */ - var aliases: MutableSet +import de.fraunhofer.aisec.cpg.graph.declarations.VariableDeclaration +import de.fraunhofer.aisec.cpg.graph.statements.expressions.Literal +import kotlin.test.Test +import kotlin.test.assertTrue + +class InterfacesTest { + + @Test + fun testRemoveArgument() { + val v: HasInitializer = VariableDeclaration() + val lit = Literal() + v.initializer = lit + assertTrue(v.removeArgument(lit)) + } }