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)