Skip to content

Commit

Permalink
Fix error when trying to get class stream for Mockito mocks (#6183)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikita-tkachenko-datadog authored and jandro996 committed Nov 14, 2023
1 parent 11955c8 commit 5799c5c
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 12 deletions.
1 change: 1 addition & 0 deletions dd-java-agent/agent-ci-visibility/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ excludedClassesCoverage += [
"datadog.trace.civisibility.source.index.RepoIndexBuilder.RepoIndexingFileVisitor",
"datadog.trace.civisibility.source.index.RepoIndexFetcher",
"datadog.trace.civisibility.source.index.RepoIndexSourcePathResolver",
"datadog.trace.civisibility.source.Utils",
"datadog.trace.civisibility.utils.ShellCommandExecutor",
"datadog.trace.civisibility.utils.ShellCommandExecutor.OutputParser",
"datadog.trace.civisibility.utils.SpanUtils"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,26 @@ public abstract class Utils {

public static InputStream getClassStream(Class<?> clazz) throws IOException {
String className = clazz.getName();
String classPath = "/" + className.replace('.', '/') + ".class";
return clazz.getResourceAsStream(classPath);
InputStream classStream = clazz.getResourceAsStream(toResourceName(className));
if (classStream != null) {
return classStream;
} else {
// might be auto-generated inner class (e.g. Mockito mock)
String topLevelClassName = stripNestedClassNames(clazz.getName());
return clazz.getResourceAsStream(toResourceName(topLevelClassName));
}
}

private static String toResourceName(String className) {
return "/" + className.replace('.', '/') + ".class";
}

public static String stripNestedClassNames(String className) {
int innerClassNameIdx = className.indexOf('$');
if (innerClassNameIdx >= 0) {
return className.substring(0, innerClassNameIdx);
} else {
return className;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public List<String> getRootPackages() {

@Nullable
public String getSourcePath(@Nonnull Class<?> c) {
String topLevelClassName = stripNestedClassNames(c.getName());
String topLevelClassName = Utils.stripNestedClassNames(c.getName());
SourceType sourceType = detectSourceType(c);
String extension = sourceType.getExtension();
String classNameWithExtension = topLevelClassName + extension;
Expand Down Expand Up @@ -107,15 +107,6 @@ private SourceType detectSourceType(Class<?> c) {
return SourceType.JAVA;
}

private String stripNestedClassNames(String className) {
int innerClassNameIdx = className.indexOf('$');
if (innerClassNameIdx >= 0) {
return className.substring(0, innerClassNameIdx);
} else {
return className;
}
}

/**
* Names of package-private classes do not have to correspond to the names of their source code
* files. For such classes filename is extracted from SourceFile attribute that is available in
Expand All @@ -126,6 +117,10 @@ private String getSourcePathForPackagePrivateOrNonJavaClass(Class<?> c) {
SourceFileAttributeVisitor sourceFileAttributeVisitor = new SourceFileAttributeVisitor();

try (InputStream classStream = Utils.getClassStream(c)) {
if (classStream == null) {
log.debug("Could not get input stream for class {}", c.getName());
return null;
}
ClassReader classReader = new ClassReader(classStream);
classReader.accept(
sourceFileAttributeVisitor, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ class RepoIndexSourcePathResolverTest extends Specification {
sourcePathResolver.getSourcePath(PackagePrivateClass) == expectedSourcePath
}

def "test source path resolution for class nested into package-private class"() {
setup:
def expectedSourcePath = givenSourceFile(RepoIndexSourcePathResolverTest, repoRoot + "/src")

when:
def sourcePathResolver = new RepoIndexSourcePathResolver(repoRoot, packageResolver, fileSystem)

then:
sourcePathResolver.getSourcePath(PackagePrivateClass.NestedIntoPackagePrivateClass) == expectedSourcePath
}

def "test source path resolution for non-java class whose file name is different from class name"() {
setup:
def expectedSourcePath = givenSourceFile(RepoIndexSourcePathResolverTest, repoRoot + "/src")
Expand Down Expand Up @@ -173,6 +184,7 @@ class RepoIndexSourcePathResolverTest extends Specification {

@PackageScope
class PackagePrivateClass {
class NestedIntoPackagePrivateClass {}
}

class PublicClassWhoseNameDoesNotCorrespondToFileName {
Expand Down

0 comments on commit 5799c5c

Please sign in to comment.