![JAR search and dependency download from the Maven repository](/logo.png)
de.fraunhofer.aisec.cpg.frontends.Handler.kt Maven / Gradle / Ivy
/*
* Copyright (c) 2019, Fraunhofer AISEC. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* $$$$$$\ $$$$$$$\ $$$$$$\
* $$ __$$\ $$ __$$\ $$ __$$\
* $$ / \__|$$ | $$ |$$ / \__|
* $$ | $$$$$$$ |$$ |$$$$\
* $$ | $$ ____/ $$ |\_$$ |
* $$ | $$\ $$ | $$ | $$ |
* \$$$$$ |$$ | \$$$$$ |
* \______/ \__| \______/
*
*/
package de.fraunhofer.aisec.cpg.frontends
import de.fraunhofer.aisec.cpg.graph.*
import de.fraunhofer.aisec.cpg.graph.newCallExpression
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
/**
* A [Handler] is an abstract base class for a class that translates AST nodes from a raw ast type,
* usually supplied by a language parser into our generic CPG nodes.
*
* It implements at least one [MetadataProvider], so that node builder extension functions (e.g.,
* [newCallExpression] can be used directly to create appropriate nodes.
*
* @param the result node or a collection of nodes
* @param the raw ast node specific to the parser
* @param the language frontend
*/
abstract class Handler(
protected val configConstructor: Supplier,
/** Returns the frontend which used this handler. */
var frontend: L
) : LanguageProvider, CodeAndLocationProvider, ScopeProvider, NamespaceProvider {
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.
*
* @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?
if (ctx == null) {
log.error(
"ctx is NULL. This can happen when ast children are optional in {}. Called by {}",
this.javaClass,
Thread.currentThread().stackTrace[2]
)
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) {
toHandle = toHandle.superclass
handler = map[toHandle]
if (
handler != null && // always ok to handle as generic literal expr
!ctx.javaClass.simpleName.contains("LiteralExpr")
) {
errorWithFileLocation(
frontend,
ctx,
log,
"No handler for type {}, resolving for its superclass {}.",
ctx.javaClass,
toHandle
)
}
if (toHandle == typeOfT || typeOfT != null && !typeOfT.isAssignableFrom(toHandle)) {
break
}
}
if (handler != null) {
val s = handler.handle(ctx)
if (s != null) {
// The language frontend might set a location, which we should respect. Otherwise,
// we will
// set the location here.
if (s.location == null) {
frontend.setCodeAndLocation(s, ctx)
}
frontend.setComment(s, ctx)
}
ret = s
} else {
errorWithFileLocation(
frontend,
ctx,
log,
"Parsing of type {} is not supported (yet)",
ctx.javaClass
)
ret = configConstructor.get()
if (ret is ProblemNode) {
val problem = ret
problem.problem =
String.format("Parsing of type {} is not supported (yet)", ctx.javaClass)
}
}
// In case the node is empty, we report a problem
if (ret == null) {
errorWithFileLocation(
frontend,
ctx,
log,
"Parsing of type {} did not produce a proper CPG node",
ctx.javaClass
)
ret = configConstructor.get()
}
frontend.process(ctx, ret)
return ret
}
private fun retrieveTypeParameter(): Class<*>? {
var clazz: Class<*> = this.javaClass
while (clazz.superclass != null && clazz.superclass != Handler::class.java) {
clazz = clazz.superclass
}
val type = clazz.genericSuperclass
if (type is ParameterizedType) {
val rawType = type.actualTypeArguments[1]
return getBaseClass(rawType)
}
log.error("Could not determine generic type of raw AST node in handler")
return null
}
private fun getBaseClass(type: Type): Class<*>? {
if (type is Class<*>) {
return type
} else if (type is ParameterizedType) {
return getBaseClass(type.rawType)
}
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
companion object {
@JvmStatic protected val log: Logger = LoggerFactory.getLogger(Handler::class.java)
}
init {
typeOfT = retrieveTypeParameter()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy