Skip to content

Commit

Permalink
feat: info if overriding member is not needed (#759)
Browse files Browse the repository at this point in the history
Closes #25

### Summary of Changes

Show an info if an overriding member is identical to the overridden one.
In this case, it can be removed.
  • Loading branch information
lars-reimann authored Nov 11, 2023
1 parent a698a6a commit 23b340e
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 55 deletions.
13 changes: 10 additions & 3 deletions packages/safe-ds-lang/src/language/validation/inheritance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import { ClassType, UnknownType } from '../typing/model.js';

export const CODE_INHERITANCE_CYCLE = 'inheritance/cycle';
export const CODE_INHERITANCE_MULTIPLE_INHERITANCE = 'inheritance/multiple-inheritance';
export const CODE_INHERITANCE_MUST_MATCH_OVERRIDDEN_MEMBER = 'inheritance/must-match-overridden-member';
export const CODE_INHERITANCE_IDENTICAL_TO_OVERRIDDEN_MEMBER = 'inheritance/identical-to-overridden-member';
export const CODE_INHERITANCE_INCOMPATIBLE_TO_OVERRIDDEN_MEMBER = 'inheritance/incompatible-to-overridden-member';
export const CODE_INHERITANCE_NOT_A_CLASS = 'inheritance/not-a-class';

export const classMemberMustMatchOverriddenMember = (services: SafeDsServices) => {
export const classMemberMustMatchOverriddenMemberAndShouldBeNeeded = (services: SafeDsServices) => {
const classHierarchy = services.types.ClassHierarchy;
const typeChecker = services.types.TypeChecker;
const typeComputer = services.types.TypeComputer;
Expand All @@ -35,9 +36,15 @@ export const classMemberMustMatchOverriddenMember = (services: SafeDsServices) =
{
node,
property: 'name',
code: CODE_INHERITANCE_MUST_MATCH_OVERRIDDEN_MEMBER,
code: CODE_INHERITANCE_INCOMPATIBLE_TO_OVERRIDDEN_MEMBER,
},
);
} else if (typeChecker.isAssignableTo(overriddenMemberType, ownMemberType)) {
accept('info', 'Overriding member is identical to overridden member and can be removed.', {
node,
property: 'name',
code: CODE_INHERITANCE_IDENTICAL_TO_OVERRIDDEN_MEMBER,
});
}
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
unionTypesShouldBeUsedWithCaution,
} from './experimentalLanguageFeatures.js';
import {
classMemberMustMatchOverriddenMember,
classMemberMustMatchOverriddenMemberAndShouldBeNeeded,
classMustNotInheritItself,
classMustOnlyInheritASingleClass,
} from './inheritance.js';
Expand Down Expand Up @@ -228,7 +228,7 @@ export const registerValidationChecks = function (services: SafeDsServices) {
classMustNotInheritItself(services),
],
SdsClassBody: [classBodyShouldNotBeEmpty],
SdsClassMember: [classMemberMustMatchOverriddenMember(services)],
SdsClassMember: [classMemberMustMatchOverriddenMemberAndShouldBeNeeded(services)],
SdsConstraintList: [constraintListsShouldBeUsedWithCaution, constraintListShouldNotBeEmpty],
SdsDeclaration: [
nameMustNotStartWithCodegenPrefix,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,75 +1,55 @@
package tests.validation.inheritance.overridingMethodMustMatchOverriddenMethod

class MySuperClass {
attr myInstanceAttribute: Int
static attr myStaticAttribute: Int
attr myInstanceAttribute: Number
static attr myStaticAttribute: Number

fun myInstanceMethod(a: Int = 0) -> r: Int
static fun myStaticMethod(a: Int = 0) -> r: Int
fun myInstanceMethod(a: Number = 0) -> r: Number
static fun myStaticMethod(a: Number = 0) -> r: Number
}

class MyClass1 sub MySuperClass {
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
attr »myInstanceAttribute«: Int
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
static attr »myStaticAttribute«: Int

// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
attr »myInstanceAttribute«: String
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
static attr »myStaticAttribute«: String
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
attr »myInstanceAttribute«: Any
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
static attr »myStaticAttribute«: Any

// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
attr »myOwnInstanceAttribute«: Int
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
static attr »myOwnStaticAttribute«: Int


// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
fun »myInstanceMethod«(a: Int = 0) -> r: Int
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
static fun »myStaticMethod«(a: Int = 0) -> r: Int
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
fun »myInstanceMethod«(a: Any = 0) -> r: Int
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
static fun »myStaticMethod«(a: Any = 0) -> r: Int

// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
fun »myInstanceMethod«() -> r: Int
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
static fun »myStaticMethod«() -> r: Int

// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
fun »myOwnInstanceMethod«(a: Int = 0) -> r: Int
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
static fun »myOwnStaticMethod«(a: Int = 0) -> r: Int
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
fun »myOwnInstanceMethod«(a: Any = 0) -> r: Int
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
static fun »myOwnStaticMethod«(a: Any = 0) -> r: Int
}

class MyClass2 sub MySuperClass {
// $TEST$ error r"Overriding member does not match the overridden member:[\s\S]*"
attr »myInstanceAttribute«: String
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
static attr »myStaticAttribute«: String
// $TEST$ error r"Overriding member does not match the overridden member:.*"
attr »myInstanceAttribute«: Any
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
static attr »myStaticAttribute«: Any

// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
attr »myInstanceAttribute«: Int
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
static attr »myStaticAttribute«: Int

// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
attr »myOwnInstanceAttribute«: Int
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
static attr »myOwnStaticAttribute«: Int


// $TEST$ error r"Overriding member does not match the overridden member:[\s\S]*"
fun »myInstanceMethod«() -> r: Int
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
static fun »myStaticMethod«() -> r: Int

// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
fun »myInstanceMethod«(a: Int = 0) -> r: Int
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
static fun »myStaticMethod«(a: Int = 0) -> r: Int

// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
fun »myOwnInstanceMethod«(a: Int = 0) -> r: Int
// $TEST$ no error r"Overriding member does not match the overridden member:[\s\S]*"
static fun »myOwnStaticMethod«(a: Int = 0) -> r: Int
// $TEST$ error r"Overriding member does not match the overridden member:.*"
fun »myInstanceMethod«(a: Number = 0) -> r: Any
// $TEST$ no error r"Overriding member does not match the overridden member:.*"
static fun »myStaticMethod«(a: Number = 0) -> r: Any
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package tests.validation.inheritance.overridingMethodShouldDifferFromOverriddenMethod

class MySuperClass {
attr myInstanceAttribute: Number
static attr myStaticAttribute: Number

fun myInstanceMethod(a: Number = 0) -> r: Number
static fun myStaticMethod(a: Number = 0) -> r: Number
}

class MyClass1 sub MySuperClass {
// $TEST$ info "Overriding member is identical to overridden member and can be removed."
attr »myInstanceAttribute«: Number
// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
static attr »myStaticAttribute«: Number

// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
attr »myInstanceAttribute«: Number
// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
static attr »myStaticAttribute«: Number

// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
attr »myOwnInstanceAttribute«: Number
// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
static attr »myOwnStaticAttribute«: Number


// $TEST$ info "Overriding member is identical to overridden member and can be removed."
fun »myInstanceMethod«(a: Number = 0) -> r: Number
// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
static fun »myStaticMethod«(a: Number = 0) -> r: Number

// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
fun »myInstanceMethod«() -> r: Number
// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
static fun »myStaticMethod«() -> r: Number

// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
fun »myOwnInstanceMethod«(a: Number = 0) -> r: Number
// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
static fun »myOwnStaticMethod«(a: Number = 0) -> r: Number
}

class MyClass2 sub MySuperClass {
// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
attr »myInstanceAttribute«: Int
// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
static attr »myStaticAttribute«: Int


// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
fun »myInstanceMethod«(a: Number = 0) -> r: Int
// $TEST$ no info "Overriding member is identical to overridden member and can be removed."
static fun »myStaticMethod«(a: Number = 0) -> r: Int
}

0 comments on commit 23b340e

Please sign in to comment.