From 7b185c9c0ce2816633ca84a80963f09d0ea81e82 Mon Sep 17 00:00:00 2001 From: Romain Lefeuvre Date: Tue, 18 Nov 2025 14:41:54 +0100 Subject: [PATCH] 2025 init --- README.md | 20 ++++++ code/Exercise3/README.md | 3 + code/Exercise4/README.md | 3 + code/Exercise5/README.md | 3 + code/Exercise6/README.md | 3 + code/javaparser-starter/pom.xml | 69 +++++++++++++++++++ .../src/main/java/fr/istic/vv/Main.java | 39 +++++++++++ .../fr/istic/vv/PublicElementsPrinter.java | 48 +++++++++++++ exercises/designer-help.md | 34 +++++++++ exercises/extending-pmd.md | 25 +++++++ exercises/jp-cc.md | 9 +++ exercises/jp-tcc.md | 11 +++ exercises/no-getter.md | 29 ++++++++ exercises/pmd-help.md | 18 +++++ exercises/tcc-vs-lcc.md | 8 +++ exercises/using-pmd.md | 6 ++ pmd-designer-docker/Dockerfile | 44 ++++++++++++ pmd-designer-docker/README.md | 12 ++++ sujet.md | 33 +++++++++ 19 files changed, 417 insertions(+) create mode 100644 README.md create mode 100644 code/Exercise3/README.md create mode 100644 code/Exercise4/README.md create mode 100644 code/Exercise5/README.md create mode 100644 code/Exercise6/README.md create mode 100644 code/javaparser-starter/pom.xml create mode 100644 code/javaparser-starter/src/main/java/fr/istic/vv/Main.java create mode 100644 code/javaparser-starter/src/main/java/fr/istic/vv/PublicElementsPrinter.java create mode 100644 exercises/designer-help.md create mode 100644 exercises/extending-pmd.md create mode 100644 exercises/jp-cc.md create mode 100644 exercises/jp-tcc.md create mode 100644 exercises/no-getter.md create mode 100644 exercises/pmd-help.md create mode 100644 exercises/tcc-vs-lcc.md create mode 100644 exercises/using-pmd.md create mode 100644 pmd-designer-docker/Dockerfile create mode 100644 pmd-designer-docker/README.md create mode 100644 sujet.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c0ff5be --- /dev/null +++ b/README.md @@ -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. diff --git a/code/Exercise3/README.md b/code/Exercise3/README.md new file mode 100644 index 0000000..200e971 --- /dev/null +++ b/code/Exercise3/README.md @@ -0,0 +1,3 @@ +# Code of your exercise + +Put here all the code created for this exercise \ No newline at end of file diff --git a/code/Exercise4/README.md b/code/Exercise4/README.md new file mode 100644 index 0000000..200e971 --- /dev/null +++ b/code/Exercise4/README.md @@ -0,0 +1,3 @@ +# Code of your exercise + +Put here all the code created for this exercise \ No newline at end of file diff --git a/code/Exercise5/README.md b/code/Exercise5/README.md new file mode 100644 index 0000000..200e971 --- /dev/null +++ b/code/Exercise5/README.md @@ -0,0 +1,3 @@ +# Code of your exercise + +Put here all the code created for this exercise \ No newline at end of file diff --git a/code/Exercise6/README.md b/code/Exercise6/README.md new file mode 100644 index 0000000..200e971 --- /dev/null +++ b/code/Exercise6/README.md @@ -0,0 +1,3 @@ +# Code of your exercise + +Put here all the code created for this exercise \ No newline at end of file diff --git a/code/javaparser-starter/pom.xml b/code/javaparser-starter/pom.xml new file mode 100644 index 0000000..39ebc8b --- /dev/null +++ b/code/javaparser-starter/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + + fr.istic.vv + javaparser-starter + 1.0 + + + UTF-8 + 9 + 9 + + + + + com.github.javaparser + javaparser-core + 3.16.2 + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.1 + + + + true + fr.istic.vv.Main + + + + + + + + maven-assembly-plugin + + + + true + fr.istic.vv.Main + + + + jar-with-dependencies + + + + + make-my-jar-with-dependencies + package + + single + + + + + + + + \ No newline at end of file diff --git a/code/javaparser-starter/src/main/java/fr/istic/vv/Main.java b/code/javaparser-starter/src/main/java/fr/istic/vv/Main.java new file mode 100644 index 0000000..702894d --- /dev/null +++ b/code/javaparser-starter/src/main/java/fr/istic/vv/Main.java @@ -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; + }); + } + + +} diff --git a/code/javaparser-starter/src/main/java/fr/istic/vv/PublicElementsPrinter.java b/code/javaparser-starter/src/main/java/fr/istic/vv/PublicElementsPrinter.java new file mode 100644 index 0000000..af5a525 --- /dev/null +++ b/code/javaparser-starter/src/main/java/fr/istic/vv/PublicElementsPrinter.java @@ -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 { + + @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)); + } + +} diff --git a/exercises/designer-help.md b/exercises/designer-help.md new file mode 100644 index 0000000..ddf7ef8 --- /dev/null +++ b/exercises/designer-help.md @@ -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 +``` diff --git a/exercises/extending-pmd.md b/exercises/extending-pmd.md new file mode 100644 index 0000000..2239dc6 --- /dev/null +++ b/exercises/extending-pmd.md @@ -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 + diff --git a/exercises/jp-cc.md b/exercises/jp-cc.md new file mode 100644 index 0000000..ceb0ef6 --- /dev/null +++ b/exercises/jp-cc.md @@ -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. diff --git a/exercises/jp-tcc.md b/exercises/jp-tcc.md new file mode 100644 index 0000000..4eda7ae --- /dev/null +++ b/exercises/jp-tcc.md @@ -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. diff --git a/exercises/no-getter.md b/exercises/no-getter.md new file mode 100644 index 0000000..5b1a341 --- /dev/null +++ b/exercises/no-getter.md @@ -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`. + +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. diff --git a/exercises/pmd-help.md b/exercises/pmd-help.md new file mode 100644 index 0000000..6ddb79f --- /dev/null +++ b/exercises/pmd-help.md @@ -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 \ No newline at end of file diff --git a/exercises/tcc-vs-lcc.md b/exercises/tcc-vs-lcc.md new file mode 100644 index 0000000..dc2a20a --- /dev/null +++ b/exercises/tcc-vs-lcc.md @@ -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 + diff --git a/exercises/using-pmd.md b/exercises/using-pmd.md new file mode 100644 index 0000000..833278a --- /dev/null +++ b/exercises/using-pmd.md @@ -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 + diff --git a/pmd-designer-docker/Dockerfile b/pmd-designer-docker/Dockerfile new file mode 100644 index 0000000..af923ef --- /dev/null +++ b/pmd-designer-docker/Dockerfile @@ -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"] diff --git a/pmd-designer-docker/README.md b/pmd-designer-docker/README.md new file mode 100644 index 0000000..085d469 --- /dev/null +++ b/pmd-designer-docker/README.md @@ -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 +``` \ No newline at end of file diff --git a/sujet.md b/sujet.md new file mode 100644 index 0000000..8fb97f5 --- /dev/null +++ b/sujet.md @@ -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) +