88import java .util .LinkedHashMap ;
99import java .util .List ;
1010import java .util .Map ;
11+ import java .util .Objects ;
1112import java .util .regex .Pattern ;
1213
1314import com .github .codeql .Logger ;
@@ -479,11 +480,13 @@ private void unlockTrapFile(File trapFile) {
479480 private static final String MAJOR_VERSION = "majorVersion" ;
480481 private static final String MINOR_VERSION = "minorVersion" ;
481482 private static final String LAST_MODIFIED = "lastModified" ;
483+ private static final String EXTRACTOR_NAME = "extractorName" ;
482484
483485 private static class TrapClassVersion {
484486 private int majorVersion ;
485487 private int minorVersion ;
486488 private long lastModified ;
489+ private String extractorName ; // May be null if not given
487490
488491 public int getMajorVersion () {
489492 return majorVersion ;
@@ -497,10 +500,13 @@ public long getLastModified() {
497500 return lastModified ;
498501 }
499502
500- private TrapClassVersion (int majorVersion , int minorVersion , long lastModified ) {
503+ public String getExtractorName () { return extractorName ; }
504+
505+ private TrapClassVersion (int majorVersion , int minorVersion , long lastModified , String extractorName ) {
501506 this .majorVersion = majorVersion ;
502507 this .minorVersion = minorVersion ;
503508 this .lastModified = lastModified ;
509+ this .extractorName = extractorName ;
504510 }
505511 private boolean newerThan (TrapClassVersion tcv ) {
506512 // Classes being compiled from source have major version 0 but should take precedence
@@ -510,6 +516,14 @@ private boolean newerThan(TrapClassVersion tcv) {
510516 return false ;
511517 else if (majorVersion ==0 )
512518 return true ;
519+ // Always consider the Kotlin extractor superior to the Java extractor, because we may decode and extract
520+ // Kotlin metadata that the Java extractor can't understand:
521+ if (!Objects .equals (tcv .extractorName , extractorName )) {
522+ if (Objects .equals (tcv .extractorName , "kotlin" ))
523+ return false ;
524+ if (Objects .equals (extractorName , "kotlin" ))
525+ return true ;
526+ }
513527 // Otherwise, determine precedence in the following order:
514528 // majorVersion, minorVersion, lastModified.
515529 return tcv .majorVersion < majorVersion ||
@@ -520,7 +534,7 @@ else if (majorVersion==0)
520534 private static TrapClassVersion fromSymbol (IrClass sym , Logger log ) {
521535 VirtualFile vf = getIrClassVirtualFile (sym );
522536 if (vf == null )
523- return new TrapClassVersion (0 , 0 , 0 );
537+ return new TrapClassVersion (0 , 0 , 0 , null );
524538
525539 final int [] versionStore = new int [1 ];
526540
@@ -551,15 +565,15 @@ private static TrapClassVersion fromSymbol(IrClass sym, Logger log) {
551565 };
552566 (new ClassReader (vf .contentsToByteArray ())).accept (versionGetter , ClassReader .SKIP_CODE | ClassReader .SKIP_DEBUG | ClassReader .SKIP_FRAMES );
553567
554- return new TrapClassVersion (versionStore [0 ] & 0xffff , versionStore [0 ] >> 16 , vf .getTimeStamp ());
568+ return new TrapClassVersion (versionStore [0 ] & 0xffff , versionStore [0 ] >> 16 , vf .getTimeStamp (), "kotlin" );
555569 }
556570 catch (IllegalAccessException e ) {
557571 log .warn ("Failed to read class file version information" , e );
558- return new TrapClassVersion (0 , 0 , 0 );
572+ return new TrapClassVersion (0 , 0 , 0 , null );
559573 }
560574 catch (IOException e ) {
561575 log .warn ("Failed to read class file version information" , e );
562- return new TrapClassVersion (0 , 0 , 0 );
576+ return new TrapClassVersion (0 , 0 , 0 , null );
563577 }
564578 }
565579 private boolean isValid () {
@@ -575,20 +589,22 @@ private TrapClassVersion readVersionInfo(File trap) {
575589 int majorVersion = 0 ;
576590 int minorVersion = 0 ;
577591 long lastModified = 0 ;
592+ String extractorName = null ;
578593 File metadataFile = new File (trap .getAbsolutePath ().replace (".trap.gz" , ".metadata" ));
579594 if (metadataFile .exists ()) {
580595 Map <String ,String > metadataMap = FileUtil .readPropertiesCSV (metadataFile );
581596 try {
582597 majorVersion = Integer .parseInt (metadataMap .get (MAJOR_VERSION ));
583598 minorVersion = Integer .parseInt (metadataMap .get (MINOR_VERSION ));
584599 lastModified = Long .parseLong (metadataMap .get (LAST_MODIFIED ));
600+ extractorName = metadataMap .get (EXTRACTOR_NAME );
585601 } catch (NumberFormatException e ) {
586602 log .warn ("Invalid class file version for " + trap .getAbsolutePath (), e );
587603 }
588604 } else {
589605 log .warn ("Trap metadata file does not exist: " + metadataFile .getAbsolutePath ());
590606 }
591- return new TrapClassVersion (majorVersion , minorVersion , lastModified );
607+ return new TrapClassVersion (majorVersion , minorVersion , lastModified , extractorName );
592608 }
593609
594610}
0 commit comments