Kotlin: fix space indentation in OdasaOutput.java

This commit is contained in:
Paolo Tranquilli
2024-04-12 10:50:02 +02:00
parent c64d02d6df
commit bc89742979

View File

@@ -67,7 +67,9 @@ public class OdasaOutput {
private final Logger log;
private final Compression compression;
/** DEBUG only: just use the given file as the root for TRAP, source archive etc */
/**
* DEBUG only: just use the given file as the root for TRAP, source archive etc
*/
OdasaOutput(File outputRoot, Compression compression, Logger log) {
this.trapFolder = new File(outputRoot, "trap");
this.sourceArchiveFolder = new File(outputRoot, "src_archive");
@@ -77,14 +79,16 @@ public class OdasaOutput {
}
public OdasaOutput(boolean trackClassOrigins, Compression compression, Logger log) {
String trapFolderVar = Env.systemEnv().getFirstNonEmpty("CODEQL_EXTRACTOR_JAVA_TRAP_DIR", Var.TRAP_FOLDER.name());
String trapFolderVar = Env.systemEnv().getFirstNonEmpty("CODEQL_EXTRACTOR_JAVA_TRAP_DIR",
Var.TRAP_FOLDER.name());
if (trapFolderVar == null) {
throw new ResourceError("CODEQL_EXTRACTOR_JAVA_TRAP_DIR was not set");
}
String sourceArchiveVar = Env.systemEnv().getFirstNonEmpty("CODEQL_EXTRACTOR_JAVA_SOURCE_ARCHIVE_DIR", Var.SOURCE_ARCHIVE.name());
String sourceArchiveVar = Env.systemEnv().getFirstNonEmpty("CODEQL_EXTRACTOR_JAVA_SOURCE_ARCHIVE_DIR",
Var.SOURCE_ARCHIVE.name());
if (sourceArchiveVar == null) {
throw new ResourceError("CODEQL_EXTRACTOR_JAVA_SOURCE_ARCHIVE_DIR was not set");
}
}
this.trapFolder = new File(trapFolderVar);
this.sourceArchiveFolder = new File(sourceArchiveVar);
this.trackClassOrigins = trackClassOrigins;
@@ -104,6 +108,7 @@ public class OdasaOutput {
* Set the source file that is currently being processed. This may affect
* things like trap and source archive directories, and persists as a
* setting until this method is called again.
*
* @param f the current source file
*/
public void setCurrentSourceFile(File f) {
@@ -130,7 +135,7 @@ public class OdasaOutput {
private File trapSetFor(File file) {
return FileUtil.appendAbsolutePath(
currentSpecFileEntry.getTrapFolder(), PathTransformer.std().fileAsDatabaseString(file) + ".set");
currentSpecFileEntry.getTrapFolder(), PathTransformer.std().fileAsDatabaseString(file) + ".set");
}
public void addDependency(IrDeclaration sym, String signature) {
@@ -185,7 +190,8 @@ public class OdasaOutput {
return null;
return FileUtil.appendAbsolutePath(
currentSpecFileEntry.getTrapFolder(),
JARS_DIR + "/" + PathTransformer.std().fileAsDatabaseString(jarFile) + ".trap" + compression.getExtension());
JARS_DIR + "/" + PathTransformer.std().fileAsDatabaseString(jarFile) + ".trap"
+ compression.getExtension());
}
private File getTrapFileForModule(String moduleName) {
@@ -213,13 +219,13 @@ public class OdasaOutput {
private String trapFilePathForDecl(IrElement sym, String signature) {
String binaryName = getIrElementBinaryName(sym);
// TODO: Reinstate this?
//if (getTrackClassOrigins())
// classId += "-" + StringDigestor.digest(sym.getSourceFileId());
// if (getTrackClassOrigins())
// classId += "-" + StringDigestor.digest(sym.getSourceFileId());
String result = CLASSES_DIR + "/" +
binaryName.replace('.', '/') +
signature +
".members" +
".trap" + compression.getExtension();
binaryName.replace('.', '/') +
signature +
".members" +
".trap" + compression.getExtension();
return result;
}
@@ -229,16 +235,21 @@ public class OdasaOutput {
/**
* Get a {@link TrapFileManager} to write members
* about a declaration, or <code>null</code> if the declaration shouldn't be populated.
* about a declaration, or <code>null</code> if the declaration shouldn't be
* populated.
*
* @param sym
* The declaration's symbol, including, in particular, its fully qualified
* binary class name.
* The declaration's symbol, including, in particular, its
* fully qualified
* binary class name.
* @param signature
* Any unique suffix needed to distinguish `sym` from other declarations with the same name.
* For functions for example, this means its parameter signature.
* Any unique suffix needed to distinguish `sym` from other
* declarations with the same name.
* For functions for example, this means its parameter
* signature.
*/
private TrapFileManager getMembersWriterForDecl(File trap, File trapFileBase, TrapClassVersion trapFileVersion, IrElement sym, String signature) {
private TrapFileManager getMembersWriterForDecl(File trap, File trapFileBase, TrapClassVersion trapFileVersion,
IrElement sym, String signature) {
// If the TRAP file already exists then we
// don't need to write it.
if (trap.exists()) {
@@ -250,7 +261,8 @@ public class OdasaOutput {
// don't need to rewrite it only to rename it
// again.
File trapFileDir = trap.getParentFile();
File trapOld = new File(trapFileDir, trap.getName().replace(".trap" + compression.getExtension(), ".trap-old" + compression.getExtension()));
File trapOld = new File(trapFileDir,
trap.getName().replace(".trap" + compression.getExtension(), ".trap-old" + compression.getExtension()));
if (trapOld.exists()) {
log.trace("Not rewriting trap file for " + trap.toString() + " as the trap-old exists");
return null;
@@ -261,11 +273,12 @@ public class OdasaOutput {
if (trapFileBase != null && trapFileVersion != null && trapFileDir.exists()) {
String trapFileBaseName = trapFileBase.getName();
for (File f: FileUtil.list(trapFileDir)) {
for (File f : FileUtil.list(trapFileDir)) {
String name = f.getName();
Matcher m = selectClassVersionComponents.matcher(name);
if (m.matches() && m.group(1).equals(trapFileBaseName)) {
TrapClassVersion v = new TrapClassVersion(Integer.valueOf(m.group(2)), Integer.valueOf(m.group(3)), Long.valueOf(m.group(4)), m.group(5));
TrapClassVersion v = new TrapClassVersion(Integer.valueOf(m.group(2)), Integer.valueOf(m.group(3)),
Long.valueOf(m.group(4)), m.group(5));
if (v.newerThan(trapFileVersion)) {
log.trace("Not rewriting trap file for " + trap.toString() + " as " + f.toString() + " exists");
return null;
@@ -285,7 +298,8 @@ public class OdasaOutput {
return concurrentWriter(trapFile, relative, log, sym, signature);
}
private TrapFileManager concurrentWriter(File trapFile, String relative, Logger log, IrElement sym, String signature) {
private TrapFileManager concurrentWriter(File trapFile, String relative, Logger log, IrElement sym,
String signature) {
if (trapFile.exists())
return null;
return new TrapFileManager(trapFile, relative, true, log, sym, signature);
@@ -299,7 +313,8 @@ public class OdasaOutput {
private String signature;
private boolean hasError = false;
private TrapFileManager(File trapFile, String relative, boolean concurrentCreation, Logger log, IrElement sym, String signature) {
private TrapFileManager(File trapFile, String relative, boolean concurrentCreation, Logger log, IrElement sym,
String signature) {
trapDependenciesForClass = new TrapDependencies(relative);
this.trapFile = trapFile;
this.sym = sym;
@@ -325,6 +340,7 @@ public class OdasaOutput {
writeTrapDependencies(trapDependenciesForClass);
}
private void writeTrapDependencies(TrapDependencies trapDependencies) {
String dep = trapDependencies.trapFile().replace(".trap" + compression.getExtension(), ".dep");
trapDependencies.save(
@@ -340,56 +356,77 @@ public class OdasaOutput {
* Trap file locking.
*/
private final Pattern selectClassVersionComponents = Pattern.compile("(.*)#(-?[0-9]+)\\.(-?[0-9]+)-(-?[0-9]+)-(.*)\\.trap.*");
private final Pattern selectClassVersionComponents = Pattern
.compile("(.*)#(-?[0-9]+)\\.(-?[0-9]+)-(-?[0-9]+)-(.*)\\.trap.*");
/**
* <b>CAUTION</b>: to avoid the potential for deadlock between multiple concurrent extractor processes,
* only one source file {@link TrapLocker} may be open at any time, and the lock must be obtained
* <b>CAUTION</b>: to avoid the potential for deadlock between multiple
* concurrent extractor processes,
* only one source file {@link TrapLocker} may be open at any time, and the lock
* must be obtained
* <b>before</b> any <b>class</b> file lock.
*
* Trap file extensions (and paths) ensure that source and class file locks are distinct.
* Trap file extensions (and paths) ensure that source and class file locks are
* distinct.
*
* @return a {@link TrapLocker} for the currently processed source file, which must have been
* previously set by a call to {@link OdasaOutput#setCurrentSourceFile(File)}.
* @return a {@link TrapLocker} for the currently processed source file, which
* must have been
* previously set by a call to
* {@link OdasaOutput#setCurrentSourceFile(File)}.
*/
public TrapLocker getTrapLockerForCurrentSourceFile() {
return new TrapLocker((IrClass)null, null, true);
return new TrapLocker((IrClass) null, null, true);
}
/**
* <b>CAUTION</b>: to avoid the potential for deadlock between multiple concurrent extractor processes,
* only one jar file {@link TrapLocker} may be open at any time, and the lock must be obtained
* <b>after</b> any <b>source</b> file lock. Only one jar or class file lock may be open at any time.
* <b>CAUTION</b>: to avoid the potential for deadlock between multiple
* concurrent extractor processes,
* only one jar file {@link TrapLocker} may be open at any time, and the lock
* must be obtained
* <b>after</b> any <b>source</b> file lock. Only one jar or class file lock may
* be open at any time.
*
* Trap file extensions (and paths) ensure that source and jar file locks are distinct.
* Trap file extensions (and paths) ensure that source and jar file locks are
* distinct.
*
* @return a {@link TrapLocker} for the trap file corresponding to the given jar file.
* @return a {@link TrapLocker} for the trap file corresponding to the given jar
* file.
*/
public TrapLocker getTrapLockerForJarFile(File jarFile) {
return new TrapLocker(jarFile);
}
/**
* <b>CAUTION</b>: to avoid the potential for deadlock between multiple concurrent extractor processes,
* only one module {@link TrapLocker} may be open at any time, and the lock must be obtained
* <b>after</b> any <b>source</b> file lock. Only one jar or class file or module lock may be open at any time.
* <b>CAUTION</b>: to avoid the potential for deadlock between multiple
* concurrent extractor processes,
* only one module {@link TrapLocker} may be open at any time, and the lock must
* be obtained
* <b>after</b> any <b>source</b> file lock. Only one jar or class file or
* module lock may be open at any time.
*
* Trap file extensions (and paths) ensure that source and module file locks are distinct.
* Trap file extensions (and paths) ensure that source and module file locks are
* distinct.
*
* @return a {@link TrapLocker} for the trap file corresponding to the given module.
* @return a {@link TrapLocker} for the trap file corresponding to the given
* module.
*/
public TrapLocker getTrapLockerForModule(String moduleName) {
return new TrapLocker(moduleName);
}
/**
* <b>CAUTION</b>: to avoid the potential for deadlock between multiple concurrent extractor processes,
* only one class file {@link TrapLocker} may be open at any time, and the lock must be obtained
* <b>after</b> any <b>source</b> file lock. Only one jar or class file lock may be open at any time.
* <b>CAUTION</b>: to avoid the potential for deadlock between multiple
* concurrent extractor processes,
* only one class file {@link TrapLocker} may be open at any time, and the lock
* must be obtained
* <b>after</b> any <b>source</b> file lock. Only one jar or class file lock may
* be open at any time.
*
* Trap file extensions (and paths) ensure that source and class file locks are distinct.
* Trap file extensions (and paths) ensure that source and class file locks are
* distinct.
*
* @return a {@link TrapLocker} for the trap file corresponding to the given class symbol.
* @return a {@link TrapLocker} for the trap file corresponding to the given
* class symbol.
*/
public TrapLocker getTrapLockerForDecl(IrElement sym, String signature, boolean fromSource) {
return new TrapLocker(sym, signature, fromSource);
@@ -403,10 +440,11 @@ public class OdasaOutput {
private File trapFileBase = null;
private TrapClassVersion trapFileVersion = null;
private final String signature;
private TrapLocker(IrElement decl, String signature, boolean fromSource) {
this.sym = decl;
this.signature = signature;
if (sym==null) {
if (sym == null) {
log.error("Null symbol passed for Kotlin TRAP locker");
trapFile = null;
} else {
@@ -422,21 +460,25 @@ public class OdasaOutput {
// in a single directory. This makes our directory listings later slow.
// To avoid this, rather than using files named .../Foo*, we use .../Foo/Foo*.
trapFileBase = new File(new File(normalTrapFile.getParentFile(), baseName), baseName);
trapFile = new File(trapFileBase.getPath() + '#' + trapFileVersion.toString() + ".trap" + compression.getExtension());
trapFile = new File(trapFileBase.getPath() + '#' + trapFileVersion.toString() + ".trap"
+ compression.getExtension());
}
}
private TrapLocker(File jarFile) {
sym = null;
signature = null;
trapFile = getTrapFileForJarFile(jarFile);
}
private TrapLocker(String moduleName) {
sym = null;
signature = null;
trapFile = getTrapFileForModule(moduleName);
}
public TrapFileManager getTrapFileManager() {
if (trapFile!=null) {
if (trapFile != null) {
return getMembersWriterForDecl(trapFile, trapFileBase, trapFileVersion, sym, signature);
} else {
return null;
@@ -445,7 +487,7 @@ public class OdasaOutput {
@Override
public void close() {
if (trapFile!=null) {
if (trapFile != null) {
// Now that we have finished writing our TRAP file, we want
// to rename and TRAP file that matches our trapFileBase
// but doesn't have the latest metadata.
@@ -458,12 +500,13 @@ public class OdasaOutput {
String trapFileBaseName = trapFileBase.getName();
List<Pair<File, TrapClassVersion>> pairs = new LinkedList<Pair<File, TrapClassVersion>>();
for (File f: FileUtil.list(trapFileDir)) {
for (File f : FileUtil.list(trapFileDir)) {
String name = f.getName();
Matcher m = selectClassVersionComponents.matcher(name);
if (m.matches()) {
if (m.group(1).equals(trapFileBaseName)) {
TrapClassVersion v = new TrapClassVersion(Integer.valueOf(m.group(2)), Integer.valueOf(m.group(3)), Long.valueOf(m.group(4)), m.group(5));
TrapClassVersion v = new TrapClassVersion(Integer.valueOf(m.group(2)),
Integer.valueOf(m.group(3)), Long.valueOf(m.group(4)), m.group(5));
pairs.add(new Pair<File, TrapClassVersion>(f, v));
} else {
// Everything in this directory should be for the same TRAP file base
@@ -490,10 +533,12 @@ public class OdasaOutput {
};
TrapClassVersion latestVersion = Collections.max(pairs, comparator).snd();
for (Pair<File, TrapClassVersion> p: pairs) {
for (Pair<File, TrapClassVersion> p : pairs) {
if (!latestVersion.equals(p.snd())) {
File f = p.fst();
File fOld = new File(f.getParentFile(), f.getName().replace(".trap" + compression.getExtension(), ".trap-old" + compression.getExtension()));
File fOld = new File(f.getParentFile(),
f.getName().replace(".trap" + compression.getExtension(),
".trap-old" + compression.getExtension()));
// We aren't interested in whether or not this succeeds;
// it may fail because a concurrent extractor has already
// renamed it.
@@ -528,7 +573,9 @@ public class OdasaOutput {
return lastModified;
}
public String getExtractorName() { return extractorName; }
public String getExtractorName() {
return extractorName;
}
private TrapClassVersion(int majorVersion, int minorVersion, long lastModified, String extractorName) {
this.majorVersion = majorVersion;
@@ -540,34 +587,37 @@ public class OdasaOutput {
@Override
public boolean equals(Object obj) {
if (obj instanceof TrapClassVersion) {
TrapClassVersion other = (TrapClassVersion)obj;
return majorVersion == other.majorVersion && minorVersion == other.minorVersion && lastModified == other.lastModified && extractorName.equals(other.extractorName);
TrapClassVersion other = (TrapClassVersion) obj;
return majorVersion == other.majorVersion && minorVersion == other.minorVersion
&& lastModified == other.lastModified && extractorName.equals(other.extractorName);
} else {
return false;
}
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + majorVersion;
hash = 31 * hash + minorVersion;
hash = 31 * hash + (int)lastModified;
hash = 31 * hash + (extractorName == null ? 0 : extractorName.hashCode());
return hash;
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + majorVersion;
hash = 31 * hash + minorVersion;
hash = 31 * hash + (int) lastModified;
hash = 31 * hash + (extractorName == null ? 0 : extractorName.hashCode());
return hash;
}
private boolean newerThan(TrapClassVersion tcv) {
// Classes being compiled from source have major version 0 but should take precedence
// Classes being compiled from source have major version 0 but should take
// precedence
// over any classes with the same qualified name loaded from the classpath
// in previous or subsequent extractor invocations.
if (tcv.majorVersion == 0 && majorVersion != 0)
return false;
else if (majorVersion == 0 && tcv.majorVersion != 0)
return true;
// Always consider the Kotlin extractor superior to the Java extractor, because we may decode and extract
// Always consider the Kotlin extractor superior to the Java extractor, because
// we may decode and extract
// Kotlin metadata that the Java extractor can't understand:
if(!Objects.equals(tcv.extractorName, extractorName)) {
if (!Objects.equals(tcv.extractorName, extractorName)) {
if (Objects.equals(tcv.extractorName, "kotlin"))
return false;
if (Objects.equals(extractorName, "kotlin"))
@@ -578,56 +628,57 @@ public class OdasaOutput {
return tcv.majorVersion < majorVersion ||
(tcv.majorVersion == majorVersion && tcv.minorVersion < minorVersion) ||
(tcv.majorVersion == majorVersion && tcv.minorVersion == minorVersion &&
tcv.lastModified < lastModified);
tcv.lastModified < lastModified);
}
private static Map<String, Map<String, Long>> jarFileEntryTimeStamps = new HashMap<>();
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 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);
}
} else {
log.warn("Expected JAR-file path " + vf.getPath() + " to have exactly one '!/' separator");
}
}
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);
}
} else {
log.warn("Expected JAR-file path " + vf.getPath() + " to have exactly one '!/' separator");
}
}
// For all files except for jar files, and a fallback in case of I/O problems reading a jar file:
return vf.getTimeStamp();
}
// 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 VirtualFile getVirtualFileIfClass(IrElement e) {
if (e instanceof IrClass)
return getIrClassVirtualFile((IrClass)e);
return getIrClassVirtualFile((IrClass) e);
else
return null;
}
@@ -635,7 +686,7 @@ public class OdasaOutput {
private static TrapClassVersion fromSymbol(IrElement sym, Logger log) {
VirtualFile vf = getVirtualFileIfClass(sym);
if (vf == null && sym instanceof IrDeclaration)
vf = getVirtualFileIfClass(((IrDeclaration)sym).getParent());
vf = getVirtualFileIfClass(((IrDeclaration) sym).getParent());
if (vf == null)
return new TrapClassVersion(-1, 0, 0, null);
@@ -646,12 +697,12 @@ public class OdasaOutput {
// We want to use the latest one that there is.
Field asmField = null;
int asmNum = -1;
for(Field f : Opcodes.class.getDeclaredFields()) {
for (Field f : Opcodes.class.getDeclaredFields()) {
String name = f.getName();
if(name.startsWith("ASM")) {
if (name.startsWith("ASM")) {
try {
int i = Integer.parseInt(name.substring(3));
if(i > asmNum) {
if (i > asmNum) {
asmNum = i;
asmField = f;
}
@@ -662,26 +713,29 @@ public class OdasaOutput {
}
int asm = asmField.getInt(null);
ClassVisitor versionGetter = new ClassVisitor(asm) {
public void visit(int version, int access, java.lang.String name, java.lang.String signature, java.lang.String superName, java.lang.String[] interfaces) {
public void visit(int version, int access, java.lang.String name, java.lang.String signature,
java.lang.String superName, java.lang.String[] interfaces) {
versionStore[0] = version;
}
};
(new ClassReader(vf.contentsToByteArray())).accept(versionGetter, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
(new ClassReader(vf.contentsToByteArray())).accept(versionGetter,
ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
return new TrapClassVersion(versionStore[0] & 0xffff, versionStore[0] >> 16, getVirtualFileTimeStamp(vf, log), "kotlin");
}
catch(IllegalAccessException e) {
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);
return new TrapClassVersion(-1, 0, 0, null);
}
catch(IOException e) {
} catch (IOException e) {
log.warn("Failed to read class file version information", e);
return new TrapClassVersion(-1, 0, 0, null);
}
}
private boolean isValid() {
return majorVersion>=0 && minorVersion>=0;
return majorVersion >= 0 && minorVersion >= 0;
}
@Override
public String toString() {
return majorVersion + "." + minorVersion + "-" + lastModified + "-" + extractorName;