From 5f754160c4e37e31cbd4b913450fea286ac4cf61 Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Thu, 21 Nov 2024 16:05:33 +0100 Subject: [PATCH] Tests work --- .../aisec/cpg/passes/SymbolResolver.kt | 2 +- .../cpg/frontends/java/ExpressionHandler.kt | 134 ++++-------------- .../cpg/frontends/java/StaticImportsTest.kt | 12 +- 3 files changed, 39 insertions(+), 109 deletions(-) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt index 42722b74f7a..65201615705 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt @@ -209,7 +209,7 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) { // 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() + var wouldResolveTo = ref.candidates.firstOrNull() // 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 diff --git a/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.kt b/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.kt index f7b6742ed89..1b6fbfd5001 100644 --- a/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.kt +++ b/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.kt @@ -29,6 +29,7 @@ import com.github.javaparser.ast.body.VariableDeclarator import com.github.javaparser.ast.expr.* import com.github.javaparser.ast.expr.Expression import com.github.javaparser.resolution.UnsolvedSymbolException +import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration import de.fraunhofer.aisec.cpg.frontends.Handler import de.fraunhofer.aisec.cpg.frontends.HandlerInterface @@ -359,113 +360,22 @@ class ExpressionHandler(lang: JavaLanguageFrontend) : ): de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression? { val nameExpr = expr.asNameExpr() - // TODO this commented code breaks field accesses to fields that don't have a primitive - // type. - // How should this be handled correctly? - // try { - // ResolvedType resolvedType = nameExpr.calculateResolvedType(); - // if (resolvedType.isReferenceType()) { - // return newReference( - // nameExpr.getNameAsString(), - // new Type(((ReferenceTypeImpl) resolvedType).getQualifiedName()), - // nameExpr.toString()); - // } - // } catch ( - // UnsolvedSymbolException - // e) { // this might throw, e.g. if the type is simply not defined (i.e., syntax - // error) - // return newReference( - // nameExpr.getNameAsString(), new Type(UNKNOWN_TYPE), nameExpr.toString()); - // } - val name = this.parseName(nameExpr.nameAsString) - - return newReference(name, rawNode = expr) - /*return try { + // Try to resolve it. We will remove this in a future where we do not really in the + // javaparser symbols anymore. This is mainly needed to resolve implicit "this.field" access + // as well as access to static fields of other classes - which we could resolve once we + // fully leverage the import system in the Java frontend. + try { val symbol = nameExpr.resolve() if (symbol.isField) { val field = symbol.asField() - if (!field.isStatic) { - // convert to FieldAccessExpr - val fieldAccessExpr = FieldAccessExpr(ThisExpr(), field.name) - expr.range.ifPresent { range: Range? -> fieldAccessExpr.setRange(range) } - expr.tokenRange.ifPresent { tokenRange: TokenRange? -> - fieldAccessExpr.setTokenRange(tokenRange) - } - expr.parentNode.ifPresent { newParentNode: Node? -> - fieldAccessExpr.setParentNode(newParentNode) - } - expr.replace(fieldAccessExpr) - fieldAccessExpr.parentNode.ifPresent { newParentNode: Node? -> - expr.setParentNode(newParentNode) - } - - // handle it as a field expression - handle(fieldAccessExpr) - as de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression? - } else { - val fieldAccessExpr = - FieldAccessExpr(NameExpr(field.declaringType().className), field.name) - expr.range.ifPresent { range: Range? -> fieldAccessExpr.setRange(range) } - expr.tokenRange.ifPresent { tokenRange: TokenRange? -> - fieldAccessExpr.setTokenRange(tokenRange) - } - expr.parentNode.ifPresent { newParentNode: Node? -> - fieldAccessExpr.setParentNode(newParentNode) - } - expr.replace(fieldAccessExpr) - fieldAccessExpr.parentNode.ifPresent { newParentNode: Node? -> - expr.setParentNode(newParentNode) - } - - // handle it as a field expression - handle(fieldAccessExpr) - as de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression? - } - } else { - // Resolve type first with ParameterizedType - var type: Type? = - frontend.typeManager.getTypeParameter( - frontend.scopeManager.currentRecord, - symbol.type.describe() - ) - if (type == null) { - type = frontend.typeOf(symbol.type) - } - newReference(symbol.name, type, rawNode = nameExpr) - } - } catch (ex: UnsolvedSymbolException) { - val typeString: String? = - if ( - ex.name.startsWith( - "We are unable to find the value declaration corresponding to" - ) - ) { - nameExpr.nameAsString - } else { - frontend.recoverTypeFromUnsolvedException(ex) - } - val t: Type - if (typeString == null) { - t = unknownType() - } else { - t = this.objectType(typeString) - t.typeOrigin = Type.Origin.GUESSED - } - val declaredReferenceExpression = newReference(name, t, rawNode = nameExpr) - val recordDeclaration = frontend.scopeManager.currentRecord - if (recordDeclaration != null && recordDeclaration.name.lastPartsMatch(name)) { - declaredReferenceExpression.refersTo = recordDeclaration + // handle it as a field expression + return handle(field.toFieldAccessExpr(nameExpr)) + as de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression? } - declaredReferenceExpression - } catch (ex: RuntimeException) { - val t = unknownType() - log.info("Unresolved symbol: {}", nameExpr.nameAsString) - newReference(nameExpr.nameAsString, t, rawNode = nameExpr) - } catch (ex: NoClassDefFoundError) { - val t = unknownType() - log.info("Unresolved symbol: {}", nameExpr.nameAsString) - newReference(nameExpr.nameAsString, t, rawNode = nameExpr) - }*/ + } catch (_: UnsolvedSymbolException) {} + + val name = this.parseName(nameExpr.nameAsString) + return newReference(name, rawNode = expr) } private fun handleInstanceOfExpression(expr: Expression): BinaryOperator { @@ -748,3 +658,21 @@ class ExpressionHandler(lang: JavaLanguageFrontend) : } } } + +fun ResolvedFieldDeclaration.toFieldAccessExpr(expr: NameExpr): FieldAccessExpr { + // Convert to FieldAccessExpr + val fieldAccessExpr = + if (this.isStatic) { + FieldAccessExpr(NameExpr(this.declaringType().className), this.name) + } else { + FieldAccessExpr(ThisExpr(), this.name) + } + + expr.range.ifPresent { fieldAccessExpr.setRange(it) } + expr.tokenRange.ifPresent { fieldAccessExpr.setTokenRange(it) } + expr.parentNode.ifPresent { fieldAccessExpr.setParentNode(it) } + expr.replace(fieldAccessExpr) + fieldAccessExpr.parentNode.ifPresent { expr.setParentNode(it) } + + return fieldAccessExpr +} diff --git a/cpg-language-java/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/java/StaticImportsTest.kt b/cpg-language-java/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/java/StaticImportsTest.kt index a6105cf0afa..df6b99abb53 100644 --- a/cpg-language-java/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/java/StaticImportsTest.kt +++ b/cpg-language-java/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/java/StaticImportsTest.kt @@ -112,17 +112,19 @@ internal class StaticImportsTest : BaseTest() { } } val testFields = a.fields - val staticField = findByUniqueName(testFields, "staticField") - val nonStaticField = findByUniqueName(testFields, "nonStaticField") + val staticField = a.fields["staticField"] + val inferredNonStaticField = b.fields["nonStaticField"] + assertNotNull(staticField) + assertNotNull(inferredNonStaticField) assertTrue(staticField.modifiers.contains("static")) - assertFalse(nonStaticField.modifiers.contains("static")) + assertFalse(inferredNonStaticField.modifiers.contains("static")) val declaredReferences = main.refs val usage = findByUniqueName(declaredReferences, "staticField") assertRefersTo(usage, staticField) val nonStatic = findByUniqueName(declaredReferences, "nonStaticField") - assertRefersTo(nonStatic, nonStaticField) - assertTrue(nonStatic.refersTo!!.isInferred) + assertRefersTo(nonStatic, inferredNonStaticField) + assertTrue(nonStatic.refersTo?.isInferred == true) } }