Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
cfccde7
notizen
Jun 17, 2024
6e533c4
Merge branch 'opalj:develop' into develop
thanhtung24 Aug 24, 2024
1919d6e
WIP
thanhtung24 Aug 24, 2024
03c42fd
Merge branch 'develop' of https://github.com/thanhtung24/opal into de…
thanhtung24 Aug 24, 2024
bdec0d3
WIP
thanhtung24 Sep 10, 2024
8b34d71
V
thanhtung24 Oct 20, 2024
ebd9ea2
v3
thanhtung24 Oct 22, 2024
eb49368
Error handling
thanhtung24 Oct 22, 2024
d710fb5
t
Oct 24, 2024
525cafc
t
Oct 26, 2024
97f9c60
Improve PR
Nov 3, 2024
cb718ae
Merge branch 'develop' of https://github.com/opalj/opal into develop
Nov 3, 2024
f80b189
Improve PR
Nov 6, 2024
d0f30d2
Improve PR
Nov 8, 2024
3f306e1
Merge branch 'opalj:develop' into develop
thanhtung24 Nov 8, 2024
ea5ec5c
Create Subcommand AnalysisCommand
Nov 8, 2024
e209443
Merge branch 'develop' of https://github.com/thanhtung24/opal into de…
Nov 8, 2024
283cfed
Merge branch 'develop' into develop
errt May 6, 2025
db3794d
Merge branch 'develop' into feature/command-line-parsing
errt Jun 26, 2025
3796a68
Reduce boiler plate
errt Jun 27, 2025
fe4abe0
Fix remaining issues from review
errt Jul 3, 2025
421ad3a
Merge branch 'develop' into feature/command-line-parsing
errt Jul 3, 2025
182d78c
Expand CLI capabilities
errt Jul 4, 2025
1fe3a73
Refactor call-graph runner
errt Jul 4, 2025
205d881
Refactor remaining support.info CLI runners
errt Jul 7, 2025
d09359b
Refactor remaining command line runners
errt Jul 8, 2025
1fe8100
Merge branch 'develop' into develop
errt Jul 8, 2025
2a1ebd1
Fix compilation issues
errt Jul 8, 2025
5d3c27c
Fix output file naming
errt Jul 9, 2025
fa9e6c7
Fix immutability runner
errt Jul 21, 2025
c783444
Fix typo
errt Jul 21, 2025
9699d3d
Fix field locality runner
errt Jul 21, 2025
8a9ec01
Fix MethodReceivers runner
errt Jul 22, 2025
8abd34b
Fix ReturnValueFreshness runner
errt Jul 22, 2025
fefbaca
Fix self-reference leakage analysis
errt Jul 21, 2025
b5a6b94
Remove accidentally added file
errt Jul 23, 2025
51f3d68
Minor fixes to CLI
errt Jul 23, 2025
947c3c2
Add documentation on ProjectsAnalysisApplication subclassing
errt Jul 23, 2025
ad6538f
Adapt remaining CLI runners to new framework
errt Jul 23, 2025
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
8 changes: 2 additions & 6 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,10 @@ indent {
}
indentOperator.exemptScope = aloneEnclosed

project.excludePaths = [
"glob:**/DEVELOPING_OPAL/demos/src/main/scala/org/opalj/fpcf/analyses/InterProceduralEscapeAnalysisDemo.scala",
"glob:**/DEVELOPING_OPAL/demos/src/main/scala/org/opalj/fpcf/analyses/SimpleEscapeAnalysisDemo.scala"
]

