diff --git a/plugin/callgraph/fixtures/testJavaArguments.java b/plugin/callgraph/fixtures/testJavaArguments.java new file mode 100644 index 0000000..1142ee0 --- /dev/null +++ b/plugin/callgraph/fixtures/testJavaArguments.java @@ -0,0 +1,65 @@ +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.awt.Canvas; +import java.awt.Dialog; +import java.awt.Window; +import java.awt.Frame; + +public class testJavaArguments { + + public static void testMessageDigest() throws NoSuchAlgorithmException { + // Test literal string argument matching - should match MD5 signature + MessageDigest md5 = MessageDigest.getInstance("MD5"); + + // Test different case variations + MessageDigest md5Upper = MessageDigest.getInstance("md5"); + + // Test SHA-256 hash algorithm + MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); + + // Test SHA-1 (should match sha1 signature) + MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); + } + + public static void testCanvasSetSize() { + Canvas canvas1 = new Canvas(); + // Test specific numeric literal arguments + canvas1.setSize(32, 99); + + Canvas canvas2 = new Canvas(); + // Test different values (should not match 32, 99 signature) + canvas2.setSize(64, 128); + + Canvas canvas3 = new Canvas(); + // Test first arg matches, second doesn't + canvas3.setSize(32, 100); + } + + public static void testDialogWithWindow() { + // Test type resolution - Dialog constructor with Window argument + Window window = new Window(new Frame()); + Dialog dialog = new Dialog(window); + + // Test nested type resolution + Dialog nestedDialog = new Dialog(new Window(new Frame())); + } + + public static void testMixedArguments() { + Canvas canvas = new Canvas(); + // Variable arguments (should not match specific literal signatures) + int width = 32; + int height = 99; + canvas.setSize(width, height); + } + + public static void main(String[] args) { + try { + testMessageDigest(); + testCanvasSetSize(); + testDialogWithWindow(); + testMixedArguments(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/plugin/callgraph/imports.go b/plugin/callgraph/imports.go index 4e140fd..313c969 100644 --- a/plugin/callgraph/imports.go +++ b/plugin/callgraph/imports.go @@ -97,6 +97,7 @@ func resolveNamespaceWithSeparator(moduleName string, lang core.Language) string if exists { return strings.Join(strings.Split(moduleName, separator), namespaceSeparator) } + return moduleName } @@ -111,5 +112,6 @@ func resolveSubmoduleIdentifier(identifier string, lang core.Language) string { parts := strings.Split(identifier, separator) return parts[len(parts)-1] } + return identifier } diff --git a/plugin/callgraph/signatures_test.go b/plugin/callgraph/signatures_test.go index 189942e..b60b83e 100644 --- a/plugin/callgraph/signatures_test.go +++ b/plugin/callgraph/signatures_test.go @@ -177,6 +177,437 @@ func TestSignatureMatcher(t *testing.T) { }, }, }, + { + Name: "Python signatures", + Language: core.LanguageCodePython, + FilePaths: []string{"fixtures/testFunctions.py"}, + Signatures: []*callgraphv1.Signature{ + { + Id: "python.print.usage", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "python": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "print", + }, + }, + }, + }, + }, + { + Id: "python.pprint.pprint.usage", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "python": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "pprint.pprint", + }, + }, + }, + }, + }, + { + Id: "python.os.getenv.usage", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "python": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "os.getenv", + }, + }, + }, + }, + }, + { + Id: "python.pstats.getsomestat.usage", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "python": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "pstats.getsomestat", + }, + }, + }, + }, + }, + }, + ExpectedMatches: []signatureMatchExpectation{ + { + SignatureID: "python.print.usage", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodePython, + MinEvidenceCount: 1, + CalleeContains: "print", + }, + { + SignatureID: "python.pprint.pprint.usage", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodePython, + MinEvidenceCount: 1, + CalleeContains: "pprint", + }, + { + SignatureID: "python.os.getenv.usage", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodePython, + MinEvidenceCount: 1, + CalleeContains: "getenv", + }, + { + SignatureID: "python.pstats.getsomestat.usage", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodePython, + MinEvidenceCount: 1, + CalleeContains: "getsomestat", + }, + }, + }, + { + Name: "Go signatures", + Language: core.LanguageCodeGo, + FilePaths: []string{"fixtures/testCallGraph.go"}, + Signatures: []*callgraphv1.Signature{ + { + Id: "go.fmt.println.usage", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "go": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "fmt/Println", + }, + }, + }, + }, + }, + { + Id: "go.os.writefile.usage", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "go": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "os/WriteFile", + }, + }, + }, + }, + }, + { + Id: "go.os.getenv.usage", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "go": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "os/Getenv", + }, + }, + }, + }, + }, + { + Id: "go.fmt.sprintf.usage", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "go": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "fmt/Sprintf", + }, + }, + }, + }, + }, + }, + ExpectedMatches: []signatureMatchExpectation{ + { + SignatureID: "go.fmt.println.usage", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeGo, + MinEvidenceCount: 1, + CalleeContains: "Println", + }, + { + SignatureID: "go.os.writefile.usage", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeGo, + MinEvidenceCount: 1, + CalleeContains: "WriteFile", + }, + { + SignatureID: "go.os.getenv.usage", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeGo, + MinEvidenceCount: 1, + CalleeContains: "Getenv", + }, + { + SignatureID: "go.fmt.sprintf.usage", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeGo, + MinEvidenceCount: 1, + CalleeContains: "Sprintf", + }, + }, + }, + { + Name: "Java signatures", + Language: core.LanguageCodeJava, + FilePaths: []string{"fixtures/CallgraphTestcases.java"}, + Signatures: []*callgraphv1.Signature{ + { + Id: "java.system.println.usage", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "java": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "System.out.println", + }, + }, + }, + }, + }, + { + Id: "java.math.random.usage", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "java": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "Math.random", + }, + }, + }, + }, + }, + { + Id: "java.awt.dialog.constructor", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "java": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "java.awt.Dialog", + }, + }, + }, + }, + }, + { + Id: "java.string.valueof.usage", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "java": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "String.valueOf", + }, + }, + }, + }, + }, + }, + ExpectedMatches: []signatureMatchExpectation{ + { + SignatureID: "java.system.println.usage", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeJava, + MinEvidenceCount: 1, + CalleeContains: "println", + }, + { + SignatureID: "java.math.random.usage", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeJava, + MinEvidenceCount: 1, + CalleeContains: "random", + }, + { + SignatureID: "java.awt.dialog.constructor", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeJava, + MinEvidenceCount: 1, + CalleeContains: "Dialog", + }, + { + SignatureID: "java.string.valueof.usage", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeJava, + MinEvidenceCount: 1, + CalleeContains: "valueOf", + }, + }, + }, + { + Name: "Java argument matching by index", + Language: core.LanguageCodeJava, + FilePaths: []string{"fixtures/testJavaArguments.java"}, + Signatures: []*callgraphv1.Signature{ + { + Id: "java.crypto.md5.literal", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "java": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "java.security.MessageDigest.getInstance", + Args: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition_Argument{ + { + Index: 0, + Values: []string{"\"MD5\"", "\"md5\""}, + }, + }, + }, + }, + }, + }, + }, + { + Id: "java.crypto.sha256.literal", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "java": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "java.security.MessageDigest.getInstance", + Args: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition_Argument{ + { + Index: 0, + Values: []string{"\"SHA-256\""}, + }, + }, + }, + }, + }, + }, + }, + { + Id: "java.awt.canvas.setsize.32.99", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "java": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "java.awt.Canvas.setSize", + Args: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition_Argument{ + { + Index: 0, + Values: []string{"32"}, + }, + { + Index: 1, + Values: []string{"99"}, + }, + }, + }, + }, + }, + }, + }, + { + Id: "java.awt.dialog.with.window.type", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "java": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "java.awt.Dialog", + Args: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition_Argument{ + { + Index: 0, + ResolvesTo: []string{"java.awt.Window"}, + }, + }, + }, + }, + }, + }, + }, + { + Id: "java.awt.canvas.setsize.32.200.should.not.match", + Languages: map[string]*callgraphv1.Signature_LanguageMatcher{ + "java": { + Match: "any", + Conditions: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition{ + { + Type: "call", + Value: "java.awt.Canvas.setSize", + Args: []*callgraphv1.Signature_LanguageMatcher_SignatureCondition_Argument{ + { + Index: 0, + Values: []string{"32"}, + }, + { + Index: 1, + Values: []string{"200"}, + }, + }, + }, + }, + }, + }, + }, + }, + ExpectedMatches: []signatureMatchExpectation{ + { + SignatureID: "java.crypto.md5.literal", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeJava, + MinEvidenceCount: 1, + CalleeContains: "MessageDigest", + }, + { + SignatureID: "java.crypto.sha256.literal", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeJava, + MinEvidenceCount: 1, + CalleeContains: "MessageDigest", + }, + { + SignatureID: "java.awt.canvas.setsize.32.99", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeJava, + MinEvidenceCount: 1, + CalleeContains: "setSize", + }, + { + SignatureID: "java.awt.dialog.with.window.type", + ShouldMatch: true, + ExpectedLanguage: core.LanguageCodeJava, + MinEvidenceCount: 1, + CalleeContains: "Dialog", + }, + { + SignatureID: "java.awt.canvas.setsize.32.200.should.not.match", + ShouldMatch: false, + ExpectedLanguage: core.LanguageCodeJava, + MinEvidenceCount: 0, + CalleeContains: "", + }, + }, + }, } for _, tc := range testCases {