Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make language frontends configurable #389

Merged
merged 13 commits into from
Apr 15, 2021
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import de.fraunhofer.aisec.cpg.TranslationManager;
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration;

var path = Paths.get("src/test/resources/openssl/client.cpp");
var config = TranslationConfiguration.builder().sourceLocations(path.toFile()).defaultPasses().debugParser(true).build();
var config = TranslationConfiguration.builder().sourceLocations(path.toFile()).defaultPasses().defaultLanguages().debugParser(true).build();
var analyzer = TranslationManager.builder().config(config).build();
var result = analyzer.analyze().get();
var tu = result.getTranslationUnits().get(0);
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ plugins {
id("org.sonarqube") version "3.1.1"
id("com.diffplug.spotless") version "5.12.1"
id("com.github.johnrengelman.shadow") version "6.1.0"
kotlin("jvm") version "1.4.20"
kotlin("jvm") version "1.4.32"
}

tasks.jacocoTestReport {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@

package de.fraunhofer.aisec.cpg;

import static de.fraunhofer.aisec.cpg.frontends.cpp.CXXLanguageFrontend.CXX_EXTENSIONS;
import static de.fraunhofer.aisec.cpg.frontends.cpp.CXXLanguageFrontend.CXX_HEADER_EXTENSIONS;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend;
import de.fraunhofer.aisec.cpg.frontends.cpp.CXXLanguageFrontend;
import de.fraunhofer.aisec.cpg.frontends.java.JavaLanguageFrontend;
import de.fraunhofer.aisec.cpg.passes.CallResolver;
import de.fraunhofer.aisec.cpg.passes.ControlFlowSensitiveDFGPass;
import de.fraunhofer.aisec.cpg.passes.EvaluationOrderGraphPass;
Expand Down Expand Up @@ -87,6 +95,12 @@ public class TranslationConfiguration {
*/
public final List<String> includeBlacklist;

/**
* This map contains a list of language frontends classes and the file types they are registered
* for.
*/
private Map<Class<? extends LanguageFrontend>, List<String>> frontends;

/**
* Switch off cleaning up TypeManager memory after analysis.
*
Expand Down Expand Up @@ -134,6 +148,7 @@ private TranslationConfiguration(
List<String> includeWhitelist,
List<String> includeBlacklist,
List<Pass> passes,
Map<Class<? extends LanguageFrontend>, List<String>> frontends,
boolean codeInNodes,
boolean processAnnotations,
boolean disableCleanup,
Expand All @@ -148,6 +163,7 @@ private TranslationConfiguration(
this.includeWhitelist = includeWhitelist;
this.includeBlacklist = includeBlacklist;
this.passes = passes != null ? passes : new ArrayList<>();
this.frontends = frontends;
// Make sure to init this AFTER sourceLocations has been set
this.codeInNodes = codeInNodes;
this.processAnnotations = processAnnotations;
Expand Down Expand Up @@ -175,6 +191,10 @@ public List<Pass> getRegisteredPasses() {
return this.passes;
}

public Map<Class<? extends LanguageFrontend>, List<String>> getFrontends() {
return this.frontends;
}

/**
* Builds a {@link TranslationConfiguration}.
*
Expand All @@ -192,6 +212,7 @@ public List<Pass> getRegisteredPasses() {
*/
public static class Builder {
private List<File> sourceLocations = new ArrayList<>();
private Map<Class<? extends LanguageFrontend>, List<String>> frontends = new HashMap<>();
private File topLevel = null;
private boolean debugParser = false;
private boolean failOnError = false;
Expand Down Expand Up @@ -322,6 +343,13 @@ public Builder registerPass(@NonNull Pass pass) {
return this;
}

/** Registers an additional {@link de.fraunhofer.aisec.cpg.frontends.LanguageFrontend}. */
public Builder registerLanguage(
@NonNull Class<? extends LanguageFrontend> frontend, List<String> fileTypes) {
this.frontends.put(frontend, fileTypes);
return this;
}

/**
* Register all default {@link Pass}es.
*
Expand Down Expand Up @@ -354,6 +382,22 @@ public Builder defaultPasses() {
return this;
}

/**
* Register all default languages.
*
* @return
*/
public Builder defaultLanguages() {
registerLanguage(
CXXLanguageFrontend.class,
Lists.newArrayList(Iterables.concat(CXX_EXTENSIONS, CXX_HEADER_EXTENSIONS)));
registerLanguage(JavaLanguageFrontend.class, JavaLanguageFrontend.JAVA_EXTENSIONS);

// do not register experimental languages by default until we have a release strategy
// registerLanguage(GoLanguageFrontend.class, GoLanguageFrontend.GOLANG_EXTENSIONS);
return this;
}

public Builder codeInNodes(boolean b) {
this.codeInNodes = b;
return this;
Expand Down Expand Up @@ -391,6 +435,7 @@ public TranslationConfiguration build() {
includeWhitelist,
includeBlacklist,
passes,
frontends,
codeInNodes,
processAnnotations,
disableCleanup,
Expand Down
35 changes: 30 additions & 5 deletions src/main/java/de/fraunhofer/aisec/cpg/TranslationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@

package de.fraunhofer.aisec.cpg;

import static de.fraunhofer.aisec.cpg.frontends.LanguageFrontendFactory.CXX_EXTENSIONS;
import static de.fraunhofer.aisec.cpg.frontends.cpp.CXXLanguageFrontend.CXX_EXTENSIONS;

import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend;
import de.fraunhofer.aisec.cpg.frontends.LanguageFrontendFactory;
import de.fraunhofer.aisec.cpg.frontends.TranslationException;
import de.fraunhofer.aisec.cpg.graph.TypeManager;
import de.fraunhofer.aisec.cpg.helpers.Benchmark;
Expand All @@ -39,6 +38,7 @@
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
Expand All @@ -53,6 +53,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -208,9 +209,7 @@ private HashSet<LanguageFrontend> runFrontends(
log.info("Parsing {}", sourceLocation.getAbsolutePath());
LanguageFrontend frontend = null;
try {
frontend =
LanguageFrontendFactory.getFrontend(
Util.getExtension(sourceLocation), config, scopeManager);
frontend = getFrontend(Util.getExtension(sourceLocation), scopeManager);
if (frontend == null) {
log.error("Found no parser frontend for {}", sourceLocation.getName());

Expand Down Expand Up @@ -258,6 +257,32 @@ private HashSet<LanguageFrontend> runFrontends(
return usedFrontends;
}

@Nullable
private LanguageFrontend getFrontend(String extension, ScopeManager scopeManager) {
var clazz =
this.config.getFrontends().entrySet().stream()
.filter(entry -> entry.getValue().contains(extension))
.map(entry -> entry.getKey())
.findAny()
.orElse(null);

if (clazz != null) {
try {
return clazz
.getConstructor(TranslationConfiguration.class, ScopeManager.class)
.newInstance(this.config, scopeManager);
} catch (InstantiationException
| IllegalAccessException
| InvocationTargetException
| NoSuchMethodException e) {
log.error("Could not instantiate language frontend {}", clazz.getName(), e);
return null;
}
}

return null;
}

/**
* Returns the current (immutable) configuration of this TranslationManager.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ public abstract class LanguageFrontend {
// Allow non-Java frontends to access the logger (i.e. jep)
public static final Logger log = LoggerFactory.getLogger(LanguageFrontend.class);
protected final TranslationConfiguration config;

protected ScopeManager scopeManager;

/**
* Two data structures used to associate Objects input to a pass to results of a pass, e.g.
* Javaparser AST-Nodes to CPG-Nodes. The "Listeners" in processedListener are called after the
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@
*/
public class CXXLanguageFrontend extends LanguageFrontend {

public static final List<String> CXX_EXTENSIONS = List.of(".c", ".cpp", ".cc");
public static final List<String> CXX_HEADER_EXTENSIONS = List.of(".h", ".hpp");

private static final Logger LOGGER = LoggerFactory.getLogger(CXXLanguageFrontend.class);
private final IncludeFileContentProvider includeFileContentProvider =
new InternalFileContentProvider() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import de.fraunhofer.aisec.cpg.sarif.PhysicalLocation
import java.io.File
import kotlin.Throws

class RawGolangNode {}

@ExperimentalGolang
class GoLanguageFrontend(config: TranslationConfiguration, scopeManager: ScopeManager?) :
LanguageFrontend(config, scopeManager, ".") {
companion object {
@kotlin.jvm.JvmField var GOLANG_EXTENSIONS: List<String> = listOf(".go")

init {
System.loadLibrary("cpgo")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@
/** Main parser for ONE Java files. */
public class JavaLanguageFrontend extends LanguageFrontend {

public static final List<String> JAVA_EXTENSIONS = List.of(".java");

public static final String THIS = "this";
public static final String ANNOTATION_MEMBER_VALUE = "value";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import jep.*
@ExperimentalPython
class PythonLanguageFrontend(config: TranslationConfiguration, scopeManager: ScopeManager?) :
LanguageFrontend(config, scopeManager, ".") {
companion object {
@kotlin.jvm.JvmField var PY_EXTENSIONS: List<String> = listOf(".py")
}

@Throws(TranslationException::class)
override fun parse(file: File): TranslationUnitDeclaration {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/de/fraunhofer/aisec/cpg/graph/TypeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,8 @@ public boolean isSupertypeOf(Type superType, Type subType) {
Class superCls = Class.forName(superType.getTypeName());
Class subCls = Class.forName(subType.getTypeName());
return superCls.isAssignableFrom(subCls);
} catch (ClassNotFoundException e) {
// Not in the class path, can't help here
} catch (ClassNotFoundException | NoClassDefFoundError e) {
// Not in the class path or other linkage exception, can't help here
return false;
}
}
Expand Down
Loading