Skip to content

Commit

Permalink
Performance improvements for CXX frontend (#1363)
Browse files Browse the repository at this point in the history
* Performance improvements for CXX frontend

* Avoid using `rawSignature` directly when creating nodes (#1362)

Previously, in the CXX frontend, we were supplying the `rawSignature` as code(override) to almost all functions that created nodes. The issue with that is, that this does not respect the `codeInNodes` config option, which might be turned on to save memory.

This PR consequently uses the `rawNode` parameter, which forwards setting code and location to the language frontend, which DOES respect the `codeInNodes` option.

* Added complexity and mermaid chart

* More cleanup of old typedef remnants
  • Loading branch information
oxisto authored Nov 24, 2023
1 parent a67b5fa commit ebd0364
Show file tree
Hide file tree
Showing 14 changed files with 275 additions and 234 deletions.
36 changes: 20 additions & 16 deletions cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,6 @@ class ScopeManager : ScopeProvider {
*/
private val aliases = mutableMapOf<PhysicalLocation.ArtifactLocation, MutableSet<Alias>>()

/**
* The language frontend tied to the scope manager. Can be used to implement language specific
* scope resolution or lookup.
*/
var lang: LanguageFrontend<*, *>? = null

/** True, if the scope manager is currently in a [BlockScope]. */
val isInBlock: Boolean
get() = this.firstScopeOrNull { it is BlockScope } != null
Expand Down Expand Up @@ -568,10 +562,7 @@ class ScopeManager : ScopeProvider {
}
}

/**
* Only used by the [de.fraunhofer.aisec.cpg.graph.TypeManager], adds typedefs to the current
* [ValueDeclarationScope].
*/
/** Only used by the [TypeManager], adds typedefs to the current [ValueDeclarationScope]. */
fun addTypedef(typedef: TypedefDeclaration) {
val scope = this.firstScopeIsInstanceOrNull<ValueDeclarationScope>()
if (scope == null) {
Expand All @@ -580,12 +571,6 @@ class ScopeManager : ScopeProvider {
}

scope.addTypedef(typedef)

if (scope.astNode == null) {
lang?.currentTU?.addTypedef(typedef)
} else {
scope.astNode?.addTypedef(typedef)
}
}

private fun getCurrentTypedefs(searchScope: Scope?): Collection<TypedefDeclaration> {
Expand Down Expand Up @@ -878,6 +863,25 @@ class ScopeManager : ScopeProvider {
list += Alias(from, to)
}

fun typedefFor(alias: Type): Type? {
var current = currentScope

// We need to build a path from the current scope to the top most one. This ensures us that
// a local definition overwrites / shadows one that was there on a higher scope.
while (current != null) {
if (current is ValueDeclarationScope) {
val decl = current.typedefs[alias]
if (decl != null) {
return decl.type
}
}

current = current.parent
}

return null
}

/** Returns the current scope for the [ScopeProvider] interface. */
override val scope: Scope?
get() = currentScope
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,7 @@ class TypeManager {

fun resolvePossibleTypedef(alias: Type, scopeManager: ScopeManager): Type {
val finalToCheck = alias.root
val applicable =
scopeManager.currentTypedefs
.firstOrNull { t: TypedefDeclaration -> t.alias.root == finalToCheck }
?.type
val applicable = scopeManager.typedefFor(finalToCheck)
return applicable ?: alias
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,6 @@ abstract class LanguageFrontend<in AstNode, TypeNode>(
val typeManager: TypeManager = ctx.typeManager
val config: TranslationConfiguration = ctx.config

init {
this.scopeManager.lang = this
}

var currentTU: TranslationUnitDeclaration? = null

@Throws(TranslationException::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import de.fraunhofer.aisec.cpg.frontends.Language
import de.fraunhofer.aisec.cpg.graph.declarations.MethodDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration
import de.fraunhofer.aisec.cpg.graph.declarations.TypedefDeclaration
import de.fraunhofer.aisec.cpg.graph.edge.*
import de.fraunhofer.aisec.cpg.graph.edge.Properties
import de.fraunhofer.aisec.cpg.graph.scopes.GlobalScope
Expand Down Expand Up @@ -203,8 +202,6 @@ open class Node : IVisitable<Node>, Persistable, LanguageProvider, ScopeProvider
/** Virtual property for accessing the parents of the Program Dependence Graph (PDG). */
var prevPDG: MutableSet<Node> by PropertyEdgeSetDelegate(Node::prevPDGEdges, false)

var typedefs: MutableSet<TypedefDeclaration> = HashSet()

/**
* If a node is marked as being inferred, it means that it was created artificially and does not
* necessarily have a real counterpart in the scanned source code. However, the nodes
Expand Down Expand Up @@ -333,10 +330,6 @@ open class Node : IVisitable<Node>, Persistable, LanguageProvider, ScopeProvider
}
}

fun addTypedef(typedef: TypedefDeclaration) {
typedefs.add(typedef)
}

fun addAnnotations(annotations: Collection<Annotation>) {
this.annotations.addAll(annotations)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,21 @@ val Statement.cyclomaticComplexity: Int
// add one for each branch (and include the children)
stmt.caseExpression?.let { i += it.cyclomaticComplexity }
}
is DoStatement -> {
// add one for the do statement (and include the children)
i += (stmt.statement?.cyclomaticComplexity ?: 0) + 1
}
is WhileStatement -> {
// add one for the while statement (and include the children)
i += (stmt.statement?.cyclomaticComplexity ?: 0) + 1
}
is GotoStatement -> {
// add one
i++
}
is StatementHolder -> {
i += stmt.cyclomaticComplexity
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class DeclarationHandler(lang: CXXLanguageFrontend) :
* done yet.
*/
private fun handleUsingDirective(using: CPPASTUsingDirective): Declaration {
return newUsingDeclaration(using.rawSignature, using.qualifiedName.toString())
return newUsingDeclaration(qualifiedName = using.qualifiedName.toString(), rawNode = using)
}

/**
Expand Down Expand Up @@ -704,18 +704,15 @@ class DeclarationHandler(lang: CXXLanguageFrontend) :

fun handleTranslationUnit(translationUnit: IASTTranslationUnit): TranslationUnitDeclaration {
val node =
newTranslationUnitDeclaration(
translationUnit.filePath,
translationUnit.rawSignature,
translationUnit
)
newTranslationUnitDeclaration(translationUnit.filePath, rawNode = translationUnit)

// There might have been errors in the previous translation unit and in any case
// we need to reset the scope manager scope to global, to avoid spilling scope errors into
// other translation units
frontend.scopeManager.resetToGlobal(node)
frontend.currentTU = node
val problematicIncludes = HashMap<String?, HashSet<ProblemDeclaration>>()

for (declaration in translationUnit.declarations) {
if (declaration is CPPASTLinkageSpecification) {
continue // do not care about these for now
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) :
ctx.name.toString(),
unknownType(), // Type will be filled out later by
// handleSimpleDeclaration
ctx.rawSignature,
implicitInitializerAllowed,
implicitInitializerAllowed = implicitInitializerAllowed,
rawNode = ctx
)

// Add this declaration to the current scope
Expand All @@ -142,10 +142,10 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) :
name.localName,
unknownType(),
emptyList(),
ctx.rawSignature,
frontend.locationOf(ctx),
initializer,
true
location = frontend.locationOf(ctx),
initializer = initializer,
implicitInitializerAllowed = true,
rawNode = ctx
)

frontend.scopeManager.addDeclaration(declaration)
Expand Down Expand Up @@ -401,19 +401,24 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) :
val recordDeclaration = frontend.scopeManager.currentRecord
if (recordDeclaration == null) {
// variable
result = newVariableDeclaration(name, unknownType(), ctx.rawSignature, true)
result =
newVariableDeclaration(
name,
unknownType(),
implicitInitializerAllowed = true,
rawNode = ctx
)
} else {
// field
val code = ctx.rawSignature
result =
newFieldDeclaration(
name,
unknownType(),
emptyList(),
code,
frontend.locationOf(ctx),
null,
false,
location = frontend.locationOf(ctx),
initializer = null,
implicitInitializerAllowed = false,
rawNode = ctx
)
}

Expand All @@ -435,7 +440,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) :
newRecordDeclaration(
ctx.name.toString(),
kind,
ctx.rawSignature,
rawNode = ctx,
)

// Handle C++ classes
Expand Down Expand Up @@ -483,7 +488,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) :
private fun handleTemplateTypeParameter(
ctx: CPPASTSimpleTypeTemplateParameter
): TypeParameterDeclaration {
return newTypeParameterDeclaration(ctx.rawSignature, ctx.rawSignature, ctx)
return newTypeParameterDeclaration(ctx.rawSignature, rawNode = ctx)
}

private fun processMembers(ctx: IASTCompositeTypeSpecifier) {
Expand Down
Loading

0 comments on commit ebd0364

Please sign in to comment.