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

SARIF output #546

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions framework/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ dependencies {
implementation "org.plumelib:plume-util:${plumeUtilVersion}"
implementation "org.plumelib:reflection-util:${reflectionUtilVersion}"
implementation 'io.github.classgraph:classgraph:4.8.161'
implementation 'de.jcup.sarif.java:sarif-2.1.0:1.1.0' // support for sarif files


testImplementation "junit:junit:${junitVersion}"
testImplementation project(':framework-test')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package org.checkerframework.framework.sarif;

import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.Pair;

import org.checkerframework.checker.nullness.qual.Nullable;

import java.nio.file.Path;
import java.util.Collections;

import javax.lang.model.element.Element;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;

import de.jcup.sarif_2_1_0.model.*;

/**
* Provide support for handling with SARIF outputs. If you want to output a SARIF you need to call
* {@link #initialize(Path)}, which also adds a shutdown hook to the JVM.
*
* <p>Use {@link #addResult(Diagnostic.Kind, String, Element)} and others to report an issue.
*
* @author Alexander Weigl <weigl@kit.edu>
* @version 1 (20.07.23)
*/
public class SarifFacade {
@Nullable private static SarifSchema210 schema;
@Nullable private static Run run1;

public static SarifSchema210 getReport() {
return schema;
}

public static void addResult(Result e) {
if (run1 != null) {
run1.getResults().add(e);
}
}

/**
* @param sink
*/
public static void initialize(Path sink) {
schema = new SarifSchema210();
run1 = new Run();
Tool toolCheckerFramework = new Tool();
ToolComponent driver = new ToolComponent();
driver.setName("checker-framework");
String driverGuid = "1234-guid-test-tool-driver-id";
driver.setGuid(driverGuid);
driver.setFullName("Only-Test");
toolCheckerFramework.setDriver(driver);
run1.setTool(toolCheckerFramework);
schema.getRuns().add(run1);

Runtime.getRuntime().addShutdownHook(new Thread(() -> SarifFacade.save(sink)));
}

public static void save(Path sink) {}

public static void addResult(Diagnostic.Kind kind, String messageText, Element preciseSource) {
JCDiagnostic.DiagnosticPosition pos = null;
JavacProcessingEnvironment processingEnv = null; // TODO How to receive this
JavacElements elemUtils = processingEnv.getElementUtils();
Pair<JCTree, JCTree.JCCompilationUnit> treeTop = elemUtils.getTreeAndTopLevel(e, a, v);
if (treeTop != null) {
JavaFileObject newSource = treeTop.snd.sourcefile;
if (newSource != null) {
// save the old version and reinstate it later
pos = treeTop.fst.pos();
}
}
}

public static void addResult(
Diagnostic.Kind kind,
String messageText,
String uri,
int lineStart,
int columnStart,
int lineEnd,
int columnEnd) {
Result e = new Result();
e.setLevel(toKind(kind));
Location loc = new Location();
PhysicalLocation pl = new PhysicalLocation();
ArtifactLocation al = new ArtifactLocation();
al.setUri(uri);
pl.setArtifactLocation(al);
Region region = new Region();
region.setStartLine(lineStart);
region.setStartColumn(columnStart);
region.setEndColumn(columnEnd);
region.setEndLine(lineEnd);
pl.setRegion(region);
loc.setPhysicalLocation(pl);
e.setLocations(Collections.singletonList(loc));
Message message = new Message();
message.setText(messageText);
e.setMessage(message);
addResult(e);
}

private static Result.Level toKind(Diagnostic.Kind kind) {
switch (kind) {
case ERROR:
return Result.Level.ERROR;
case WARNING:
case MANDATORY_WARNING:
return Result.Level.WARNING;
case NOTE:
return Result.Level.NOTE;
case OTHER:
return Result.Level.NONE;
}
throw new IllegalArgumentException("unreachable");
}

public static void addResult(
Diagnostic.Kind kind,
String messageText,
Tree preciseSource,
CompilationUnitTree currentRoot) {
JCDiagnostic.DiagnosticPosition pos = ((JCTree) preciseSource).pos();
// addResult(kind, messageText, );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.checkerframework.checker.signature.qual.FullyQualifiedName;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.framework.qual.AnnotatedFor;
import org.checkerframework.framework.sarif.SarifFacade;
import org.checkerframework.framework.type.AnnotatedTypeFactory;
import org.checkerframework.framework.util.CheckerMain;
import org.checkerframework.framework.util.OptionConfiguration;
Expand Down Expand Up @@ -57,6 +58,7 @@
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.net.URI;
import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayDeque;
import java.util.ArrayList;
Expand Down Expand Up @@ -345,6 +347,10 @@
// org.checkerframework.framework.source.SourceChecker.message(Kind, Object, String, Object...)
"detailedmsgtext",

// SARIF output: Specify a path where the sarif file should be written (JSON)
// Useful for further processing!
"sarif",

/// Stub and JDK libraries

// Ignore the standard jdk.astub file; primarily for testing or debugging.
Expand Down Expand Up @@ -585,6 +591,11 @@ public abstract class SourceChecker extends AbstractTypeProcessor implements Opt
/** Default constructor. */
protected SourceChecker() {}

/**
* If not null, initialize the {@link SarifFacade} and dump a sarif output to the given path.
*/
@Nullable private Path sarifOutput;

/** True if the -Afilenames command-line argument was passed. */
private boolean printFilenames;

Expand Down Expand Up @@ -986,12 +997,20 @@ public void initChecker() {
this.activeLints = createActiveLints(getOptions());
}

final String sarif = getOption("sarif");
if (sarif != null) {
sarifOutput = Paths.get(sarif);
}
printFilenames = hasOption("filenames");
warns = hasOption("warns");
showSuppressWarningsStrings = hasOption("showSuppressWarningsStrings");
requirePrefixInWarningSuppressions = hasOption("requirePrefixInWarningSuppressions");
showPrefixInWarningMessages = hasOption("showPrefixInWarningMessages");
warnUnneededSuppressions = hasOption("warnUnneededSuppressions");

if (sarifOutput != null) {
SarifFacade.initialize(sarifOutput);
}
}

/** Output the warning about source level at most once. */
Expand Down Expand Up @@ -1236,8 +1255,10 @@ private void report(
}

if (preciseSource instanceof Element) {
SarifFacade.addResult(kind, messageText, (Element) preciseSource);
messager.printMessage(kind, messageText, (Element) preciseSource);
} else if (preciseSource instanceof Tree) {
SarifFacade.addResult(kind, messageText, (Tree) preciseSource, currentRoot);
printOrStoreMessage(kind, messageText, (Tree) preciseSource, currentRoot);
} else {
throw new BugInCF("invalid position source, class=" + preciseSource.getClass());
Expand Down Expand Up @@ -1679,7 +1700,7 @@ public final boolean getLintOption(String name, boolean def) {
* @param name the name of the lint option to set
* @param val the option value
* @see SourceChecker#getLintOption(String)
* @see SourceChecker#getLintOption(String,boolean)
* @see SourceChecker#getLintOption(String, boolean)
*/
protected final void setLintOption(String name, boolean val) {
if (!this.getSupportedLintOptions().contains(name)) {
Expand Down Expand Up @@ -1864,7 +1885,7 @@ public final boolean hasOption(String name) {
/**
* {@inheritDoc}
*
* @see SourceChecker#getLintOption(String,boolean)
* @see SourceChecker#getLintOption(String, boolean)
*/
@Override
public final String getOption(String name) {
Expand All @@ -1874,7 +1895,7 @@ public final String getOption(String name) {
/**
* {@inheritDoc}
*
* @see SourceChecker#getLintOption(String,boolean)
* @see SourceChecker#getLintOption(String, boolean)
*/
@Override
public final boolean getBooleanOption(String name) {
Expand All @@ -1884,7 +1905,7 @@ public final boolean getBooleanOption(String name) {
/**
* {@inheritDoc}
*
* @see SourceChecker#getLintOption(String,boolean)
* @see SourceChecker#getLintOption(String, boolean)
*/
@Override
public final boolean getBooleanOption(String name, boolean defaultValue) {
Expand Down Expand Up @@ -1914,7 +1935,7 @@ public Map<String, String> getOptions() {
/**
* {@inheritDoc}
*
* @see SourceChecker#getLintOption(String,boolean)
* @see SourceChecker#getLintOption(String, boolean)
*/
@Override
public final String getOption(String name, String defaultValue) {
Expand Down