Add call graph fixtures for various languages and scenarios
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Findings Ledger CI / build-test (push) Has been cancelled
Findings Ledger CI / migration-validation (push) Has been cancelled
Findings Ledger CI / generate-manifest (push) Has been cancelled
Lighthouse CI / Lighthouse Audit (push) Has been cancelled
Lighthouse CI / Axe Accessibility Audit (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Reachability Corpus Validation / validate-corpus (push) Has been cancelled
Reachability Corpus Validation / validate-ground-truths (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Reachability Corpus Validation / determinism-check (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Findings Ledger CI / build-test (push) Has been cancelled
Findings Ledger CI / migration-validation (push) Has been cancelled
Findings Ledger CI / generate-manifest (push) Has been cancelled
Lighthouse CI / Lighthouse Audit (push) Has been cancelled
Lighthouse CI / Axe Accessibility Audit (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Reachability Corpus Validation / validate-corpus (push) Has been cancelled
Reachability Corpus Validation / validate-ground-truths (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Reachability Corpus Validation / determinism-check (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
- Introduced `all-edge-reasons.json` to test edge resolution reasons in .NET. - Added `all-visibility-levels.json` to validate method visibility levels in .NET. - Created `dotnet-aspnetcore-minimal.json` for a minimal ASP.NET Core application. - Included `go-gin-api.json` for a Go Gin API application structure. - Added `java-spring-boot.json` for the Spring PetClinic application in Java. - Introduced `legacy-no-schema.json` for legacy application structure without schema. - Created `node-express-api.json` for an Express.js API application structure.
This commit is contained in:
@@ -108,12 +108,12 @@ internal sealed class JavaCallgraphBuilder
|
||||
var edgeId = JavaGraphIdentifiers.ComputeEdgeId(callerId, calleeId, edge.InstructionOffset);
|
||||
var confidence = edge.Confidence == JavaReflectionConfidence.High ? 0.9 : 0.5;
|
||||
|
||||
var edgeType = edge.Reason switch
|
||||
var (edgeType, edgeReason) = edge.Reason switch
|
||||
{
|
||||
JavaReflectionReason.ClassForName => JavaEdgeType.Reflection,
|
||||
JavaReflectionReason.ClassLoaderLoadClass => JavaEdgeType.Reflection,
|
||||
JavaReflectionReason.ServiceLoaderLoad => JavaEdgeType.ServiceLoader,
|
||||
_ => JavaEdgeType.Reflection,
|
||||
JavaReflectionReason.ClassForName => (JavaEdgeType.Reflection, JavaEdgeReason.ReflectionString),
|
||||
JavaReflectionReason.ClassLoaderLoadClass => (JavaEdgeType.Reflection, JavaEdgeReason.ReflectionString),
|
||||
JavaReflectionReason.ServiceLoaderLoad => (JavaEdgeType.ServiceLoader, JavaEdgeReason.ServiceLoader),
|
||||
_ => (JavaEdgeType.Reflection, JavaEdgeReason.ReflectionString),
|
||||
};
|
||||
|
||||
_edges.Add(new JavaCallEdge(
|
||||
@@ -123,6 +123,7 @@ internal sealed class JavaCallgraphBuilder
|
||||
CalleePurl: null, // Reflection targets often unknown
|
||||
CalleeMethodDigest: null,
|
||||
EdgeType: edgeType,
|
||||
EdgeReason: edgeReason,
|
||||
BytecodeOffset: edge.InstructionOffset,
|
||||
IsResolved: isResolved,
|
||||
Confidence: confidence));
|
||||
@@ -229,6 +230,16 @@ internal sealed class JavaCallgraphBuilder
|
||||
var isSynthetic = (method.AccessFlags & 0x1000) != 0;
|
||||
var isBridge = (method.AccessFlags & 0x0040) != 0;
|
||||
|
||||
// Extract visibility from access flags
|
||||
var visibility = ExtractVisibility(method.AccessFlags);
|
||||
|
||||
// Determine if this method is an entrypoint candidate
|
||||
// Public non-synthetic methods that aren't constructors or accessors
|
||||
var isEntrypointCandidate = isPublic &&
|
||||
!isSynthetic &&
|
||||
!method.Name.StartsWith("<") &&
|
||||
!method.Name.StartsWith("lambda$");
|
||||
|
||||
var node = new JavaMethodNode(
|
||||
MethodId: methodId,
|
||||
ClassName: className,
|
||||
@@ -241,11 +252,34 @@ internal sealed class JavaCallgraphBuilder
|
||||
IsStatic: isStatic,
|
||||
IsPublic: isPublic,
|
||||
IsSynthetic: isSynthetic,
|
||||
IsBridge: isBridge);
|
||||
IsBridge: isBridge,
|
||||
Visibility: visibility,
|
||||
IsEntrypointCandidate: isEntrypointCandidate);
|
||||
|
||||
_methods.TryAdd(methodId, node);
|
||||
}
|
||||
|
||||
private static JavaVisibility ExtractVisibility(int accessFlags)
|
||||
{
|
||||
// ACC_PUBLIC = 0x0001, ACC_PRIVATE = 0x0002, ACC_PROTECTED = 0x0004
|
||||
if ((accessFlags & 0x0001) != 0)
|
||||
{
|
||||
return JavaVisibility.Public;
|
||||
}
|
||||
else if ((accessFlags & 0x0002) != 0)
|
||||
{
|
||||
return JavaVisibility.Private;
|
||||
}
|
||||
else if ((accessFlags & 0x0004) != 0)
|
||||
{
|
||||
return JavaVisibility.Protected;
|
||||
}
|
||||
else
|
||||
{
|
||||
return JavaVisibility.Package; // Package-private (default)
|
||||
}
|
||||
}
|
||||
|
||||
private void FindSyntheticRoots(string className, JavaClassFileParser.ClassFile classFile, string jarPath)
|
||||
{
|
||||
var rootOrder = 0;
|
||||
@@ -380,13 +414,14 @@ internal sealed class JavaCallgraphBuilder
|
||||
methodRef.Value.Name,
|
||||
methodRef.Value.Descriptor);
|
||||
|
||||
var edgeType = opcode switch
|
||||
var (edgeType, edgeReason) = opcode switch
|
||||
{
|
||||
0xB8 => JavaEdgeType.InvokeStatic,
|
||||
0xB6 => JavaEdgeType.InvokeVirtual,
|
||||
0xB7 => methodRef.Value.Name == "<init>" ? JavaEdgeType.Constructor : JavaEdgeType.InvokeSpecial,
|
||||
0xB9 => JavaEdgeType.InvokeInterface,
|
||||
_ => JavaEdgeType.InvokeVirtual,
|
||||
0xB8 => (JavaEdgeType.InvokeStatic, JavaEdgeReason.DirectCall),
|
||||
0xB6 => (JavaEdgeType.InvokeVirtual, JavaEdgeReason.VirtualCall),
|
||||
0xB7 when methodRef.Value.Name == "<init>" => (JavaEdgeType.Constructor, JavaEdgeReason.NewObj),
|
||||
0xB7 => (JavaEdgeType.InvokeSpecial, JavaEdgeReason.SuperCall),
|
||||
0xB9 => (JavaEdgeType.InvokeInterface, JavaEdgeReason.InterfaceCall),
|
||||
_ => (JavaEdgeType.InvokeVirtual, JavaEdgeReason.VirtualCall),
|
||||
};
|
||||
|
||||
// Check if target is resolved (known in our method set)
|
||||
@@ -403,6 +438,7 @@ internal sealed class JavaCallgraphBuilder
|
||||
CalleePurl: calleePurl,
|
||||
CalleeMethodDigest: null, // Would compute if method is in our set
|
||||
EdgeType: edgeType,
|
||||
EdgeReason: edgeReason,
|
||||
BytecodeOffset: instructionOffset,
|
||||
IsResolved: isResolved,
|
||||
Confidence: isResolved ? 1.0 : 0.7));
|
||||
@@ -448,6 +484,7 @@ internal sealed class JavaCallgraphBuilder
|
||||
CalleePurl: null,
|
||||
CalleeMethodDigest: null,
|
||||
EdgeType: JavaEdgeType.InvokeDynamic,
|
||||
EdgeReason: JavaEdgeReason.DynamicImport,
|
||||
BytecodeOffset: instructionOffset,
|
||||
IsResolved: false,
|
||||
Confidence: 0.3));
|
||||
|
||||
@@ -31,6 +31,8 @@ public sealed record JavaReachabilityGraph(
|
||||
/// <param name="IsPublic">Whether the method is public.</param>
|
||||
/// <param name="IsSynthetic">Whether the method is synthetic (compiler-generated).</param>
|
||||
/// <param name="IsBridge">Whether the method is a bridge method.</param>
|
||||
/// <param name="Visibility">Access visibility (public, private, protected, package).</param>
|
||||
/// <param name="IsEntrypointCandidate">Whether this method could be an entrypoint (public, controller action, etc.).</param>
|
||||
public sealed record JavaMethodNode(
|
||||
string MethodId,
|
||||
string ClassName,
|
||||
@@ -43,7 +45,27 @@ public sealed record JavaMethodNode(
|
||||
bool IsStatic,
|
||||
bool IsPublic,
|
||||
bool IsSynthetic,
|
||||
bool IsBridge);
|
||||
bool IsBridge,
|
||||
JavaVisibility Visibility,
|
||||
bool IsEntrypointCandidate);
|
||||
|
||||
/// <summary>
|
||||
/// Access visibility levels for Java methods.
|
||||
/// </summary>
|
||||
public enum JavaVisibility
|
||||
{
|
||||
/// <summary>Accessible from anywhere.</summary>
|
||||
Public,
|
||||
|
||||
/// <summary>Accessible only within the same class.</summary>
|
||||
Private,
|
||||
|
||||
/// <summary>Accessible within the same package or subclasses.</summary>
|
||||
Protected,
|
||||
|
||||
/// <summary>Package-private (default access).</summary>
|
||||
Package
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A call edge in the Java call graph.
|
||||
@@ -54,6 +76,7 @@ public sealed record JavaMethodNode(
|
||||
/// <param name="CalleePurl">PURL of the callee if resolvable.</param>
|
||||
/// <param name="CalleeMethodDigest">Method digest of the callee.</param>
|
||||
/// <param name="EdgeType">Type of edge (invoke type).</param>
|
||||
/// <param name="EdgeReason">Semantic reason for the edge (DirectCall, VirtualCall, etc.).</param>
|
||||
/// <param name="BytecodeOffset">Bytecode offset where call occurs.</param>
|
||||
/// <param name="IsResolved">Whether the callee was successfully resolved.</param>
|
||||
/// <param name="Confidence">Confidence level (1.0 for resolved, lower for heuristic).</param>
|
||||
@@ -64,6 +87,7 @@ public sealed record JavaCallEdge(
|
||||
string? CalleePurl,
|
||||
string? CalleeMethodDigest,
|
||||
JavaEdgeType EdgeType,
|
||||
JavaEdgeReason EdgeReason,
|
||||
int BytecodeOffset,
|
||||
bool IsResolved,
|
||||
double Confidence);
|
||||
@@ -98,6 +122,46 @@ public enum JavaEdgeType
|
||||
Constructor,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Semantic reason for why a Java edge exists.
|
||||
/// Maps to the schema's EdgeReason enum for explainability.
|
||||
/// </summary>
|
||||
public enum JavaEdgeReason
|
||||
{
|
||||
/// <summary>Direct static method call (invokestatic).</summary>
|
||||
DirectCall,
|
||||
|
||||
/// <summary>Virtual method dispatch (invokevirtual, invokeinterface).</summary>
|
||||
VirtualCall,
|
||||
|
||||
/// <summary>Reflection-based invocation (Class.forName, Method.invoke).</summary>
|
||||
ReflectionString,
|
||||
|
||||
/// <summary>Dependency injection binding (Spring, Guice).</summary>
|
||||
DiBinding,
|
||||
|
||||
/// <summary>Dynamic lambda or method reference (invokedynamic).</summary>
|
||||
DynamicImport,
|
||||
|
||||
/// <summary>Constructor/object instantiation (invokespecial <init>).</summary>
|
||||
NewObj,
|
||||
|
||||
/// <summary>Super or private method call (invokespecial non-init).</summary>
|
||||
SuperCall,
|
||||
|
||||
/// <summary>ServiceLoader-based service discovery.</summary>
|
||||
ServiceLoader,
|
||||
|
||||
/// <summary>Interface method dispatch.</summary>
|
||||
InterfaceCall,
|
||||
|
||||
/// <summary>Native interop (JNI).</summary>
|
||||
NativeInterop,
|
||||
|
||||
/// <summary>Reason could not be determined.</summary>
|
||||
Unknown
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A synthetic root in the Java call graph.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user