TNG / ArchUnit

A Java architecture test library, to specify and assert architecture rules in plain Java
http://archunit.org
Apache License 2.0
3.18k stars 288 forks source link

Exception in thread "main" java.lang.IllegalStateException: Never found a JavaCodeUnit that matches supposed origin CodeUnit #1194

Closed heyuxiang1996 closed 9 months ago

heyuxiang1996 commented 10 months ago

    at com.tngtech.archunit.core.importer.RawAccessRecord$CodeUnit.resolveFrom(RawAccessRecord.java:132)
    at com.tngtech.archunit.core.importer.AccessRecord$Factory.lambda$createOriginSupplier$0(AccessRecord.java:294)
    at com.tngtech.archunit.thirdparty.com.google.common.base.Suppliers$NonSerializableMemoizingSupplier.get(Suppliers.java:181)
    at com.tngtech.archunit.core.importer.AccessRecord$Factory$RawAccessRecordProcessed.getOrigin(AccessRecord.java:255)
    at com.tngtech.archunit.core.importer.ClassGraphCreator.tryProcess(ClassGraphCreator.java:147)
    at com.tngtech.archunit.core.importer.ClassGraphCreator.lambda$completeCodeUnitDependencies$2(ClassGraphCreator.java:131)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
    at java.util.stream.Streams$StreamBuilderImpl.forEachRemaining(Streams.java:419)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:647)
    at java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:272)
    at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1580)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485)
    at com.tngtech.archunit.core.importer.ClassFileImportRecord.forEachRawConstructorCallRecord(ClassFileImportRecord.java:268)
    at com.tngtech.archunit.core.importer.ClassGraphCreator.completeCodeUnitDependencies(ClassGraphCreator.java:130)
    at com.tngtech.archunit.core.importer.ClassGraphCreator.complete(ClassGraphCreator.java:109)
    at com.tngtech.archunit.core.importer.ClassFileProcessor.process(ClassFileProcessor.java:75)
    at com.tngtech.archunit.core.importer.ClassFileImporter.importLocations(ClassFileImporter.java:325)
    at com.transsion.admtool.Main.main(Main.java:17)```
heyuxiang1996 commented 10 months ago

I am using version 1.2 of archUnit

hankem commented 10 months ago

Thanks for reporting the issue! I've started to look at your byte code and saw that the failure during the class file import

java.lang.IllegalStateException:
Never found a JavaCodeUnit that matches supposed origin CodeUnit{
    name='access$084',
    descriptor=(Lcom/transsion/auto/bluetooth/BluetoothUtils;Ljava/lang/Object;)Ljava/lang/String;,
    declaringClassName='com.transsion.auto.bluetooth.BluetoothUtils'
}

seems to be caused by

BluetoothUtils's synthetic method access$084 ``` static java.lang.String access$084(com.transsion.auto.bluetooth.BluetoothUtils, java.lang.Object); descriptor: (Lcom/transsion/auto/bluetooth/BluetoothUtils;Ljava/lang/Object;)Ljava/lang/String; flags: (0x1008) ACC_STATIC, ACC_SYNTHETIC Code: stack=3, locals=2, args_size=2 0: new #5 // class java/lang/StringBuilder 3: dup 4: invokespecial #6 // Method java/lang/StringBuilder."":()V 7: aload_0 8: dup_x1 9: getfield #7 // Field dev_mac_address:Ljava/lang/String; 12: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 15: aload_1 16: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; 19: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 22: dup_x1 23: putfield #7 // Field dev_mac_address:Ljava/lang/String; 26: areturn LineNumberTable: line 28: 0 LocalVariableTable: Start Length Slot Name Signature 0 27 0 x0 Lcom/transsion/auto/bluetooth/BluetoothUtils; 0 27 1 x1 Ljava/lang/Object; ```
(which is called from BluetoothUtils$1's method onReceive) ``` public void onReceive(android.content.Context, android.content.Intent); descriptor: (Landroid/content/Context;Landroid/content/Intent;)V flags: (0x0001) ACC_PUBLIC Code: stack=6, locals=6, args_size=3 0: ldc #4 // String BT 2: new #5 // class java/lang/StringBuilder 5: dup 6: invokespecial #6 // Method java/lang/StringBuilder."":()V 9: ldc #7 // String onReceive: 11: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 14: aload_2 15: invokevirtual #9 // Method android/content/Intent.getAction:()Ljava/lang/String; 18: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 21: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 24: invokestatic #11 // Method android/util/Log.i:(Ljava/lang/String;Ljava/lang/String;)I 27: pop 28: ldc #13 // String android.bluetooth.device.action.FOUND 30: aload_2 31: invokevirtual #9 // Method android/content/Intent.getAction:()Ljava/lang/String; 34: invokevirtual #14 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 37: ifeq 289 40: aload_2 41: ldc #15 // String android.bluetooth.device.extra.DEVICE 43: invokevirtual #16 // Method android/content/Intent.getParcelableExtra:(Ljava/lang/String;)Landroid/os/Parcelable; 46: checkcast #12 // class android/bluetooth/BluetoothDevice 49: astore_3 50: aload_3 51: invokevirtual #17 // Method android/bluetooth/BluetoothDevice.getName:()Ljava/lang/String; 54: ifnull 286 57: aload_0 58: getfield #2 // Field this$0:Lcom/transsion/auto/bluetooth/BluetoothUtils; 61: invokestatic #18 // Method com/transsion/auto/bluetooth/BluetoothUtils.access$000:(Lcom/transsion/auto/bluetooth/BluetoothUtils;)Ljava/lang/String; 64: aload_3 65: invokevirtual #19 // Method android/bluetooth/BluetoothDevice.getAddress:()Ljava/lang/String; 68: invokevirtual #20 // Method java/lang/String.contains:(Ljava/lang/CharSequence;)Z 71: ifne 286 74: aload_0 75: getfield #2 // Field this$0:Lcom/transsion/auto/bluetooth/BluetoothUtils; 78: aload_3 79: invokevirtual #19 // Method android/bluetooth/BluetoothDevice.getAddress:()Ljava/lang/String; 82: invokestatic #21 // Method com/transsion/auto/bluetooth/BluetoothUtils.access$084:(Lcom/transsion/auto/bluetooth/BluetoothUtils;Ljava/lang/Object;)Ljava/lang/String; // ... ```

I need to look deeper into the problem, but already want to ask:

heyuxiang1996 commented 10 months ago

This is my Java file. The class file is an intermediate product of compiling APK using Gradle

hankem commented 10 months ago

It's the same problem as in #1146, which occurs when inner classes use += on a private String field of the outer class.

Minimal example:

class Outer {
    private String privateString = "";

    class Inner {
        void method() {
            privateString += "+";
        }
    }
}

Some compiler( configuration)s, e.g. OpenJDK 11 with -source 8 -target 8, may produce a synthetic method that uses a StringBuilder, which ArchUnit at the moment unfortunately cannot handle correctly:

static java.lang.String access$084(Outer, java.lang.Object);
  descriptor: (LOuter;Ljava/lang/Object;)Ljava/lang/String;
  flags: (0x1008) ACC_STATIC, ACC_SYNTHETIC
  Code:
    stack=3, locals=2, args_size=2
       0: new           #1  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #2  // Method java/lang/StringBuilder."<init>":()V
       7: aload_0
       8: dup_x1
       9: getfield      #3  // Field privateString:Ljava/lang/String;
      12: invokevirtual #4  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: aload_1
      16: invokevirtual #5  // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      19: invokevirtual #6  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: dup_x1
      23: putfield      #3  // Field privateString:Ljava/lang/String;
      26: areturn
hankem commented 10 months ago

@heyuxiang1996, as a workaround, you can probably replace your dev_mac_address += device.getAddress(); with dev_mac_address = dev_mac_address + device.getAddress();.