ArchUnit icon indicating copy to clipboard operation
ArchUnit copied to clipboard

Add support for casts

Open codecholeric opened this issue 4 years ago • 6 comments

At the moment casts without any further dependencies on the target type are not detected as dependencies. I.e.

SomeClass example(Object rawInput) {
  return (SomeClassImpl) rawInput; // should forbid dependencies on SomeClassImpl
}

Since there are no further dependencies on SomeClassImpl this would be missed. It does likely not cause a maintenance problem later, because the cast could at any time be weakened to (SomeClass) without any further compile or runtime issues, but still it would be nice to detect these things. Also to be able to access all casts that a class or method applies could be useful for other scenarios.

We could add this the following way:

  • extend Set<TypeCast> JavaCodeUnit.getCasts() (compare InstanceofCheck)
  • add the TypeCasts to JavaClass.directDependencies{From/To}Self

(open for discussion: What is the best name for the domain object? TypeCast, Cast, JavaCast, ClassCast, ...?)

codecholeric avatar Oct 30 '21 14:10 codecholeric

Is this issue open? If yes I would like to try to work on it. I have a few questions about the task. JavaClass.directDependencies{From/To}Self those methods are returning a set of Dependency objects. TypeCasts should be added to the dependency object or a new version of those methods is required like this: "getDirectDependenciesFromSelf(TypeCasts typeCasts)"?

Kaammill avatar Feb 23 '22 12:02 Kaammill

IMO we want both: (1) a specific method to ask domain objects for casts, and (2) register those as dependencies.

Random previous examples:

  • instanceof checks
    • (1)+(2) were added with c89adacbe10e12ece545bfb5e271f39e2e81b63e.
  • .class references
    • (1) was added with 66737c0b5f0ce72836a7dd6825ee8957c4fa01b1.
    • (2) was added with 9123d39c1a17321464d330b76e149bac04a066f6.

hankem avatar Feb 23 '22 13:02 hankem

@Kaammill and yes, the issue is up for grabs and we're always super happy about contributions :smiley:

codecholeric avatar Feb 23 '22 16:02 codecholeric

Some information about checkcast

The compiler might add some checkcast instructions:

  void foobar(java.lang.Object);
    Code:
       0: aload_1
       1: invokestatic  #29                 // Method com/foobar/SomeClass.of:(Ljava/lang/Object;)Lcom/foobar/SomeClass;
       4: ldc           #35                 // class java/lang/Boolean
       6: invokevirtual #37                 // Method com/foobar/SomeClass.someMethod:(Ljava/lang/Class;)Ljava/lang/Object;
       9: checkcast     #35                 // class java/lang/Boolean

What I noticed: if the previous instruction is invokevirtual or invokeinterface, the checkcast was generated by the compiler

ratoaq2 avatar Mar 09 '23 15:03 ratoaq2

Also bridge methods will have more compiler checkcast instructions

ratoaq2 avatar Mar 09 '23 16:03 ratoaq2

Detecting casts are also useful when working with polymorphism in hibernate, where instanceof and direct casts should not be used due to hibernate proxies.

Having this feature in archunit would also help in building rules for this case

ratoaq2 avatar Mar 10 '23 23:03 ratoaq2