Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
92d8909
:bug: Implement filepath filtering in gRPC providers for chained cond…
tsanders-rh Nov 27, 2025
00aa5d6
Fix test expectations for Windows case-insensitive comparison
tsanders-rh Nov 27, 2025
48bc002
Fix missing imports in filepath filtering tests
tsanders-rh Nov 27, 2025
571864d
Fix nodejs filepath filtering test compilation issues
tsanders-rh Nov 27, 2025
9d9e3b1
Fix incorrect path generation in benchmark tests
tsanders-rh Dec 2, 2025
5bbe00a
:recycle: Refactor duplicate normalizePathForComparison to shared fun…
tsanders-rh Dec 2, 2025
a1b8c5a
:construction: Use FileSearcher for comprehensive filepath filtering
tsanders-rh Dec 2, 2025
5fbc1c9
:recycle: Move NormalizePathForComparison test to provider/lib_test.go
tsanders-rh Dec 2, 2025
a1d3414
:bug: Always use FileSearcher to apply all filepath constraints
tsanders-rh Dec 2, 2025
43f8ba1
:zap: Parallelize file search and symbol retrieval for better perform…
tsanders-rh Dec 2, 2025
634b491
:fire: Remove accidentally committed test scripts and temporary docs
tsanders-rh Dec 2, 2025
03015ec
:bug: Handle FileSearcher errors gracefully to avoid false negatives
tsanders-rh Dec 2, 2025
aaab5f9
:recycle: Use channel-based approach to eliminate race conditions
tsanders-rh Dec 2, 2025
4e0217a
:white_check_mark: Update demo golden files with correct filtering be…
tsanders-rh Dec 2, 2025
ece91be
:bug: Fix java provider to allow dependency code analysis
tsanders-rh Dec 2, 2025
36a81f8
:test_tube: Trigger CI to test dependency analysis fix
tsanders-rh Dec 2, 2025
cfa5f27
:twisted_rightwards_arrows: Merge upstream/main to resolve conflicts
tsanders-rh Dec 2, 2025
4d6b6ba
:sparkles: Use provider init config includedPaths in nodejs provider
tsanders-rh Dec 2, 2025
f8bfe6f
:zap: Optimize nodejs provider path normalization
tsanders-rh Dec 2, 2025
f31d2f4
:fire: Remove local testing replace directive from java provider go.mod
tsanders-rh Dec 2, 2025
76b0b0e
:bug: Fix nodejs rules being filtered out by empty dependency folder …
tsanders-rh Dec 2, 2025
f3982e8
:wrench: Fix nodejs provider config to use empty array instead of arr…
tsanders-rh Dec 2, 2025
28ed870
:sparkles: Add filepaths support to nodejs provider condition
tsanders-rh Dec 2, 2025
bdcfa3c
:sparkles: Add FileSearcher integration to Java provider for comprehe…
tsanders-rh Dec 2, 2025
e9dab9e
Fix nodejs provider includedPaths being silently ignored
tsanders-rh Dec 2, 2025
7662a26
Add missing go.sum entries for java provider
tsanders-rh Dec 2, 2025
ad48415
:wrench: Add replace directive to java provider go.mod to fix CI
tsanders-rh Dec 3, 2025
68d24f5
:white_check_mark: Update demo golden files for nodejs provider fixes
tsanders-rh Dec 3, 2025
674255c
Fix unsafe type assertion in Java provider filepath filtering
tsanders-rh Dec 3, 2025
c52ac90
Fix filepath filtering to apply file-level constraints for includedPaths
tsanders-rh Dec 3, 2025
069703e
Parallelize file search and language server query for performance
tsanders-rh Dec 3, 2025
8d5e49f
Fix log message to reference correct variable
tsanders-rh Dec 3, 2025
b2659c4
Revert parallelization to fix test failure
tsanders-rh Dec 3, 2025
2c8875d
Re-implement parallelization with correct constraint logic
tsanders-rh Dec 3, 2025
d67d7f4
Removing replace from go mod and updating the test workflow to handle…
shawn-hurley Dec 3, 2025
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
84 changes: 4 additions & 80 deletions demo-output.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -597,63 +597,6 @@
name: javax.activation.activation
version: "1.1"
effort: 1
node-sample-rule-001:
description: Testing that the node provider works - type
category: potential
incidents:
- uri: file:///examples/nodejs/test_a.ts
message: nodejs sample rule 001
codeSnip: " 1 export interface Greeter {\n 2 name: string;\n 3 hello(): string;\n 4 }\n 5 \n 6 export const greeter: Greeter = {\n 7 name: \"Person1\",\n 8 hello() {\n 9 return `Hello, I'm ${this.name}`;\n10 },\n11 };\n"
lineNumber: 6
variables:
file: file:///examples/nodejs/test_a.ts
- uri: file:///examples/nodejs/test_b.ts
message: nodejs sample rule 001
codeSnip: " 1 import { greeter } from './test_a';\n 2 \n 3 console.log(greeter.hello());\n"
lineNumber: 1
variables:
file: file:///examples/nodejs/test_b.ts
- uri: file:///examples/nodejs/test_b.ts
message: nodejs sample rule 001
codeSnip: " 1 import { greeter } from './test_a';\n 2 \n 3 console.log(greeter.hello());\n"
lineNumber: 3
variables:
file: file:///examples/nodejs/test_b.ts
effort: 1
node-sample-rule-002:
description: Testing that the node provider works - function
category: potential
incidents:
- uri: file:///examples/nodejs/test_a.ts
message: nodejs sample rule 002
codeSnip: " 1 export interface Greeter {\n 2 name: string;\n 3 hello(): string;\n 4 }\n 5 \n 6 export const greeter: Greeter = {\n 7 name: \"Person1\",\n 8 hello() {\n 9 return `Hello, I'm ${this.name}`;\n10 },\n11 };\n"
lineNumber: 3
variables:
file: file:///examples/nodejs/test_a.ts
- uri: file:///examples/nodejs/test_a.ts
message: nodejs sample rule 002
codeSnip: " 1 export interface Greeter {\n 2 name: string;\n 3 hello(): string;\n 4 }\n 5 \n 6 export const greeter: Greeter = {\n 7 name: \"Person1\",\n 8 hello() {\n 9 return `Hello, I'm ${this.name}`;\n10 },\n11 };\n"
lineNumber: 8
variables:
file: file:///examples/nodejs/test_a.ts
- uri: file:///examples/nodejs/test_b.ts
message: nodejs sample rule 002
codeSnip: " 1 import { greeter } from './test_a';\n 2 \n 3 console.log(greeter.hello());\n"
lineNumber: 3
variables:
file: file:///examples/nodejs/test_b.ts
effort: 1
node-sample-rule-003:
description: Testing that the node module files are not matched
category: potential
incidents:
- uri: file:///examples/nodejs/test_b.ts
message: nodejs sample rule 003
codeSnip: " 1 import { greeter } from './test_a';\n 2 \n 3 console.log(greeter.hello());\n"
lineNumber: 3
variables:
file: file:///examples/nodejs/test_b.ts
effort: 1
python-sample-rule-001:
description: ""
category: potential
Expand Down Expand Up @@ -793,29 +736,6 @@
variables:
matchingText: import React
effort: 1
test-tsx-support-00010:
description: Test that nodejs provider can find references in TypeScript/React files
category: potential
incidents:
- uri: file:///examples/nodejs/Component.tsx
message: Found React reference using nodejs provider
codeSnip: " 1 import React from 'react';\n 2 \n 3 export const MyComponent: React.FC = () => {\n 4 return <div>Hello from TypeScript React</div>;\n 5 };\n"
lineNumber: 1
variables:
file: file:///examples/nodejs/Component.tsx
- uri: file:///examples/nodejs/Component.tsx
message: Found React reference using nodejs provider
codeSnip: " 1 import React from 'react';\n 2 \n 3 export const MyComponent: React.FC = () => {\n 4 return <div>Hello from TypeScript React</div>;\n 5 };\n"
lineNumber: 3
variables:
file: file:///examples/nodejs/Component.tsx
- uri: file:///examples/nodejs/LegacyComponent.jsx
message: Found React reference using nodejs provider
codeSnip: " 1 import React from 'react';\n 2 \n 3 export const LegacyComponent = () => {\n 4 return <div>Hello from JavaScript React</div>;\n 5 };\n"
lineNumber: 1
variables:
file: file:///examples/nodejs/LegacyComponent.jsx
effort: 1
xml-pom-001:
description: ""
category: potential
Expand Down Expand Up @@ -1382,4 +1302,8 @@
unmatched:
- file-002
- lang-ref-002
- node-sample-rule-001
- node-sample-rule-002
- node-sample-rule-003
- python-sample-rule-003
- test-tsx-support-00010
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
package dotnet

