Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

A type used before its declaration, in a file shared by two independent source sets, resolves to the other source set's copy

Abierto
#179 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
58/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
java
Área
compilers

Línea de trabajo

Start with the reproducing test in maddi-inspection-openjdk/src/test/java/io/codelaser/maddi/inspection/openjdk/TestSharedSourceFileInTwoSourceSets.java and run ./gradlew :maddi-inspection-openjdk:test --tests 'TestSharedSourceFileInTwoSourceSets'. Trace how JavaInspector.parseMultiSourceSet resolves the nested type used before its declaration, then inspect InfoByFqn.getType and computeDistance as suggested by the issue. Done means both test cases pass and each source set's reference resolves to its own class.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

What happens

When one Java source file is compiled into two source sets that do not depend on each other, maddi parses one copy of the file per source set — correct. But in the second copy, a use of a type that is declared further down the same file resolves to the first source set's copy of that type.

javac compiles each source set on its own, so the second copy can only ever mean its own type. The first source set is not even a dependency of the second.

Minimal shape (the file is in both source sets):

public final class ClassificationMetadataResolver {
    private static void checkStatus(HttpURLConnection connection, URI uri) throws IOException {
        if ( connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND ) {
            throw new MissingMetadataException( uri );     // <-- in the 2nd source set, this links to the 1st set's class
        }
    }

    private static final class MissingMetadataException extends IOException {   // declared AFTER its use
        ...
    }
}

With the nested class declared before checkStatus, both copies resolve correctly.

Reproducing test

Branch test/shared-source-file-in-two-source-sets (one commit on top of main), file
maddi-inspection-openjdk/src/test/java/io/codelaser/maddi/inspection/openjdk/TestSharedSourceFileInTwoSourceSets.java.

It only uses maddi: two source sets depending on java.base only, the same in-memory source in both, parsed with JavaInspector.parseMultiSourceSet (the same setup as TestStubMeetsItsOwnSource).

./gradlew :maddi-inspection-openjdk:test --tests '*TestSharedSourceFileInTwoSourceSets*'
Test Result on main (527709bb6)
typeUsedBeforeItsDeclaration — nested class declared after its use fails
typeDeclaredBeforeItsUse — control, nested class declared before its use passes

Failure:

the copy of checkStatus in source set 'test-protocolB' does `new MissingMetadataException( uri )`; the list is
the source set of the MissingMetadataException that call resolved to, and it must be the same source set
==> expected: <[test-protocolB]> but was: <[test-protocol]>

Probable cause (not verified in the code path)

The second scan meets new MissingMetadataException( uri ) before it has registered its own copy of the nested class, asks InfoByFqn.getType(fqn, sourceSetOfCurrentTask), and gets the only copy registered so far:

  • getType returns an entry of singleTypeByFqn directly, without looking at its source set;
  • with several entries, computeDistance gives an unreachable source set Integer.MAX_VALUE, and the choice sorts rather than excludes, so an unreachable copy still wins when it is the only candidate.

Where it was found, and what it costs

hibernate-orm d6c1a87f14 compiles shared/classification/src/main/java into two Gradle projects:

local-build-plugins/build.gradle:                           sourceSets.main.java.srcDir("../shared/classification/src/main/java")
tooling/hibernate-dialect-provider/hibernate-dialect-provider-tooling.gradle:   main.java.srcDir rootProject.file("shared/classification/src/main/java")

The CodeLaser dead-code analysis then saw nothing creating the tooling/hibernate-dialect-provider/main copy of ClassificationMetadataResolver.MissingMetadataException, reported its constructor and its field uri dead while the checkStatus that creates it (correctly) stayed alive, and the removal refused the whole hibernate-orm run.

Any project that compiles one source folder into several modules, with a type used before its declaration, gets the same wrong link: the copy that is really used looks unused, and the other copy looks used.

Lenguaje dominante
Java
Estrellas
1
Forks
1
Merge medio
1 h 55 min
PR fusionados (30 d)
8

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de CodeLaser/maddi

Todos los issues de CodeLaser/maddi

Issues similares

Más issues de Java

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.