redhat-developer / redhat-developer/vscode-java

Inline Method changes behavior for polymorphic method call

Offen
#4,425 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

bug
Vorherrschende Sprache
TypeScript
Sterne
2.3k
Forks
546
Ø Merge
20 Std. 1 Min.
Gemergte PRs (30 T.)
11

Beschreibung

Description

When using Inline Method on a method that is overridden in a subclass, VS Code Java performs the refactoring successfully, but the refactored program changes its runtime behavior.

The original program relies on dynamic dispatch. After inlining the superclass method body, the polymorphic method call is replaced with a fixed value, which breaks the original behavior.

Steps to reproduce

  1. Create the following Java code.
  2. Place the caret on method f in class A.
  3. Invoke Refactor -> Inline Method.
  4. Apply the inline refactoring.
  5. Run the program before and after refactoring.

Original code

package org.example;

public class Main {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();

        a1.test();
        a2.test();
    }
}

class A {

    int f() {
        return 1;
    }

    void test() {
        int x = f(); // Inline target
        System.out.println(x);
    }
}

class B extends A {
    @Override
    int f() {
        return 2;
    }
}

Actual behavior

VS Code Java performs the inline refactoring. The refactored program still compiles, but its runtime behavior changes.

Original output:

1
2

Refactored output:

1
1

Refactored code generated by VS Code Java:

package org.example;

public class Main {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();

        a1.test();
        a2.test();
    }
}

class A {

    void test() {
        int x = 1;
        System.out.println(x);
    }
}

class B extends A {
    @Override
    int f() {
        return 2;
    }
}

The inline refactoring replaces the polymorphic method call f() with the body of A.f(). However, the call inside A.test() is dynamically dispatched at runtime. When test() is invoked on an instance of B, the original program calls B.f() and prints 2.

After refactoring, this dynamic dispatch is removed, so both calls print 1.

Expected behavior

Inline Method should preserve the runtime behavior of the original program.

The refactoring should either:

  1. reject the inline operation, or
  2. report a warning/error indicating that inlining this method may change behavior because the method is overridden and the call is dynamically dispatched.

It should not silently generate behavior-changing code.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Das Issue nennt keine Implementierungsdatei und keinen Test. Beginne damit, den Einstiegspunkt für das Refactoring Inline Method und die vorhandenen Regressionstests zu finden, reproduziere dann das A/B-Beispiel und verfolge, wie überschriebene Methoden und dynamisch dispatchte Aufrufe behandelt werden. Erledigt ist die Aufgabe, wenn die Operation abgelehnt wird oder vor der Verhaltensänderung warnt und ein Regressionstest die Ausgaben 1 und 2 abdeckt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
java, typescript
Bereich
devtools
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Ruhig
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
55/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.