import (
"strconv"
"testing"

"github.com/konveyor/analyzer-lsp/provider"
"go.lsp.dev/protocol"
"go.lsp.dev/uri"
)

func TestFilepathFiltering(t *testing.T) {
// Create test locations
createLocation := func(path string) protocol.Location {
return protocol.Location{
URI: uri.URI(path),
Range: protocol.Range{
Start: protocol.Position{Line: 10, Character: 5},
},
}
}

tests := []struct {
name string
locations []protocol.Location
includedFilepaths []string
excludedFilepaths []string
expectedCount int
expectedPaths []string
}{
{
name: "no filtering - all locations included",
locations: []protocol.Location{
createLocation("file:///project/src/Program.cs"),
createLocation("file:///project/src/Utils.cs"),
},
includedFilepaths: []string{},
excludedFilepaths: []string{},
expectedCount: 2,
expectedPaths: []string{"/project/src/Program.cs", "/project/src/Utils.cs"},
},
{
name: "included paths filtering",
locations: []protocol.Location{
createLocation("file:///project/src/Program.cs"),
createLocation("file:///project/src/Utils.cs"),
createLocation("file:///project/tests/ProgramTests.cs"),
},
includedFilepaths: []string{"/project/src/Program.cs"},
excludedFilepaths: []string{},
expectedCount: 1,
expectedPaths: []string{"/project/src/Program.cs"},
},
{
name: "excluded paths filtering",
locations: []protocol.Location{
createLocation("file:///project/src/Program.cs"),
createLocation("file:///project/src/Utils.cs"),
createLocation("file:///project/tests/ProgramTests.cs"),
},
includedFilepaths: []string{},
excludedFilepaths: []string{"/project/tests/ProgramTests.cs"},
expectedCount: 2,
expectedPaths: []string{"/project/src/Program.cs", "/project/src/Utils.cs"},
},
{
name: "both included and excluded paths",
locations: []protocol.Location{
createLocation("file:///project/src/Program.cs"),
createLocation("file:///project/src/Utils.cs"),
createLocation("file:///project/src/Config.cs"),
createLocation("file:///project/tests/ProgramTests.cs"),
},
includedFilepaths: []string{
"/project/src/Program.cs",
"/project/src/Utils.cs",
"/project/src/Config.cs",
},
excludedFilepaths: []string{"/project/src/Config.cs"},
expectedCount: 2,
expectedPaths: []string{"/project/src/Program.cs", "/project/src/Utils.cs"},
},
{
name: "no false positives - similar filenames",
locations: []protocol.Location{
createLocation("file:///project/src/Service.cs"),
createLocation("file:///project/src/ServiceImpl.cs"),
createLocation("file:///project/src/ServiceFactory.cs"),
},
includedFilepaths: []string{"/project/src/Service.cs"},
excludedFilepaths: []string{},
expectedCount: 1,
expectedPaths: []string{"/project/src/Service.cs"},
},
{
name: "URI normalization - different schemes match",
locations: []protocol.Location{
createLocation("file:///project/src/Program.cs"),
createLocation("file:/project/src/Utils.cs"),
},
includedFilepaths: []string{
"file:///project/src/Program.cs", // Triple slash
"/project/src/Utils.cs", // Plain path
},
excludedFilepaths: []string{},
expectedCount: 2,
expectedPaths: []string{"/project/src/Program.cs", "/project/src/Utils.cs"},
},
{
name: "path cleaning - .. and . resolved",
locations: []protocol.Location{
createLocation("file:///project/src/../src/Program.cs"),
createLocation("file:///project/./src/Utils.cs"),
},
includedFilepaths: []string{
"/project/src/Program.cs",
"/project/src/Utils.cs",
},
excludedFilepaths: []string{},
expectedCount: 2,
expectedPaths: []string{"/project/src/Program.cs", "/project/src/Utils.cs"},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Build maps for O(1) lookups
excludedPathsMap := make(map[string]bool, len(tt.excludedFilepaths))
for _, excludedPath := range tt.excludedFilepaths {
normalizedPath := provider.NormalizePathForComparison(excludedPath)
excludedPathsMap[normalizedPath] = true
}

includedPathsMap := make(map[string]bool, len(tt.includedFilepaths))
for _, includedPath := range tt.includedFilepaths {
normalizedPath := provider.NormalizePathForComparison(includedPath)
includedPathsMap[normalizedPath] = true
}

// Filter locations
filteredLocations := []protocol.Location{}
for _, loc := range tt.locations {
normalizedPath := provider.NormalizePathForComparison(string(loc.URI))

// Check if excluded
if excludedPathsMap[normalizedPath] {
continue
}

// Check if included
if len(includedPathsMap) > 0 && !includedPathsMap[normalizedPath] {
continue
}

filteredLocations = append(filteredLocations, loc)
}

// Verify count
if len(filteredLocations) != tt.expectedCount {
t.Errorf("Expected %d locations, got %d", tt.expectedCount, len(filteredLocations))
}

// Verify expected paths are present
foundPaths := make(map[string]bool)
for _, loc := range filteredLocations {
normalizedPath := provider.NormalizePathForComparison(string(loc.URI))
foundPaths[normalizedPath] = true
}

for _, expectedPath := range tt.expectedPaths {
normalizedExpectedPath := provider.NormalizePathForComparison(expectedPath)
if !foundPaths[normalizedExpectedPath] {
t.Errorf("Expected path %q not found in filtered locations", expectedPath)
}
}
})
}
}

