Override Detection Fails with Mixins in Class Inheritance

Issue #2694 resolved
Stanley Zapata created an issue

The IDE correctly identifies overridden properties and methods in a child class when inheriting from a base class. However, as soon as a mixin is introduced alongside class inheritance, the override detection stops working. This makes it harder to determine if a child class properly overrides properties or methods from either the mixin or the base class.

Expected Behavior: The IDE should display overridden methods and properties consistently, regardless of whether the class inherits from a base class, uses a mixin, or both.

Actual Behavior: The IDE fails to detect overridden properties and methods when a mixin is applied alongside a base class.

Environment:

  • IDE version: IntelliJ IDEA 2024.2.4 (Ultimate Edition)
  • Illuminated Cloud Version 2.3.3.8
  • Operating system: Mac OS Sequoia 15.1.1 (24B91)

Comments (12)

  1. Scott Wells repo owner
    • changed status to open

    This one is more tricky than the other I just resolved. At least one of the following is causing this issue:

    1. The way that I've declared NavigationMixin in lwc-standard.d.ts isn't correct for how a mixin should be declared to trigger proper inhertance behavior. This is quite possible as I'm far from a TypeScript expert. Any advice you have on changes that might help there are welcomed.
    2. The JetBrains JavaScript/TypeScript plugin isn't properly interpreting the mixin syntax -- whether what I've done is correct now or not -- as something that should result in an inheritance relationship with the mixin parameter type.

    I think I need to rule out the first case before logging a bug with JetBrains on the second. I need to be fully confident that the way the mixin is declared should imply an inheritance relationship with the mixin parameter type and it's not properly working.

  2. Scott Wells repo owner

    Actually I think I figured it out. If all goes well, I’ll be committing a fix for the next build shortly.

  3. Stanley Zapata reporter

    Nice! After looking into this more, I noticed that the TypeScript plugin in IntelliJ detects overrides for base class functions or properties even when a mixin is applied. It will be great for IlluminatedCloud to have this same behavior. IntelliJ doesn't currently seem to detect when mixin properties or functions are overridden, although I think it should. Having that functionality in IlluminatedCloud will definitely make working with mixins much easier.

    Looking forward to seeing the fix in action—thanks again for the quick turnaround!

    Attaching my test below.

  4. Stanley Zapata reporter

    I am not seeing it working, if you notice when I add a mixin the icons showing that something is being overridden are not showing up as soon as I add the mixin. Should I open a new issue or this can be reopen?

  5. Scott Wells repo owner

    To be clear about what was fixed in this build, it was specifically NavigationMixin and not anything more general than that.

    If you’re seeing other issues with mixin behavior in JavaScript, let’s try to see whether it’s something IC-specific or more general to the JetBrains IDE’s JavaScript/TypeScript support. If you create a non-IC project and apply the same mixin pattern, does it work properly or not? If not, you’ll likely need to log a bug with JetBrains. If it works outside of IC and the exact same pattern does not work in an IC project, please provide a standalone reproducible example so I can take a look at what the difference might be.

  6. Stanley Zapata reporter

    yeah here’s an example of a Typescript Project. After applying a Mixin to an inherited class I can still see that the icon showing that the greet method from the Base Class is being overridden.

  7. Scott Wells repo owner

    And that exact same code doesn’t work the same way in IC? Can you provide it as text instead of as an image?

  8. Stanley Zapata reporter

    Sure, here’s same exact code for both Typescript and LWC.

    Typescript:

    type Constructor<T = {}> = new (...args: any[]) => T;
    
    function LoggerMixin<T extends Constructor>(Base: T) {
        return class extends Base {
    
            log(message: string): void {
                console.log(`[LOG]: ${message}`);
            }
        };
    }
    
    class BaseClass {
        prop = 1;
    
        greet() {
            console.log("Hello from BaseClass!");
        }
    }
    
    class EnhancedClass extends LoggerMixin(BaseClass) {
        prop = 2;
    
        log(message: string) {
            console.log(`[EnhancedClass LOG]: ${message}`);
        }
    
        greet(): void {
            this.log("Hello from EnhancedClass!");
        }
    
        doSomething(): void {
            this.log("Doing something...");
        }
    }
    
    const instance = new EnhancedClass();
    instance.greet();
    instance.doSomething();
    

    LWC:

    import { LightningElement } from "lwc";
    
    class BaseClass extends LightningElement {
        prop = 1;
    
        greet() {
            console.log("Hello from BaseClass!");
        }
    
    }
    
    function LoggerMixin (Base) {
        return class extends Base {
    
            log(message) {
                console.log(`[LOG]: ${message}`);
            }
        }
    }
    
    export default class EnhancedClass extends LoggerMixin(BaseClass) {
        prop = 2;
    
        log(message) {
            console.log(`[EnhancedClass LOG]: ${message}`);
        }
    
        greet() {
            this.log("Hello from EnhancedClass!");
        }
    
        doSomething() {
            this.log("Doing something...");
        }
    }
    

    the expectations is that the greet method shows the overridden icon like in Typescript

  9. Scott Wells repo owner

    Thanks. I’m not sure I asked the question quite correctly. Let me try again. If you create a 100% pure JavaScript project – nothing to do with Illuminated Cloud – and try to implement this exact same mixin pattern in JavaScript – not TypeScript – do you see the same behavior as if you did the exact same thing in a JavaScript-based LWC component in an Illuminated Cloud project?

    When I take the LWC JavaScript version of your code and strip the LWC-specific aspects out of it:

    function LoggerMixin (Base) {
        return class extends Base {
    
            log(message) {
                console.log(`[LOG]: ${message}`);
            }
        }
    }
    
    class BaseClass {
        prop = 1;
    
        greet() {
            console.log("Hello from BaseClass!");
        }
    }
    
    class EnhancedClass extends LoggerMixin(BaseClass) {
        prop = 2;
    
        log(message) {
            console.log(`[EnhancedClass LOG]: ${message}`);
        }
    
        greet() {
            this.log("Hello from EnhancedClass!");
        }
    
        doSomething() {
            this.log("Doing something...");
        }
    }
    
    const instance = new EnhancedClass();
    instance.greet();
    instance.doSomething();
    

    and then I execute that script, I see that overrides are being properly processed:

    node issue2694.js 
    [EnhancedClass LOG]: Hello from EnhancedClass!
    [EnhancedClass LOG]: Doing something...
    

    but I don’t see the JetBrains IDE adding override gutter annotations for the overridden methods.

    If I comment out the override of greet() in EnhancedClass and execute the script again, I can confirm proper inheritance/polymorphic behavior:

    node issue2694.js 
    Hello from BaseClass!
    [EnhancedClass LOG]: Doing something...
    

    Unless I’m misunderstanding the issue, I think what you’re seeing probably needs to be reported to JetBrains, no? Apologies if I’m still misunderstanding the problem.

  10. Stanley Zapata reporter

    You are completely right, I didn’t expect to see a difference when using a Javacript Project but it isn’t showing gutter icons for the overridden functions. Thanks for all the help!, I’ll report it to Jetbrains.

  11. Scott Wells repo owner

    Okay…whew! I was thinking I was missing something pretty fundamental there. Yeah, just distill the general reproducible example – no IC2/LWC specific stuff – and log a bug with them.

  12. Log in to comment