2025 init

This commit is contained in:
Romain Lefeuvre
2025-11-18 14:41:54 +01:00
commit 7b185c9c0c
19 changed files with 417 additions and 0 deletions

20
README.md Normal file
View File

@@ -0,0 +1,20 @@
# Validation and Verification: Practical Session #2
The goal of this practical session is to use and implement static analysis tools to compute metrics such as Cyclomatic Complexity(CC) or Tight Class Cohesion (TCC).
After this session you should be able to use existing static analysis tools, and to extend them to implement your own analysis.
## Exercises
You can access the exercises [here](sujet.md)
## Lab implementation
You can realize this lab by group of 1 or 2.
## Deliverable and evaluation
This lab will be graded. You must **fork this repository** and submit a **merge request** with your answers directly here.
**Deadline:** December 19th, 2025, at 23:59.
**Important:** To be considered for grading, all members of the group must be **tagged in the description** of the merge request.

3
code/Exercise3/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Code of your exercise
Put here all the code created for this exercise

3
code/Exercise4/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Code of your exercise
Put here all the code created for this exercise

3
code/Exercise5/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Code of your exercise
Put here all the code created for this exercise

3
code/Exercise6/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Code of your exercise
Put here all the code created for this exercise

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.istic.vv</groupId>
<artifactId>javaparser-starter</artifactId>
<version>1.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>9</maven.compiler.source>
<maven.compiler.target>9</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>3.16.2</version>
</dependency>
</dependencies>
<build>
<!-- Creates a jar and sets the main class so it can be executed directly wit java -jar .-->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>fr.istic.vv.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<!-- Creates a jar containing the compiled code and all dependencies. Useful for distribution. -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>fr.istic.vv.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-my-jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,39 @@
package fr.istic.vv;
import com.github.javaparser.Problem;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.visitor.VoidVisitor;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.github.javaparser.utils.SourceRoot;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) throws IOException {
if(args.length == 0) {
System.err.println("Should provide the path to the source code");
System.exit(1);
}
File file = new File(args[0]);
if(!file.exists() || !file.isDirectory() || !file.canRead()) {
System.err.println("Provide a path to an existing readable directory");
System.exit(2);
}
SourceRoot root = new SourceRoot(file.toPath());
PublicElementsPrinter printer = new PublicElementsPrinter();
root.parse("", (localPath, absolutePath, result) -> {
result.ifSuccessful(unit -> unit.accept(printer, null));
return SourceRoot.Callback.Result.DONT_SAVE;
});
}
}

View File

@@ -0,0 +1,48 @@
package fr.istic.vv;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.visitor.VoidVisitorWithDefaults;
// This class visits a compilation unit and
// prints all public enum, classes or interfaces along with their public methods
public class PublicElementsPrinter extends VoidVisitorWithDefaults<Void> {
@Override
public void visit(CompilationUnit unit, Void arg) {
for(TypeDeclaration<?> type : unit.getTypes()) {
type.accept(this, null);
}
}
public void visitTypeDeclaration(TypeDeclaration<?> declaration, Void arg) {
if(!declaration.isPublic()) return;
System.out.println(declaration.getFullyQualifiedName().orElse("[Anonymous]"));
for(MethodDeclaration method : declaration.getMethods()) {
method.accept(this, arg);
}
// Printing nested types in the top level
for(BodyDeclaration<?> member : declaration.getMembers()) {
if (member instanceof TypeDeclaration)
member.accept(this, arg);
}
}
@Override
public void visit(ClassOrInterfaceDeclaration declaration, Void arg) {
visitTypeDeclaration(declaration, arg);
}
@Override
public void visit(EnumDeclaration declaration, Void arg) {
visitTypeDeclaration(declaration, arg);
}
@Override
public void visit(MethodDeclaration declaration, Void arg) {
if(!declaration.isPublic()) return;
System.out.println(" " + declaration.getDeclarationAsString(true, true));
}
}

View File

