@@ -50,6 +50,13 @@ class AstUsedJarFinderTest extends FunSuite {
50
50
)
51
51
}
52
52
53
+ private def verifyAndConvertDepToClass (dep : String ): String = {
54
+ val classPath = tmpDir.resolve(s " $dep.class " )
55
+ // Make sure the dep refers to a real file
56
+ assert(classPath.toFile.isFile)
57
+ classPath.toString
58
+ }
59
+
53
60
def checkStrictDepsErrorsReported (
54
61
code : String ,
55
62
expectedStrictDeps : List [String ]
@@ -61,7 +68,7 @@ class AstUsedJarFinderTest extends FunSuite {
61
68
dependencyAnalyzerParamsOpt =
62
69
Some (
63
70
DependencyAnalyzerTestParams (
64
- indirectJars = expectedStrictDeps.map(name => tmpDir.resolve( s " $name .class " ).toString ),
71
+ indirectJars = expectedStrictDeps.map(verifyAndConvertDepToClass ),
65
72
indirectTargets = expectedStrictDeps,
66
73
strictDeps = true ,
67
74
dependencyTrackingMethod = DependencyTrackingMethod .Ast
@@ -94,7 +101,7 @@ class AstUsedJarFinderTest extends FunSuite {
94
101
dependencyAnalyzerParamsOpt =
95
102
Some (
96
103
DependencyAnalyzerTestParams (
97
- directJars = expectedUnusedDeps.map(name => tmpDir.resolve( s " $name .class " ).toString ),
104
+ directJars = expectedUnusedDeps.map(verifyAndConvertDepToClass ),
98
105
directTargets = expectedUnusedDeps,
99
106
unusedDeps = true ,
100
107
dependencyTrackingMethod = DependencyTrackingMethod .Ast
@@ -421,6 +428,70 @@ class AstUsedJarFinderTest extends FunSuite {
421
428
)
422
429
}
423
430
431
+ test(" imports are complicated" ) {
432
+ // This test documents the behavior of imports as is currently.
433
+ // Ideally all imports would be direct dependencies. However there
434
+ // are complications. The main one being that the scala AST treats
435
+ // imports as (expr, selectors) where in e.g. `import a.b.{c, d}`
436
+ // expr=`a.b` and selectors=[c, d]. (Note selectors are always formed
437
+ // from the last part of the import).
438
+ // And only the expr part has type information attached. In order
439
+ // to gather type information from the selector, we would need to
440
+ // do some resolution of types, which is possible but probably complex.
441
+ // Note also that fixing this is probably less of a priority, as
442
+ // people who want to check unused deps generally also want to check
443
+ // unused imports, so they wouldn't run into these problems in the
444
+ // first place.
445
+
446
+ def testImport (importString : String , isDirect : Boolean ): Unit = {
447
+ withSandbox { sandbox =>
448
+ sandbox.compileWithoutAnalyzer(
449
+ s """
450
+ |package foo.bar
451
+ |
452
+ |object A { val i: Int = 0 }
453
+ | """ .stripMargin
454
+ )
455
+
456
+ val bCode =
457
+ s """
458
+ |import $importString
459
+ |
460
+ |class B
461
+ | """ .stripMargin
462
+ val dep = " foo/bar/A"
463
+
464
+ if (isDirect) {
465
+ sandbox.checkStrictDepsErrorsReported(
466
+ code = bCode,
467
+ expectedStrictDeps = List (dep)
468
+ )
469
+ } else {
470
+ sandbox.checkUnusedDepsErrorReported(
471
+ code = bCode,
472
+ expectedUnusedDeps = List (dep)
473
+ )
474
+ }
475
+ }
476
+ }
477
+
478
+ // In this case, expr=foo.bar.A and selectors=[i], so looking at expr does
479
+ // give us a type.
480
+ testImport(" foo.bar.A.i" , isDirect = true )
481
+
482
+ // In this case expr=foo.bar and selectors=[A], so expr does not have
483
+ // a type which corresponds with A.
484
+ testImport(" foo.bar.A" , isDirect = false )
485
+
486
+ // In this case expr=foo and selectors=[bar], so expr does not have
487
+ // a type which corresponds with A.
488
+ testImport(" foo.bar" , isDirect = false )
489
+
490
+ // In this case expr=foo.bar and selectors=[_], so expr does not have
491
+ // a type which corresponds with A.
492
+ testImport(" foo.bar._" , isDirect = false )
493
+ }
494
+
424
495
test(" java interface method argument is direct" ) {
425
496
withSandbox { sandbox =>
426
497
sandbox.compileJava(
0 commit comments