diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a1739e55ef..b5031ebacb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -132,7 +132,7 @@ jobs: - name: Prepare test and coverage reports if: ${{ always() }} run: | - zip reports.zip **/build/reports/** + zip reports.zip **/build/reports/**/** || true - name: Archive test and coverage reports if: ${{ always() }} uses: actions/upload-artifact@v3 diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt index 3507dd9f56..f1a6fed996 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt @@ -75,7 +75,7 @@ class ScopeManager : ScopeProvider { * The language frontend tied to the scope manager. Can be used to implement language specific * scope resolution or lookup. */ - var lang: LanguageFrontend? = null + var lang: LanguageFrontend<*, *>? = null /** True, if the scope manager is currently in a [BlockScope]. */ val isInBlock: Boolean diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationConfiguration.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationConfiguration.kt index a3f9f9135f..f421af0141 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationConfiguration.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationConfiguration.kt @@ -99,7 +99,7 @@ private constructor( */ val replacedPasses: Map>, KClass>>, KClass>>, - languages: List>, + languages: List>, codeInNodes: Boolean, processAnnotations: Boolean, disableCleanup: Boolean, @@ -112,7 +112,7 @@ private constructor( addIncludesToGraph: Boolean ) { /** This list contains all languages which we want to translate. */ - val languages: List> + val languages: List> /** * Switch off cleaning up TypeManager memory after analysis. @@ -215,7 +215,7 @@ private constructor( */ class Builder { private var softwareComponents: MutableMap> = HashMap() - private val languages = mutableListOf>() + private val languages = mutableListOf>() private var topLevel: File? = null private var debugParser = false private var failOnError = false @@ -405,7 +405,7 @@ private constructor( } /** Registers an additional [Language]. */ - fun registerLanguage(language: Language): Builder { + fun registerLanguage(language: Language<*>): Builder { languages.add(language) log.info( "Registered language frontend '${language::class.simpleName}' for following file types: ${language.fileExtensions}" @@ -414,7 +414,7 @@ private constructor( } /** Registers an additional [Language]. */ - inline fun > registerLanguage(): Builder { + inline fun > registerLanguage(): Builder { T::class.primaryConstructor?.call()?.let { registerLanguage(it) } return this } @@ -443,8 +443,8 @@ private constructor( } /** Unregisters a registered [de.fraunhofer.aisec.cpg.frontends.Language]. */ - fun unregisterLanguage(language: Class?>): Builder { - languages.removeIf { obj: Language? -> language.isInstance(obj) } + fun unregisterLanguage(language: Class?>): Builder { + languages.removeIf { obj: Language<*>? -> language.isInstance(obj) } return this } @@ -490,7 +490,7 @@ private constructor( return } - for (frontend in languages.map(Language::frontend)) { + for (frontend in languages.map(Language<*>::frontend)) { val extraPasses = frontend.findAnnotations() if (extraPasses.isNotEmpty()) { for (p in extraPasses) { @@ -505,7 +505,7 @@ private constructor( } private fun registerReplacedPasses() { - for (frontend in languages.map(Language::frontend)) { + for (frontend in languages.map(Language<*>::frontend)) { val replacedPasses = frontend.findAnnotations() if (replacedPasses.isNotEmpty()) { for (p in replacedPasses) { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationManager.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationManager.kt index bb5a52392a..da2eccc9cb 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationManager.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationManager.kt @@ -75,7 +75,7 @@ private constructor( } private fun analyzeNonAsync(): TranslationResult { - var executedFrontends = setOf() + var executedFrontends = setOf>() // Build a new global translation context val ctx = TranslationContext(config, ScopeManager(), TypeManager()) @@ -135,8 +135,8 @@ private constructor( private fun runFrontends( ctx: TranslationContext, result: TranslationResult - ): Set { - val usedFrontends = mutableSetOf() + ): Set> { + val usedFrontends = mutableSetOf>() for (sc in ctx.config.softwareComponents.keys) { val component = Component() component.name = Name(sc) @@ -252,14 +252,14 @@ private constructor( result: TranslationResult, globalCtx: TranslationContext, sourceLocations: Collection - ): Set { - val usedFrontends = mutableSetOf() + ): Set> { + val usedFrontends = mutableSetOf>() log.info("Parallel parsing started") - val futures = mutableListOf>>() + val futures = mutableListOf?>>() val parallelContexts = mutableListOf() - val futureToFile: MutableMap>, File> = + val futureToFile: MutableMap?>, File> = IdentityHashMap() for (sourceLocation in sourceLocations) { @@ -284,7 +284,8 @@ private constructor( for (future in futures) { try { - future.get().ifPresent { f: LanguageFrontend -> + val f = future.get() + if (f != null) { handleCompletion(result, usedFrontends, futureToFile[future], f) } } catch (e: InterruptedException) { @@ -310,13 +311,14 @@ private constructor( result: TranslationResult, ctx: TranslationContext, sourceLocations: Collection - ): Set { - val usedFrontends = mutableSetOf() + ): Set> { + val usedFrontends = mutableSetOf>() for (sourceLocation in sourceLocations) { log.info("Parsing {}", sourceLocation.absolutePath) - parse(component, ctx, sourceLocation).ifPresent { f: LanguageFrontend -> + var f = parse(component, ctx, sourceLocation) + if (f != null) { handleCompletion(result, usedFrontends, sourceLocation, f) } } @@ -326,9 +328,9 @@ private constructor( private fun handleCompletion( result: TranslationResult, - usedFrontends: MutableSet, + usedFrontends: MutableSet>, sourceLocation: File?, - f: LanguageFrontend + f: LanguageFrontend<*, *> ) { usedFrontends.add(f) @@ -345,8 +347,8 @@ private constructor( component: Component, ctx: TranslationContext, sourceLocation: File, - ): Optional { - var frontend: LanguageFrontend? = null + ): LanguageFrontend<*, *>? { + var frontend: LanguageFrontend<*, *>? = null try { frontend = getFrontend(sourceLocation, ctx) @@ -358,7 +360,7 @@ private constructor( "Found no parser frontend for ${sourceLocation.name}" ) } - return Optional.empty() + return null } component.translationUnits.add(frontend.parse(sourceLocation)) } catch (ex: TranslationException) { @@ -367,10 +369,10 @@ private constructor( throw ex } } - return Optional.ofNullable(frontend) + return frontend } - private fun getFrontend(file: File, ctx: TranslationContext): LanguageFrontend? { + private fun getFrontend(file: File, ctx: TranslationContext): LanguageFrontend<*, *>? { val language = file.language return if (language != null) { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Handler.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Handler.kt index c5857a75cc..ea90d57954 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Handler.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Handler.kt @@ -25,14 +25,11 @@ */ package de.fraunhofer.aisec.cpg.frontends -import de.fraunhofer.aisec.cpg.TranslationContext import de.fraunhofer.aisec.cpg.graph.* -import de.fraunhofer.aisec.cpg.graph.scopes.Scope import de.fraunhofer.aisec.cpg.helpers.Util.errorWithFileLocation import java.lang.reflect.ParameterizedType import java.lang.reflect.Type import java.util.function.Supplier -import org.eclipse.cdt.internal.core.dom.parser.ASTNode import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -47,24 +44,29 @@ import org.slf4j.LoggerFactory * @param the raw ast node specific to the parser * @param the language frontend */ -abstract class Handler( - protected val configConstructor: Supplier, +abstract class Handler>( + protected val configConstructor: Supplier, /** Returns the frontend which used this handler. */ - var frontend: L -) : LanguageProvider, CodeAndLocationProvider, ScopeProvider, NamespaceProvider, ContextProvider { - protected val map = HashMap, HandlerInterface>() + val frontend: L +) : + LanguageProvider by frontend, + CodeAndLocationProvider by frontend, + ScopeProvider by frontend, + NamespaceProvider by frontend, + ContextProvider by frontend { + protected val map = HashMap, HandlerInterface>() private val typeOfT: Class<*>? /** - * Searches for a handler matching the most specific superclass of [T]. The created map should - * thus contain a handler for every semantically different AST node and can reuse handler code - * as long as the handled AST nodes have a common ancestor. + * Searches for a handler matching the most specific superclass of [HandlerNode]. The created + * map should thus contain a handler for every semantically different AST node and can reuse + * handler code as long as the handled AST nodes have a common ancestor. * * @param ctx The AST node, whose handler is matched with respect to the AST node class. * @return most specific handler. */ - open fun handle(ctx: T): S? { - var ret: S? + open fun handle(ctx: HandlerNode): ResultNode? { + var ret: ResultNode? if (ctx == null) { log.error( "ctx is NULL. This can happen when ast children are optional in ${this.javaClass}. Called by ${Thread.currentThread().stackTrace[2]}" @@ -72,17 +74,6 @@ abstract class Handler( return null } - // If we do not want to load includes into the CPG and the current fileLocation was included - if (!frontend.config.loadIncludes && ctx is ASTNode) { - val astNode = ctx as ASTNode - if ( - astNode.fileLocation != null && - astNode.fileLocation.contextInclusionStatement != null - ) { - log.debug("Skip parsing include file ${astNode.containingFilename}") - return null - } - } var toHandle: Class<*> = ctx.javaClass var handler = map[toHandle] while (handler == null) { @@ -92,7 +83,7 @@ abstract class Handler( handler != null && // always ok to handle as generic literal expr !ctx.javaClass.simpleName.contains("LiteralExpr") ) { - errorWithFileLocation( + errorWithFileLocation( frontend, ctx, log, @@ -110,13 +101,13 @@ abstract class Handler( // we will // set the location here. if (s.location == null) { - frontend.setCodeAndLocation(s, ctx) + frontend.setCodeAndLocation(s, ctx) } - frontend.setComment(s, ctx) + frontend.setComment(s, ctx) } ret = s } else { - errorWithFileLocation( + errorWithFileLocation( frontend, ctx, log, @@ -132,7 +123,7 @@ abstract class Handler( // In case the node is empty, we report a problem if (ret == null) { - errorWithFileLocation( + errorWithFileLocation( frontend, ctx, log, @@ -167,23 +158,6 @@ abstract class Handler( return null } - /** Returns the language which this handler is parsing. */ - override val language: Language - get() = frontend.language as Language - - override fun setCodeAndLocation(cpgNode: N, astNode: S?) { - frontend.setCodeAndLocation(cpgNode, astNode) - } - - override val scope: Scope? - get() = frontend.scope - - override val namespace: Name? - get() = frontend.namespace - - override val ctx: TranslationContext - get() = frontend.ctx - companion object { @JvmStatic protected val log: Logger = LoggerFactory.getLogger(Handler::class.java) } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Language.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Language.kt index c332229432..8fef40a6fc 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Language.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Language.kt @@ -48,7 +48,7 @@ import kotlin.reflect.full.primaryConstructor * persisted in the final graph (database) and each node links to its corresponding language using * the [Node.language] property. */ -abstract class Language : Node() { +abstract class Language> : Node() { /** The file extensions without the dot */ abstract val fileExtensions: List diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageFrontend.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageFrontend.kt index 383462388f..d1e8e12453 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageFrontend.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageFrontend.kt @@ -32,6 +32,7 @@ import de.fraunhofer.aisec.cpg.TranslationResult import de.fraunhofer.aisec.cpg.graph.* import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration import de.fraunhofer.aisec.cpg.graph.scopes.Scope +import de.fraunhofer.aisec.cpg.graph.types.Type import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation import de.fraunhofer.aisec.cpg.sarif.Region import java.io.File @@ -47,9 +48,9 @@ import org.slf4j.LoggerFactory * More information can be found in the * [github wiki page](https://github.com/Fraunhofer-AISEC/cpg/wiki/Language-Frontends). */ -abstract class LanguageFrontend( +abstract class LanguageFrontend( /** The language this frontend works for. */ - override val language: Language, + override val language: Language>, /** * The translation context, which contains all necessary managers used in this frontend parsing @@ -59,7 +60,7 @@ abstract class LanguageFrontend( final override var ctx: TranslationContext, ) : ProcessedListener(), - CodeAndLocationProvider, + CodeAndLocationProvider, LanguageProvider, ScopeProvider, NamespaceProvider, @@ -91,10 +92,22 @@ abstract class LanguageFrontend( * This function returns a [TranslationResult], but rather than parsing source code, the * function [init] is used to build nodes in the Node Fluent DSL. */ - fun build(init: LanguageFrontend.() -> TranslationResult): TranslationResult { + fun build(init: LanguageFrontend<*, *>.() -> TranslationResult): TranslationResult { return init(this) } + /** + * This function serves as an entry-point to type parsing in the language frontend. It needs to + * return a [Type] object based on the ast type object used by the language frontend, e.g., the + * parser. + * + * A language frontend will usually de-construct the ast type object, e.g., in case of pointer + * or array types and then either recursively call this function or call other helper functions + * similar to this one. Ideally, they should share the [typeOf] name, but have different method + * signatures. + */ + abstract fun typeOf(type: TypeNode): Type + /** * Returns the raw code of the ast node, generic for java or c++ ast nodes. * @@ -102,7 +115,7 @@ abstract class LanguageFrontend( * @param astNode the ast node * @return the source code */ - abstract fun getCodeFromRawNode(astNode: T): String? + abstract fun codeOf(astNode: AstNode): String? /** * Returns the [Region] of the code with line and column, index starting at 1, generic for java @@ -112,21 +125,19 @@ abstract class LanguageFrontend( * @param astNode the ast node * @return the location */ - abstract fun getLocationFromRawNode(astNode: T): PhysicalLocation? - - override fun setCodeAndLocation(cpgNode: N, astNode: S?) { - if (cpgNode is Node && astNode != null) { - if (config.codeInNodes) { - // only set code, if it's not already set or empty - val code = getCodeFromRawNode(astNode) - if (code != null) { - (cpgNode as Node).code = code - } else { - log.warn("Unexpected: No code for node {}", astNode) - } + abstract fun locationOf(astNode: AstNode): PhysicalLocation? + + override fun setCodeAndLocation(cpgNode: Node, astNode: AstNode) { + if (config.codeInNodes) { + // only set code, if it's not already set or empty + val code = codeOf(astNode) + if (code != null) { + cpgNode.code = code + } else { + log.warn("Unexpected: No code for node {}", astNode) } - (cpgNode as Node).location = getLocationFromRawNode(astNode) } + cpgNode.location = locationOf(astNode) } /** @@ -225,7 +236,7 @@ abstract class LanguageFrontend( clearProcessed() } - abstract fun setComment(s: S, ctx: T) + abstract fun setComment(node: Node, astNode: AstNode) companion object { // Allow non-Java frontends to access the logger (i.e. jep) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Name.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Name.kt index cb8aa9717d..2e2d52b496 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Name.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Name.kt @@ -46,7 +46,7 @@ class Name( constructor( localName: String, parent: Name? = null, - language: Language? + language: Language<*>? ) : this(localName, parent, language?.namespaceDelimiter ?: ".") /** diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt index 2b35842570..7089f436fd 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt @@ -31,7 +31,6 @@ import de.fraunhofer.aisec.cpg.PopulatedByPass import de.fraunhofer.aisec.cpg.TranslationContext import de.fraunhofer.aisec.cpg.frontends.Handler import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.graph.declarations.MethodDeclaration import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration @@ -89,7 +88,7 @@ open class Node : IVisitable, Persistable, LanguageProvider, ScopeProvider */ @Relationship(value = "LANGUAGE", direction = Relationship.Direction.OUTGOING) @JsonBackReference - override var language: Language? = null + override var language: Language<*>? = null /** * The scope this node "lives" in / in which it is defined. This property is set in diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt index 5d947622fa..6d05808cf4 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt @@ -56,15 +56,15 @@ interface MetadataProvider * each [Node], but also transformation steps, such as [Handler]. */ interface LanguageProvider : MetadataProvider { - val language: Language? + val language: Language<*>? } /** * This interface denotes that the class is able to provide source code and location information for * a specific node and set it using the [setCodeAndLocation] function. */ -interface CodeAndLocationProvider : MetadataProvider { - fun setCodeAndLocation(cpgNode: N, astNode: S?) +interface CodeAndLocationProvider : MetadataProvider { + fun setCodeAndLocation(cpgNode: Node, astNode: AstNode) } /** @@ -103,8 +103,8 @@ fun Node.applyMetadata( localNameOnly: Boolean = false, defaultNamespace: Name? = null, ) { - if (provider is CodeAndLocationProvider) { - provider.setCodeAndLocation(this, rawNode) + if (provider is CodeAndLocationProvider<*> && rawNode != null) { + (provider as CodeAndLocationProvider).setCodeAndLocation(this, rawNode) } if (provider is LanguageProvider) { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/builder/Fluent.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/builder/Fluent.kt index 631d5319ad..5f42bdb53b 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/builder/Fluent.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/builder/Fluent.kt @@ -35,7 +35,9 @@ import de.fraunhofer.aisec.cpg.graph.statements.expressions.* import de.fraunhofer.aisec.cpg.graph.types.Type import de.fraunhofer.aisec.cpg.passes.executePassSequential -fun LanguageFrontend.translationResult(init: TranslationResult.() -> Unit): TranslationResult { +fun LanguageFrontend<*, *>.translationResult( + init: TranslationResult.() -> Unit +): TranslationResult { val node = TranslationResult( TranslationManager.builder().config(ctx.config).build(), @@ -57,7 +59,7 @@ fun LanguageFrontend.translationResult(init: TranslationResult.() -> Unit): Tran */ context(TranslationResult) -fun LanguageFrontend.translationUnit( +fun LanguageFrontend<*, *>.translationUnit( name: CharSequence = Node.EMPTY_NAME, init: TranslationUnitDeclaration.() -> Unit ): TranslationUnitDeclaration { @@ -77,7 +79,7 @@ fun LanguageFrontend.translationUnit( */ context(DeclarationHolder) -fun LanguageFrontend.namespace( +fun LanguageFrontend<*, *>.namespace( name: CharSequence, init: NamespaceDeclaration.() -> Unit ): NamespaceDeclaration { @@ -97,7 +99,7 @@ fun LanguageFrontend.namespace( */ context(DeclarationHolder) -fun LanguageFrontend.record( +fun LanguageFrontend<*, *>.record( name: CharSequence, kind: String = "class", init: RecordDeclaration.() -> Unit @@ -119,7 +121,7 @@ fun LanguageFrontend.record( */ context(DeclarationHolder) -fun LanguageFrontend.field( +fun LanguageFrontend<*, *>.field( name: CharSequence, type: Type = newUnknownType(), init: FieldDeclaration.() -> Unit @@ -141,7 +143,7 @@ fun LanguageFrontend.field( */ context(DeclarationHolder) -fun LanguageFrontend.function( +fun LanguageFrontend<*, *>.function( name: CharSequence, returnType: Type = newUnknownType(), returnTypes: List? = null, @@ -171,7 +173,7 @@ fun LanguageFrontend.function( */ context(RecordDeclaration) -fun LanguageFrontend.method( +fun LanguageFrontend<*, *>.method( name: CharSequence, returnType: Type = newUnknownType(), init: MethodDeclaration.() -> Unit @@ -196,7 +198,9 @@ fun LanguageFrontend.method( */ context(RecordDeclaration) -fun LanguageFrontend.constructor(init: ConstructorDeclaration.() -> Unit): ConstructorDeclaration { +fun LanguageFrontend<*, *>.constructor( + init: ConstructorDeclaration.() -> Unit +): ConstructorDeclaration { val recordDecl: RecordDeclaration = this@RecordDeclaration val node = newConstructorDeclaration(recordDecl.name, recordDeclaration = recordDecl) @@ -217,7 +221,7 @@ fun LanguageFrontend.constructor(init: ConstructorDeclaration.() -> Unit): Const */ context(FunctionDeclaration) -fun LanguageFrontend.body( +fun LanguageFrontend<*, *>.body( needsScope: Boolean = true, init: CompoundStatement.() -> Unit ): CompoundStatement { @@ -236,7 +240,7 @@ fun LanguageFrontend.body( */ context(FunctionDeclaration) -fun LanguageFrontend.param( +fun LanguageFrontend<*, *>.param( name: CharSequence, type: Type = newUnknownType(), init: (ParamVariableDeclaration.() -> Unit)? = null @@ -260,7 +264,7 @@ fun LanguageFrontend.param( */ context(StatementHolder) -fun LanguageFrontend.returnStmt(init: ReturnStatement.() -> Unit): ReturnStatement { +fun LanguageFrontend<*, *>.returnStmt(init: ReturnStatement.() -> Unit): ReturnStatement { val node = (this@LanguageFrontend).newReturnStatement() init(node) @@ -276,7 +280,7 @@ fun LanguageFrontend.returnStmt(init: ReturnStatement.() -> Unit): ReturnStateme */ context(StatementHolder) -fun LanguageFrontend.declare(init: DeclarationStatement.() -> Unit): DeclarationStatement { +fun LanguageFrontend<*, *>.declare(init: DeclarationStatement.() -> Unit): DeclarationStatement { val node = (this@LanguageFrontend).newDeclarationStatement() init(node) @@ -292,7 +296,7 @@ fun LanguageFrontend.declare(init: DeclarationStatement.() -> Unit): Declaration */ context(DeclarationStatement) -fun LanguageFrontend.variable( +fun LanguageFrontend<*, *>.variable( name: String, type: Type = newUnknownType(), init: (VariableDeclaration.() -> Unit)? = null @@ -321,7 +325,7 @@ fun LanguageFrontend.variable( */ context(Holder) -fun LanguageFrontend.call( +fun LanguageFrontend<*, *>.call( name: CharSequence, isStatic: Boolean = false, init: (CallExpression.() -> Unit)? = null @@ -364,7 +368,7 @@ fun LanguageFrontend.call( */ context(Holder) -fun LanguageFrontend.memberCall( +fun LanguageFrontend<*, *>.memberCall( localName: CharSequence, member: Expression, isStatic: Boolean = false, @@ -395,7 +399,7 @@ fun LanguageFrontend.memberCall( */ context(Holder) -fun LanguageFrontend.construct( +fun LanguageFrontend<*, *>.construct( name: CharSequence, init: (ConstructExpression.() -> Unit)? = null ): ConstructExpression { @@ -418,7 +422,7 @@ fun LanguageFrontend.construct( context(Holder) -fun LanguageFrontend.new(init: (NewExpression.() -> Unit)? = null): NewExpression { +fun LanguageFrontend<*, *>.new(init: (NewExpression.() -> Unit)? = null): NewExpression { val node = newNewExpression() if (init != null) init(node) @@ -431,7 +435,7 @@ fun LanguageFrontend.new(init: (NewExpression.() -> Unit)? = null): NewExpressio return node } -fun LanguageFrontend.memberOrRef(name: Name, type: Type = newUnknownType()): Expression { +fun LanguageFrontend<*, *>.memberOrRef(name: Name, type: Type = newUnknownType()): Expression { val node = if (name.parent != null) { newMemberExpression(name.localName, memberOrRef(name.parent)) @@ -450,7 +454,7 @@ fun LanguageFrontend.memberOrRef(name: Name, type: Type = newUnknownType()): Exp */ context(StatementHolder) -fun LanguageFrontend.ifStmt(init: IfStatement.() -> Unit): IfStatement { +fun LanguageFrontend<*, *>.ifStmt(init: IfStatement.() -> Unit): IfStatement { val node = newIfStatement() init(node) @@ -466,7 +470,7 @@ fun LanguageFrontend.ifStmt(init: IfStatement.() -> Unit): IfStatement { */ context(StatementHolder) -fun LanguageFrontend.forEachStmt(init: ForEachStatement.() -> Unit): ForEachStatement { +fun LanguageFrontend<*, *>.forEachStmt(init: ForEachStatement.() -> Unit): ForEachStatement { val node = newForEachStatement() init(node) @@ -483,7 +487,7 @@ fun LanguageFrontend.forEachStmt(init: ForEachStatement.() -> Unit): ForEachStat */ context(StatementHolder) -fun LanguageFrontend.switchStmt( +fun LanguageFrontend<*, *>.switchStmt( selector: Expression, needsScope: Boolean = true, init: SwitchStatement.() -> Unit @@ -504,7 +508,7 @@ fun LanguageFrontend.switchStmt( */ context(StatementHolder) -fun LanguageFrontend.whileStmt( +fun LanguageFrontend<*, *>.whileStmt( needsScope: Boolean = true, init: WhileStatement.() -> Unit ): WhileStatement { @@ -525,7 +529,7 @@ fun LanguageFrontend.whileStmt( */ context(IfStatement) -fun LanguageFrontend.condition(init: IfStatement.() -> BinaryOperator): BinaryOperator { +fun LanguageFrontend<*, *>.condition(init: IfStatement.() -> BinaryOperator): BinaryOperator { return init(this@IfStatement) } @@ -536,7 +540,9 @@ fun LanguageFrontend.condition(init: IfStatement.() -> BinaryOperator): BinaryOp */ context(WhileStatement) -fun LanguageFrontend.whileCondition(init: WhileStatement.() -> BinaryOperator): BinaryOperator { +fun LanguageFrontend<*, *>.whileCondition( + init: WhileStatement.() -> BinaryOperator +): BinaryOperator { return init(this@WhileStatement) } @@ -547,7 +553,7 @@ fun LanguageFrontend.whileCondition(init: WhileStatement.() -> BinaryOperator): */ context(IfStatement) -fun LanguageFrontend.thenStmt( +fun LanguageFrontend<*, *>.thenStmt( needsScope: Boolean = true, init: CompoundStatement.() -> Unit ): CompoundStatement { @@ -566,7 +572,7 @@ fun LanguageFrontend.thenStmt( */ context(IfStatement) -fun LanguageFrontend.elseIf(init: IfStatement.() -> Unit): IfStatement { +fun LanguageFrontend<*, *>.elseIf(init: IfStatement.() -> Unit): IfStatement { val node = newIfStatement() init(node) @@ -584,7 +590,7 @@ fun LanguageFrontend.elseIf(init: IfStatement.() -> Unit): IfStatement { */ context(WhileStatement) -fun LanguageFrontend.loopBody(init: CompoundStatement.() -> Unit): CompoundStatement { +fun LanguageFrontend<*, *>.loopBody(init: CompoundStatement.() -> Unit): CompoundStatement { val node = newCompoundStatement() init(node) statement = node @@ -598,7 +604,7 @@ fun LanguageFrontend.loopBody(init: CompoundStatement.() -> Unit): CompoundState */ context(ForEachStatement) -fun LanguageFrontend.loopBody(init: CompoundStatement.() -> Unit): CompoundStatement { +fun LanguageFrontend<*, *>.loopBody(init: CompoundStatement.() -> Unit): CompoundStatement { val node = newCompoundStatement() init(node) statement = node @@ -613,7 +619,7 @@ fun LanguageFrontend.loopBody(init: CompoundStatement.() -> Unit): CompoundState */ context(SwitchStatement) -fun LanguageFrontend.switchBody(init: CompoundStatement.() -> Unit): CompoundStatement { +fun LanguageFrontend<*, *>.switchBody(init: CompoundStatement.() -> Unit): CompoundStatement { val node = newCompoundStatement() init(node) statement = node @@ -628,7 +634,7 @@ fun LanguageFrontend.switchBody(init: CompoundStatement.() -> Unit): CompoundSta */ context(IfStatement) -fun LanguageFrontend.elseStmt( +fun LanguageFrontend<*, *>.elseStmt( needsScope: Boolean = true, init: CompoundStatement.() -> Unit ): CompoundStatement { @@ -646,7 +652,7 @@ fun LanguageFrontend.elseStmt( */ context(Holder) -fun LanguageFrontend.label( +fun LanguageFrontend<*, *>.label( label: String, init: (LabelStatement.() -> Statement)? = null ): LabelStatement { @@ -671,7 +677,7 @@ fun LanguageFrontend.label( */ context(StatementHolder) -fun LanguageFrontend.continueStmt(label: String? = null): ContinueStatement { +fun LanguageFrontend<*, *>.continueStmt(label: String? = null): ContinueStatement { val node = newContinueStatement() node.label = label @@ -686,7 +692,7 @@ fun LanguageFrontend.continueStmt(label: String? = null): ContinueStatement { */ context(Holder) -fun LanguageFrontend.breakStmt(label: String? = null): BreakStatement { +fun LanguageFrontend<*, *>.breakStmt(label: String? = null): BreakStatement { val node = newBreakStatement() node.label = label @@ -705,7 +711,7 @@ fun LanguageFrontend.breakStmt(label: String? = null): BreakStatement { */ context(Holder) -fun LanguageFrontend.case(caseExpr: Expression? = null): CaseStatement { +fun LanguageFrontend<*, *>.case(caseExpr: Expression? = null): CaseStatement { val node = newCaseStatement() node.caseExpression = caseExpr @@ -724,7 +730,7 @@ fun LanguageFrontend.case(caseExpr: Expression? = null): CaseStatement { */ context(Holder) -fun LanguageFrontend.default(): DefaultStatement { +fun LanguageFrontend<*, *>.default(): DefaultStatement { val node = newDefaultStatement() // Only add this to a statement holder if the nearest holder is a statement holder @@ -742,7 +748,7 @@ fun LanguageFrontend.default(): DefaultStatement { */ context(Holder) -fun LanguageFrontend.literal(value: N, type: Type = newUnknownType()): Literal { +fun LanguageFrontend<*, *>.literal(value: N, type: Type = newUnknownType()): Literal { val node = newLiteral(value, type) // Only add this to an argument holder if the nearest holder is an argument holder @@ -761,7 +767,7 @@ fun LanguageFrontend.literal(value: N, type: Type = newUnknownType()): Liter */ context(Holder) -fun LanguageFrontend.ref( +fun LanguageFrontend<*, *>.ref( name: CharSequence, type: Type = newUnknownType(), init: (DeclaredReferenceExpression.() -> Unit)? = null @@ -789,7 +795,7 @@ fun LanguageFrontend.ref( */ context(Holder) -fun LanguageFrontend.member( +fun LanguageFrontend<*, *>.member( name: CharSequence, base: Expression? = null, operatorCode: String = "." @@ -823,7 +829,7 @@ fun LanguageFrontend.member( * Creates a new [BinaryOperator] with a `*` [BinaryOperator.operatorCode] in the Fluent Node DSL * and invokes [ArgumentHolder.addArgument] of the nearest enclosing [ArgumentHolder]. */ -context(LanguageFrontend, ArgumentHolder) +context(LanguageFrontend<*, *>, ArgumentHolder) operator fun Expression.times(rhs: Expression): BinaryOperator { val node = (this@LanguageFrontend).newBinaryOperator("*") @@ -845,7 +851,7 @@ operator fun Expression.times(rhs: Expression): BinaryOperator { * Creates a new [BinaryOperator] with a `+` [BinaryOperator.operatorCode] in the Fluent Node DSL * and invokes [ArgumentHolder.addArgument] of the nearest enclosing [ArgumentHolder]. */ -context(LanguageFrontend, ArgumentHolder) +context(LanguageFrontend<*, *>, ArgumentHolder) operator fun Expression.plus(rhs: Expression): BinaryOperator { val node = (this@LanguageFrontend).newBinaryOperator("+") @@ -867,7 +873,7 @@ operator fun Expression.plus(rhs: Expression): BinaryOperator { * Creates a new [BinaryOperator] with a `+` [BinaryOperator.operatorCode] in the Fluent Node DSL * and invokes [StatementHolder.addStatement] of the nearest enclosing [StatementHolder]. */ -context(LanguageFrontend, StatementHolder) +context(LanguageFrontend<*, *>, StatementHolder) operator fun Expression.plusAssign(rhs: Expression): Unit { val node = (this@LanguageFrontend).newBinaryOperator("+=") @@ -881,7 +887,7 @@ operator fun Expression.plusAssign(rhs: Expression): Unit { * Creates a new [BinaryOperator] with a `+` [BinaryOperator.operatorCode] in the Fluent Node DSL * and invokes [ArgumentHolder.addArgument] of the nearest enclosing [ArgumentHolder]. */ -context(LanguageFrontend, ArgumentHolder) +context(LanguageFrontend<*, *>, ArgumentHolder) operator fun Expression.rem(rhs: Expression): BinaryOperator { val node = (this@LanguageFrontend).newBinaryOperator("%") @@ -903,7 +909,7 @@ operator fun Expression.rem(rhs: Expression): BinaryOperator { * Creates a new [BinaryOperator] with a `-` [BinaryOperator.operatorCode] in the Fluent Node DSL * and invokes [ArgumentHolder.addArgument] of the nearest enclosing [ArgumentHolder]. */ -context(LanguageFrontend, ArgumentHolder) +context(LanguageFrontend<*, *>, ArgumentHolder) operator fun Expression.minus(rhs: Expression): BinaryOperator { val node = (this@LanguageFrontend).newBinaryOperator("-") @@ -919,7 +925,7 @@ operator fun Expression.minus(rhs: Expression): BinaryOperator { * Creates a new [UnaryOperator] with a `&` [UnaryOperator.operatorCode] in the Fluent Node DSL and * invokes [ArgumentHolder.addArgument] of the nearest enclosing [ArgumentHolder]. */ -context(LanguageFrontend, ArgumentHolder) +context(LanguageFrontend<*, *>, ArgumentHolder) fun reference(input: Expression): UnaryOperator { val node = (this@LanguageFrontend).newUnaryOperator("&", false, false) @@ -934,7 +940,7 @@ fun reference(input: Expression): UnaryOperator { * Creates a new [UnaryOperator] with a `--` [UnaryOperator.operatorCode] in the Fluent Node DSL and * invokes [StatementHolder.addStatement] of the nearest enclosing [StatementHolder]. */ -context(LanguageFrontend, Holder) +context(LanguageFrontend<*, *>, Holder) operator fun Expression.dec(): UnaryOperator { val node = (this@LanguageFrontend).newUnaryOperator("--", true, false) @@ -951,7 +957,7 @@ operator fun Expression.dec(): UnaryOperator { * Creates a new [UnaryOperator] with a `++` [UnaryOperator.operatorCode] in the Fluent Node DSL and * invokes [ArgumentHolder.addArgument] of the nearest enclosing [ArgumentHolder]. */ -context(LanguageFrontend, Holder) +context(LanguageFrontend<*, *>, Holder) operator fun Expression.inc(): UnaryOperator { val node = (this@LanguageFrontend).newUnaryOperator("++", true, false) @@ -968,7 +974,7 @@ operator fun Expression.inc(): UnaryOperator { * Creates a new [BinaryOperator] with a `==` [BinaryOperator.operatorCode] in the Fluent Node DSL * and invokes [ArgumentHolder.addArgument] of the nearest enclosing [ArgumentHolder]. */ -context(LanguageFrontend, ArgumentHolder) +context(LanguageFrontend<*, *>, ArgumentHolder) infix fun Expression.eq(rhs: Expression): BinaryOperator { val node = (this@LanguageFrontend).newBinaryOperator("==") @@ -984,7 +990,7 @@ infix fun Expression.eq(rhs: Expression): BinaryOperator { * Creates a new [BinaryOperator] with a `>` [BinaryOperator.operatorCode] in the Fluent Node DSL * and invokes [ArgumentHolder.addArgument] of the nearest enclosing [ArgumentHolder]. */ -context(LanguageFrontend, ArgumentHolder) +context(LanguageFrontend<*, *>, ArgumentHolder) infix fun Expression.gt(rhs: Expression): BinaryOperator { val node = (this@LanguageFrontend).newBinaryOperator(">") @@ -1000,7 +1006,7 @@ infix fun Expression.gt(rhs: Expression): BinaryOperator { * Creates a new [BinaryOperator] with a `<` [BinaryOperator.operatorCode] in the Fluent Node DSL * and invokes [ArgumentHolder.addArgument] of the nearest enclosing [ArgumentHolder]. */ -context(LanguageFrontend, ArgumentHolder) +context(LanguageFrontend<*, *>, ArgumentHolder) infix fun Expression.lt(rhs: Expression): BinaryOperator { val node = (this@LanguageFrontend).newBinaryOperator("<") @@ -1016,7 +1022,7 @@ infix fun Expression.lt(rhs: Expression): BinaryOperator { * Creates a new [ConditionalExpression] with a `=` [BinaryOperator.operatorCode] in the Fluent Node * DSL and invokes [StatementHolder.addStatement] of the nearest enclosing [StatementHolder]. */ -context(LanguageFrontend, StatementHolder) +context(LanguageFrontend<*, *>, StatementHolder) fun Expression.conditional( condition: Expression, @@ -1034,7 +1040,7 @@ fun Expression.conditional( * Creates a new [BinaryOperator] with a `=` [BinaryOperator.operatorCode] in the Fluent Node DSL * and invokes [StatementHolder.addStatement] of the nearest enclosing [StatementHolder]. */ -context(LanguageFrontend, StatementHolder) +context(LanguageFrontend<*, *>, StatementHolder) infix fun Expression.assign(init: BinaryOperator.() -> Expression): BinaryOperator { val node = (this@LanguageFrontend).newBinaryOperator("=") @@ -1050,7 +1056,7 @@ infix fun Expression.assign(init: BinaryOperator.() -> Expression): BinaryOperat * Creates a new [BinaryOperator] with a `=` [BinaryOperator.operatorCode] in the Fluent Node DSL * and invokes [StatementHolder.addStatement] of the nearest enclosing [StatementHolder]. */ -context(LanguageFrontend, Holder) +context(LanguageFrontend<*, *>, Holder) infix fun Expression.assign(rhs: Expression): BinaryOperator { val node = (this@LanguageFrontend).newBinaryOperator("=") @@ -1065,7 +1071,7 @@ infix fun Expression.assign(rhs: Expression): BinaryOperator { } /** Creates a new [Type] with the given [name] in the Fluent Node DSL. */ -fun LanguageFrontend.t(name: CharSequence, init: (Type.() -> Unit)? = null): Type { +fun LanguageFrontend<*, *>.t(name: CharSequence, init: (Type.() -> Unit)? = null): Type { val type = parseType(name) if (init != null) { init(type) @@ -1077,7 +1083,7 @@ fun LanguageFrontend.t(name: CharSequence, init: (Type.() -> Unit)? = null): Typ * Internally used to enter a new scope if [needsScope] is true before invoking [init] and leaving * it afterwards. */ -private fun LanguageFrontend.scopeIfNecessary( +private fun LanguageFrontend<*, *>.scopeIfNecessary( needsScope: Boolean, node: T, init: T.() -> Unit diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/BooleanType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/BooleanType.kt index a81cb7363b..e3b951dcd0 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/BooleanType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/BooleanType.kt @@ -26,13 +26,12 @@ package de.fraunhofer.aisec.cpg.graph.types import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend /** Instances of this class represent boolean types. */ class BooleanType( typeName: CharSequence = "bool", bitWidth: Int? = 1, - language: Language? = null, + language: Language<*>? = null, modifier: Modifier = Modifier.NOT_APPLICABLE ) : NumericType(typeName, bitWidth, language, modifier) { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FloatingPointType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FloatingPointType.kt index e34c4a01c6..9a33cfafda 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FloatingPointType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FloatingPointType.kt @@ -26,13 +26,12 @@ package de.fraunhofer.aisec.cpg.graph.types import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend /** Instances of this class represent floating point types. */ class FloatingPointType( typeName: CharSequence = "", bitWidth: Int? = null, - language: Language? = null, + language: Language<*>? = null, modifier: Modifier = Modifier.SIGNED ) : NumericType(typeName, bitWidth, language, modifier) { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionPointerType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionPointerType.kt index 1a43e19cce..a4d0d47119 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionPointerType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionPointerType.kt @@ -26,7 +26,6 @@ package de.fraunhofer.aisec.cpg.graph.types import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge.Companion.propertyEqualsList import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge.Companion.transformIntoOutgoingPropertyEdgeList @@ -57,7 +56,7 @@ class FunctionPointerType : Type { constructor( parameters: List = listOf(), - language: Language? = null, + language: Language<*>? = null, returnType: Type = UnknownType.getUnknownType(language) ) : super(EMPTY_NAME, language) { parametersPropertyEdge = transformIntoOutgoingPropertyEdgeList(parameters, this) @@ -67,7 +66,7 @@ class FunctionPointerType : Type { constructor( type: Type, parameters: List = listOf(), - language: Language? = null, + language: Language<*>? = null, returnType: Type = UnknownType.getUnknownType(language) ) : super(type) { parametersPropertyEdge = transformIntoOutgoingPropertyEdgeList(parameters, this) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionType.kt index 182a2b2d47..7f10a8172c 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionType.kt @@ -26,7 +26,6 @@ package de.fraunhofer.aisec.cpg.graph.types import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration import de.fraunhofer.aisec.cpg.graph.newUnknownType import de.fraunhofer.aisec.cpg.graph.registerType @@ -43,7 +42,7 @@ constructor( typeName: String = "", var parameters: List = listOf(), var returnTypes: List = listOf(), - language: Language? = null + language: Language<*>? = null ) : Type(typeName, language) { override fun reference(pointer: PointerType.PointerOrigin?): Type { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/IntegerType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/IntegerType.kt index 353ac3e599..c788bc970f 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/IntegerType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/IntegerType.kt @@ -26,13 +26,12 @@ package de.fraunhofer.aisec.cpg.graph.types import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend /** Instances of this class represent integer types. */ class IntegerType( typeName: CharSequence = "", bitWidth: Int? = null, - language: Language? = null, + language: Language<*>? = null, modifier: Modifier = Modifier.SIGNED ) : NumericType(typeName, bitWidth, language, modifier) { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/NumericType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/NumericType.kt index 876cf833b0..498fd2a252 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/NumericType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/NumericType.kt @@ -26,14 +26,13 @@ package de.fraunhofer.aisec.cpg.graph.types import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import java.util.* /** This type collects all kind of numeric types. */ open class NumericType( typeName: CharSequence = "", val bitWidth: Int? = null, - language: Language? = null, + language: Language<*>? = null, val modifier: Modifier = Modifier.SIGNED ) : ObjectType(typeName, listOf(), true, language) { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/ObjectType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/ObjectType.kt index d453007679..d81ecc441e 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/ObjectType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/ObjectType.kt @@ -26,7 +26,6 @@ package de.fraunhofer.aisec.cpg.graph.types import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.graph.HasType.SecondaryTypeEdge import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration import de.fraunhofer.aisec.cpg.graph.edge.Properties @@ -58,7 +57,7 @@ open class ObjectType : Type, SecondaryTypeEdge { typeName: CharSequence, generics: List, primitive: Boolean, - language: Language? + language: Language<*>? ) : super(typeName, language) { this.genericsPropertyEdges = transformIntoOutgoingPropertyEdgeList(generics, this) isPrimitive = primitive @@ -69,7 +68,7 @@ open class ObjectType : Type, SecondaryTypeEdge { type: Type?, generics: List, primitive: Boolean, - language: Language? + language: Language<*>? ) : super(type) { this.language = language this.genericsPropertyEdges = transformIntoOutgoingPropertyEdgeList(generics, this) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/ParameterizedType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/ParameterizedType.kt index 77a9a06953..2ced2d0d51 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/ParameterizedType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/ParameterizedType.kt @@ -26,7 +26,6 @@ package de.fraunhofer.aisec.cpg.graph.types import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.graph.types.PointerType.PointerOrigin /** @@ -38,7 +37,7 @@ class ParameterizedType : Type { language = type.language } - constructor(typeName: String?, language: Language?) : super(typeName) { + constructor(typeName: String?, language: Language<*>?) : super(typeName) { this.language = language } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/StringType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/StringType.kt index 633a1dbf8d..0be5e3eb34 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/StringType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/StringType.kt @@ -26,11 +26,10 @@ package de.fraunhofer.aisec.cpg.graph.types import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend class StringType( typeName: CharSequence = "", - language: Language? = null, + language: Language<*>? = null, generics: List = listOf() ) : ObjectType(typeName, generics, false, language) { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/Type.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/Type.kt index a666695879..f293c99218 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/Type.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/Type.kt @@ -27,7 +27,6 @@ package de.fraunhofer.aisec.cpg.graph.types import de.fraunhofer.aisec.cpg.PopulatedByPass import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.graph.Name import de.fraunhofer.aisec.cpg.graph.Node import de.fraunhofer.aisec.cpg.graph.parseName @@ -68,7 +67,7 @@ abstract class Type : Node { typeOrigin = type?.typeOrigin } - constructor(typeName: CharSequence, language: Language?) { + constructor(typeName: CharSequence, language: Language<*>?) { name = if (this is FunctionType) { Name(typeName.toString(), null, language) @@ -79,7 +78,7 @@ abstract class Type : Node { typeOrigin = Origin.UNRESOLVED } - constructor(fullTypeName: Name, language: Language?) { + constructor(fullTypeName: Name, language: Language<*>?) { name = fullTypeName.clone() typeOrigin = Origin.UNRESOLVED this.language = language diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/UnknownType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/UnknownType.kt index a31b79dd44..84a5947453 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/UnknownType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/UnknownType.kt @@ -26,7 +26,6 @@ package de.fraunhofer.aisec.cpg.graph.types import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.graph.Name import de.fraunhofer.aisec.cpg.graph.types.PointerType.PointerOrigin import java.util.* @@ -88,7 +87,7 @@ class UnknownType : Type { /** Use this function to obtain an [UnknownType] for the particular [language]. */ @JvmStatic - fun getUnknownType(language: Language?): UnknownType { + fun getUnknownType(language: Language<*>?): UnknownType { if (language == null) return unknownTypeNull return unknownTypes.computeIfAbsent(language) { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalker.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalker.kt index fd13835ba4..a86ca0329a 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalker.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/SubgraphWalker.kt @@ -393,7 +393,7 @@ object SubgraphWalker { private var walker: IterativeGraphWalker? = null private val scopeManager: ScopeManager - constructor(lang: LanguageFrontend) { + constructor(lang: LanguageFrontend<*, *>) { scopeManager = lang.scopeManager } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/Util.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/Util.kt index e7e57d3bad..ab9f412817 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/Util.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/helpers/Util.kt @@ -177,9 +177,9 @@ object Util { } @JvmStatic - fun warnWithFileLocation( - lang: LanguageFrontend, - astNode: S, + fun warnWithFileLocation( + lang: LanguageFrontend, + astNode: AstNode, log: Logger, format: String?, vararg arguments: Any? @@ -187,7 +187,7 @@ object Util { log.warn( String.format( "%s: %s", - PhysicalLocation.locationLink(lang.getLocationFromRawNode(astNode)), + PhysicalLocation.locationLink(lang.locationOf(astNode)), format ), *arguments @@ -195,9 +195,9 @@ object Util { } @JvmStatic - fun errorWithFileLocation( - lang: LanguageFrontend, - astNode: S, + fun errorWithFileLocation( + lang: LanguageFrontend, + astNode: AstNode, log: Logger, format: String?, vararg arguments: Any? @@ -205,7 +205,7 @@ object Util { log.error( String.format( "%s: %s", - PhysicalLocation.locationLink(lang.getLocationFromRawNode(astNode)), + PhysicalLocation.locationLink(lang.locationOf(astNode)), format ), *arguments diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/CallResolver.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/CallResolver.kt index e1322036a0..ae2f943134 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/CallResolver.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/CallResolver.kt @@ -553,7 +553,7 @@ open class CallResolver(ctx: TranslationContext) : SymbolResolverPass(ctx) { } } - protected val Language?.isCPP: Boolean + protected val Language<*>?.isCPP: Boolean get() { return this != null && this::class.simpleName == "CPPLanguage" } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/Pass.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/Pass.kt index 5a466b8c40..2ad6a0ac13 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/Pass.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/Pass.kt @@ -99,7 +99,7 @@ sealed class Pass(final override val ctx: TranslationContext) : * @return true, if the pass does not require a specific language frontend or if it matches the * [RequiredFrontend] */ - fun runsWithCurrentFrontend(usedFrontends: Collection): Boolean { + fun runsWithCurrentFrontend(usedFrontends: Collection>): Boolean { if (!this.javaClass.isAnnotationPresent(RequiredFrontend::class.java)) return true val requiredFrontend = this.javaClass.getAnnotation(RequiredFrontend::class.java).value for (used in usedFrontends) { @@ -123,7 +123,7 @@ fun executePassSequential( cls: KClass>, ctx: TranslationContext, result: TranslationResult, - executedFrontends: Collection + executedFrontends: Collection> ) { // This is a bit tricky but actually better than other reflection magic. We are creating a // "prototype" instance of our pass class, so we can deduce certain type information more @@ -160,7 +160,7 @@ inline fun executePass( cls: KClass>, ctx: TranslationContext, target: T, - executedFrontends: Collection + executedFrontends: Collection> ): Pass? { val language = if (target is LanguageProvider) { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt index 5352160dbb..d532673e72 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt @@ -28,7 +28,6 @@ package de.fraunhofer.aisec.cpg.passes.inference import de.fraunhofer.aisec.cpg.TranslationContext import de.fraunhofer.aisec.cpg.frontends.HasClasses import de.fraunhofer.aisec.cpg.frontends.Language -import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.graph.* import de.fraunhofer.aisec.cpg.graph.declarations.* import de.fraunhofer.aisec.cpg.graph.scopes.Scope @@ -54,7 +53,7 @@ class Inference(val start: Node, override val ctx: TranslationContext) : LanguageProvider, ScopeProvider, IsInferredProvider, ContextProvider { val log: Logger = LoggerFactory.getLogger(Inference::class.java) - override val language: Language? + override val language: Language<*>? get() = start.language override val isInferred: Boolean diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/order/RequiredFrontend.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/order/RequiredFrontend.kt index de3d1574c2..d79fd21a8f 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/order/RequiredFrontend.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/order/RequiredFrontend.kt @@ -34,4 +34,4 @@ import kotlin.reflect.KClass */ @Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.CLASS) -annotation class RequiredFrontend(val value: KClass) +annotation class RequiredFrontend(val value: KClass>) diff --git a/cpg-core/src/testFixtures/kotlin/de/fraunhofer/aisec/cpg/frontends/TestLanguage.kt b/cpg-core/src/testFixtures/kotlin/de/fraunhofer/aisec/cpg/frontends/TestLanguage.kt index 8230d9c1dc..9cb0346740 100644 --- a/cpg-core/src/testFixtures/kotlin/de/fraunhofer/aisec/cpg/frontends/TestLanguage.kt +++ b/cpg-core/src/testFixtures/kotlin/de/fraunhofer/aisec/cpg/frontends/TestLanguage.kt @@ -29,6 +29,7 @@ import de.fraunhofer.aisec.cpg.* import de.fraunhofer.aisec.cpg.graph.Node import de.fraunhofer.aisec.cpg.graph.TypeManager import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration +import de.fraunhofer.aisec.cpg.graph.newUnknownType import de.fraunhofer.aisec.cpg.graph.statements.expressions.ProblemExpression import de.fraunhofer.aisec.cpg.graph.types.* import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation @@ -74,27 +75,32 @@ class StructTestLanguage(namespaceDelimiter: String = "::") : open class TestLanguageFrontend( namespaceDelimiter: String = "::", - language: Language = TestLanguage(namespaceDelimiter), + language: Language = TestLanguage(namespaceDelimiter), ctx: TranslationContext = TranslationContext( TranslationConfiguration.builder().build(), ScopeManager(), TypeManager() ), -) : LanguageFrontend(language, ctx) { +) : LanguageFrontend(language, ctx) { override fun parse(file: File): TranslationUnitDeclaration { TODO("Not yet implemented") } - override fun getCodeFromRawNode(astNode: T): String? { + override fun typeOf(type: Any): Type { + // reserved for future use + return newUnknownType() + } + + override fun codeOf(astNode: Any): String? { TODO("Not yet implemented") } - override fun getLocationFromRawNode(astNode: T): PhysicalLocation? { + override fun locationOf(astNode: Any): PhysicalLocation? { TODO("Not yet implemented") } - override fun setComment(s: S, ctx: T) { + override fun setComment(node: Node, astNode: Any) { TODO("Not yet implemented") } } diff --git a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXHandler.kt b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXHandler.kt index e2b5224d7f..3b2cba1412 100644 --- a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXHandler.kt +++ b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXHandler.kt @@ -30,9 +30,10 @@ import de.fraunhofer.aisec.cpg.graph.Node import de.fraunhofer.aisec.cpg.graph.ProblemNode import de.fraunhofer.aisec.cpg.helpers.Util import java.util.function.Supplier +import org.eclipse.cdt.core.dom.ast.IASTNode import org.eclipse.cdt.internal.core.dom.parser.ASTNode -abstract class CXXHandler( +abstract class CXXHandler( configConstructor: Supplier, lang: CXXLanguageFrontend ) : Handler(configConstructor, lang) { @@ -58,7 +59,7 @@ abstract class CXXHandler( // The language frontend might set a location, which we should respect. Otherwise, we will // set the location here. if (node.location == null) { - frontend.setCodeAndLocation(node, ctx) + frontend.setCodeAndLocation(node, ctx) } frontend.setComment(node, ctx) diff --git a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontend.kt b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontend.kt index e102a7cea0..891382a383 100644 --- a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontend.kt +++ b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontend.kt @@ -79,7 +79,7 @@ import org.slf4j.LoggerFactory */ @RegisterExtraPass(FunctionPointerCallResolver::class) class CXXLanguageFrontend(language: Language, ctx: TranslationContext) : - LanguageFrontend(language, ctx) { + LanguageFrontend(language, ctx) { /** * The dialect used by this language frontend, either [GCCLanguage] for C or [GPPLanguage] for @@ -266,21 +266,13 @@ class CXXLanguageFrontend(language: Language, ctx: Translat } } - override fun getCodeFromRawNode(astNode: T): String? { - if (astNode is ASTNode) { - val node = astNode as ASTNode - return node.rawSignature - } - - return null + override fun codeOf(astNode: IASTNode): String? { + val node = astNode as ASTNode + return node.rawSignature } - override fun getLocationFromRawNode(astNode: T): PhysicalLocation? { - if (astNode !is ASTNode) { - return null - } - val node = astNode as ASTNode - val fLocation = node.fileLocation ?: return null + override fun locationOf(astNode: IASTNode): PhysicalLocation? { + val fLocation = astNode.fileLocation ?: return null val lineBreaks: IntArray = try { val fLoc = getField(fLocation.javaClass, "fLocationCtx") @@ -313,19 +305,19 @@ class CXXLanguageFrontend(language: Language, ctx: Translat } // our start line, indexed by 0 - val startLine = node.fileLocation.startingLineNumber - 1 + val startLine = astNode.fileLocation.startingLineNumber - 1 // our end line, indexed by 0 - val endLine = node.fileLocation.endingLineNumber - 1 + val endLine = astNode.fileLocation.endingLineNumber - 1 // our start column, index by 0 val startColumn = if (startLine == 0) { // if we are in the first line, the start column is just the node offset - node.fileLocation.nodeOffset + astNode.fileLocation.nodeOffset } else { // otherwise, we need to calculate the difference to the previous line break - node.fileLocation.nodeOffset - + astNode.fileLocation.nodeOffset - lineBreaks[startLine - 1] - 1 // additional -1 because of the '\n' itself } @@ -334,10 +326,10 @@ class CXXLanguageFrontend(language: Language, ctx: Translat val endColumn = if (endLine == 0) { // if we are in the first line, the end column is just the node offset - node.fileLocation.nodeOffset + node.fileLocation.nodeLength + astNode.fileLocation.nodeOffset + astNode.fileLocation.nodeLength } else { // otherwise, we need to calculate the difference to the previous line break - (node.fileLocation.nodeOffset + node.fileLocation.nodeLength) - + (astNode.fileLocation.nodeOffset + astNode.fileLocation.nodeLength) - lineBreaks[endLine - 1] - 1 // additional -1 because of the '\n' itself } @@ -345,7 +337,7 @@ class CXXLanguageFrontend(language: Language, ctx: Translat // for a SARIF compliant format, we need to add +1, since its index begins at 1 and // not 0 val region = Region(startLine + 1, startColumn + 1, endLine + 1, endColumn + 1) - return PhysicalLocation(Path.of(node.containingFilename).toUri(), region) + return PhysicalLocation(Path.of(astNode.containingFilename).toUri(), region) } /** @@ -446,28 +438,25 @@ class CXXLanguageFrontend(language: Language, ctx: Translat } } - override fun setComment(s: S, ctx: T) { - if (ctx is ASTNode && s is Node) { - val cpgNode = s as Node - val location = cpgNode.location ?: return + override fun setComment(node: Node, astNode: IASTNode) { + val location = node.location ?: return - // No location, no comment + // No location, no comment - val loc: Pair = - Pair(location.artifactLocation.uri.path, location.region.endLine) - comments[loc]?.let { - // only exact match for now} - cpgNode.comment = it - } - // TODO: handle orphanComments? i.e. comments which do not correspond to one line - // todo: what to do with comments which are in a line which contains multiple - // statements? + val loc: Pair = + Pair(location.artifactLocation.uri.path, location.region.endLine) + comments[loc]?.let { + // only exact match for now} + node.comment = it } + // TODO: handle orphanComments? i.e. comments which do not correspond to one line + // TODO: what to do with comments which are in a line which contains multiple + // statements? } /** Returns the [Type] that is represented by an [IASTTypeId]. */ - fun typeOf(id: IASTTypeId): Type { - return typeOf(id.abstractDeclarator, id.declSpecifier) + override fun typeOf(type: IASTTypeId): Type { + return typeOf(type.abstractDeclarator, type.declSpecifier) } /** diff --git a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclarationHandler.kt b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclarationHandler.kt index 968d817e86..4f70039e99 100644 --- a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclarationHandler.kt +++ b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclarationHandler.kt @@ -87,8 +87,7 @@ class DeclarationHandler(lang: CXXLanguageFrontend) : * into a [NamespaceDeclaration]. */ private fun handleNamespace(ctx: CPPASTNamespaceDefinition): NamespaceDeclaration { - val declaration = - newNamespaceDeclaration(ctx.name.toString(), frontend.getCodeFromRawNode(ctx)) + val declaration = newNamespaceDeclaration(ctx.name.toString(), frontend.codeOf(ctx)) frontend.scopeManager.addDeclaration(declaration) @@ -270,12 +269,12 @@ class DeclarationHandler(lang: CXXLanguageFrontend) : val templateDeclaration: TemplateDeclaration = if (ctx.declaration is CPPASTFunctionDefinition) { - newFunctionTemplateDeclaration(name, frontend.getCodeFromRawNode(ctx)) + newFunctionTemplateDeclaration(name, frontend.codeOf(ctx)) } else { - newClassTemplateDeclaration(name, frontend.getCodeFromRawNode(ctx)) + newClassTemplateDeclaration(name, frontend.codeOf(ctx)) } - templateDeclaration.location = frontend.getLocationFromRawNode(ctx) + templateDeclaration.location = frontend.locationOf(ctx) frontend.scopeManager.addDeclaration(templateDeclaration) frontend.scopeManager.enterScope(templateDeclaration) addTemplateParameters(ctx, templateDeclaration) @@ -543,7 +542,7 @@ class DeclarationHandler(lang: CXXLanguageFrontend) : val declaration = frontend.typeManager.createTypeAlias( frontend, - frontend.getCodeFromRawNode(ctx), + frontend.codeOf(ctx), type, nameDecl.name.toString() ) @@ -562,7 +561,7 @@ class DeclarationHandler(lang: CXXLanguageFrontend) : val enum = newEnumDeclaration( name = declSpecifier.name.toString(), - location = frontend.getLocationFromRawNode(ctx), + location = frontend.locationOf(ctx), ) // Loop through its members @@ -570,8 +569,8 @@ class DeclarationHandler(lang: CXXLanguageFrontend) : val enumConst = newEnumConstantDeclaration( enumerator.name.toString(), - frontend.getCodeFromRawNode(enumerator), - frontend.getLocationFromRawNode(enumerator), + frontend.codeOf(enumerator), + frontend.locationOf(enumerator), ) // In C/C++, default enums are of type int diff --git a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclaratorHandler.kt b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclaratorHandler.kt index 7c4291fb58..08cbc829c2 100644 --- a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclaratorHandler.kt +++ b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclaratorHandler.kt @@ -51,9 +51,9 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.* * See [DeclarationHandler] for a detailed explanation, why this is split into a dedicated handler. */ class DeclaratorHandler(lang: CXXLanguageFrontend) : - CXXHandler(Supplier(::ProblemDeclaration), lang) { + CXXHandler(Supplier(::ProblemDeclaration), lang) { - override fun handleNode(node: IASTNameOwner): Declaration { + override fun handleNode(node: IASTNode): Declaration { return when (node) { is CPPASTFunctionDeclarator -> handleCPPFunctionDeclarator(node) is IASTStandardFunctionDeclarator -> handleFunctionDeclarator(node) @@ -105,7 +105,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : // Check, if the name is qualified or if we are within a record scope return if ( (frontend.scopeManager.currentScope is RecordScope || - name.contains(language.namespaceDelimiter)) + language?.namespaceDelimiter?.let { name.contains(it) } == true) ) { // If yes, treat this like a field declaration this.handleFieldDeclarator(ctx) @@ -144,32 +144,18 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : private fun handleFieldDeclarator(ctx: IASTDeclarator): FieldDeclaration { val initializer = ctx.initializer?.let { frontend.initializerHandler.handle(it) } - val name = ctx.name.toString() + val name = parseName(ctx.name.toString()) val declaration = - if (name.contains(language.namespaceDelimiter)) { - val rr = name.split(language.namespaceDelimiter).toTypedArray() - val fieldName = rr[rr.size - 1] - newFieldDeclaration( - fieldName, - newUnknownType(), - emptyList(), - ctx.rawSignature, - frontend.getLocationFromRawNode(ctx), - initializer, - true - ) - } else { - newFieldDeclaration( - name, - newUnknownType(), - emptyList(), - ctx.rawSignature, - frontend.getLocationFromRawNode(ctx), - initializer, - true - ) - } + newFieldDeclaration( + name.localName, + newUnknownType(), + emptyList(), + ctx.rawSignature, + frontend.locationOf(ctx), + initializer, + true + ) frontend.scopeManager.addDeclaration(declaration) @@ -370,7 +356,7 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : "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." ) - Util.warnWithFileLocation(frontend, ctx, log, problem.problem) + Util.warnWithFileLocation(frontend, ctx, log, problem.problem) return problem } @@ -434,13 +420,13 @@ class DeclaratorHandler(lang: CXXLanguageFrontend) : newUnknownType(), emptyList(), code, - frontend.getLocationFromRawNode(ctx), + frontend.locationOf(ctx), initializer, true ) } - result.location = frontend.getLocationFromRawNode(ctx) + result.location = frontend.locationOf(ctx) frontend.scopeManager.addDeclaration(result) return result } diff --git a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/ExpressionHandler.kt b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/ExpressionHandler.kt index 33dfd68221..14002004a0 100644 --- a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/ExpressionHandler.kt +++ b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/ExpressionHandler.kt @@ -82,7 +82,7 @@ class ExpressionHandler(lang: CXXLanguageFrontend) : } private fun handleLambdaExpression(node: CPPASTLambdaExpression): Expression { - val lambda = newLambdaExpression(frontend.getCodeFromRawNode(node)) + val lambda = newLambdaExpression(frontend.codeOf(node)) // Variables passed by reference are mutable. If we have initializers, we have to model the // variable explicitly. @@ -206,8 +206,7 @@ class ExpressionHandler(lang: CXXLanguageFrontend) : } // new returns a pointer, so we need to reference the type by pointer - val newExpression = - newNewExpression(code, t.reference(PointerOrigin.POINTER), frontend.language) + val newExpression = newNewExpression(code, t.reference(PointerOrigin.POINTER), ctx) newExpression.templateParameters = templateParameters val initializer: Expression? if (init != null) { @@ -357,10 +356,10 @@ class ExpressionHandler(lang: CXXLanguageFrontend) : // this can either be just a meaningless bracket or it can be a cast expression val typeName = (ctx.operand as IASTIdExpression).name.toString() if (frontend.typeManager.typeExists(typeName)) { - val cast = newCastExpression(frontend.getCodeFromRawNode(ctx)) + val cast = newCastExpression(frontend.codeOf(ctx)) cast.castType = parseType(typeName) cast.expression = input ?: newProblemExpression("could not parse input") - cast.location = frontend.getLocationFromRawNode(ctx) + cast.location = frontend.locationOf(ctx) return cast } } diff --git a/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/PerformanceRegressionTest.kt b/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/PerformanceRegressionTest.kt index ef33d46eaf..03b473a6af 100644 --- a/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/PerformanceRegressionTest.kt +++ b/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/PerformanceRegressionTest.kt @@ -53,7 +53,7 @@ class PerformanceRegressionTest { * in reasonable time. We had issues with literals and their hashcode when they were inserted * into a set. * * Second, we want to make that list essentially a one-liner because we had issues when - * populating the [Node.location] property using [CXXLanguageFrontend.getLocationFromRawNode]. + * populating the [Node.location] property using [CXXLanguageFrontend.locationOf]. */ @Test fun testParseLargeList() { diff --git a/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontendTest.kt b/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontendTest.kt index 9c1c5b0692..088206af73 100644 --- a/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontendTest.kt +++ b/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontendTest.kt @@ -1076,10 +1076,10 @@ internal class CXXLanguageFrontendTest : BaseTest() { fun testLocation() { val file = File("src/test/resources/components/foreachstmt.cpp") val tu = analyzeAndGetFirstTU(listOf(file), file.parentFile.toPath(), true) - val main = tu.getDeclarationsByName("main", FunctionDeclaration::class.java) - assertFalse(main.isEmpty()) + val main = tu.functions["main"] + assertNotNull(main) - val location = main.iterator().next().location + val location = main.location assertNotNull(location) val path = Path.of(location.artifactLocation.uri) diff --git a/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/GoLanguageFrontend.kt b/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/GoLanguageFrontend.kt index a615d99d00..d1a9ffe7a1 100644 --- a/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/GoLanguageFrontend.kt +++ b/cpg-language-go/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/golang/GoLanguageFrontend.kt @@ -30,7 +30,10 @@ import de.fraunhofer.aisec.cpg.frontends.Language import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.frontends.SupportsParallelParsing import de.fraunhofer.aisec.cpg.frontends.TranslationException +import de.fraunhofer.aisec.cpg.graph.Node import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration +import de.fraunhofer.aisec.cpg.graph.newUnknownType +import de.fraunhofer.aisec.cpg.graph.types.Type import de.fraunhofer.aisec.cpg.passes.GoExtraPass import de.fraunhofer.aisec.cpg.passes.order.RegisterExtraPass import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation @@ -40,7 +43,7 @@ import java.io.FileOutputStream @SupportsParallelParsing(false) @RegisterExtraPass(GoExtraPass::class) class GoLanguageFrontend(language: Language, ctx: TranslationContext) : - LanguageFrontend(language, ctx) { + LanguageFrontend(language, ctx) { companion object { init { @@ -88,17 +91,24 @@ class GoLanguageFrontend(language: Language, ctx: Translatio ) } - override fun getCodeFromRawNode(astNode: T): String? { + override fun typeOf(type: Any): Type { + // this is handled by native code + return newUnknownType() + } + + override fun codeOf(astNode: Any): String? { // this is handled by native code return null } - override fun getLocationFromRawNode(astNode: T): PhysicalLocation? { + override fun locationOf(astNode: Any): PhysicalLocation? { // this is handled by native code return null } - override fun setComment(s: S, ctx: T) {} + override fun setComment(node: Node, astNode: Any) { + // this is handled by native code + } private external fun parseInternal( s: String?, diff --git a/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/DeclarationHandler.kt b/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/DeclarationHandler.kt index 59900c62db..0ef6768d38 100644 --- a/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/DeclarationHandler.kt +++ b/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/DeclarationHandler.kt @@ -323,7 +323,7 @@ open class DeclarationHandler(lang: JavaLanguageFrontend) : val variable = fieldDecl.getVariable(0) val modifiers = fieldDecl.modifiers.map { modifier -> modifier.keyword.asString() } val joinedModifiers = java.lang.String.join(" ", modifiers) + " " - val location = frontend.getLocationFromRawNode(fieldDecl) + val location = frontend.locationOf(fieldDecl) val initializer = variable.initializer .map { ctx: Expression -> frontend.expressionHandler.handle(ctx) } @@ -374,7 +374,7 @@ open class DeclarationHandler(lang: JavaLanguageFrontend) : enumDecl: com.github.javaparser.ast.body.EnumDeclaration ): EnumDeclaration { val name = enumDecl.nameAsString - val location = frontend.getLocationFromRawNode(enumDecl) + val location = frontend.locationOf(enumDecl) val enumDeclaration = this.newEnumDeclaration(name, enumDecl.toString(), location) val entries = enumDecl.entries.mapNotNull { handle(it) as EnumConstantDeclaration? } @@ -392,7 +392,7 @@ open class DeclarationHandler(lang: JavaLanguageFrontend) : return this.newEnumConstantDeclaration( enumConstDecl.nameAsString, enumConstDecl.toString(), - frontend.getLocationFromRawNode(enumConstDecl) + frontend.locationOf(enumConstDecl) ) } diff --git a/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.kt b/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.kt index cacbab7f16..1428eae0d4 100644 --- a/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.kt +++ b/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/ExpressionHandler.kt @@ -49,8 +49,8 @@ class ExpressionHandler(lang: JavaLanguageFrontend) : private fun handleLambdaExpr(expr: Expression): Statement { val lambdaExpr = expr.asLambdaExpr() - val lambda = newLambdaExpression(frontend.getCodeFromRawNode(lambdaExpr)) - val anonymousFunction = newFunctionDeclaration("", frontend.getCodeFromRawNode(lambdaExpr)) + val lambda = newLambdaExpression(frontend.codeOf(lambdaExpr)) + val anonymousFunction = newFunctionDeclaration("", frontend.codeOf(lambdaExpr)) frontend.scopeManager.enterScope(anonymousFunction) for (parameter in lambdaExpr.parameters) { val resolvedType = frontend.getTypeAsGoodAsPossible(parameter.type) @@ -326,12 +326,7 @@ class ExpressionHandler(lang: JavaLanguageFrontend) : scope.toString() ) base.isStaticAccess = isStaticAccess - frontend.setCodeAndLocation< - de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression, Expression - >( - base, - fieldAccessExpr.scope - ) + frontend.setCodeAndLocation(base, fieldAccessExpr.scope) } else if (scope.isFieldAccessExpr) { base = handle(scope) as de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression? @@ -423,7 +418,7 @@ class ExpressionHandler(lang: JavaLanguageFrontend) : return memberExpression } if (base.location == null) { - base.location = frontend.getLocationFromRawNode(fieldAccessExpr) + base.location = frontend.locationOf(fieldAccessExpr) } return this.newMemberExpression(fieldAccessExpr.name.identifier, base, fieldType, ".") } @@ -838,7 +833,7 @@ class ExpressionHandler(lang: JavaLanguageFrontend) : if (objectCreationExpr.anonymousClassBody.isPresent) { // We have an anonymous class and will create a RecordDeclaration for it and add all the // implemented methods. - val locationHash = frontend.getLocationFromRawNode(objectCreationExpr)?.hashCode() + val locationHash = frontend.locationOf(objectCreationExpr)?.hashCode() // We use the hash of the location to distinguish multiple instances of the anonymous // class' superclass diff --git a/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/JavaLanguageFrontend.kt b/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/JavaLanguageFrontend.kt index a277e5b7a2..0d26100047 100644 --- a/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/JavaLanguageFrontend.kt +++ b/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/JavaLanguageFrontend.kt @@ -71,7 +71,7 @@ import java.util.function.Consumer JavaExternalTypeHierarchyResolver::class ) // this pass is always required for Java open class JavaLanguageFrontend(language: Language, ctx: TranslationContext) : - LanguageFrontend(language, ctx) { + LanguageFrontend(language, ctx) { var context: CompilationUnit? = null var javaSymbolResolver: JavaSymbolSolver? @@ -115,7 +115,7 @@ open class JavaLanguageFrontend(language: Language, ctx: T var namespaceDeclaration: NamespaceDeclaration? = null if (packDecl != null) { namespaceDeclaration = - newNamespaceDeclaration(packDecl.name.asString(), getCodeFromRawNode(packDecl)) + newNamespaceDeclaration(packDecl.name.asString(), codeOf(packDecl)) setCodeAndLocation(namespaceDeclaration, packDecl) scopeManager.addDeclaration(namespaceDeclaration) scopeManager.enterScope(namespaceDeclaration) @@ -144,6 +144,11 @@ open class JavaLanguageFrontend(language: Language, ctx: T } } + override fun typeOf(type: Type): de.fraunhofer.aisec.cpg.graph.types.Type { + // reserved for future use + return newUnknownType() + } + @Throws(TranslationException::class, FileNotFoundException::class) fun parse(file: File?, parser: JavaParser): CompilationUnit { val result = parser.parse(file) @@ -170,38 +175,31 @@ open class JavaLanguageFrontend(language: Language, ctx: T return optional.get() } - override fun getCodeFromRawNode(astNode: T): String { - if (astNode is Node) { - val node = astNode as Node - val optional = node.tokenRange - if (optional.isPresent) { - return optional.get().toString() - } + override fun codeOf(astNode: Node): String? { + val optional = astNode.tokenRange + if (optional?.isPresent == true) { + return optional.get().toString() } return astNode.toString() } - override fun getLocationFromRawNode(astNode: T): PhysicalLocation? { - if (astNode is Node) { - val node = astNode as Node - - // find compilation unit of node - val cu = node.findCompilationUnit().orElse(null) ?: return null - - // retrieve storage - val storage = cu.storage.orElse(null) ?: return null - val optional = node.range - if (optional.isPresent) { - val r = optional.get() - val region = - Region( - r.begin.line, - r.begin.column, - r.end.line, - r.end.column + 1 - ) // +1 for SARIF compliance - return PhysicalLocation(storage.path.toUri(), region) - } + override fun locationOf(astNode: Node): PhysicalLocation? { + // find compilation unit of node + val cu = astNode.findCompilationUnit().orElse(null) ?: return null + + // retrieve storage + val storage = cu.storage.orElse(null) ?: return null + val optional = astNode.range + if (optional.isPresent) { + val r = optional.get() + val region = + Region( + r.begin.line, + r.begin.column, + r.end.line, + r.end.column + 1 + ) // +1 for SARIF compliance + return PhysicalLocation(storage.path.toUri(), region) } return null } @@ -424,13 +422,8 @@ open class JavaLanguageFrontend(language: Language, ctx: T context = null } - override fun setComment(s: S, ctx: T) { - if (ctx is Node && s is de.fraunhofer.aisec.cpg.graph.Node) { - val node = ctx as Node - val cpgNode = s as de.fraunhofer.aisec.cpg.graph.Node - node.comment.ifPresent { comment: Comment -> cpgNode.comment = comment.content } - // TODO: handle orphanComments? - } + override fun setComment(node: de.fraunhofer.aisec.cpg.graph.Node, astNode: Node) { + astNode.comment.ifPresent { comment: Comment -> node.comment = comment.content } } /** @@ -451,7 +444,7 @@ open class JavaLanguageFrontend(language: Language, ctx: T private fun handleAnnotations(owner: NodeWithAnnotations<*>): List { val list = ArrayList() for (expr in owner.annotations) { - val annotation = newAnnotation(expr.nameAsString, getCodeFromRawNode(expr)) + val annotation = newAnnotation(expr.nameAsString, codeOf(expr)) val members = ArrayList() // annotations can be specified as member / value pairs @@ -461,7 +454,7 @@ open class JavaLanguageFrontend(language: Language, ctx: T newAnnotationMember( pair.nameAsString, expressionHandler.handle(pair.value) as Expression, - getCodeFromRawNode(pair) + codeOf(pair) ) members.add(member) } @@ -473,7 +466,7 @@ open class JavaLanguageFrontend(language: Language, ctx: T newAnnotationMember( ANNOTATION_MEMBER_VALUE, expressionHandler.handle(value.asLiteralExpr()) as Expression, - getCodeFromRawNode(value) + codeOf(value) ) members.add(member) } diff --git a/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/StatementHandler.kt b/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/StatementHandler.kt index 0ed5969add..2e74aad2f8 100644 --- a/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/StatementHandler.kt +++ b/cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/StatementHandler.kt @@ -46,9 +46,6 @@ import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation import de.fraunhofer.aisec.cpg.sarif.Region import java.util.function.Supplier import java.util.stream.Collectors -import kotlin.collections.ArrayList -import kotlin.collections.MutableList -import kotlin.collections.mapNotNull import kotlin.collections.set import org.slf4j.LoggerFactory @@ -63,7 +60,10 @@ class StatementHandler(lang: JavaLanguageFrontend?) : val expression = frontend.expressionHandler.handle(stmt.asExpressionStmt().expression) // update expression's code and location to match the statement - frontend.setCodeAndLocation(expression, stmt) + if (expression != null) { + frontend.setCodeAndLocation(expression, stmt) + } + return expression } @@ -189,10 +189,11 @@ class StatementHandler(lang: JavaLanguageFrontend?) : val initExprList = this.newExpressionList() for (initExpr in forStmt.initialization) { val s = frontend.expressionHandler.handle(initExpr) - - // make sure location is set - frontend.setCodeAndLocation(s, initExpr) - s?.let { initExprList.addExpression(it) } + s?.let { + // make sure location is set + frontend.setCodeAndLocation(it, initExpr) + initExprList.addExpression(it) + } // can not update location if (s?.location == null) { @@ -242,10 +243,11 @@ class StatementHandler(lang: JavaLanguageFrontend?) : val iterationExprList = this.newExpressionList() for (updateExpr in forStmt.update) { val s = frontend.expressionHandler.handle(updateExpr) - - // make sure location is set - frontend.setCodeAndLocation(s, updateExpr) - s?.let { iterationExprList.addExpression(it) } + s?.let { + // make sure location is set + frontend.setCodeAndLocation(s, updateExpr) + iterationExprList.addExpression(it) + } // can not update location if (s?.location == null) { @@ -353,7 +355,7 @@ class StatementHandler(lang: JavaLanguageFrontend?) : caseExpression: Expression?, sEntry: SwitchEntry ): de.fraunhofer.aisec.cpg.graph.statements.Statement { - val parentLocation = frontend.getLocationFromRawNode(sEntry) + val parentLocation = frontend.locationOf(sEntry) val optionalTokenRange = sEntry.tokenRange var caseTokens = Pair(null, null) if (optionalTokenRange.isEmpty) { diff --git a/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/DeclarationHandler.kt b/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/DeclarationHandler.kt index 177c6189fd..e547148e18 100644 --- a/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/DeclarationHandler.kt +++ b/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/DeclarationHandler.kt @@ -58,7 +58,7 @@ class DeclarationHandler(lang: LLVMIRLanguageFrontend) : newProblemDeclaration( "Not handling declaration kind $kind yet.", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(value) + frontend.codeOf(value) ) } } @@ -75,7 +75,7 @@ class DeclarationHandler(lang: LLVMIRLanguageFrontend) : val type = frontend.typeOf(valueRef) val variableDeclaration = - newVariableDeclaration(name, type, frontend.getCodeFromRawNode(valueRef), false) + newVariableDeclaration(name, type, frontend.codeOf(valueRef), false) // cache binding frontend.bindingsCache[valueRef.symbolName] = variableDeclaration @@ -98,8 +98,7 @@ class DeclarationHandler(lang: LLVMIRLanguageFrontend) : */ private fun handleFunction(func: LLVMValueRef): FunctionDeclaration { val name = LLVMGetValueName(func) - val functionDeclaration = - newFunctionDeclaration(name.string, frontend.getCodeFromRawNode(func)) + val functionDeclaration = newFunctionDeclaration(name.string, frontend.codeOf(func)) // return types are a bit tricky, because the type of the function is a pointer to the // function type, which then has the return type in it @@ -120,13 +119,7 @@ class DeclarationHandler(lang: LLVMIRLanguageFrontend) : val type = frontend.typeOf(param) // TODO: support variardic - val decl = - newParamVariableDeclaration( - paramName, - type, - false, - frontend.getCodeFromRawNode(param) - ) + val decl = newParamVariableDeclaration(paramName, type, false, frontend.codeOf(param)) frontend.scopeManager.addDeclaration(decl) frontend.bindingsCache[paramSymbolName] = decl @@ -227,17 +220,7 @@ class DeclarationHandler(lang: LLVMIRLanguageFrontend) : // there are no names, so we need to invent some dummy ones for easier reading val fieldName = "field_$i" - val field = - newFieldDeclaration( - fieldName, - fieldType, - listOf(), - "", - null, - null, - false, - frontend.language - ) + val field = newFieldDeclaration(fieldName, fieldType, listOf(), "", null, null, false) frontend.scopeManager.addDeclaration(field) } diff --git a/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/ExpressionHandler.kt b/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/ExpressionHandler.kt index ce70d27af5..c37c551af4 100644 --- a/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/ExpressionHandler.kt +++ b/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/ExpressionHandler.kt @@ -64,11 +64,11 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : newDeclaredReferenceExpression("poison", frontend.typeOf(value), "poison") } LLVMConstantTokenNoneValueKind -> - newLiteral(null, newUnknownType(), frontend.getCodeFromRawNode(value)) + newLiteral(null, newUnknownType(), frontend.codeOf(value)) LLVMUndefValueValueKind -> - initializeAsUndef(frontend.typeOf(value), frontend.getCodeFromRawNode(value)) + initializeAsUndef(frontend.typeOf(value), frontend.codeOf(value)) LLVMConstantAggregateZeroValueKind -> - initializeAsZero(frontend.typeOf(value), frontend.getCodeFromRawNode(value)) + initializeAsZero(frontend.typeOf(value), frontend.codeOf(value)) LLVMArgumentValueKind, LLVMGlobalVariableValueKind, // this is a little tricky. It seems weird, that an instruction value kind turns @@ -80,11 +80,7 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : LLVMFunctionValueKind -> handleFunction(value) LLVMGlobalAliasValueKind -> { val name = frontend.getNameOf(value).first - newDeclaredReferenceExpression( - name, - frontend.typeOf(value), - frontend.getCodeFromRawNode(value) - ) + newDeclaredReferenceExpression(name, frontend.typeOf(value), frontend.codeOf(value)) } LLVMMetadataAsValueValueKind, LLVMInlineAsmValueKind -> { @@ -92,7 +88,7 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : return newProblemExpression( "Metadata or ASM value kind not supported yet", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(value) + frontend.codeOf(value) ) } else -> { @@ -125,7 +121,7 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : newProblemExpression( "Unknown expression $kind", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(value) + frontend.codeOf(value) ) } } @@ -137,7 +133,7 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : return newDeclaredReferenceExpression( valueRef.name, frontend.typeOf(valueRef), - frontend.getCodeFromRawNode(valueRef) + frontend.codeOf(valueRef) ) } @@ -237,7 +233,7 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : ?: newProblemExpression( "Wrong type of constant binary operation +", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(value) + frontend.codeOf(value) ) LLVMSub, LLVMFSub -> @@ -245,7 +241,7 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : ?: newProblemExpression( "Wrong type of constant binary operation -", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(value) + frontend.codeOf(value) ) LLVMAShr -> frontend.statementHandler.handleBinaryOperator(value, ">>", false) @@ -253,20 +249,20 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : ?: newProblemExpression( "Wrong type of constant binary operation >>", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(value) + frontend.codeOf(value) ) LLVMICmp -> frontend.statementHandler.handleIntegerComparison(value) as? Expression ?: newProblemExpression( "Wrong type of constant comparison", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(value) + frontend.codeOf(value) ) else -> { log.error("Not handling constant expression of opcode {} yet", kind) newProblemExpression( "Not handling constant expression of opcode $kind yet", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(value) + frontend.codeOf(value) ) } } @@ -284,7 +280,7 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : // retrieve the type val type = frontend.typeOf(value) - val expr: ConstructExpression = newConstructExpression(frontend.getCodeFromRawNode(value)) + val expr: ConstructExpression = newConstructExpression(frontend.codeOf(value)) // map the construct expression to the record declaration of the type expr.instantiates = (type as? ObjectType)?.recordDeclaration @@ -313,14 +309,10 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : if (LLVMIsConstantString(valueRef) == 1) { val string = LLVMGetAsString(valueRef, SizeTPointer(0)).string - return newLiteral( - string, - frontend.typeOf(valueRef), - frontend.getCodeFromRawNode(valueRef) - ) + return newLiteral(string, frontend.typeOf(valueRef), frontend.codeOf(valueRef)) } - val list = newInitializerListExpression(frontend.getCodeFromRawNode(valueRef)) + val list = newInitializerListExpression(frontend.codeOf(valueRef)) val arrayType = LLVMTypeOf(valueRef) val length = if (LLVMIsAConstantDataArray(valueRef) != null) { @@ -400,7 +392,7 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : /** Returns a literal with the type of [value] and value `null`. */ private fun handleNullPointer(value: LLVMValueRef): Expression { val type = frontend.typeOf(value) - return newLiteral(null, type, frontend.getCodeFromRawNode(value)) + return newLiteral(null, type, frontend.codeOf(value)) } /** @@ -444,7 +436,7 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : newProblemExpression( "Default node for getelementptr", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(instr) + frontend.codeOf(instr) ) // loop through all operands / indices @@ -563,7 +555,7 @@ class ExpressionHandler(lang: LLVMIRLanguageFrontend) : * [cast instruction](https://llvm.org/docs/LangRef.html#conversion-operations). */ fun handleCastInstruction(instr: LLVMValueRef): Expression { - val castExpr = newCastExpression(frontend.getCodeFromRawNode(instr)) + val castExpr = newCastExpression(frontend.codeOf(instr)) castExpr.castType = frontend.typeOf(instr) castExpr.expression = frontend.getOperandValueAtIndex(instr, 0) return castExpr diff --git a/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/LLVMIRLanguageFrontend.kt b/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/LLVMIRLanguageFrontend.kt index 6d379022c8..ed44dba0e2 100644 --- a/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/LLVMIRLanguageFrontend.kt +++ b/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/LLVMIRLanguageFrontend.kt @@ -29,6 +29,7 @@ import de.fraunhofer.aisec.cpg.TranslationContext import de.fraunhofer.aisec.cpg.frontends.Language import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.frontends.TranslationException +import de.fraunhofer.aisec.cpg.graph.Node import de.fraunhofer.aisec.cpg.graph.declarations.Declaration import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration @@ -47,12 +48,18 @@ import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation import java.io.File import java.nio.ByteBuffer import org.bytedeco.javacpp.BytePointer +import org.bytedeco.javacpp.Pointer import org.bytedeco.llvm.LLVM.* import org.bytedeco.llvm.global.LLVM.* +/** + * Because we are using the C LLVM API, there are two possibly AST nodes that we need to consider: + * [LLVMValueRef] and [LLVMBasicBlockRef]. Because they do not share any class hierarchy, we need to + * resort to use [Pointer] as the AST node type here. + */ @RegisterExtraPass(CompressLLVMPass::class) class LLVMIRLanguageFrontend(language: Language, ctx: TranslationContext) : - LanguageFrontend(language, ctx) { + LanguageFrontend(language, ctx) { val statementHandler = StatementHandler(this) val declarationHandler = DeclarationHandler(this) @@ -155,6 +162,10 @@ class LLVMIRLanguageFrontend(language: Language, ctx: Tr return tu } + override fun typeOf(type: LLVMTypeRef): Type { + return typeFrom(type, mutableMapOf()) + } + /** Returns a pair of the name and symbol name of [valueRef]. */ fun getNameOf(valueRef: LLVMValueRef): Pair { var name = valueRef.name @@ -213,23 +224,23 @@ class LLVMIRLanguageFrontend(language: Language, ctx: Tr return res } - override fun getCodeFromRawNode(astNode: T): String? { + override fun codeOf(astNode: Pointer): String? { if (astNode is LLVMValueRef) { val code = LLVMPrintValueToString(astNode) return code.string } else if (astNode is LLVMBasicBlockRef) { - return this.getCodeFromRawNode(LLVMBasicBlockAsValue(astNode)) + return this.codeOf(LLVMBasicBlockAsValue(astNode)) } return null } - override fun getLocationFromRawNode(astNode: T): PhysicalLocation? { + override fun locationOf(astNode: Pointer): PhysicalLocation? { return null } - override fun setComment(s: S, ctx: T) { + override fun setComment(node: Node, astNode: Pointer) { // There are no comments in LLVM } @@ -251,7 +262,7 @@ class LLVMIRLanguageFrontend(language: Language, ctx: Tr } fun guessSlotNumber(valueRef: LLVMValueRef): String { - val code = getCodeFromRawNode(valueRef) + val code = codeOf(valueRef) return if (code?.contains("=") == true) { code.split("=").firstOrNull()?.trim()?.trim('%') ?: "" } else { diff --git a/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/StatementHandler.kt b/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/StatementHandler.kt index e29edb41e4..2c027c2d8d 100644 --- a/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/StatementHandler.kt +++ b/cpg-language-llvm/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/llvm/StatementHandler.kt @@ -74,7 +74,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : when (opcode) { LLVMRet -> { - val ret = newReturnStatement(frontend.getCodeFromRawNode(instr)) + val ret = newReturnStatement(frontend.codeOf(instr)) val numOps = LLVMGetNumOperands(instr) if (numOps != 0) { @@ -98,14 +98,14 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : } LLVMUnreachable -> { // Does nothing - return newEmptyStatement(frontend.getCodeFromRawNode(instr)) + return newEmptyStatement(frontend.codeOf(instr)) } LLVMCallBr -> { // Maps to a call but also to a goto statement? Barely used => not relevant log.error("Cannot parse callbr instruction yet") } LLVMFNeg -> { - val fneg = newUnaryOperator("-", false, true, frontend.getCodeFromRawNode(instr)) + val fneg = newUnaryOperator("-", false, true, frontend.codeOf(instr)) fneg.input = frontend.getOperandValueAtIndex(instr, 0) return fneg } @@ -133,7 +133,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : } LLVMPHI -> { frontend.phiList.add(instr) - return newEmptyStatement(frontend.getCodeFromRawNode(instr)) + return newEmptyStatement(frontend.codeOf(instr)) } LLVMSelect -> { return declarationOrNot(frontend.expressionHandler.handleSelect(instr), instr) @@ -143,7 +143,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : log.info( "userop instruction is not a real instruction. Replacing it with empty statement" ) - return newEmptyStatement(frontend.getCodeFromRawNode(instr)) + return newEmptyStatement(frontend.codeOf(instr)) } LLVMVAArg -> { return handleVaArg(instr) @@ -179,7 +179,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : "throw", postfix = false, prefix = true, - code = frontend.getCodeFromRawNode(instr) + code = frontend.codeOf(instr) ) } LLVMLandingPad -> { @@ -216,7 +216,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : return newProblemExpression( "Not handling instruction opcode $opcode yet", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(instr) + frontend.codeOf(instr) ) } @@ -249,7 +249,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : gotoStatement.name = name gotoStatement } else { - val emptyStatement = newEmptyStatement(frontend.getCodeFromRawNode(instr)) + val emptyStatement = newEmptyStatement(frontend.codeOf(instr)) emptyStatement.name = name emptyStatement } @@ -267,7 +267,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : @FunctionReplacement(["llvm.catchswitch", "llvm.matchesCatchpad"], "catchswitch") private fun handleCatchswitch(instr: LLVMValueRef): Statement { val numOps = LLVMGetNumOperands(instr) - val nodeCode = frontend.getCodeFromRawNode(instr) + val nodeCode = frontend.codeOf(instr) val parent = frontend.getOperandValueAtIndex(instr, 0) @@ -277,7 +277,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : newCallExpression( llvmInternalRef("llvm.catchswitch"), "llvm.catchswitch", - frontend.getCodeFromRawNode(instr), + frontend.codeOf(instr), false ) dummyCall.addArgument(parent, "parent") @@ -309,7 +309,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : newCallExpression( llvmInternalRef("llvm.matchesCatchpad"), "llvm.matchesCatchpad", - frontend.getCodeFromRawNode(instr), + frontend.codeOf(instr), false ) @@ -365,7 +365,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : newCallExpression( llvmInternalRef("llvm.cleanuppad"), "llvm.cleanuppad", - frontend.getCodeFromRawNode(instr), + frontend.codeOf(instr), false ) dummyCall.addArgument(catchswitch, "parentCatchswitch") @@ -392,7 +392,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : newCallExpression( llvmInternalRef("llvm.catchpad"), "llvm.catchpad", - frontend.getCodeFromRawNode(instr), + frontend.codeOf(instr), false ) dummyCall.addArgument(catchswitch, "parentCatchswitch") @@ -415,13 +415,13 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : newCallExpression( llvmInternalRef("llvm.va_arg"), "llvm.va_arg", - frontend.getCodeFromRawNode(instr), + frontend.codeOf(instr), false ) val operandName = frontend.getOperandValueAtIndex(instr, 0) callExpr.addArgument(operandName) val expectedType = frontend.typeOf(instr) - val typeLiteral = newLiteral(expectedType, expectedType, frontend.getCodeFromRawNode(instr)) + val typeLiteral = newLiteral(expectedType, expectedType, frontend.codeOf(instr)) callExpr.addArgument(typeLiteral) // TODO: Is this correct?? return declarationOrNot(callExpr, instr) } @@ -477,7 +477,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : return newProblemExpression( "Not opcode found for binary operator", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(instr) + frontend.codeOf(instr) ) } @@ -487,7 +487,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : * [ArrayCreationExpression], which creates a fixed sized array, i.e., a block of memory. */ private fun handleAlloca(instr: LLVMValueRef): Statement { - val array = newArrayCreationExpression(frontend.getCodeFromRawNode(instr)) + val array = newArrayCreationExpression(frontend.codeOf(instr)) array.type = frontend.typeOf(instr) @@ -506,7 +506,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : * of a de-referenced pointer in C like `*a = 1`. */ private fun handleStore(instr: LLVMValueRef): Statement { - val binOp = newBinaryOperator("=", frontend.getCodeFromRawNode(instr)) + val binOp = newBinaryOperator("=", frontend.codeOf(instr)) val dereference = newUnaryOperator("*", postfix = false, prefix = true, "") dereference.input = frontend.getOperandValueAtIndex(instr, 1) @@ -637,7 +637,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : newProblemExpression( "Default statement for insertvalue", ProblemNode.ProblemType.TRANSLATION, - frontend.getCodeFromRawNode(instr) + frontend.codeOf(instr) ) if (operand !is ConstructExpression) { copy = declarationOrNot(operand, instr) @@ -646,7 +646,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : newDeclaredReferenceExpression( copy.singleDeclaration?.name?.localName, (copy.singleDeclaration as? VariableDeclaration)?.type ?: newUnknownType(), - frontend.getCodeFromRawNode(instr) + frontend.codeOf(instr) ) } } @@ -706,9 +706,9 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : } } - val compoundStatement = newCompoundStatement(frontend.getCodeFromRawNode(instr)) + val compoundStatement = newCompoundStatement(frontend.codeOf(instr)) - val assignment = newBinaryOperator("=", frontend.getCodeFromRawNode(instr)) + val assignment = newBinaryOperator("=", frontend.codeOf(instr)) assignment.lhs = base assignment.rhs = valueToSet compoundStatement.addStatement(copy) @@ -728,7 +728,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : @FunctionReplacement(["llvm.freeze"], "freeze") private fun handleFreeze(instr: LLVMValueRef): Statement { val operand = frontend.getOperandValueAtIndex(instr, 0) - val instrCode = frontend.getCodeFromRawNode(instr) + val instrCode = frontend.codeOf(instr) // condition: arg != undef && arg != poison val condition = newBinaryOperator("&&", instrCode) @@ -775,11 +775,10 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : */ @FunctionReplacement(["llvm.fence"], "fence") private fun handleFence(instr: LLVMValueRef): Statement { - val instrString = frontend.getCodeFromRawNode(instr) + val instrString = frontend.codeOf(instr) val callExpression = newCallExpression(llvmInternalRef("llvm.fence"), "llvm.fence", instrString, false) - val ordering = - newLiteral(LLVMGetOrdering(instr), parseType("i32"), frontend.getCodeFromRawNode(instr)) + val ordering = newLiteral(LLVMGetOrdering(instr), parseType("i32"), frontend.codeOf(instr)) callExpression.addArgument(ordering, "ordering") if (instrString?.contains("syncscope") == true) { val syncscope = instrString.split("\"")[1] @@ -805,7 +804,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : * the if-then statement. */ private fun handleAtomiccmpxchg(instr: LLVMValueRef): Statement { - val instrStr = frontend.getCodeFromRawNode(instr) + val instrStr = frontend.codeOf(instr) val compoundStatement = newCompoundStatement(instrStr) compoundStatement.name = Name("atomiccmpxchg") val ptr = frontend.getOperandValueAtIndex(instr, 0) @@ -867,7 +866,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : */ private fun handleAtomicrmw(instr: LLVMValueRef): Statement { val lhs = LLVMGetValueName(instr).string - val instrStr = frontend.getCodeFromRawNode(instr) + val instrStr = frontend.codeOf(instr) val operation = LLVMGetAtomicRMWBinOp(instr) val ptr = frontend.getOperandValueAtIndex(instr, 0) val value = frontend.getOperandValueAtIndex(instr, 1) @@ -958,12 +957,12 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : ">" } val condition = newBinaryOperator(operatorCode, instrStr) - val castExprLhs = newCastExpression(frontend.getCodeFromRawNode(instr)) + val castExprLhs = newCastExpression(frontend.codeOf(instr)) castExprLhs.castType = parseType("u${ty.name}") castExprLhs.expression = ptrDeref condition.lhs = castExprLhs - val castExprRhs = newCastExpression(frontend.getCodeFromRawNode(instr)) + val castExprRhs = newCastExpression(frontend.codeOf(instr)) castExprRhs.castType = parseType("u${ty.name}") castExprRhs.expression = value condition.rhs = castExprRhs @@ -1006,7 +1005,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : */ private fun handleIndirectbrStatement(instr: LLVMValueRef): Statement { val numOps = LLVMGetNumOperands(instr) - val nodeCode = frontend.getCodeFromRawNode(instr) + val nodeCode = frontend.codeOf(instr) if (numOps < 2) throw TranslationException( "Indirectbr statement without address and at least one target" @@ -1042,7 +1041,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : private fun handleBrStatement(instr: LLVMValueRef): Statement { if (LLVMGetNumOperands(instr) == 3) { // if(op) then {goto label1} else {goto label2} - val ifStatement = newIfStatement(frontend.getCodeFromRawNode(instr)) + val ifStatement = newIfStatement(frontend.codeOf(instr)) val condition = frontend.getOperandValueAtIndex(instr, 0) ifStatement.condition = condition @@ -1071,7 +1070,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : */ private fun handleSwitchStatement(instr: LLVMValueRef): Statement { val numOps = LLVMGetNumOperands(instr) - val nodeCode = frontend.getCodeFromRawNode(instr) + val nodeCode = frontend.codeOf(instr) if (numOps < 2 || numOps % 2 != 0) throw TranslationException("Switch statement without operand and default branch") @@ -1113,7 +1112,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : * Returns either a [DeclarationStatement] or a [CallExpression]. */ private fun handleFunctionCall(instr: LLVMValueRef): Statement { - val instrStr = frontend.getCodeFromRawNode(instr) + val instrStr = frontend.codeOf(instr) val calledFunc = LLVMGetCalledValue(instr) var calledFuncName: CharSequence = LLVMGetValueName(calledFunc).string var max = LLVMGetNumOperands(instr) - 1 @@ -1146,7 +1145,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : newDeclaredReferenceExpression( calledFuncName, frontend.typeOf(calledFunc), - frontend.getCodeFromRawNode(calledFunc) + frontend.codeOf(calledFunc) ) val callExpr = newCallExpression(callee, calledFuncName, instrStr, false) @@ -1176,7 +1175,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : newUnknownType(), instrStr, true, - frontend.language + instr ) val catchCompoundStatement = newCompoundStatement(instrStr) @@ -1196,7 +1195,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : * [CompressLLVMPass] will move this instruction to the correct location */ private fun handleLandingpad(instr: LLVMValueRef): Statement { - val catchInstr = newCatchClause(frontend.getCodeFromRawNode(instr)) + val catchInstr = newCatchClause(frontend.codeOf(instr)) /* Get the number of clauses on the landingpad instruction and iterate through the clauses to get all types for the catch clauses */ val numClauses = LLVMGetNumClauses(instr) var catchType = "" @@ -1227,9 +1226,9 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : newVariableDeclaration( exceptionName, parseType(catchType), // TODO: This doesn't work for multiple types to catch - frontend.getCodeFromRawNode(instr), + frontend.codeOf(instr), false, - frontend.language + instr ) frontend.bindingsCache["%${exceptionName}"] = except catchInstr.parameter = except @@ -1243,7 +1242,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : * modified value is constructed. */ private fun handleInsertelement(instr: LLVMValueRef): Statement { - val instrStr = frontend.getCodeFromRawNode(instr) + val instrStr = frontend.codeOf(instr) val compoundStatement = newCompoundStatement(instrStr) // TODO: Probably we should make a proper copy of the array @@ -1273,7 +1272,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : * instruction which is modeled as access to an array at a given index. */ private fun handleExtractelement(instr: LLVMValueRef): Statement { - val arrayExpr = newArraySubscriptionExpression(frontend.getCodeFromRawNode(instr)) + val arrayExpr = newArraySubscriptionExpression(frontend.codeOf(instr)) arrayExpr.arrayExpression = frontend.getOperandValueAtIndex(instr, 0) arrayExpr.subscriptExpression = frontend.getOperandValueAtIndex(instr, 1) @@ -1289,7 +1288,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : * barely used and also the features of LLVM are very limited in that scenario. */ private fun handleShufflevector(instr: LLVMValueRef): Statement { - val instrStr = frontend.getCodeFromRawNode(instr) + val instrStr = frontend.codeOf(instr) val list = newInitializerListExpression(instrStr) val elementType = frontend.typeOf(instr).dereference() @@ -1420,8 +1419,8 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : val firstBB = (functions[0] as FunctionDeclaration).body as CompoundStatement val varName = instr.name val type = frontend.typeOf(instr) - val code = frontend.getCodeFromRawNode(instr) - val declaration = newVariableDeclaration(varName, type, code, false, frontend.language) + val code = frontend.codeOf(instr) + val declaration = newVariableDeclaration(varName, type, code, false, instr) declaration.type = type flatAST.add(declaration) @@ -1474,9 +1473,9 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : newVariableDeclaration( lhs, frontend.typeOf(valueRef), - frontend.getCodeFromRawNode(valueRef), + frontend.codeOf(valueRef), false, - frontend.language + valueRef ) decl.initializer = rhs @@ -1503,7 +1502,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : var instr = LLVMGetFirstInstruction(bb) while (instr != null) { - log.debug("Parsing {}", frontend.getCodeFromRawNode(instr)) + log.debug("Parsing {}", frontend.codeOf(instr)) val stmt = frontend.statementHandler.handle(instr) if (stmt != null) { @@ -1578,17 +1577,17 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : binaryOperator.input = unorderedCall } else { // Resulting statement: lhs = op1 op2. - binaryOperator = newBinaryOperator(op, frontend.getCodeFromRawNode(instr)) + binaryOperator = newBinaryOperator(op, frontend.codeOf(instr)) if (unsigned) { val op1Type = "u${op1.type.name}" - val castExprLhs = newCastExpression(frontend.getCodeFromRawNode(instr)) + val castExprLhs = newCastExpression(frontend.codeOf(instr)) castExprLhs.castType = parseType(op1Type) castExprLhs.expression = op1 binaryOperator.lhs = castExprLhs val op2Type = "u${op2.type.name}" - val castExprRhs = newCastExpression(frontend.getCodeFromRawNode(instr)) + val castExprRhs = newCastExpression(frontend.codeOf(instr)) castExprRhs.castType = parseType(op2Type) castExprRhs.expression = op2 binaryOperator.rhs = castExprRhs @@ -1601,7 +1600,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : // Special case for floating point comparisons which check if a value is "unordered // or ". // Statement is then lhs = isunordered(op1, op2) || (op1 op2) - binOpUnordered = newBinaryOperator("||", frontend.getCodeFromRawNode(instr)) + binOpUnordered = newBinaryOperator("||", frontend.codeOf(instr)) binOpUnordered.rhs = binaryOperator val unorderedCall = newCallExpression( @@ -1635,7 +1634,7 @@ class StatementHandler(lang: LLVMIRLanguageFrontend) : * statement has been processed. */ private fun assembleGotoStatement(instr: LLVMValueRef, bbTarget: LLVMValueRef): GotoStatement { - val goto = newGotoStatement(frontend.getCodeFromRawNode(instr)) + val goto = newGotoStatement(frontend.codeOf(instr)) val assigneeTargetLabel = BiConsumer { _: Any, to: Node -> if (to is LabelStatement) { goto.targetLabel = to diff --git a/cpg-language-python/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/python/PythonLanguageFrontend.kt b/cpg-language-python/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/python/PythonLanguageFrontend.kt index f4db007664..11f1116b10 100644 --- a/cpg-language-python/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/python/PythonLanguageFrontend.kt +++ b/cpg-language-python/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/python/PythonLanguageFrontend.kt @@ -29,7 +29,10 @@ import de.fraunhofer.aisec.cpg.TranslationContext import de.fraunhofer.aisec.cpg.frontends.Language import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend import de.fraunhofer.aisec.cpg.frontends.TranslationException +import de.fraunhofer.aisec.cpg.graph.Node import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration +import de.fraunhofer.aisec.cpg.graph.newUnknownType +import de.fraunhofer.aisec.cpg.graph.types.Type import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation import java.io.File import java.nio.file.Paths @@ -37,7 +40,7 @@ import jep.JepException import kotlin.io.path.absolutePathString class PythonLanguageFrontend(language: Language, ctx: TranslationContext) : - LanguageFrontend(language, ctx) { + LanguageFrontend(language, ctx) { private val jep = JepSingleton // configure Jep @Throws(TranslationException::class) @@ -45,17 +48,22 @@ class PythonLanguageFrontend(language: Language, ctx: Tr return parseInternal(file.readText(Charsets.UTF_8), file.path) } - override fun getCodeFromRawNode(astNode: T): String? { + override fun typeOf(type: Any): Type { + // will be invoked by native function + return newUnknownType() + } + + override fun codeOf(astNode: Any): String? { // will be invoked by native function return null } - override fun getLocationFromRawNode(astNode: T): PhysicalLocation? { + override fun locationOf(astNode: Any): PhysicalLocation? { // will be invoked by native function return null } - override fun setComment(s: S, ctx: T) { + override fun setComment(node: Node, astNode: Any) { // will be invoked by native function } 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 e433844b9c..a0317bd83a 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 @@ -64,8 +64,8 @@ class DeclarationHandler(lang: TypeScriptLanguageFrontend) : name, type, listOf(), - this.frontend.getCodeFromRawNode(node), - this.frontend.getLocationFromRawNode(node), + this.frontend.codeOf(node), + this.frontend.locationOf(node), null, false, ) @@ -86,7 +86,7 @@ class DeclarationHandler(lang: TypeScriptLanguageFrontend) : } else { "class" }, - this.frontend.getCodeFromRawNode(node) + this.frontend.codeOf(node) ) this.frontend.scopeManager.enterScope(record) @@ -113,20 +113,11 @@ class DeclarationHandler(lang: TypeScriptLanguageFrontend) : val type = node.typeChildNode?.let { this.frontend.typeHandler.handle(it) } ?: newUnknownType() - return newParamVariableDeclaration( - name, - type, - false, - this.frontend.getCodeFromRawNode(node) - ) + return newParamVariableDeclaration(name, type, false, this.frontend.codeOf(node)) } fun handleSourceFile(node: TypeScriptNode): TranslationUnitDeclaration { - val tu = - newTranslationUnitDeclaration( - node.location.file, - this.frontend.getCodeFromRawNode(node) - ) + val tu = newTranslationUnitDeclaration(node.location.file, this.frontend.codeOf(node)) this.frontend.scopeManager.resetToGlobal(tu) @@ -155,23 +146,18 @@ class DeclarationHandler(lang: TypeScriptLanguageFrontend) : "MethodDeclaration" -> { val record = this.frontend.scopeManager.currentRecord - newMethodDeclaration( - name, - this.frontend.getCodeFromRawNode(node), - false, - record - ) + newMethodDeclaration(name, this.frontend.codeOf(node), false, record) } "Constructor" -> { val record = this.frontend.scopeManager.currentRecord newConstructorDeclaration( record?.name?.toString() ?: "", - this.frontend.getCodeFromRawNode(node), + this.frontend.codeOf(node), record ) } - else -> newFunctionDeclaration(name, this.frontend.getCodeFromRawNode(node)) + else -> newFunctionDeclaration(name, this.frontend.codeOf(node)) } node.typeChildNode?.let { @@ -215,20 +201,15 @@ class DeclarationHandler(lang: TypeScriptLanguageFrontend) : // TODO: support ObjectBindingPattern (whatever it is). seems to be multiple assignment - val `var` = - newVariableDeclaration( - name, - newUnknownType(), - this.frontend.getCodeFromRawNode(node), - false - ) - `var`.location = this.frontend.getLocationFromRawNode(node) + val declaration = + newVariableDeclaration(name, newUnknownType(), this.frontend.codeOf(node), false) + declaration.location = this.frontend.locationOf(node) // the last node that is not an identifier or an object binding pattern is an initializer node.children ?.lastOrNull { it.type != "Identifier" && it.type != "ObjectBindingPattern" } - ?.let { `var`.initializer = this.frontend.expressionHandler.handle(it) } + ?.let { declaration.initializer = this.frontend.expressionHandler.handle(it) } - return `var` + return declaration } } diff --git a/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/ExpressionHandler.kt b/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/ExpressionHandler.kt index 0837f41d35..224e388e56 100644 --- a/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/ExpressionHandler.kt +++ b/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/ExpressionHandler.kt @@ -65,12 +65,12 @@ class ExpressionHandler(lang: TypeScriptLanguageFrontend) : val key = node.children?.first()?.let { this.handle(it) } val value = node.children?.last()?.let { this.handle(it) } - return newKeyValueExpression(key, value, this.frontend.getCodeFromRawNode(node)) + return newKeyValueExpression(key, value, this.frontend.codeOf(node)) } private fun handleJsxClosingElement(node: TypeScriptNode): Expression { // this basically represents an HTML tag with attributes - val tag = newExpressionList(this.frontend.getCodeFromRawNode(node)) + val tag = newExpressionList(this.frontend.codeOf(node)) // it contains an Identifier node, we map this into the name this.frontend.getIdentifierName(node).let { tag.name = Name("") } @@ -86,7 +86,7 @@ class ExpressionHandler(lang: TypeScriptLanguageFrontend) : private fun handleJsxOpeningElement(node: TypeScriptNode): ExpressionList { // this basically represents an HTML tag with attributes - val tag = newExpressionList(this.frontend.getCodeFromRawNode(node)) + val tag = newExpressionList(this.frontend.codeOf(node)) // it contains an Identifier node, we map this into the name this.frontend.getIdentifierName(node).let { tag.name = Name("<$it>") } @@ -100,7 +100,7 @@ class ExpressionHandler(lang: TypeScriptLanguageFrontend) : } private fun handeJsxElement(node: TypeScriptNode): ExpressionList { - val jsx = newExpressionList(this.frontend.getCodeFromRawNode(node)) + val jsx = newExpressionList(this.frontend.codeOf(node)) jsx.expressions = node.children?.mapNotNull { this.handle(it) } ?: emptyList() @@ -129,7 +129,7 @@ class ExpressionHandler(lang: TypeScriptLanguageFrontend) : // we cannot directly return a function declaration as an expression, so we // wrap it into a lambda expression - val lambda = newLambdaExpression(frontend.getCodeFromRawNode(node)) + val lambda = newLambdaExpression(frontend.codeOf(node)) lambda.function = func return lambda @@ -139,11 +139,11 @@ class ExpressionHandler(lang: TypeScriptLanguageFrontend) : val key = node.children?.first()?.let { this.handle(it) } val value = node.children?.last()?.let { this.handle(it) } - return newKeyValueExpression(key, value, this.frontend.getCodeFromRawNode(node)) + return newKeyValueExpression(key, value, this.frontend.codeOf(node)) } private fun handleObjectLiteralExpression(node: TypeScriptNode): InitializerListExpression { - val ile = newInitializerListExpression(this.frontend.getCodeFromRawNode(node)) + val ile = newInitializerListExpression(this.frontend.codeOf(node)) ile.initializers = node.children?.mapNotNull { this.handle(it) } ?: emptyList() @@ -156,24 +156,20 @@ class ExpressionHandler(lang: TypeScriptLanguageFrontend) : // https://github.com/Fraunhofer-AISEC/cpg/issues/463 val value = this.frontend - .getCodeFromRawNode(node) + .codeOf(node) ?.trim() ?.replace("\"", "") ?.replace("`", "") ?.replace("'", "") ?: "" - return newLiteral(value, parseType("String"), frontend.getCodeFromRawNode(node)) + return newLiteral(value, parseType("String"), frontend.codeOf(node)) } private fun handleIdentifier(node: TypeScriptNode): Expression { - val name = this.frontend.getCodeFromRawNode(node)?.trim() ?: "" + val name = this.frontend.codeOf(node)?.trim() ?: "" - return newDeclaredReferenceExpression( - name, - newUnknownType(), - this.frontend.getCodeFromRawNode(node) - ) + return newDeclaredReferenceExpression(name, newUnknownType(), this.frontend.codeOf(node)) } private fun handlePropertyAccessExpression(node: TypeScriptNode): Expression { @@ -181,15 +177,9 @@ class ExpressionHandler(lang: TypeScriptLanguageFrontend) : node.children?.first()?.let { this.handle(it) } ?: ProblemExpression("problem parsing base") - val name = this.frontend.getCodeFromRawNode(node.children?.last()) ?: "" + val name = node.children?.last()?.let { this.frontend.codeOf(it) } ?: "" - return newMemberExpression( - name, - base, - newUnknownType(), - ".", - this.frontend.getCodeFromRawNode(node) - ) + return newMemberExpression(name, base, newUnknownType(), ".", this.frontend.codeOf(node)) } private fun handleCallExpression(node: TypeScriptNode): Expression { @@ -198,25 +188,22 @@ class ExpressionHandler(lang: TypeScriptLanguageFrontend) : // peek at the children, to check whether it is a call expression or member call expression val propertyAccess = node.firstChild("PropertyAccessExpression") - if (propertyAccess != null) { - val memberExpression = - this.handle(propertyAccess) as? MemberExpression - ?: return ProblemExpression("node is not a member expression") + call = + if (propertyAccess != null) { + val memberExpression = + this.handle(propertyAccess) as? MemberExpression + ?: return ProblemExpression("node is not a member expression") - call = - newMemberCallExpression( - memberExpression, - code = this.frontend.getCodeFromRawNode(node) - ) - } else { - // TODO: fqn - how? - val fqn = this.frontend.getIdentifierName(node) - // regular function call + newMemberCallExpression(memberExpression, code = this.frontend.codeOf(node)) + } else { + // TODO: fqn - how? + val fqn = this.frontend.getIdentifierName(node) + // regular function call - val ref = newDeclaredReferenceExpression(fqn) + val ref = newDeclaredReferenceExpression(fqn) - call = newCallExpression(ref, fqn, this.frontend.getCodeFromRawNode(node), false) - } + newCallExpression(ref, fqn, this.frontend.codeOf(node), false) + } // parse the arguments. the first node is the identifier, so we skip that val remainingNodes = node.children?.drop(1) diff --git a/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/StatementHandler.kt b/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/StatementHandler.kt index 0d49979e57..77ae321271 100644 --- a/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/StatementHandler.kt +++ b/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/StatementHandler.kt @@ -58,7 +58,7 @@ class StatementHandler(lang: TypeScriptLanguageFrontend) : private fun handleFunctionDeclaration(node: TypeScriptNode): Statement { // typescript allows to declare function on a statement level, e.g. within a compound // statement. We can wrap it into a declaration statement - val statement = newDeclarationStatement(this.frontend.getCodeFromRawNode(node)) + val statement = newDeclarationStatement(this.frontend.codeOf(node)) val decl = this.frontend.declarationHandler.handle(node) @@ -72,7 +72,7 @@ class StatementHandler(lang: TypeScriptLanguageFrontend) : } private fun handleReturnStatement(node: TypeScriptNode): ReturnStatement { - val returnStmt = newReturnStatement(this.frontend.getCodeFromRawNode(node)) + val returnStmt = newReturnStatement(this.frontend.codeOf(node)) node.children?.first()?.let { returnStmt.returnValue = this.frontend.expressionHandler.handle(it) @@ -82,7 +82,7 @@ class StatementHandler(lang: TypeScriptLanguageFrontend) : } private fun handleBlock(node: TypeScriptNode): CompoundStatement { - val block = newCompoundStatement(this.frontend.getCodeFromRawNode(node)) + val block = newCompoundStatement(this.frontend.codeOf(node)) node.children?.forEach { this.handle(it)?.let { it1 -> block.addStatement(it1) } } @@ -98,7 +98,7 @@ class StatementHandler(lang: TypeScriptLanguageFrontend) : } private fun handleVariableStatement(node: TypeScriptNode): DeclarationStatement { - val statement = newDeclarationStatement(this.frontend.getCodeFromRawNode(node)) + val statement = newDeclarationStatement(this.frontend.codeOf(node)) // the declarations are contained in a VariableDeclarationList val nodes = node.firstChild("VariableDeclarationList")?.children diff --git a/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/TypeScriptLanguageFrontend.kt b/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/TypeScriptLanguageFrontend.kt index edaf51eb6c..8eb7e3eeda 100644 --- a/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/TypeScriptLanguageFrontend.kt +++ b/cpg-language-typescript/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/typescript/TypeScriptLanguageFrontend.kt @@ -35,6 +35,7 @@ import de.fraunhofer.aisec.cpg.graph.* import de.fraunhofer.aisec.cpg.graph.Annotation import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression +import de.fraunhofer.aisec.cpg.graph.types.Type import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation import de.fraunhofer.aisec.cpg.sarif.Region import java.io.File @@ -58,7 +59,7 @@ import java.nio.file.StandardCopyOption class TypeScriptLanguageFrontend( language: Language, ctx: TranslationContext -) : LanguageFrontend(language, ctx) { +) : LanguageFrontend(language, ctx) { val declarationHandler = DeclarationHandler(this) val statementHandler = StatementHandler(this) @@ -107,6 +108,11 @@ class TypeScriptLanguageFrontend( return translationUnit } + override fun typeOf(type: TypeScriptNode): Type { + // reserved for future use + return newUnknownType() + } + /** * Extracts comments from the file with a regular expression and calls a best effort approach * function that matches them to the closes ast node in the cpg. @@ -146,29 +152,24 @@ class TypeScriptLanguageFrontend( } } - override fun getCodeFromRawNode(astNode: T): String? { - return (astNode as? TypeScriptNode)?.code + override fun codeOf(astNode: TypeScriptNode): String? { + return astNode.code } - override fun getLocationFromRawNode(astNode: T): PhysicalLocation? { - return if (astNode is TypeScriptNode) { - - var position = astNode.location.pos - - // Correcting node positions as we have noticed that the parser computes wrong - // positions, it is apparent when a file starts with a comment - astNode.code?.let { code -> - currentFileContent?.let { position = it.indexOf(code, position) } - } + override fun locationOf(astNode: TypeScriptNode): PhysicalLocation { + var position = astNode.location.pos - // From here on the invariant 'astNode.location.end - position != astNode.code!!.length' - // should hold, only exceptions are mispositioned empty ast elements - val region = - getRegionFromStartEnd(File(astNode.location.file), position, astNode.location.end) - PhysicalLocation(File(astNode.location.file).toURI(), region ?: Region()) - } else { - null + // Correcting node positions as we have noticed that the parser computes wrong + // positions, it is apparent when a file starts with a comment + astNode.code?.let { code -> + currentFileContent?.let { position = it.indexOf(code, position) } } + + // From here on the invariant 'astNode.location.end - position != astNode.code!!.length' + // should hold, only exceptions are mispositioned empty ast elements + val region = + getRegionFromStartEnd(File(astNode.location.file), position, astNode.location.end) + return PhysicalLocation(File(astNode.location.file).toURI(), region ?: Region()) } fun getRegionFromStartEnd(file: File, start: Int, end: Int): Region? { @@ -197,12 +198,12 @@ class TypeScriptLanguageFrontend( return region } - override fun setComment(s: S, ctx: T) { + override fun setComment(node: Node, astNode: TypeScriptNode) { // not implemented } internal fun getIdentifierName(node: TypeScriptNode) = - this.getCodeFromRawNode(node.firstChild("Identifier")) ?: "" + node.firstChild("Identifier")?.let { this.codeOf(it) } ?: "" fun processAnnotations(node: Node, astNode: TypeScriptNode) { // filter for decorators @@ -218,7 +219,7 @@ class TypeScriptLanguageFrontend( return if (callExpr != null) { val call = this.expressionHandler.handle(callExpr) as CallExpression - val annotation = newAnnotation(call.name.localName, this.getCodeFromRawNode(node) ?: "") + val annotation = newAnnotation(call.name.localName, this.codeOf(node) ?: "") annotation.members = call.arguments.map { newAnnotationMember("", it, it.code ?: "") }.toMutableList() @@ -230,7 +231,7 @@ class TypeScriptLanguageFrontend( // or a decorator just has a simple identifier val name = this.getIdentifierName(node) - newAnnotation(name, this.getCodeFromRawNode(node) ?: "") + newAnnotation(name, this.codeOf(node) ?: "") } } }