diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/DeclarationHandler.kt b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/DeclarationHandler.kt index 52cb97b250..0b8067733c 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/DeclarationHandler.kt +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/DeclarationHandler.kt @@ -289,7 +289,7 @@ class DeclarationHandler(lang: CXXLanguageFrontend) : templateDeclaration.name = templateDeclaration.getRealizationDeclarations()[0].name } else (innerDeclaration as? RecordDeclaration)?.let { - fixTypeOfInnerDeclaration(templateDeclaration, it) + addParameterizedTypesToRecord(templateDeclaration, it) } addRealizationToScope(templateDeclaration) @@ -362,32 +362,30 @@ class DeclarationHandler(lang: CXXLanguageFrontend) : } /** - * Fixed the Types created by the innerDeclaration with the ParameterizedTypes of the - * TemplateDeclaration + * Adjusts the type created in a [RecordDeclaration] to include the parametrized types of the + * [templateDeclaration]. This is necessary because templates are being parsed after all record + * types (e.g. used in receivers) are created. * - * @param templateDeclaration - * @param innerDeclaration If RecordDeclaration + * @param templateDeclaration the template + * @param innerDeclaration the record */ - private fun fixTypeOfInnerDeclaration( + private fun addParameterizedTypesToRecord( templateDeclaration: TemplateDeclaration, - innerDeclaration: Declaration + innerDeclaration: RecordDeclaration ) { - var type: Type - type = - if ((innerDeclaration as RecordDeclaration).getThis() == null) { - TypeParser.createFrom(innerDeclaration.name, true) - } else { - innerDeclaration.getThis().type - } val parameterizedTypes = TypeManager.getInstance().getAllParameterizedType(templateDeclaration) - // Add ParameterizedTypes to type - addParameterizedTypesToType(type, parameterizedTypes) - // Add ParameterizedTypes to ConstructorDeclaration Type - for (constructorDeclaration in innerDeclaration.constructors) { - type = constructorDeclaration.type - addParameterizedTypesToType(type, parameterizedTypes) + // Loop through all the methods and adjust their receiver types + for (method in (innerDeclaration as? RecordDeclaration)?.methods ?: listOf()) { + // Add ParameterizedTypes to type + method.receiver?.let { addParameterizedTypesToType(it.type, parameterizedTypes) } + } + + // Add parameterizedTypes to ConstructorDeclaration type and adjust their receiver types + for (constructor in innerDeclaration.constructors) { + constructor.receiver?.let { addParameterizedTypesToType(it.type, parameterizedTypes) } + addParameterizedTypesToType(constructor.type, parameterizedTypes) } } @@ -405,6 +403,8 @@ class DeclarationHandler(lang: CXXLanguageFrontend) : for (parameterizedType in parameterizedTypes) { type.addGeneric(parameterizedType) } + } else if (type is PointerType) { + addParameterizedTypesToType(type.elementType, parameterizedTypes) } } diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/DeclaratorHandler.kt b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/DeclaratorHandler.kt index bea5f10662..c13e3fb62e 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/DeclaratorHandler.kt +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/DeclaratorHandler.kt @@ -27,10 +27,18 @@ package de.fraunhofer.aisec.cpg.frontends.cpp import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.graph.DeclarationHolder -import de.fraunhofer.aisec.cpg.graph.NodeBuilder +import de.fraunhofer.aisec.cpg.graph.NodeBuilder.newConstructorDeclaration +import de.fraunhofer.aisec.cpg.graph.NodeBuilder.newFieldDeclaration +import de.fraunhofer.aisec.cpg.graph.NodeBuilder.newFunctionDeclaration +import de.fraunhofer.aisec.cpg.graph.NodeBuilder.newMethodDeclaration +import de.fraunhofer.aisec.cpg.graph.NodeBuilder.newMethodParameterIn +import de.fraunhofer.aisec.cpg.graph.NodeBuilder.newProblemDeclaration import de.fraunhofer.aisec.cpg.graph.NodeBuilder.newRecordDeclaration +import de.fraunhofer.aisec.cpg.graph.NodeBuilder.newTypeParamDeclaration +import de.fraunhofer.aisec.cpg.graph.NodeBuilder.newVariableDeclaration import de.fraunhofer.aisec.cpg.graph.declarations.* import de.fraunhofer.aisec.cpg.graph.types.IncompleteType +import de.fraunhofer.aisec.cpg.graph.types.PointerType import de.fraunhofer.aisec.cpg.graph.types.TypeParser import de.fraunhofer.aisec.cpg.graph.types.UnknownType import de.fraunhofer.aisec.cpg.helpers.Util @@ -100,7 +108,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : val implicitInitializerAllowed = lang.dialect is GPPLanguage val declaration = - NodeBuilder.newVariableDeclaration( + newVariableDeclaration( ctx.name.toString(), UnknownType.getUnknownType(), // Type will be filled out later by // handleSimpleDeclaration @@ -134,7 +142,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : if (name.contains(lang.namespaceDelimiter)) { val rr = name.split(lang.namespaceDelimiter).toTypedArray() val fieldName = rr[rr.size - 1] - NodeBuilder.newFieldDeclaration( + newFieldDeclaration( fieldName, UnknownType.getUnknownType(), emptyList(), @@ -144,7 +152,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : true ) } else { - NodeBuilder.newFieldDeclaration( + newFieldDeclaration( name, UnknownType.getUnknownType(), emptyList(), @@ -166,13 +174,18 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : lang: LanguageFrontend, ctx: IASTNode, ): MethodDeclaration { - // check, if its a constructor - return if (name == recordDeclaration?.name) { - NodeBuilder.newConstructorDeclaration(name, null, recordDeclaration, lang, ctx) - } else NodeBuilder.newMethodDeclaration(name, null, false, recordDeclaration, lang, ctx) + // Check, if it's a constructor + val method = + if (name == recordDeclaration?.name) { + newConstructorDeclaration(name, null, recordDeclaration, lang, ctx) + } else { + newMethodDeclaration(name, null, false, recordDeclaration, lang, ctx) + } + + return method } - fun handleFunctionDeclarator(ctx: IASTStandardFunctionDeclarator): ValueDeclaration { + private fun handleFunctionDeclarator(ctx: IASTStandardFunctionDeclarator): ValueDeclaration { // Programmers can wrap the function name in as many levels of parentheses as they like. CDT // treats these levels as separate declarators, so we need to get to the bottom for the // actual name... @@ -196,7 +209,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : // If this is a method, this is its record declaration var recordDeclaration: RecordDeclaration? = null - // remember, if this is a method declaration outside of the record + // remember, if this is a method declaration outside the record val outsideOfRecord = !(lang.scopeManager.currentRecord != null || lang.scopeManager.currentScope is TemplateScope) @@ -217,12 +230,11 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : declaration = createMethodOrConstructor(name, recordDeclaration, lang, ctx.parent) } else { // a plain old function, outside any record scope - declaration = - NodeBuilder.newFunctionDeclaration(name, ctx.rawSignature, lang, ctx.parent) + declaration = newFunctionDeclaration(name, ctx.rawSignature, lang, ctx.parent) } // If we know our record declaration, but are outside the actual record, we - // need to temporary enter the record scope. This way, we can do a little trick + // need to temporarily enter the record scope. This way, we can do a little trick // and (manually) add the declaration to the AST element of the current scope // (probably the global scope), but associate it to the record scope. Otherwise, we // will get a lot of false-positives such as A::foo, when we look for the function foo. @@ -252,6 +264,12 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : // Enter the scope of the function itself lang.scopeManager.enterScope(declaration) + + // Create the method receiver (if this is a method) + if (declaration is MethodDeclaration) { + createMethodReceiver(declaration) + } + var i = 0 for (param in ctx.parameters) { val arg = lang.parameterDeclarationHandler.handle(param) @@ -294,11 +312,9 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : // Check for varargs. Note the difference to Java: here, we don't have a named array // containing the varargs, but they are rather treated as kind of an invisible arg list that // is appended to the original ones. For coherent graph behaviour, we introduce an implicit - // declaration that - // wraps this list + // declaration that wraps this list if (ctx.takesVarArgs()) { - val varargs = - NodeBuilder.newMethodParameterIn("va_args", UnknownType.getUnknownType(), true, "") + val varargs = newMethodParameterIn("va_args", UnknownType.getUnknownType(), true, "") varargs.isImplicit = true varargs.argumentIndex = i lang.scopeManager.addDeclaration(varargs) @@ -319,7 +335,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : lang.scopeManager.currentFunction != null ) { val problem = - NodeBuilder.newProblemDeclaration( + newProblemDeclaration( "CDT tells us this is a (named) function declaration in parenthesis without a body directly within a block scope, this might be an ambiguity which we cannot solve currently." ) @@ -331,6 +347,41 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : return declaration } + /** + * This function takes cares of creating a receiver and setting it to the supplied + * [MethodDeclaration]. In C++ this is called the + * [implicit object parameter](https://en.cppreference.com/w/cpp/language/overload_resolution#Implicit_object_parameter) + * . + */ + private fun createMethodReceiver(declaration: MethodDeclaration) { + val recordDeclaration = declaration.recordDeclaration + + // Create a pointer to the class type (if we know it) + val type = + if (recordDeclaration != null) { + recordDeclaration.toType().reference(PointerType.PointerOrigin.POINTER) + } else { + UnknownType.getUnknownType() + } + + // Create the receiver. + val thisDeclaration = + newVariableDeclaration( + "this", + type = type, + lang = lang, + implicitInitializerAllowed = false + ) + // Yes, this is implicit + thisDeclaration.isImplicit = true + + // Add it to the scope of the method + lang.scopeManager.addDeclaration(thisDeclaration) + + // We need to manually set the receiver, since the scope manager cannot figure this out + declaration.receiver = thisDeclaration + } + private fun handleFunctionPointer(ctx: IASTFunctionDeclarator, name: String): ValueDeclaration { val initializer = if (ctx.initializer == null) null else lang.initializerHandler.handle(ctx.initializer) @@ -341,12 +392,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : if (recordDeclaration == null) { // variable result = - NodeBuilder.newVariableDeclaration( - name, - UnknownType.getUnknownType(), - ctx.rawSignature, - true - ) + newVariableDeclaration(name, UnknownType.getUnknownType(), ctx.rawSignature, true) result.initializer = initializer } else { // field @@ -358,7 +404,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : fieldName = matcher.group("name").trim() } result = - NodeBuilder.newFieldDeclaration( + newFieldDeclaration( fieldName, UnknownType.getUnknownType(), emptyList(), @@ -388,7 +434,6 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : lang.scopeManager.currentNamePrefixWithDelimiter + ctx.name.toString(), kind, ctx.rawSignature, - true, lang ) @@ -406,18 +451,18 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : lang.scopeManager.enterScope(recordDeclaration) - lang.scopeManager.addDeclaration(recordDeclaration.getThis()) - processMembers(ctx) if (recordDeclaration.constructors.isEmpty()) { val constructorDeclaration = - NodeBuilder.newConstructorDeclaration( + newConstructorDeclaration( recordDeclaration.name, recordDeclaration.name, recordDeclaration ) + createMethodReceiver(constructorDeclaration) + // set this as implicit constructorDeclaration.isImplicit = true @@ -441,7 +486,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : private fun handleTemplateTypeParameter( ctx: CPPASTSimpleTypeTemplateParameter ): TypeParamDeclaration { - return NodeBuilder.newTypeParamDeclaration(ctx.rawSignature, ctx.rawSignature) + return newTypeParamDeclaration(ctx.rawSignature, ctx.rawSignature) } private fun processMembers(ctx: IASTCompositeTypeSpecifier) { diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/ExpressionHandler.kt b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/ExpressionHandler.kt index 997b0df928..dd1f758d99 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/ExpressionHandler.kt +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/cpp/ExpressionHandler.kt @@ -329,21 +329,23 @@ class ExpressionHandler(lang: CXXLanguageFrontend) : return castExpression } - private fun handleFieldReference(ctx: IASTFieldReference): Expression { + /** + * Translates a C/C++ + * [member access](https://en.cppreference.com/w/cpp/language/operator_member_access) into a + * [MemberExpression]. + */ + private fun handleFieldReference(ctx: IASTFieldReference): MemberExpression { var base = handle(ctx.fieldOwner) - // Replace Literal this with a reference pointing to this + + // Replace Literal this with a reference pointing to the receiver, which also called an + // implicit object parameter in C++ (see + // https://en.cppreference.com/w/cpp/language/overload_resolution#Implicit_object_parameter). It is sufficient to have the refers, it will be connected by the resolver later. if (base is Literal<*> && base.value == "this") { val location = base.location - val recordDeclaration = lang.scopeManager.currentRecord - base = - NodeBuilder.newDeclaredReferenceExpression( - "this", - if (recordDeclaration != null) recordDeclaration.getThis().type - else UnknownType.getUnknownType(), - base.code - ) + base = NodeBuilder.newDeclaredReferenceExpression("this", base.type, base.code) base.location = location } + return NodeBuilder.newMemberExpression( base, UnknownType.getUnknownType(), diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/java/DeclarationHandler.java b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/java/DeclarationHandler.java index 9c2414c4eb..b9ebb2baf4 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/java/DeclarationHandler.java +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/java/DeclarationHandler.java @@ -43,12 +43,10 @@ import com.github.javaparser.resolution.declarations.ResolvedConstructorDeclaration; import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; import de.fraunhofer.aisec.cpg.frontends.Handler; +import de.fraunhofer.aisec.cpg.graph.NodeBuilder; import de.fraunhofer.aisec.cpg.graph.ProblemNode; import de.fraunhofer.aisec.cpg.graph.TypeManager; -import de.fraunhofer.aisec.cpg.graph.declarations.Declaration; -import de.fraunhofer.aisec.cpg.graph.declarations.ParamVariableDeclaration; -import de.fraunhofer.aisec.cpg.graph.declarations.ProblemDeclaration; -import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration; +import de.fraunhofer.aisec.cpg.graph.declarations.*; import de.fraunhofer.aisec.cpg.graph.statements.CompoundStatement; import de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression; import de.fraunhofer.aisec.cpg.graph.types.ParameterizedType; @@ -112,14 +110,16 @@ private static void addImplicitReturn(BlockStmt body) { com.github.javaparser.ast.body.ConstructorDeclaration constructorDecl) { ResolvedConstructorDeclaration resolvedConstructor = constructorDecl.resolve(); + var record = lang.getScopeManager().getCurrentRecord(); de.fraunhofer.aisec.cpg.graph.declarations.ConstructorDeclaration declaration = newConstructorDeclaration( - resolvedConstructor.getName(), - constructorDecl.toString(), - lang.getScopeManager().getCurrentRecord()); + resolvedConstructor.getName(), constructorDecl.toString(), record); lang.getScopeManager().addDeclaration(declaration); lang.getScopeManager().enterScope(declaration); + + createMethodReceiver(record, declaration); + declaration.addThrowTypes( constructorDecl.getThrownExceptions().stream() .map(type -> TypeParser.createFrom(type.asString(), true)) @@ -171,20 +171,10 @@ var record = lang.getScopeManager().getCurrentRecord(); newMethodDeclaration( resolvedMethod.getName(), methodDecl.toString(), methodDecl.isStatic(), record); - // create the receiver - var receiver = - newVariableDeclaration( - "this", - record != null - ? TypeParser.createFrom(record.getName(), false) - : UnknownType.getUnknownType(), - "this", - false); - - functionDeclaration.setReceiver(receiver); - lang.getScopeManager().enterScope(functionDeclaration); + createMethodReceiver(record, functionDeclaration); + functionDeclaration.addThrowTypes( methodDecl.getThrownExceptions().stream() .map(type -> TypeParser.createFrom(type.asString(), true)) @@ -237,6 +227,23 @@ record != null return functionDeclaration; } + private void createMethodReceiver( + RecordDeclaration record, MethodDeclaration functionDeclaration) { + // create the receiver + var receiver = + newVariableDeclaration( + "this", + record != null + ? TypeParser.createFrom(record.getName(), false) + : UnknownType.getUnknownType(), + "this", + false); + + functionDeclaration.setReceiver(receiver); + + lang.getScopeManager().addDeclaration(receiver); + } + public RecordDeclaration handleClassOrInterfaceDeclaration( ClassOrInterfaceDeclaration classInterDecl) { // TODO: support other kinds, such as interfaces @@ -250,7 +257,7 @@ public RecordDeclaration handleClassOrInterfaceDeclaration( // add a type declaration RecordDeclaration recordDeclaration = - newRecordDeclaration(fqn, "class", null, true, lang, classInterDecl); + newRecordDeclaration(fqn, "class", null, lang, classInterDecl); recordDeclaration.setSuperClasses( classInterDecl.getExtendedTypes().stream() .map(this.lang::getTypeAsGoodAsPossible) @@ -286,7 +293,6 @@ public RecordDeclaration handleClassOrInterfaceDeclaration( recordDeclaration.setImportStatements(partitioned.get(false)); lang.getScopeManager().enterScope(recordDeclaration); - lang.getScopeManager().addDeclaration(recordDeclaration.getThis()); // TODO: 'this' identifier for multiple instances? for (BodyDeclaration decl : classInterDecl.getMembers()) { @@ -328,6 +334,29 @@ public RecordDeclaration handleClassOrInterfaceDeclaration( lang.processAnnotations(recordDeclaration, classInterDecl); lang.getScopeManager().leaveScope(recordDeclaration); + + // We need special handling if this is a so called "inner class". In this case we need to store + // a "this" reference to the outer class, so methods can use a "qualified this" + // (OuterClass.this.someFunction()). This is the same as the java compiler does. The reference + // is stored as an implicit field. + if (lang.getScopeManager().getCurrentScope() instanceof RecordScope) { + var scope = (RecordScope) lang.getScopeManager().getCurrentScope(); + + var field = + NodeBuilder.newFieldDeclaration( + scope.getSimpleName() + ".this", + TypeParser.createFrom(scope.getScopedName(), false), + null, + null, + null, + false); + field.setImplicit(true); + + lang.getScopeManager().enterScope(recordDeclaration); + lang.getScopeManager().addDeclaration(field); + lang.getScopeManager().leaveScope(recordDeclaration); + } + return recordDeclaration; } diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.java b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.java index 63ca7d357b..4e269f5aa9 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.java +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.java @@ -450,7 +450,6 @@ private DeclaredReferenceExpression handleClassExpression(Expression expr) { } private DeclaredReferenceExpression handleThisExpression(Expression expr) { - // TODO: use a separate ThisExpression (issue #8) ThisExpr thisExpr = expr.asThisExpr(); ResolvedTypeDeclaration resolvedValueDeclaration = thisExpr.resolve(); @@ -465,7 +464,7 @@ private DeclaredReferenceExpression handleThisExpression(Expression expr) { private DeclaredReferenceExpression handleSuperExpression(Expression expr) { // The actual type is hard to determine at this point, as we may not have full information - // about the inheritance structure. Thus we delay the resolving to the variable resolving + // about the inheritance structure. Thus, we delay the resolving to the variable resolving // process DeclaredReferenceExpression superExpression = NodeBuilder.newDeclaredReferenceExpression( diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt index d100b43159..61276e6036 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt @@ -26,13 +26,11 @@ package de.fraunhofer.aisec.cpg.graph import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend -import de.fraunhofer.aisec.cpg.frontends.cpp.CXXLanguageFrontend -import de.fraunhofer.aisec.cpg.graph.NodeBuilder.setCodeAndRegion import de.fraunhofer.aisec.cpg.graph.declarations.* import de.fraunhofer.aisec.cpg.graph.statements.* import de.fraunhofer.aisec.cpg.graph.statements.expressions.* import de.fraunhofer.aisec.cpg.graph.types.Type -import de.fraunhofer.aisec.cpg.graph.types.TypeParser +import de.fraunhofer.aisec.cpg.graph.types.UnknownType import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation import org.slf4j.LoggerFactory @@ -200,14 +198,14 @@ object NodeBuilder { @JvmOverloads fun newDeclaredReferenceExpression( name: String?, - typeFullName: Type?, + type: Type? = UnknownType.getUnknownType(), code: String? = null, lang: LanguageFrontend? = null, rawNode: Any? = null ): DeclaredReferenceExpression { val node = DeclaredReferenceExpression() node.name = name!! - node.type = typeFullName + node.type = type node.setCodeAndRegion(lang, rawNode, code) log(node) @@ -648,7 +646,6 @@ object NodeBuilder { fqn: String, kind: String, code: String? = null, - createThis: Boolean = true, lang: LanguageFrontend? = null, rawNode: Any? = null ): RecordDeclaration { @@ -662,21 +659,6 @@ object NodeBuilder { node.code = code } - // In cpp, structs are also classes - if ((kind == "class" || (lang is CXXLanguageFrontend && kind == "struct")) && createThis) { - val thisDeclaration = - newFieldDeclaration( - "this", - TypeParser.createFrom(fqn, true), - listOf(), - "this", - null, - null, - true - ) - node.addField(thisDeclaration) - } - log(node) return node diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/MethodDeclaration.java b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/MethodDeclaration.java deleted file mode 100644 index 8abd170066..0000000000 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/MethodDeclaration.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2020, 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.declarations; - -import de.fraunhofer.aisec.cpg.graph.SubGraph; -import org.jetbrains.annotations.Nullable; - -/** - * A method declaration is a {@link FunctionDeclaration} tied to a specific {@link - * RecordDeclaration}. - */ -public class MethodDeclaration extends FunctionDeclaration { - - private boolean isStatic; - - /** - * The {@link RecordDeclaration} this method is tied to. This can be empty if we do not know about - * the type. - */ - @Nullable private RecordDeclaration recordDeclaration; - - /** - * The receiver variable of this method. In most cases, this variable is called 'this', but in - * some languages, it is 'self' (e.g. in Rust or Python) or can be freely named (e.g. in Golang). - * - *

It can be empty, i.e., for pure function definitions as part as an interface. - */ - @SubGraph("AST") - @Nullable - private VariableDeclaration receiver; - - public boolean isStatic() { - return isStatic; - } - - public void setStatic(boolean isStatic) { - this.isStatic = isStatic; - } - - @Nullable - public RecordDeclaration getRecordDeclaration() { - return recordDeclaration; - } - - public void setRecordDeclaration(@Nullable RecordDeclaration recordDeclaration) { - this.recordDeclaration = recordDeclaration; - } - - @Nullable - public VariableDeclaration getReceiver() { - return receiver; - } - - public void setReceiver(@Nullable VariableDeclaration receiver) { - this.receiver = receiver; - } -} diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/MethodDeclaration.kt b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/MethodDeclaration.kt new file mode 100644 index 0000000000..364f1d212b --- /dev/null +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/MethodDeclaration.kt @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020, 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.declarations + +import de.fraunhofer.aisec.cpg.graph.SubGraph +import de.fraunhofer.aisec.cpg.graph.statements.expressions.DeclaredReferenceExpression +import de.fraunhofer.aisec.cpg.passes.CallResolver +import de.fraunhofer.aisec.cpg.passes.VariableUsageResolver + +/** + * A method declaration is a [FunctionDeclaration] that is part of to a specific [RecordDeclaration] + * . + */ +open class MethodDeclaration : FunctionDeclaration() { + var isStatic = false + + /** + * The [RecordDeclaration] this method is part of. This can be empty if we do not know about it. + */ + open var recordDeclaration: RecordDeclaration? = null + + /** + * The receiver variable of this method. In most cases, this variable is called `this`, but in + * some languages, it is `self` (e.g. in Rust or Python) or can be freely named (e.g. in + * Golang). It can be empty, i.e., for pure function declarations as part of an interface. + * + * Hints for language frontend developers: When a method is translated, the receiver must be + * created (usually in the form of a [VariableDeclaration] and added to the scope of the + * [MethodDeclaration] by a language frontend. Furthermore, it must be manually set to the + * [receiver] property of the method, since the scope manager cannot do this. If the name of the + * receiver, e.g., `this`, is used anywhere in the method body, a [DeclaredReferenceExpression] + * must be created by the language frontend, and its [DeclaredReferenceExpression.refersTo] + * property must point to this [receiver]. The latter is done automatically by the + * [VariableUsageResolver], which treats it like any other regular variable. + * + * Some languages (for example Python) denote the first argument in a method declaration as the + * receiver (e.g., in `def foo(self, arg1)`, `self` is the receiver). In this case, extra care + * needs to be taken that for the first argument of the method, a [VariableDeclaration] is + * created and stored in [receiver]. All other arguments must then be processed normally + * (usually into a [ParamVariableDeclaration]). This is also important because from the + * "outside" the method only has the remaining arguments, when called (e.g., + * `object.foo("myarg1")`). + * + * There is one special case that concerns the Java language: In Java, there also exists a + * `super` keyword, which can be used to explicitly access methods or fields of the (single) + * superclass of the current class. In this case, a [DeclaredReferenceExpression] will also be + * created (with the name `super`) and it will also refer to this receiver, even though the + * receiver's name is `this`. This is one of the very few exceptions where the reference and its + * declaration do not share the same name. The [CallResolver] will recognize this and treat the + * scoping aspect of the super-call accordingly. + */ + @field:SubGraph("AST") var receiver: VariableDeclaration? = null +} diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/RecordDeclaration.java b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/RecordDeclaration.java index 3e7f4b222a..3139216980 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/RecordDeclaration.java +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/RecordDeclaration.java @@ -141,14 +141,6 @@ public void setFields(List fields) { this.fields = PropertyEdge.transformIntoOutgoingPropertyEdgeList(fields, this); } - public FieldDeclaration getThis() { - return fields.stream() - .map(PropertyEdge::getEnd) - .filter(f -> f.getName().equals("this")) - .findFirst() - .orElse(null); - } - public List getMethods() { return unwrap(this.methods); } diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/TranslationUnitDeclaration.java b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/TranslationUnitDeclaration.java index 6b8a60670d..ec80a83d0f 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/TranslationUnitDeclaration.java +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/graph/declarations/TranslationUnitDeclaration.java @@ -33,7 +33,10 @@ import de.fraunhofer.aisec.cpg.graph.SubGraph; import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge; import de.fraunhofer.aisec.cpg.graph.statements.Statement; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang3.builder.ToStringBuilder; import org.jetbrains.annotations.NotNull; diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/CallResolver.java b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/CallResolver.java index 63a3d02725..b059a77338 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/CallResolver.java +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/CallResolver.java @@ -193,9 +193,17 @@ public static void addImplicitTemplateParametersToCall( * @param call The call to be resolved */ protected void handleSuperCall(RecordDeclaration curClass, CallExpression call) { + // We need to connect this super reference to the receiver of this method + var func = lang.getScopeManager().getCurrentFunction(); + if (func instanceof MethodDeclaration) { + ((DeclaredReferenceExpression) call.getBase()) + .setRefersTo(((MethodDeclaration) func).getReceiver()); + } + RecordDeclaration target = null; if (call.getBase().getName().equals("super")) { - // direct superclass, either defined explicitly or java.lang.Object by default + + // Direct superclass, either defined explicitly or java.lang.Object by default if (!curClass.getSuperClasses().isEmpty()) { target = recordMap.get(curClass.getSuperClasses().get(0).getRoot().getTypeName()); } else { @@ -210,8 +218,13 @@ protected void handleSuperCall(RecordDeclaration curClass, CallExpression call) // interface that is implemented target = handleSpecificSupertype(curClass, call); } + if (target != null) { - ((DeclaredReferenceExpression) call.getBase()).setRefersTo(target.getThis()); + var superType = target.toType(); + // Explicitly set the type of the call's base to the super type + call.getBase().setType(superType); + // And set the possible subtypes, to ensure, that really only our super type is in there + call.getBase().updatePossibleSubtypes(Collections.singletonList(superType)); handleMethodCall(target, call); } } @@ -1722,11 +1735,9 @@ protected Set getPossibleContainingTypes(Node node, RecordDeclaration curC Set possibleTypes = new HashSet<>(); if (node instanceof MemberCallExpression) { MemberCallExpression memberCall = (MemberCallExpression) node; - if (memberCall.getBase() instanceof HasType) { - HasType base = memberCall.getBase(); - possibleTypes.add(base.getType()); - possibleTypes.addAll(base.getPossibleSubTypes()); - } + HasType base = memberCall.getBase(); + possibleTypes.add(base.getType()); + possibleTypes.addAll(base.getPossibleSubTypes()); } else if (node instanceof StaticCallExpression) { StaticCallExpression staticCall = (StaticCallExpression) node; if (staticCall.getTargetRecord() != null) { diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/TypeResolver.java b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/TypeResolver.java index 473cf8b6fc..dfae88aaee 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/TypeResolver.java +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/TypeResolver.java @@ -46,11 +46,13 @@ public class TypeResolver extends Pass { protected void processSecondOrderTypes(Type type) { Type root = type.getRoot(); - if (typeState.get(root).contains(type)) { + var state = typeState.computeIfAbsent(root, (param) -> new ArrayList<>()); + + if (state.contains(type)) { return; } - typeState.get(root).add(type); + state.add(type); Type element = null; if (type instanceof SecondOrderType) { @@ -62,8 +64,7 @@ protected void processSecondOrderTypes(Type type) { return; } Type finalElement = element; - Type newElement = - typeState.get(root).stream().filter(t -> t.equals(finalElement)).findAny().orElse(null); + Type newElement = state.stream().filter(t -> t.equals(finalElement)).findAny().orElse(null); if (newElement != null) { ((SecondOrderType) type).setElementType(newElement); diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/VariableUsageResolver.java b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/VariableUsageResolver.java index e3e1b27a16..bb1b6ec0e4 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/VariableUsageResolver.java +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/VariableUsageResolver.java @@ -275,8 +275,20 @@ protected void resolveFieldUsages(Node current, RecordDeclaration curClass) { curClass.getName()); base.setType(TypeParser.createFrom(Object.class.getName(), true)); } else { - baseTarget = superRecord.getThis(); - base.setRefersTo(baseTarget); + // We need to connect this super reference to the receiver of this method + var func = lang.getScopeManager().getCurrentFunction(); + if (func instanceof MethodDeclaration) { + baseTarget = ((MethodDeclaration) func).getReceiver(); + } + + if (baseTarget != null) { + base.setRefersTo(baseTarget); + // Explicitly set the type of the call's base to the super type + base.setType(superType); + // And set the possible subtypes, to ensure, that really only our super type is in + // there + base.updatePossibleSubtypes(Collections.singletonList(superType)); + } } } else { // no explicit super type -> java.lang.Object @@ -349,22 +361,7 @@ protected Declaration resolveBase(DeclaredReferenceExpression reference) { return enumMap.get(reference.getType()); } - if (recordMap.containsKey(reference.getType())) { - RecordDeclaration recordDeclaration = recordMap.get(reference.getType()); - if (reference.isStaticAccess()) { - return recordDeclaration; - } else { - // check if we have this type as a class in our graph. If so, we can refer to its "this" - // field - if (recordDeclaration.getThis() != null) { - return recordDeclaration.getThis(); - } else { - return recordDeclaration; - } - } - } else { - return null; - } + return recordMap.getOrDefault(reference.getType(), null); } @Nullable diff --git a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/scopes/NameScope.java b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/scopes/NameScope.java index 111fa1b426..c48524647b 100644 --- a/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/scopes/NameScope.java +++ b/cpg-core/src/main/java/de/fraunhofer/aisec/cpg/passes/scopes/NameScope.java @@ -26,13 +26,18 @@ package de.fraunhofer.aisec.cpg.passes.scopes; import de.fraunhofer.aisec.cpg.graph.Node; +import java.util.regex.Pattern; public class NameScope extends StructureDeclarationScope { private String namePrefix; + private String delimiter = "."; public NameScope(Node node, String currentPrefix, String delimiter) { super(node); + + this.delimiter = delimiter; + if (currentPrefix == null || !currentPrefix.isEmpty()) { String nodeName = node.getName(); // If the name already contains some form of prefix we have to remove it. @@ -54,4 +59,15 @@ public String getNamePrefix() { public void setNamePrefix(String namePrefix) { this.namePrefix = namePrefix; } + + public String getSimpleName() { + // Split scoped named by delimiter + var names = this.scopedName.split(Pattern.quote(delimiter)); + + if (names.length > 0) { + return names[names.length - 1]; + } else { + return null; + } + } } diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/calls/SuperCallTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/calls/SuperCallTest.kt index 026bd8116e..f2be91292f 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/calls/SuperCallTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/calls/SuperCallTest.kt @@ -40,7 +40,6 @@ import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression import de.fraunhofer.aisec.cpg.graph.statements.expressions.DeclaredReferenceExpression import de.fraunhofer.aisec.cpg.graph.statements.expressions.MemberExpression import java.nio.file.Path -import java.util.stream.Collectors import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -104,10 +103,10 @@ internal class SuperCallTest : BaseTest() { refs = flattenIsInstance(getSuperField) val superFieldRef = findByUniquePredicate(refs) { "super.field" == it.code } assertTrue(fieldRef.base is DeclaredReferenceExpression) - assertRefersTo(fieldRef.base, subClass.`this`) + assertRefersTo(fieldRef.base, getField.receiver) assertEquals(field, fieldRef.refersTo) assertTrue(superFieldRef.base is DeclaredReferenceExpression) - assertRefersTo(superFieldRef.base, superClass.`this`) + assertRefersTo(superFieldRef.base, getSuperField.receiver) assertEquals(superField, superFieldRef.refersTo) } @@ -133,24 +132,15 @@ internal class SuperCallTest : BaseTest() { val result = analyze("java", topLevel, true) val records = flattenListIsInstance(result) val superClass = findByUniqueName(records, "SuperClass") - assertEquals(2, superClass.fields.size) - assertEquals( - mutableSetOf("this", "field"), - superClass.fields.stream().map(Node::name).collect(Collectors.toSet()) - ) + assertEquals(1, superClass.fields.size) + assertEquals(listOf("field"), superClass.fields.map(Node::name)) val subClass = findByUniqueName(records, "SubClass") - assertEquals(2, subClass.fields.size) - assertEquals( - mutableSetOf("this", "field"), - subClass.fields.stream().map(Node::name).collect(Collectors.toSet()) - ) + assertEquals(1, subClass.fields.size) + assertEquals(listOf("field"), subClass.fields.map(Node::name)) val inner = findByUniqueName(records, "SubClass.Inner") assertEquals(1, inner.fields.size) - assertEquals( - mutableSetOf("this"), - inner.fields.stream().map(Node::name).collect(Collectors.toSet()) - ) + assertEquals(listOf("SubClass.this"), inner.fields.map(Node::name)) } } diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/templates/ClassTemplateTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/templates/ClassTemplateTest.kt index 3a996c5cce..9defda2aea 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/templates/ClassTemplateTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/templates/ClassTemplateTest.kt @@ -30,7 +30,7 @@ import de.fraunhofer.aisec.cpg.TestUtils.analyze import de.fraunhofer.aisec.cpg.TestUtils.findByUniqueName import de.fraunhofer.aisec.cpg.TestUtils.findByUniquePredicate import de.fraunhofer.aisec.cpg.TestUtils.flattenListIsInstance -import de.fraunhofer.aisec.cpg.graph.TypeManager +import de.fraunhofer.aisec.cpg.graph.byNameOrNull import de.fraunhofer.aisec.cpg.graph.declarations.* import de.fraunhofer.aisec.cpg.graph.edge.Properties import de.fraunhofer.aisec.cpg.graph.statements.expressions.* @@ -59,29 +59,31 @@ internal class ClassTemplateTest : BaseTest() { private fun testClassTemplateFields( pair: RecordDeclaration, - thisField: FieldDeclaration?, first: FieldDeclaration?, second: FieldDeclaration? ) { - assertTrue(pair.fields.contains(thisField)) assertTrue(pair.fields.contains(first)) assertTrue(pair.fields.contains(second)) } private fun testClassTemplatesTypes( pair: RecordDeclaration?, - thisField: FieldDeclaration, + receiver: VariableDeclaration, type1: TypeParamDeclaration, type2: TypeParamDeclaration ): ObjectType { - assertEquals("Pair", thisField.type.name) - assertTrue(thisField.type is ObjectType) - val pairType = thisField.type as ObjectType + assertEquals("Pair*", receiver.type.name) + assertTrue(receiver.type is PointerType) + + val pairType = (receiver.type as PointerType).elementType as? ObjectType + assertNotNull(pairType) + assertEquals("Type1", type1.type.name) assertEquals("Type2", type2.type.name) assertEquals(type1.type, pairType.generics[0]) assertEquals(type2.type, pairType.generics[1]) assertEquals(pair, pairType.recordDeclaration) + return pairType } @@ -135,8 +137,6 @@ internal class ClassTemplateTest : BaseTest() { @Test @Throws(Exception::class) fun testClassTemplateStructure() { - TypeManager.reset() - val result = analyze(listOf(Path.of(topLevel.toString(), "pair.cpp").toFile()), topLevel, true) val classTemplateDeclarations = flattenListIsInstance(result) @@ -152,7 +152,9 @@ internal class ClassTemplateTest : BaseTest() { findByUniqueName(flattenListIsInstance(result), "class Type2") val first = findByUniqueName(flattenListIsInstance(result), "first") val second = findByUniqueName(flattenListIsInstance(result), "second") - val thisField = findByUniqueName(flattenListIsInstance(result), "this") + val receiver = pair.byNameOrNull("Pair")?.receiver + assertNotNull(receiver) + val pairConstructorDeclaration = findByUniqueName(flattenListIsInstance(result), "Pair") val constructExpression = @@ -165,10 +167,10 @@ internal class ClassTemplateTest : BaseTest() { testTemplateStructure(template, pair, type1, type2) // Test Fields - testClassTemplateFields(pair, thisField, first, second) + testClassTemplateFields(pair, first, second) // Test Types - val pairType = testClassTemplatesTypes(pair, thisField, type1, type2) + val pairType = testClassTemplatesTypes(pair, receiver, type1, type2) // Test Constructor testClassTemplateConstructor(pair, pairType, pairConstructorDeclaration) @@ -188,8 +190,6 @@ internal class ClassTemplateTest : BaseTest() { @Throws(Exception::class) fun testClassTemplateWithValueParameter() { // Test pair2.cpp: Add Value Parameter to Template Instantiation - TypeManager.reset() - val result = analyze(listOf(Path.of(topLevel.toString(), "pair2.cpp").toFile()), topLevel, true) val classTemplateDeclarations = flattenListIsInstance(result) @@ -201,7 +201,9 @@ internal class ClassTemplateTest : BaseTest() { val pair = findByUniqueName(flattenListIsInstance(result), "Pair") val paramN = findByUniqueName(flattenListIsInstance(result), "N") val n = findByUniqueName(flattenListIsInstance(result), "n") - val thisField = findByUniqueName(flattenListIsInstance(result), "this") + val receiver = pair.byNameOrNull("Pair")?.receiver + assertNotNull(receiver) + val pairConstructorDeclaration = findByUniqueName(flattenListIsInstance(result), "Pair") val constructExpression = @@ -223,7 +225,8 @@ internal class ClassTemplateTest : BaseTest() { assertEquals(paramN, (n.initializer as? DeclaredReferenceExpression)?.refersTo) // Test Type - val type = thisField.type as ObjectType + val type = ((receiver.type as? PointerType)?.elementType as? ObjectType) + assertNotNull(type) assertEquals(pairConstructorDeclaration.type, type) assertEquals(pair, type.recordDeclaration) assertEquals(2, type.generics.size) @@ -292,8 +295,6 @@ internal class ClassTemplateTest : BaseTest() { @Throws(Exception::class) fun testStructTemplateWithSameDefaultType() { // Test pair3.cpp: Template a struct instead of a class and use a Type1 as default of Type2 - TypeManager.reset() - val result = analyze(listOf(Path.of(topLevel.toString(), "pair3.cpp").toFile()), topLevel, true) val template = @@ -335,9 +336,9 @@ internal class ClassTemplateTest : BaseTest() { assertEquals(2, pairType.generics.size) assertEquals(type1ParameterizedType, pairType.generics[0]) assertEquals(type2ParameterizedType, pairType.generics[1]) - assertEquals(3, pair.fields.size) // cpp has implicit `this` field - assertEquals(first, pair.fields[1]) - assertEquals(second, pair.fields[2]) + assertEquals(2, pair.fields.size) + assertEquals(first, pair.fields[0]) + assertEquals(second, pair.fields[1]) assertEquals(type1ParameterizedType, first.type) assertEquals(type2ParameterizedType, second.type) testStructTemplateWithSameDefaultTypeInvocation( @@ -353,8 +354,6 @@ internal class ClassTemplateTest : BaseTest() { @Throws(Exception::class) fun testTemplateOverrindingDefaults() { // Test pair3-1.cpp: Override defaults of template - TypeManager.reset() - val result = analyze(listOf(Path.of(topLevel.toString(), "pair3-1.cpp").toFile()), topLevel, true) val template = @@ -419,8 +418,6 @@ internal class ClassTemplateTest : BaseTest() { @Throws(Exception::class) fun testTemplateRecursiveDefaults() { // Test pair3-2.cpp: Use recursive template parameters using defaults - TypeManager.reset() - val result = analyze(listOf(Path.of(topLevel.toString(), "pair3-2.cpp").toFile()), topLevel, true) val template = @@ -432,11 +429,11 @@ internal class ClassTemplateTest : BaseTest() { val paramA = findByUniqueName(flattenListIsInstance(result), "A") val paramB = findByUniqueName(flattenListIsInstance(result), "B") val constructExpression = - findByUniquePredicate(flattenListIsInstance(result)) { - it.code == "()" + findByUniquePredicate(flattenListIsInstance(result)) { c: ConstructExpression -> + c.code == "()" } val literal1 = - findByUniquePredicate>(flattenListIsInstance(result)) { it.value == 1 } + findByUniquePredicate(flattenListIsInstance(result)) { l: Literal<*> -> l.value == 1 } assertEquals(4, template.parameters.size) assertEquals(paramA, template.parameters[2]) assertEquals(literal1, paramA.default) @@ -501,8 +498,6 @@ internal class ClassTemplateTest : BaseTest() { @Throws(Exception::class) fun testReferenceInTemplates() { // Test array.cpp: checks usage of referencetype of parameterized type (T[]) - TypeManager.reset() - val result = analyze(listOf(Path.of(topLevel.toString(), "array.cpp").toFile()), topLevel, true) val template = @@ -516,17 +511,19 @@ internal class ClassTemplateTest : BaseTest() { findByUniqueName(flattenListIsInstance(result), "typename T") val literal10 = findByUniquePredicate(flattenListIsInstance>(result)) { it.value == 10 } - val thisField = findByUniqueName(flattenListIsInstance(result), "this") val mArray = findByUniqueName(flattenListIsInstance(result), "m_Array") assertEquals(2, template.parameters.size) assertEquals(paramT, template.parameters[0]) assertEquals(paramN, template.parameters[1]) assertEquals(literal10, paramN.default) - assertEquals(2, array.fields.size) - assertEquals(thisField, array.fields[0]) - assertEquals(mArray, array.fields[1]) + assertEquals(1, array.fields.size) + assertEquals(mArray, array.fields[0]) - val arrayType = thisField.type as ObjectType + val receiver = array.byNameOrNull("GetSize")?.receiver + assertNotNull(receiver) + + val arrayType = ((receiver.type as? PointerType)?.elementType) as? ObjectType + assertNotNull(arrayType) assertEquals(1, arrayType.generics.size) assertEquals("T", arrayType.generics[0].name) @@ -556,8 +553,6 @@ internal class ClassTemplateTest : BaseTest() { @Throws(Exception::class) fun testTemplateInstantiationWithNew() { // Test array2.cpp: Test template usage with new keyword - TypeManager.reset() - val result = analyze(listOf(Path.of(topLevel.toString(), "array2.cpp").toFile()), topLevel, true) val template = diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VRUtil.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VRUtil.kt index a61991d9f0..8e36cd1561 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VRUtil.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VRUtil.kt @@ -70,8 +70,8 @@ object VRUtil { assertSame(usedNode, usingNode) } else { assertTrue(usingNode is DeclaredReferenceExpression) - val reference = usingNode as DeclaredReferenceExpression? - assertEquals(reference!!.refersTo, usedNode) + val reference = usingNode as? DeclaredReferenceExpression + assertEquals(reference?.refersTo, usedNode) } } diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VariableResolverCppTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VariableResolverCppTest.kt index 59f5a3da1b..5e762ade52 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VariableResolverCppTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VariableResolverCppTest.kt @@ -32,6 +32,7 @@ import de.fraunhofer.aisec.cpg.TestUtils.getSubnodeOfTypeWithName import de.fraunhofer.aisec.cpg.TranslationConfiguration import de.fraunhofer.aisec.cpg.TranslationManager.Companion.builder import de.fraunhofer.aisec.cpg.graph.Node +import de.fraunhofer.aisec.cpg.graph.byNameOrNull import de.fraunhofer.aisec.cpg.graph.declarations.* import de.fraunhofer.aisec.cpg.graph.statements.CatchClause import de.fraunhofer.aisec.cpg.graph.statements.CompoundStatement @@ -57,12 +58,10 @@ internal class VariableResolverCppTest : BaseTest() { private var outerClass: RecordDeclaration? = null private var outerVarName: FieldDeclaration? = null private var outerStaticVarName: FieldDeclaration? = null - private var outerImpThis: FieldDeclaration? = null + private var function2Receiver: VariableDeclaration? = null private var innerClass: RecordDeclaration? = null private var innerVarName: FieldDeclaration? = null private var innerStaticVarName: FieldDeclaration? = null - private var innerImpThis: FieldDeclaration? = null - private val innerImpOuter: FieldDeclaration? = null private var main: FunctionDeclaration? = null private var outerFunction1: MethodDeclaration? = null private var forStatements: List? = null @@ -77,7 +76,7 @@ internal class VariableResolverCppTest : BaseTest() { @Throws(ExecutionException::class, InterruptedException::class) fun initTests() { val topLevelPath = "src/test/resources/variables_extended/cpp/" - val fileNames = Arrays.asList("scope_variables.cpp", "external_class.cpp") + val fileNames = listOf("scope_variables.cpp", "external_class.cpp") val fileLocations = fileNames .stream() @@ -112,27 +111,9 @@ internal class VariableResolverCppTest : BaseTest() { externStaticVarName = getSubnodeOfTypeWithName(externalClass, FieldDeclaration::class.java, "staticVarName") outerClass = getOfTypeWithName(nodes, RecordDeclaration::class.java, "ScopeVariables") - outerVarName = - outerClass!! - .fields - .stream() - .filter { n: FieldDeclaration -> n.name == "varName" } - .findFirst() - .get() - outerStaticVarName = - outerClass!! - .fields - .stream() - .filter { n: FieldDeclaration -> n.name == "staticVarName" } - .findFirst() - .get() - outerImpThis = - outerClass!! - .fields - .stream() - .filter { n: FieldDeclaration -> n.name == "this" } - .findFirst() - .get() + outerVarName = outerClass!!.byNameOrNull("varName") + outerStaticVarName = outerClass!!.byNameOrNull("staticVarName") + function2Receiver = outerClass!!.byNameOrNull("function2")?.receiver val classes = Util.filterCast(nodes, RecordDeclaration::class.java) // Inner class and its fields @@ -152,13 +133,6 @@ internal class VariableResolverCppTest : BaseTest() { .filter { n: FieldDeclaration -> n.name == "staticVarName" } .findFirst() .get() - innerImpThis = - innerClass!! - .fields - .stream() - .filter { n: FieldDeclaration -> n.name == "this" } - .findFirst() - .get() main = getOfTypeWithName(nodes, FunctionDeclaration::class.java, "main") // Functions in the outer and inner object @@ -214,7 +188,7 @@ internal class VariableResolverCppTest : BaseTest() { } } - fun getCallWithReference(literal: String): DeclaredReferenceExpression? { + private fun getCallWithReference(literal: String): DeclaredReferenceExpression? { val exp = callParamMap[literal] return if (exp is DeclaredReferenceExpression) exp else null } @@ -277,7 +251,7 @@ internal class VariableResolverCppTest : BaseTest() { fun testMemberVarNameOverExplicitThis() { VRUtil.assertUsageOfMemberAndBase( callParamMap["func2_this_varName"], - outerImpThis, + function2Receiver, outerVarName ) } diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VariableResolverJavaTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VariableResolverJavaTest.kt index 71c3cb6c22..1639f14335 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VariableResolverJavaTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/variable_resolution/VariableResolverJavaTest.kt @@ -31,6 +31,7 @@ import de.fraunhofer.aisec.cpg.TestUtils.getOfTypeWithName import de.fraunhofer.aisec.cpg.TestUtils.getSubnodeOfTypeWithName import de.fraunhofer.aisec.cpg.TranslationConfiguration import de.fraunhofer.aisec.cpg.TranslationManager.Companion.builder +import de.fraunhofer.aisec.cpg.graph.byNameOrNull import de.fraunhofer.aisec.cpg.graph.declarations.* import de.fraunhofer.aisec.cpg.graph.statements.ForStatement import de.fraunhofer.aisec.cpg.graph.statements.expressions.* @@ -75,7 +76,7 @@ internal class VariableResolverJavaTest : BaseTest() { fun testImplicitThisVarNameAfterLoops() { VRUtil.assertUsageOfMemberAndBase( callParamMap["func1_imp_this_varName"], - outerImpThis, + outerClass, outerVarName ) } @@ -128,7 +129,7 @@ internal class VariableResolverJavaTest : BaseTest() { fun testVarNameOverImpThisInnerClass() { VRUtil.assertUsageOfMemberAndBase( callParamMap["func1_inner_imp_this_varName"], - innerImpThis, + function1Receiver, innerVarName ) } @@ -137,7 +138,7 @@ internal class VariableResolverJavaTest : BaseTest() { fun testVarNameInOuterFromInnerClass() { VRUtil.assertUsageOfMemberAndBase( callParamMap["func1_outer_this_varName"], - outerImpThis, + implicitOuterThis, outerVarName ) } @@ -167,7 +168,7 @@ internal class VariableResolverJavaTest : BaseTest() { fun testInnerVarnameOverExplicitThis() { VRUtil.assertUsageOfMemberAndBase( callParamMap["func2_inner_this_varName"], - innerImpThis, + function2Receiver, innerVarName ) } @@ -201,11 +202,12 @@ internal class VariableResolverJavaTest : BaseTest() { private var outerClass: RecordDeclaration? = null private var outerVarName: FieldDeclaration? = null private var outerStaticVarName: FieldDeclaration? = null - private var outerImpThis: FieldDeclaration? = null private var innerClass: RecordDeclaration? = null private var innerVarName: FieldDeclaration? = null private var innerStaticVarName: FieldDeclaration? = null - private var innerImpThis: FieldDeclaration? = null + private var implicitOuterThis: FieldDeclaration? = null + private var function1Receiver: VariableDeclaration? = null + private var function2Receiver: VariableDeclaration? = null private var innerImpOuter: FieldDeclaration? = null private var main: MethodDeclaration? = null private var outerFunction1: MethodDeclaration? = null @@ -285,13 +287,6 @@ internal class VariableResolverJavaTest : BaseTest() { .filter { n: FieldDeclaration -> n.name == "staticVarName" } .findFirst() .get() - outerImpThis = - outerClass!! - .fields - .stream() - .filter { n: FieldDeclaration -> n.name == "this" } - .findFirst() - .get() // Inner class and its fields innerClass = @@ -300,6 +295,10 @@ internal class VariableResolverJavaTest : BaseTest() { RecordDeclaration::class.java, "variables_extended.ScopeVariables.InnerClass" ) + implicitOuterThis = + innerClass?.fields?.firstOrNull { n: FieldDeclaration -> + n.name == "ScopeVariables.this" + } innerVarName = innerClass!! .fields @@ -309,8 +308,8 @@ internal class VariableResolverJavaTest : BaseTest() { .get() innerStaticVarName = getSubnodeOfTypeWithName(innerClass, FieldDeclaration::class.java, "staticVarName") - innerImpThis = - getSubnodeOfTypeWithName(innerClass, FieldDeclaration::class.java, "this") + function1Receiver = innerClass!!.byNameOrNull("function1")?.receiver + function2Receiver = innerClass!!.byNameOrNull("function2")?.receiver innerImpOuter = getSubnodeOfTypeWithName( innerClass, diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cpp/CXXLanguageFrontendTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cpp/CXXLanguageFrontendTest.kt index 988c966f13..52fdb213c2 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cpp/CXXLanguageFrontendTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cpp/CXXLanguageFrontendTest.kt @@ -50,13 +50,8 @@ import java.nio.file.Path import java.util.* import java.util.function.Consumer import java.util.stream.Collectors -import kotlin.collections.ArrayList -import kotlin.collections.HashMap -import kotlin.collections.List -import kotlin.collections.MutableMap import kotlin.collections.set import kotlin.test.* -import kotlin.test.Test internal class CXXLanguageFrontendTest : BaseTest() { @Test @@ -687,13 +682,13 @@ internal class CXXLanguageFrontendTest : BaseTest() { @Test @Throws(Exception::class) fun testRecordDeclaration() { - val file = File("src/test/resources/recordstmt.cpp") + val file = File("src/test/resources/cxx/recordstmt.cpp") val declaration = analyzeAndGetFirstTU(listOf(file), file.parentFile.toPath(), true) val recordDeclaration = declaration.getDeclarationAs(0, RecordDeclaration::class.java) assertNotNull(recordDeclaration) assertEquals("SomeClass", recordDeclaration.name) assertEquals("class", recordDeclaration.kind) - assertEquals(3, recordDeclaration.fields.size) + assertEquals(2, recordDeclaration.fields.size) val field = recordDeclaration.getField("field") assertNotNull(field) @@ -1015,7 +1010,9 @@ internal class CXXLanguageFrontendTest : BaseTest() { fun testLocalVariables() { val file = File("src/test/resources/variables/local_variables.cpp") val declaration = analyzeAndGetFirstTU(listOf(file), file.parentFile.toPath(), true) - val function = declaration.getDeclarationAs(2, FunctionDeclaration::class.java) + + val function = + declaration.byNameOrNull("testExpressionInExpressionList") assertEquals("testExpressionInExpressionList()int", function!!.signature) val locals = function.body.locals @@ -1026,10 +1023,6 @@ internal class CXXLanguageFrontendTest : BaseTest() { assertTrue(localNames.contains("t")) // ... and nothing else assertEquals(3, localNames.size) - - val clazz = declaration.getDeclarationAs(0, RecordDeclaration::class.java) - assertEquals("this", clazz!!.fields[0].name) - assertEquals(1, clazz.fields.size) } @Test @@ -1217,50 +1210,43 @@ internal class CXXLanguageFrontendTest : BaseTest() { @Test @Throws(Exception::class) - fun testCppThisField() { + fun testCppThis() { val file = File("src/test/resources/cpp-this-field.cpp") val tu = analyzeAndGetFirstTU(listOf(file), file.parentFile.toPath(), true) - val main = - tu.getDeclarationsByName("main", FunctionDeclaration::class.java).iterator().next() + val main = tu.byNameOrNull("main") assertNotNull(main) - val classT = tu.getDeclarationsByName("T", RecordDeclaration::class.java).iterator().next() + val classT = tu.byNameOrNull("T") assertNotNull(classT) - val classTFoo = classT.methods.iterator().next() + val classTFoo = classT.methods.firstOrNull() assertNotNull(classTFoo) - val classTThis = classT.getThis() - assertNotNull(classTThis) - - val classTReturn = classTFoo.getBodyStatementAs(0, ReturnStatement::class.java) + val classTReturn = classTFoo.bodyOrNull() assertNotNull(classTReturn) - val classTReturnMember = classTReturn.returnValue as MemberExpression + val classTReturnMember = classTReturn.returnValue as? MemberExpression assertNotNull(classTReturnMember) - val classTThisExpression = classTReturnMember.base as DeclaredReferenceExpression - assertEquals(classTThisExpression.refersTo, classTThis) + val classTThisExpression = classTReturnMember.base as? DeclaredReferenceExpression + assertEquals(classTThisExpression?.refersTo, classTFoo.receiver) - val classS = tu.getDeclarationsByName("S", RecordDeclaration::class.java).iterator().next() + val classS = tu.byNameOrNull("S") assertNotNull(classS) - val classSFoo = classS.methods.iterator().next() + val classSFoo = classS.methods.firstOrNull() assertNotNull(classSFoo) - val classSThis = classS.getThis() - assertNotNull(classSThis) - - val classSReturn = classSFoo.getBodyStatementAs(0, ReturnStatement::class.java) + val classSReturn = classSFoo.bodyOrNull() assertNotNull(classSReturn) - val classSReturnMember = classSReturn.returnValue as MemberExpression + val classSReturnMember = classSReturn.returnValue as? MemberExpression assertNotNull(classSReturnMember) - val classSThisExpression = classSReturnMember.base as DeclaredReferenceExpression - assertEquals(classSThisExpression.refersTo, classSThis) + val classSThisExpression = classSReturnMember.base as? DeclaredReferenceExpression + assertEquals(classSThisExpression?.refersTo, classSFoo.receiver) assertNotEquals(classTFoo, classSFoo) - assertNotEquals(classTThis, classSThis) + assertNotEquals(classTFoo.receiver, classSFoo.receiver) } @Test diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/java/JavaLanguageFrontendTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/java/JavaLanguageFrontendTest.kt index a9cdbc3408..9f23563910 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/java/JavaLanguageFrontendTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/java/JavaLanguageFrontendTest.kt @@ -263,18 +263,14 @@ internal class JavaLanguageFrontendTest : BaseTest() { val file = File("src/test/resources/compiling/RecordDeclaration.java") val declaration = analyzeAndGetFirstTU(listOf(file), file.parentFile.toPath(), true) assertNotNull(declaration) + val namespaceDeclaration = declaration.getDeclarationAs(0, NamespaceDeclaration::class.java) val recordDeclaration = namespaceDeclaration?.getDeclarationAs(0, RecordDeclaration::class.java) assertNotNull(recordDeclaration) - val fields = - recordDeclaration.fields - .stream() - .map(FieldDeclaration::name) - .collect(Collectors.toList()) - assertTrue(fields.contains("this")) + val fields = recordDeclaration.fields.map(FieldDeclaration::name) assertTrue(fields.contains("field")) val method = recordDeclaration.methods[0] @@ -533,9 +529,6 @@ internal class JavaLanguageFrontendTest : BaseTest() { assertNotNull(func) assertNotNull(func.receiver) - // make sure, that the type system correctly cleans up these duplicate types - assertSame(record.getThis()?.type, func.receiver?.type) - val nodes = SubgraphWalker.flattenAST(record) val request = nodes @@ -580,11 +573,11 @@ internal class JavaLanguageFrontendTest : BaseTest() { assertNotNull(op) val lhs = op.lhs as? MemberExpression - val superThisField = - (lhs?.base as? DeclaredReferenceExpression)?.refersTo as? FieldDeclaration? - assertNotNull(superThisField) - assertEquals("this", superThisField.name) - assertEquals(TypeParser.createFrom("my.Animal", false), superThisField.type) + val receiver = + (lhs?.base as? DeclaredReferenceExpression)?.refersTo as? VariableDeclaration? + assertNotNull(receiver) + assertEquals("this", receiver.name) + assertEquals(TypeParser.createFrom("my.Animal", false), receiver.type) } @Test diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalkerTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalkerTest.kt index 7f470b0a3d..4d1c61370d 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalkerTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalkerTest.kt @@ -52,8 +52,8 @@ internal class SubgraphWalkerTest : BaseTest() { val ast = recordDeclaration.astChildren assertFalse(ast.isEmpty()) - // should contain 4 AST nodes, 1 field (+1 this field), 1 method, 1 constructor - assertEquals(4, ast.size) + // should contain 3 AST nodes, 1 field, 1 method, 1 constructor + assertEquals(3, ast.size) } @Test diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/VariableResolverTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/VariableResolverTest.kt index ad751ced68..e04e8b38e7 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/VariableResolverTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/VariableResolverTest.kt @@ -35,7 +35,6 @@ import de.fraunhofer.aisec.cpg.graph.statements.ReturnStatement import de.fraunhofer.aisec.cpg.graph.statements.expressions.DeclaredReferenceExpression import de.fraunhofer.aisec.cpg.graph.statements.expressions.MemberExpression import java.nio.file.Path -import java.util.stream.Collectors import kotlin.test.* internal class VariableResolverTest : BaseTest() { @@ -88,37 +87,4 @@ internal class VariableResolverTest : BaseTest() { assertNotEquals(field, returnValue.refersTo) assertEquals(local, returnValue.refersTo) } - - @Test - @Throws(Exception::class) - fun testLocalVarsCpp() { - val tu = analyze("cpp", topLevel, true).firstOrNull() - assertNotNull(tu) - - val function = tu.getDeclarationAs(2, FunctionDeclaration::class.java) - assertEquals("testExpressionInExpressionList()int", function!!.signature) - - val locals = function.body.locals - - // Expecting x, foo, t - val localNames = - locals.stream().map { l: VariableDeclaration -> l.name }.collect(Collectors.toSet()) - assertTrue(localNames.contains("x")) - assertTrue(localNames.contains("foo")) - assertTrue(localNames.contains("t")) - // ... and nothing else - assertEquals(3, localNames.size) - - // Class "Test" has only one (virtual) field "this" - val clazz = tu.getDeclarationAs(0, RecordDeclaration::class.java) - for (f in clazz!!.fields) { - if (f == null) { - println("NULL") - continue - } - println(f.name + " " + f.initializer) - } - // FIXME Fails. Actually has "this", "a" and "foo" - assertEquals(1, clazz.fields.size) - } } diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/scopes/ScopeManagerTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/scopes/ScopeManagerTest.kt index a80c72076d..f5dea63f5f 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/scopes/ScopeManagerTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/passes/scopes/ScopeManagerTest.kt @@ -63,7 +63,7 @@ internal class ScopeManagerTest : BaseTest() { fun testReplaceNode() { val scopeManager = ScopeManager() val frontend = CXXLanguageFrontend(config, scopeManager) - val tu = frontend.parse(File("src/test/resources/recordstmt.cpp")) + val tu = frontend.parse(File("src/test/resources/cxx/recordstmt.cpp")) val methods = flattenListIsInstance(tu.declarations).filter { it !is ConstructorDeclaration diff --git a/cpg-core/src/test/resources/recordstmt.cpp b/cpg-core/src/test/resources/cxx/recordstmt.cpp similarity index 100% rename from cpg-core/src/test/resources/recordstmt.cpp rename to cpg-core/src/test/resources/cxx/recordstmt.cpp diff --git a/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/DeclarationHandler.kt b/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/DeclarationHandler.kt index dc1e74edd6..060feb9228 100644 --- a/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/DeclarationHandler.kt +++ b/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/DeclarationHandler.kt @@ -91,8 +91,7 @@ class DeclarationHandler(lang: TypeScriptLanguageFrontend) : } else { "class" }, - this.lang.getCodeFromRawNode(node), - false + this.lang.getCodeFromRawNode(node) ) this.lang.scopeManager.enterScope(record)