Skip to content

Commit

Permalink
Merge pull request #1163 from soot-oss/streamify/AnalysisInputLocation
Browse files Browse the repository at this point in the history
Streamify AnalysisInputLocation getClasses
  • Loading branch information
stschott authored Jan 23, 2025
2 parents d162ee6 + 2511462 commit b37d99c
Show file tree
Hide file tree
Showing 39 changed files with 565 additions and 476 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 @@ -58,10 +58,10 @@ public interface AnalysisInputLocation {
/**
* Scan the input location and create ClassSources for every compilation / interpretation unit.
*
* @return The source entries.
* @return an Autocloseable resource that must be closed!
*/
@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,19 +100,22 @@ 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) {
throw new RuntimeException("Failed to retrieve file system from cache for " + path, e);
}
}

/** returns a Autocloseable resource that must be closed! */
@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,113 @@
package sootup.java.bytecode.frontend.inputlocation;

/*-
* #%L
* SootUp
* %%
* Copyright (C) 1997 - 2024 Raja Vallée-Rai and others
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/

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,70 @@
package sootup.java.bytecode.frontend.inputlocation;

/*-
* #%L
* Soot
* %%
* Copyright (C) 2018-2020 Manuel Benz, Christian Brüggemann, Markus Schmidt and others
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/

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));
}
}
Loading

0 comments on commit b37d99c

Please sign in to comment.