Skip to content

Commit

Permalink
Removing this field and moving all languages into the receiver lo…
Browse files Browse the repository at this point in the history
…gic (#835)
  • Loading branch information
oxisto authored Jul 20, 2022
1 parent 9f3ea99 commit daac296
Show file tree
Hide file tree
Showing 26 changed files with 389 additions and 414 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
}
}

Expand All @@ -405,6 +403,8 @@ class DeclarationHandler(lang: CXXLanguageFrontend) :
for (parameterizedType in parameterizedTypes) {
type.addGeneric(parameterizedType)
}
} else if (type is PointerType) {
addParameterizedTypesToType(type.elementType, parameterizedTypes)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(),
Expand All @@ -144,7 +152,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) :
true
)
} else {
NodeBuilder.newFieldDeclaration(
newFieldDeclaration(
name,
UnknownType.getUnknownType(),
emptyList(),
Expand All @@ -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...
Expand All @@ -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)
Expand All @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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."
)

Expand All @@ -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)
Expand All @@ -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
Expand All @@ -358,7 +404,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) :
fieldName = matcher.group("name").trim()
}
result =
NodeBuilder.newFieldDeclaration(
newFieldDeclaration(
fieldName,
UnknownType.getUnknownType(),
emptyList(),
Expand Down Expand Up @@ -388,7 +434,6 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) :
lang.scopeManager.currentNamePrefixWithDelimiter + ctx.name.toString(),
kind,
ctx.rawSignature,
true,
lang
)

Expand All @@ -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

Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
Loading

0 comments on commit daac296

Please sign in to comment.