func BenchmarkFilepathFiltering(b *testing.B) {
// Create test data with many locations and scoped paths
locations := make([]protocol.Location, 10000)
for i := 0; i < 10000; i++ {
path := uri.URI("file:///project/src/File" + strconv.Itoa(i) + ".cs")
locations[i] = protocol.Location{
URI: path,
Range: protocol.Range{
Start: protocol.Position{Line: 10, Character: 5},
},
}
}

includedPaths := make([]string, 100)
for i := 0; i < 100; i++ {
includedPaths[i] = "/project/src/File" + strconv.Itoa(i) + ".cs"
}

b.Run("with map optimization", func(b *testing.B) {
for n := 0; n < b.N; n++ {
// Build maps
includedPathsMap := make(map[string]bool, len(includedPaths))
for _, includedPath := range includedPaths {
normalizedPath := provider.NormalizePathForComparison(includedPath)
includedPathsMap[normalizedPath] = true
}

// Filter
filtered := []protocol.Location{}
for _, loc := range locations {
normalizedPath := provider.NormalizePathForComparison(string(loc.URI))
if len(includedPathsMap) > 0 && !includedPathsMap[normalizedPath] {
continue
}
filtered = append(filtered, loc)
}
}
})

b.Run("without map optimization (nested loops)", func(b *testing.B) {
for n := 0; n < b.N; n++ {
// Filter with nested loops
filtered := []protocol.Location{}
for _, loc := range locations {
normalizedLocPath := provider.NormalizePathForComparison(string(loc.URI))

if len(includedPaths) > 0 {
found := false
for _, includedPath := range includedPaths {
normalizedIncludedPath := provider.NormalizePathForComparison(includedPath)
if normalizedLocPath == normalizedIncludedPath {
found = true
break
}
}
if !found {
continue
}
}

filtered = append(filtered, loc)
}
}
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ type stdioRWCloser struct {
}

type dotnetCondition struct {
Referenced referenceCondition `yaml:"referenced"`
Referenced referenceCondition `yaml:"referenced"`
provider.ProviderContext `yaml:",inline"`
}

// Example:
Expand Down
Loading
Loading