Kotlin: use the same mtimes as Java

Previously Kotlin's use of IntelliJ's VirtualFile interface meant we got the containing JAR file's mtime, not that of the individual file entry.
This commit is contained in:
Chris Smowton
2022-05-25 17:03:31 +01:00
parent ae1f5bbe25
commit 3bd581a052

View File

@@ -4,10 +4,14 @@ import java.lang.reflect.*;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import com.github.codeql.Logger;
import static com.github.codeql.ClassNamesKt.getIrDeclBinaryName;
@@ -547,6 +551,49 @@ public class OdasaOutput {
(tcv.majorVersion == majorVersion && tcv.minorVersion == minorVersion &&
tcv.lastModified < lastModified);
}
private static Map<String, Map<String, Long>> jarFileEntryTimeStamps = new HashMap<>();
private static Map<String, Long> getZipFileEntryTimeStamps(String path, Logger log) {
try {
Map<String, Long> result = new HashMap<>();
ZipFile zf = new ZipFile(path);
Enumeration<? extends ZipEntry> entries = zf.entries();
while (entries.hasMoreElements()) {
ZipEntry ze = entries.nextElement();
result.put(ze.getName(), ze.getLastModifiedTime().toMillis());
}
return result;
} catch(IOException e) {
log.warn("Failed to get entry timestamps from " + path, e);
return null;
}
}
private static long getVirtualFileTimeStamp(VirtualFile vf, Logger log) {
if (vf.getFileSystem().getProtocol().equals("jar")) {
String[] parts = vf.getPath().split("!/");
if (parts.length == 2) {
String jarFilePath = parts[0];
String entryPath = parts[1];
if (!jarFileEntryTimeStamps.containsKey(jarFilePath)) {
jarFileEntryTimeStamps.put(jarFilePath, getZipFileEntryTimeStamps(jarFilePath, log));
}
Map<String, Long> entryTimeStamps = jarFileEntryTimeStamps.get(jarFilePath);
if (entryTimeStamps != null) {
Long entryTimeStamp = entryTimeStamps.get(entryPath);
if (entryTimeStamp != null)
return entryTimeStamp;
else
log.warn("Couldn't find timestamp for jar file " + jarFilePath + " entry " + entryPath);
}
}
}
// For all files except for jar files, and a fallback in case of I/O problems reading a jar file:
return vf.getTimeStamp();
}
private static TrapClassVersion fromSymbol(IrDeclaration sym, Logger log) {
VirtualFile vf = sym instanceof IrClass ? getIrClassVirtualFile((IrClass)sym) :
sym.getParent() instanceof IrClass ? getIrClassVirtualFile((IrClass)sym.getParent()) :
@@ -583,7 +630,7 @@ public class OdasaOutput {
};
(new ClassReader(vf.contentsToByteArray())).accept(versionGetter, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
return new TrapClassVersion(versionStore[0] & 0xffff, versionStore[0] >> 16, vf.getTimeStamp(), "kotlin");
return new TrapClassVersion(versionStore[0] & 0xffff, versionStore[0] >> 16, getVirtualFileTimeStamp(vf, log), "kotlin");
}
catch(IllegalAccessException e) {
log.warn("Failed to read class file version information", e);