Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streamify AnalysisInputLocation getClasses #1163

Merged
merged 4 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading