Skip to content

Commit

Permalink
refactor AnalysisInputLocations Collection getClassSources(...) t…
Browse files Browse the repository at this point in the history
…o `Stream getClassSources(...) -> passing the Autoclosable object to the callers to avoid collecting streams and re-stream() them in the meantime
  • Loading branch information
swissiety committed Jan 21, 2025
1 parent b07b544 commit cb2af47
Show file tree
Hide file tree
Showing 37 changed files with 492 additions and 472 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.jf.dexlib2.iface.DexFile;
import sootup.apk.frontend.Util.*;
import sootup.apk.frontend.dexpler.DexClassProvider;
Expand Down Expand Up @@ -104,17 +103,16 @@ private Optional<? extends SootClassSource> getClassSourceInternal(

@Nonnull
@Override
public Collection<? extends SootClassSource> getClassSources(@Nonnull View view) {
public Stream<? extends SootClassSource> getClassSources(@Nonnull View view) {
return classNamesList.entrySet().stream()
.flatMap(
className ->
StreamUtils.optionalToStream(
getClassSource(
view.getIdentifierFactory().getClassType(className.getKey()), view)))
.collect(Collectors.toList());
view.getIdentifierFactory().getClassType(className.getKey()), view)));
}

@Nullable
@Nonnull
@Override
public SourceType getSourceType() {
return SourceType.Application;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@
public abstract class AbstractClassSource {

// holds information about the class
protected final AnalysisInputLocation classSource;
protected final AnalysisInputLocation analysisInputLocation;
// holds information about the specific data unit where the information about a class is stored
protected final Path sourcePath;
// the classType that identifies the containing class information
protected ClassType classSignature;

public AbstractClassSource(
@Nonnull AnalysisInputLocation classSource,
@Nonnull AnalysisInputLocation analysisInputLocation,
@Nonnull ClassType classSignature,
@Nonnull Path sourcePath) {
this.classSource = classSource;
this.analysisInputLocation = analysisInputLocation;
this.classSignature = classSignature;
this.sourcePath = sourcePath;
}
Expand All @@ -65,7 +65,7 @@ public ClassType getClassType() {
}

public AnalysisInputLocation getAnalysisInputLocation() {
return classSource;
return analysisInputLocation;
}

public Path getSourcePath() {
Expand All @@ -88,12 +88,12 @@ public boolean equals(@Nullable Object o) {
return false;
}
AbstractClassSource that = (AbstractClassSource) o;
return Objects.equal(classSource, that.classSource)
return Objects.equal(analysisInputLocation, that.analysisInputLocation)
&& Objects.equal(sourcePath, that.sourcePath);
}

@Override
public int hashCode() {
return Objects.hashCode(classSource, sourcePath);
return Objects.hashCode(analysisInputLocation, sourcePath);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public SootClassSource(
}

protected SootClassSource(SootClassSource delegate) {
super(delegate.classSource, delegate.getClassType(), delegate.getSourcePath());
super(delegate.analysisInputLocation, delegate.getClassType(), delegate.getSourcePath());
}

/** Reads from the source to retrieve its methods. This may be an expensive operation. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
* #L%
*/

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import sootup.core.frontend.SootClassSource;
import sootup.core.model.SootClass;
Expand Down Expand Up @@ -61,7 +61,7 @@ public interface AnalysisInputLocation {
* @return The source entries.
*/
@Nonnull
Collection<? extends SootClassSource> getClassSources(@Nonnull View view);
Stream<? extends SootClassSource> getClassSources(@Nonnull View view);

/**
* If the AnalysisInputLocation is initialized with the SourceType then this method should return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/
import com.google.common.collect.ImmutableMap;
import java.util.*;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import sootup.core.frontend.SootClassSource;
Expand Down Expand Up @@ -69,9 +70,9 @@ public EagerInputLocation(

@Nonnull
@Override
public Collection<SootClassSource> getClassSources(@Nullable View view) {
public Stream<SootClassSource> getClassSources(@Nullable View view) {
// FIXME: add classloadingoptions
return map.values();
return map.values().stream();
}

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@
* #L%
*/

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import sootup.core.frontend.SootClassSource;
import sootup.core.model.SourceType;
Expand Down Expand Up @@ -60,12 +59,8 @@ public Optional<? extends SootClassSource> getClassSource(

@Nonnull
@Override
public Collection<? extends SootClassSource> getClassSources(@Nonnull View view) {
// possibility to streamify this method to apply the filter at earlier stage i.e. before
// creating the ClassSources would be a faster approach..
return inputLocation.getClassSources(view).stream()
.filter(type -> filter(type.getClassType()))
.collect(Collectors.toList());
public Stream<? extends SootClassSource> getClassSources(@Nonnull View view) {
return inputLocation.getClassSources(view).filter(type -> filter(type.getClassType()));
}

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import sootup.core.model.SourceType;
import sootup.core.transform.BodyInterceptor;
Expand Down Expand Up @@ -99,6 +100,7 @@ public Optional<JavaSootClassSource> getClassSource(@Nonnull ClassType type, @No
try {
FileSystem fs = fileSystemCache.get(path);
final Path archiveRoot = fs.getPath("/");
// TODO: dont create a new AsmJavaClassProvider all the time!
return getClassSourceInternal(
(JavaClassType) type, archiveRoot, new AsmJavaClassProvider(view));
} catch (ExecutionException e) {
Expand All @@ -108,10 +110,11 @@ public Optional<JavaSootClassSource> getClassSource(@Nonnull ClassType type, @No

@Override
@Nonnull
public Collection<JavaSootClassSource> getClassSources(@Nonnull View view) {
public Stream<JavaSootClassSource> getClassSources(@Nonnull View view) {
try {
FileSystem fs = fileSystemCache.get(path);
final Path archiveRoot = fs.getPath("/");
// TODO: dont create a new AsmJavaClassProvider all the time!
return walkDirectory(
archiveRoot, view.getIdentifierFactory(), new AsmJavaClassProvider(view));
} catch (ExecutionException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package sootup.java.bytecode.frontend.inputlocation;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import org.apache.commons.io.FilenameUtils;
import sootup.core.IdentifierFactory;
import sootup.core.model.SourceType;
import sootup.core.transform.BodyInterceptor;
import sootup.core.types.ClassType;
import sootup.core.views.View;
import sootup.interceptors.BytecodeBodyInterceptors;
import sootup.java.bytecode.frontend.conversion.AsmJavaClassProvider;
import sootup.java.core.JavaSootClassSource;
import sootup.java.core.types.JavaClassType;

public class ClassFileBasedAnalysisInputLocation extends PathBasedAnalysisInputLocation {

@Nonnull private final String omittedPackageName;

public ClassFileBasedAnalysisInputLocation(
@Nonnull Path classFilePath,
@Nonnull String omittedPackageName,
@Nonnull SourceType srcType) {
this(
classFilePath,
omittedPackageName,
srcType,
BytecodeBodyInterceptors.Default.getBodyInterceptors());
}

public ClassFileBasedAnalysisInputLocation(
@Nonnull Path classFilePath,
@Nonnull String omittedPackageName,
@Nonnull SourceType srcType,
@Nonnull List<BodyInterceptor> bodyInterceptors) {
super(classFilePath, srcType, bodyInterceptors);
this.omittedPackageName = omittedPackageName;

if (!Files.isRegularFile(classFilePath)) {
throw new IllegalArgumentException("Needs to point to a regular file!");
}

if (Files.isDirectory(classFilePath)) {
throw new IllegalArgumentException("Needs to point to a regular file - not to a directory.");
}
}

@Override
@Nonnull
public Optional<JavaSootClassSource> getClassSource(@Nonnull ClassType type, @Nonnull View view) {

if (!type.getPackageName().getName().startsWith(omittedPackageName)) {
return Optional.empty();
}

return getSingleClass((JavaClassType) type, path, new AsmJavaClassProvider(view));
}

@Nonnull
@Override
public Stream<JavaSootClassSource> getClassSources(@Nonnull View view) {
AsmJavaClassProvider classProvider = new AsmJavaClassProvider(view);
IdentifierFactory factory = view.getIdentifierFactory();
Path dirPath = this.path.getParent();

final String fullyQualifiedName = fromPath(dirPath, path);

Optional<JavaSootClassSource> javaSootClassSource =
classProvider
.createClassSource(this, path, factory.getClassType(fullyQualifiedName))
.map(src -> (JavaSootClassSource) src);

return Stream.of(javaSootClassSource.get());
}

@Nonnull
protected String fromPath(@Nonnull Path baseDirPath, Path packageNamePathAndClass) {
String str =
FilenameUtils.removeExtension(
packageNamePathAndClass
.subpath(baseDirPath.getNameCount(), packageNamePathAndClass.getNameCount())
.toString()
.replace(packageNamePathAndClass.getFileSystem().getSeparator(), "."));

return omittedPackageName.isEmpty() ? str : omittedPackageName + "." + str;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
* #L%
*/

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import sootup.core.frontend.SootClassSource;
import sootup.core.inputlocation.AnalysisInputLocation;
Expand Down Expand Up @@ -68,7 +68,7 @@ public Optional<? extends SootClassSource> getClassSource(

@Nonnull
@Override
public Collection<? extends SootClassSource> getClassSources(@Nonnull View view) {
public Stream<? extends SootClassSource> getClassSources(@Nonnull View view) {
return backingInputLocation.getClassSources(view);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package sootup.java.bytecode.frontend.inputlocation;

import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import sootup.core.model.SourceType;
import sootup.core.transform.BodyInterceptor;
import sootup.core.types.ClassType;
import sootup.core.views.View;
import sootup.java.bytecode.frontend.conversion.AsmJavaClassProvider;
import sootup.java.core.JavaSootClassSource;
import sootup.java.core.types.JavaClassType;

class DirectoryBasedAnalysisInputLocation extends PathBasedAnalysisInputLocation {

protected DirectoryBasedAnalysisInputLocation(
@Nonnull Path path,
@Nonnull SourceType srcType,
@Nonnull List<BodyInterceptor> bodyInterceptors) {
this(path, srcType, bodyInterceptors, Collections.emptyList());
}

protected DirectoryBasedAnalysisInputLocation(
@Nonnull Path path,
@Nonnull SourceType srcType,
@Nonnull List<BodyInterceptor> bodyInterceptors,
@Nonnull Collection<Path> ignoredPaths) {
super(path, srcType, bodyInterceptors, ignoredPaths);
}

@Override
@Nonnull
public Stream<JavaSootClassSource> getClassSources(@Nonnull View view) {
// FIXME: 1) store the classprovider reference as a field; 2) and above too; and 3) move view
// which is only used in SootNode to be just there?
return walkDirectory(path, view.getIdentifierFactory(), new AsmJavaClassProvider(view));
}

@Override
@Nonnull
public Optional<JavaSootClassSource> getClassSource(@Nonnull ClassType type, @Nonnull View view) {
return getClassSourceInternal((JavaClassType) type, path, new AsmJavaClassProvider(view));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -168,20 +168,17 @@ public List<BodyInterceptor> getBodyInterceptors() {
* @param entry A class path entry
* @return A stream of class path entries with wildcards exploded
*/
private static @Nonnull Stream<Path> handleWildCards(@Nonnull String entry) {
@Nonnull
private static Stream<Path> handleWildCards(@Nonnull String entry) {
return handleWildCards(entry, FileSystems.getDefault());
}

@Override
@Nonnull
public Collection<JavaSootClassSource> getClassSources(@Nonnull View view) {
// By using a set here, already added classes won't be overwritten and the class which is found
// first will be kept
Set<SootClassSource> found = new HashSet<>();
for (AnalysisInputLocation inputLocation : cpEntries) {
found.addAll(inputLocation.getClassSources(view));
}
return found.stream().map(src -> (JavaSootClassSource) src).collect(Collectors.toList());
public Stream<JavaSootClassSource> getClassSources(@Nonnull View view) {
return cpEntries.stream()
.flatMap(inputLocation -> inputLocation.getClassSources(view))
.map(src -> (JavaSootClassSource) src);
}

@Override
Expand Down
Loading

0 comments on commit cb2af47

Please sign in to comment.