@@ -0,0 +1,34 @@
# Use PMD designer
## Download JavaFX
If JavaFX is not installed you can download it [here](https://gluonhq.com/products/javafx/).
Check the current version of your JDK by running ```java --version``` and download the corresponding version ("Minimum JDK" column).
* Java 17 => JavaFX 21
* Java 11 => JavaDX 17
## Set up JavaFX
Before using `designer` you need to specify JavaFX path.
#### Linux/Unix
```shell
$ export JAVAFX_HOME=path/to/javafx-sdk-{version}
```
#### Windows
```shell
$ set JAVAFX_HOME=path\to\javafx-sdk-{version}
```
## Run designer
#### Linux/Unix
```shell
$ run.sh designer
```
#### Windows
```shell
$ pmd.bat designer
```

View File

@@ -0,0 +1,25 @@
# Extending PMD
Use XPath to define a new rule for PMD to prevent complex code. The rule should detect the use of three or more nested `if` statements in Java programs so it can detect patterns like the following:
```Java
if (...) {
...
if (...) {
...
if (...) {
....
}
}
}
```
Notice that the nested `if`s may not be direct children of the outer `if`s. They may be written, for example, inside a `for` loop or any other statement.
Write below the XML definition of your rule.
You can find more information on extending PMD in the following link: https://pmd.github.io/latest/pmd_userdocs_extending_writing_rules_intro.html, as well as help for using `pmd-designer` [here](https://github.com/selabs-ur1/VV-ISTIC-TP2/blob/master/exercises/designer-help.md).
Use your rule with different projects and describe you findings below. See the [instructions](../sujet.md) for suggestions on the projects to use.
## Answer

9
exercises/jp-cc.md Normal file
View File

@@ -0,0 +1,9 @@
# Cyclomatic Complexity with JavaParser
With the help of JavaParser implement a program that computes the Cyclomatic Complexity (CC) of all methods in a given Java project. The program should take as input the path to the source code of the project. It should produce a report in the format of your choice (TXT, CSV, Markdown, HTML, etc.) containing a table showing for each method: the package and name of the declaring class, the name of the method, the types of the parameters and the value of CC.
Your application should also produce a histogram showing the distribution of CC values in the project. Compare the histogram of two or more projects.
Include in this repository the code of your application. Remove all unnecessary files like compiled binaries. Do include the reports and plots you obtained from different projects. See the [instructions](../sujet.md) for suggestions on the projects to use.
You may use [javaparser-starter](../code/javaparser-starter) as a starting point.

11
exercises/jp-tcc.md Normal file
View File

@@ -0,0 +1,11 @@
# Class cohesion with JavaParser
With the help of JavaParser implement a program that computes the Tight Class Cohesion (TCC) for each class in a given Java project. The program should take as input the path to the source code of the project. It should produce a report in the format of your choice (TXT, CSV, Markdown, HTML, etc.) containing a table showing for each class: the package, name and TCC value.
Your application should also produce a histogram showing the distribution of CC values in the project. Compare the histogram of two or more projects.
Finally, your application should also produce the dependency graph of each class (cf. example [here](https://people.irisa.fr/Benoit.Combemale/pub/course/vv/vv-textbook-v0.1.pdf#cohesion-graph)). The graph should be written using the [GraphViz DOT format](https://www.graphviz.org/)
Ignore inherited members to compute TCC of a class.
Include in this repository the code of your application. Remove all unnecessary files like compiled binaries. Do include the reports and plots you obtained from different projects. See the [instructions](../sujet.md) for suggestions on the projects to use.
You may use [javaparser-starter](../code/javaparser-starter) as a starting point.

29
exercises/no-getter.md Normal file
View File

@@ -0,0 +1,29 @@
# No getter!
With the help of JavaParser implement a program that obtains the private fields of public classes that have no public getter in a Java project.
A field has a public getter if, in the same class, there is a public method that simply returns the value of the field and whose name is `get<name-of-the-field>`.
For example, in the following class:
```Java
class Person {
private int age;
private String name;
public String getName() { return name; }
public boolean isAdult() {
return age > 17;
}
}
```
`name` has a public getter, while `age` doesn't.
The program should take as input the path to the source code of the project. It should produce a report in the format of your choice (TXT, CSV, Markdown, HTML, etc.) that lists for each detected field: its name, the name of the declaring class and the package of the declaring class.
Include in this repository the code of your application. Remove all unnecessary files like compiled binaries. See the [instructions](../sujet.md) for suggestions on the projects to use.
*Disclaimer* In a real project not all fields need to be accessed with a public getter.

18
exercises/pmd-help.md Normal file
View File

@@ -0,0 +1,18 @@
# PMD
### Requirement
* Java 8 or above
### Installation
* download latest release https://github.com/pmd/pmd/releases/download/pmd_releases%2F7.5.0/pmd-dist-7.5.0-bin.zip
* unzip
* add the bin folder to your path
### Usage
(Instruction for linux use ```pmd.bat``` for windows)
* Do not hesitate to have a look on the help page ```pmd -h```
* Same thing for the check help page```pmd check -h```
* Run the analysis ```pmd check -f text -R rulesets/java/quickstart.xml -d [PROJECT_PATH] -r [REPORT_FILE_PATH]```
For more information consult the instructions given in https://pmd.github.io/pmd/pmd_userdocs_installation.html

8
exercises/tcc-vs-lcc.md Normal file
View File

@@ -0,0 +1,8 @@
# TCC *vs* LCC
Explain under which circumstances *Tight Class Cohesion* (TCC) and *Loose Class Cohesion* (LCC) metrics produce the same value for a given Java class. Build an example of such as class and include the code below or find one example in an open-source project from Github and include the link to the class below. Could LCC be lower than TCC for any given class? Explain.
A refresher on TCC and LCC is available in the [course notes](https://oscarlvp.github.io/vandv-classes/#cohesion-graph).
## Answer

6
exercises/using-pmd.md Normal file
View File

@@ -0,0 +1,6 @@
# Using PMD
Pick a Java project from Github (see the [instructions](../sujet.md) for suggestions). Run PMD on its source code using any ruleset (see the [pmd install instruction](./pmd-help.md)). Describe below an issue found by PMD that you think should be solved (true positive) and include below the changes you would add to the source code. Describe below an issue found by PMD that is not worth solving (false positive). Explain why you would not solve this issue.
## Answer

View File

@@ -0,0 +1,44 @@
# Use an official OpenJDK base image
FROM openjdk:23-jdk-slim
# Install necessary dependencies (e.g., X11 libraries for GUI)
RUN apt-get update && apt-get install -y \
libx11-dev \
libxext-dev \
libxrender-dev \
libxtst-dev \
libxi6 \
xauth \
libx11-xcb1 \
libxrandr2 \
libxrender1 \
libxxf86vm1 \
libgtk-3-0 \
libgl1-mesa-glx \
wget \
unzip \
&& apt-get clean
# Download and install OpenJFX 23.0.1 SDK for Linux
RUN wget https://download2.gluonhq.com/openjfx/23.0.1/openjfx-23.0.1_linux-x64_bin-sdk.zip -O /tmp/openjfx.zip \
&& mkdir -p /opt/openjfx \
&& unzip /tmp/openjfx.zip -d /opt/openjfx \
&& rm /tmp/openjfx.zip
# Download and install PMD 7.7.0
RUN wget https://github.com/pmd/pmd/releases/download/pmd_releases%2F7.7.0/pmd-dist-7.7.0-bin.zip -O /tmp/pmd.zip \
&& mkdir -p /opt/pmd \
&& unzip /tmp/pmd.zip -d /opt/pmd \
&& rm /tmp/pmd.zip
# Set environment variables for Java, OpenJFX, and PMD
ENV JAVA_HOME=/usr/lib/jvm/java-23-openjdk
ENV PATH=$JAVA_HOME/bin:$PATH
ENV JAVAFX_HOME=/opt/openjfx/javafx-sdk-23.0.1
ENV PMD_HOME=/opt/pmd/pmd-bin-7.7.0
# Expose necessary ports for the X server (if running on a host machine)
EXPOSE 6000
# Command to run PMD Designer with OpenJFX 23.0.1
CMD ["/opt/pmd/pmd-bin-7.7.0/bin/pmd", "designer"]

View File

@@ -0,0 +1,12 @@
Command to run :
```
docker build -t pmd-designer-javafx:7.7.0 .
xhost +local:docker
docker run -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix pmd-designer-javafx:7.7.0
```
For windows :
```
docker run -e DISPLAY=host.docker.internal:0 pmd-designer-javafx:7.7.0
```

33
sujet.md Normal file
View File

@@ -0,0 +1,33 @@
# Static analysis
## Instructions
Some of the exercises in this practical session use PMD, JavaParser or require a full project as input.
To obtain and use PMD, consult the instructions given in https://pmd.github.io/pmd/pmd_userdocs_installation.html
The folder [javaparser-starter](code/javaparser-starter) contains the code of an application that uses JavaParser to print all public classes and public methods from a given project. You can use this example as a starting point for all exercises using JavaParser.
We recommend you use the following projects as input for the exercises:
- [Apache Commons Collections](https://github.com/apache/commons-collections)
- [Apache Commons CLI](https://github.com/apache/commons-cli)
- [Apache Commons Math](https://github.com/apache/commons-math)
- [Apache Commons Lang](https://github.com/apache/commons-lang)
Feel free to use any other project you want.
## Exercises
1. [TCC *vs* LCC](exercises/tcc-vs-lcc.md)
2. [Using PMD](exercises/using-pmd.md)
3. [Extending PMD](exercises/extending-pmd.md)
4. [No getter!](exercises/no-getter.md)
5. [Cyclomatic Complexity with JavaParser](exercises/jp-cc.md)
6. [Class cohesion with JavaParser](exercises/jp-tcc.md) (bonus)