newlines {
source = keep
afterCurlyLambdaParams = squash
avoidForSimpleOverflow = [slc, tooLong, punct] # singe line comment, does not add newline if line would be too long after, punctuation
avoidForSimpleOverflow = [slc, tooLong, punct] # single line comment, does not add newline if line would be too long after punctuation
topLevelStatementBlankLines = [{ blanks { before = 1 }, maxNest = 0 }]
sometimesBeforeColonInMethodReturnType = false
ignoreInSyntax = false
Expand Down Expand Up @@ -66,6 +61,7 @@ rewrite {
"org\\.scalatest\\..*",
"org\\.scalatestplus\\..*"],
["com\\.typesafe\\.config\\..*"],
["org\\.rogach\\.scallop\\..*"],
["org\\.opalj\\..*"],
["scala\\.collection\\.parallel\\.CollectionConverters\\..*"]
// Catch all
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package org.opalj
package ai

import java.io.File
import java.net.URL
import java.util.concurrent.ConcurrentLinkedQueue
import scala.jdk.CollectionConverters._
Expand All @@ -12,7 +13,8 @@ import org.opalj.br.MethodDescriptor.JustReturnsString
import org.opalj.br.PCAndInstruction
import org.opalj.br.analyses.BasicReport
import org.opalj.br.analyses.Project
import org.opalj.br.analyses.ProjectAnalysisApplication
import org.opalj.br.analyses.ProjectsAnalysisApplication
import org.opalj.br.fpcf.cli.MultiProjectAnalysisConfig
import org.opalj.br.instructions.GETFIELD
import org.opalj.br.instructions.INVOKEINTERFACE
import org.opalj.br.instructions.INVOKESTATIC
Expand All @@ -28,11 +30,15 @@ import org.opalj.br.instructions.LoadString
*
* @author Michael Reif
*/
object CipherGetInstanceStringUsage extends ProjectAnalysisApplication {
object CipherGetInstanceStrings extends ProjectsAnalysisApplication {

override def title: String = "input value analysis for Chipher.getInstance calls"
protected class CipherInstanceConfig(args: Array[String]) extends MultiProjectAnalysisConfig(args) {
val description = "Collects parameter values of Cipher.getInstance calls"
}

protected type ConfigType = CipherInstanceConfig

override def description: String = "Analyzes the input values of Chipher.getInstance calls."
protected def createConfig(args: Array[String]): CipherInstanceConfig = new CipherInstanceConfig(args)

// #################### CONSTANTS ####################

Expand All @@ -42,11 +48,12 @@ object CipherGetInstanceStringUsage extends ProjectAnalysisApplication {

// #################### ANALYSIS ####################

override def doAnalyze(
project: Project[URL],
parameters: Seq[String],
isInterrupted: () => Boolean
): BasicReport = {
override protected def analyze(
cp: Iterable[File],
analysisConfig: CipherInstanceConfig,
execution: Int
): (Project[URL], BasicReport) = {
val (project, _) = analysisConfig.setupProject(cp)

val report = new ConcurrentLinkedQueue[String]

Expand All @@ -71,6 +78,6 @@ object CipherGetInstanceStringUsage extends ProjectAnalysisApplication {
}
}

BasicReport(report.asScala.mkString("\n"))
(project, BasicReport(report.asScala.mkString("\n")))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,35 @@
package org.opalj
package ai

import java.io.File
import java.net.URL
import java.util.concurrent.ConcurrentLinkedQueue
import scala.jdk.CollectionConverters._

import org.opalj.br.Method
import org.opalj.br.analyses.BasicReport
import org.opalj.br.analyses.Project
import org.opalj.br.analyses.ProjectAnalysisApplication
import org.opalj.br.analyses.ProjectsAnalysisApplication
import org.opalj.br.analyses.SomeProject
import org.opalj.br.fpcf.cli.MultiProjectAnalysisConfig
import org.opalj.br.instructions.IFICMPInstruction

/**
* A shallow analysis that tries to identify useless computations; here, "ifs" where the condition
* is constant.
* A shallow analysis that tries to identify useless computations; here, "ifs" where the condition is constant.
*
* @author Michael Eichberg
*/
object UselessComputationsMinimal extends ProjectAnalysisApplication {
object ConstantIfs extends ProjectsAnalysisApplication {

class AnalysisDomain(val project: Project[URL], val method: Method)
protected class ConstantIfsConfig(args: Array[String]) extends MultiProjectAnalysisConfig(args) {
val description = "Collects ifs where the condition is constant"
}

protected type ConfigType = ConstantIfsConfig

protected def createConfig(args: Array[String]): ConstantIfsConfig = new ConstantIfsConfig(args)

class AnalysisDomain(val project: SomeProject, val method: Method)
extends CorrelationalDomain
with domain.DefaultSpecialDomainValuesBinding
with domain.DefaultHandlingOfMethodResults
Expand All @@ -39,16 +49,17 @@ object UselessComputationsMinimal extends ProjectAnalysisApplication {
with domain.TheProject
with domain.TheMethod

def doAnalyze(
theProject: Project[URL],
parameters: Seq[String],
isInterrupted: () => Boolean
): BasicReport = {
override protected def analyze(
cp: Iterable[File],
analysisConfig: ConstantIfsConfig,
execution: Int
): (Project[URL], BasicReport) = {
val (project, _) = analysisConfig.setupProject(cp)

val results = new ConcurrentLinkedQueue[String]()
theProject.parForeachMethodWithBody(isInterrupted) { m =>
project.parForeachMethodWithBody() { m =>
val method = m.method
val result = BaseAI(method, new AnalysisDomain(theProject, method))
val result = BaseAI(method, new AnalysisDomain(project, method))
import result.domain.ConcreteIntegerValue
collectPCWithOperands(result.domain)(method.body.get, result.operandsArray) {
case (
Expand All @@ -62,6 +73,6 @@ object UselessComputationsMinimal extends ProjectAnalysisApplication {
}
}

BasicReport(results.asScala.mkString(s"${results.size} useless computations:\n", "\n", "\n"))
(project, BasicReport(results.asScala.mkString(s"${results.size} useless computations:\n", "\n", "\n")))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,25 @@
package org.opalj
package ai

import java.io.File
import java.net.URL

import org.opalj.br._
import org.opalj.br.analyses._
import org.opalj.br.instructions._
import org.opalj.br.ClassHierarchy
import org.opalj.br.ClassType
import org.opalj.br.Method
import org.opalj.br.MethodWithBody
import org.opalj.br.PC
import org.opalj.br.analyses.BasicReport
import org.opalj.br.analyses.Project
import org.opalj.br.analyses.ProjectsAnalysisApplication
import org.opalj.br.analyses.SomeProject
import org.opalj.br.fpcf.cli.MultiProjectAnalysisConfig
import org.opalj.br.instructions.AASTORE
import org.opalj.br.instructions.ARETURN
import org.opalj.br.instructions.ATHROW
import org.opalj.br.instructions.FieldWriteAccess
import org.opalj.br.instructions.MethodInvocationInstruction
import org.opalj.log.OPALLogger

import scala.collection.parallel.CollectionConverters.ImmutableIterableIsParallelizable

Expand All @@ -15,32 +29,36 @@ import scala.collection.parallel.CollectionConverters.ImmutableIterableIsParalle
*
* @author Michael Eichberg
*/
object ExceptionUsage extends ProjectAnalysisApplication {
object ExceptionUsage extends ProjectsAnalysisApplication {

override def title: String = "Intra-procedural Usage of Exceptions"
protected class ExceptionUsageConfig(args: Array[String]) extends MultiProjectAnalysisConfig(args) {
val description = "Collects intra-procedural usage of exceptions"
}

protected type ConfigType = ExceptionUsageConfig

override def description: String = "Analyses the usage of exceptions."
protected def createConfig(args: Array[String]): ExceptionUsageConfig = new ExceptionUsageConfig(args)

override def doAnalyze(
theProject: Project[URL],
parameters: Seq[String],
isInterrupted: () => Boolean
): BasicReport = {
override protected def analyze(
cp: Iterable[File],
analysisConfig: ExceptionUsageConfig,
execution: Int
): (Project[URL], BasicReport) = {
val (project, _) = analysisConfig.setupProject(cp)

implicit val ch: ClassHierarchy = theProject.classHierarchy
implicit val ch: ClassHierarchy = project.classHierarchy

if (theProject.classFile(ClassType("java/lang/Object")).isEmpty) {
Console.err.println(
"[warn] It seems as if the JDK was not loaded" +
"(use: -libcp=<PATH TO THE JRE>); " +
"the results of the analysis might not be useful."
)
if (project.classFile(ClassType("java/lang/Object")).isEmpty) {
OPALLogger.error(
"analysis configuration",
"It seems as if the JDK was not loaded; the results of the analysis might not be useful."
)(project.logContext)
}

val usages = (for {
classFile <- theProject.allProjectClassFiles.par
classFile <- project.allProjectClassFiles.par
method @ MethodWithBody(body) <- classFile.methods
result = BaseAI(method, new ExceptionUsageAnalysisDomain(theProject, method))
result = BaseAI(method, new ExceptionUsageAnalysisDomain(project, method))
} yield {
import scala.collection.mutable._

Expand Down Expand Up @@ -133,13 +151,13 @@ object ExceptionUsage extends ProjectAnalysisApplication {
else {
Some(usages)
}
}).filter(_.isDefined).map(_.get).flatten
}).filter(_.isDefined).flatMap(_.get)

val (notUsed, used) = usages.toSeq.partition(_.usageInformation.isEmpty)
var report = used.map(_.toString).toList.sorted.mkString("\nUsed\n", "\n", "\n")
report += notUsed.map(_.toString).toList.sorted.mkString("\nNot Used\n", "\n", "\n")

BasicReport(report)
(project, BasicReport(report))
}

}
Expand Down Expand Up @@ -171,7 +189,7 @@ object UsageKind extends Enumeration {
val StoredInField = UsageKind.Value
}

class ExceptionUsageAnalysisDomain(val project: Project[java.net.URL], val method: Method)
class ExceptionUsageAnalysisDomain(val project: SomeProject, val method: Method)
extends CorrelationalDomain
with domain.DefaultSpecialDomainValuesBinding
with domain.l0.TypeLevelPrimitiveValuesConversions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package ai

import scala.language.existentials

import java.io.File
import java.net.URL
import scala.Console.BLUE
import scala.Console.BOLD
Expand All @@ -12,8 +13,9 @@ import scala.Console.RESET
import org.opalj.br.Method
import org.opalj.br.analyses.BasicReport
import org.opalj.br.analyses.Project
import org.opalj.br.analyses.ProjectAnalysisApplication
import org.opalj.br.analyses.ProjectsAnalysisApplication
import org.opalj.br.analyses.SomeProject
import org.opalj.br.fpcf.cli.MultiProjectAnalysisConfig
import org.opalj.br.instructions.INVOKEINTERFACE
import org.opalj.br.instructions.INVOKESPECIAL
import org.opalj.br.instructions.INVOKESTATIC
Expand All @@ -28,19 +30,22 @@ import scala.collection.parallel.CollectionConverters.IterableIsParallelizable
* @author Marco Jacobasch
* @author Michael Eichberg
*/
object InfiniteRecursions extends ProjectAnalysisApplication {
object InfiniteRecursions extends ProjectsAnalysisApplication {

override def title: String = "infinite recursions analysis"

override def description: String = {
"identifies method which calls themselves using infinite recursion"
protected class InfiniteRecursionConfig(args: Array[String]) extends MultiProjectAnalysisConfig(args) {
val description = "Identifies method which calls themselves using infinite recursion"
}

override def doAnalyze(
project: Project[URL],
parameters: Seq[String] = List.empty,
isInterrupted: () => Boolean
): BasicReport = {
protected type ConfigType = InfiniteRecursionConfig

protected def createConfig(args: Array[String]): InfiniteRecursionConfig = new InfiniteRecursionConfig(args)

override protected def analyze(
cp: Iterable[File],
analysisConfig: InfiniteRecursionConfig,
execution: Int
): (Project[URL], BasicReport) = {
val (project, _) = analysisConfig.setupProject(cp)

// In a real application we should take this from a parameter
val maxRecursionDepth = 3
Expand Down Expand Up @@ -72,7 +77,7 @@ object InfiniteRecursions extends ProjectAnalysisApplication {
result <- inifiniteRecursions(maxRecursionDepth, project, method, pcs)
} yield { result }

BasicReport(result.map(_.toString).mkString("\n"))
(project, BasicReport(result.map(_.toString).mkString("\n")))
}

/**
Expand Down
Loading