feat: Add dependency analysis to fix command#4035
feat: Add dependency analysis to fix command#4035krrish175-byte wants to merge 3 commits intoVirtusLab:mainfrom
Conversation
igor-ramazanov
left a comment
There was a problem hiding this comment.
I don't think this will work with a code like1:
package foo // imports `foo.*`
package bar // imports `foo.bar.*`
import baz.* // imports `foo.bar.baz.*`
Gedochao
left a comment
There was a problem hiding this comment.
Note: tests aren't working, commented on why.
| val output = os.proc( | ||
| TestUtil.cli, | ||
| "fix", | ||
| ".", | ||
| "--with-unused-deps", | ||
| extraOptions, | ||
| enableRulesOptions(enableScalafix = false) | ||
| ) | ||
| .call(cwd = root, mergeErrIntoOut = true).out.trim() |
There was a problem hiding this comment.
| val output = os.proc( | |
| TestUtil.cli, | |
| "fix", | |
| ".", | |
| "--with-unused-deps", | |
| extraOptions, | |
| enableRulesOptions(enableScalafix = false) | |
| ) | |
| .call(cwd = root, mergeErrIntoOut = true).out.trim() | |
| val output = os.proc( | |
| TestUtil.cli, | |
| "fix", | |
| ".", | |
| "--power", | |
| "--with-unused-deps", | |
| extraOptions, | |
| enableRulesOptions(enableScalafix = false) | |
| ) | |
| .call(cwd = root, mergeErrIntoOut = true).out.trim() |
this won't even run without the --power option, as --with-unused-deps is experimental... Please make sure to run the tests locally before pushing them to the CI.
| val output = os.proc( | ||
| TestUtil.cli, | ||
| "fix", | ||
| ".", | ||
| "--with-explicit-deps", | ||
| extraOptions, | ||
| enableRulesOptions(enableScalafix = false) | ||
| ) | ||
| .call(cwd = root, mergeErrIntoOut = true).out.trim() |
There was a problem hiding this comment.
| val output = os.proc( | |
| TestUtil.cli, | |
| "fix", | |
| ".", | |
| "--with-explicit-deps", | |
| extraOptions, | |
| enableRulesOptions(enableScalafix = false) | |
| ) | |
| .call(cwd = root, mergeErrIntoOut = true).out.trim() | |
| val output = os.proc( | |
| TestUtil.cli, | |
| "fix", | |
| ".", | |
| "--power", | |
| "--with-explicit-deps", | |
| extraOptions, | |
| enableRulesOptions(enableScalafix = false) | |
| ) | |
| .call(cwd = root, mergeErrIntoOut = true).out.trim() |
Same as in the other test, please test it locally first.
modules/integration/src/test/scala/scala/cli/integration/FixBuiltInRulesTestDefinitions.scala
Outdated
Show resolved
Hide resolved
|
@Gedochao : Apologies for the oversight, I missed that these experimental options require the |
|
@krrish175-byte they still seem to fail on the CI... |
|
@Gedochao: Hi! I have addressed the failing dependency analysis tests with the latest commit. Changes:
Fixed detect missing explicit dependencies test:
Waiting for next review! |
Code Review – Key FindingsSummary: Issues
|
Gedochao
left a comment
There was a problem hiding this comment.
Left some comments.
BTW it seems formatting is still failing.
| val possiblePackages = Set( | ||
| org.replace('-', '.').toLowerCase, | ||
| name.replace('-', '.').toLowerCase, | ||
| simpleName.replace('-', '.').toLowerCase, | ||
| s"$org.$name".replace('-', '.').toLowerCase, | ||
| s"$org.$simpleName".replace('-', '.').toLowerCase | ||
| ) |
There was a problem hiding this comment.
I wonder if guesswork such as this is necessary, when you could inspect what package names are actually there, in the dependency
modules/cli/src/main/scala/scala/cli/commands/fix/DependencyAnalyzer.scala
Outdated
Show resolved
Hide resolved
modules/cli/src/main/scala/scala/cli/commands/fix/FixOptions.scala
Outdated
Show resolved
Hide resolved
modules/cli/src/main/scala/scala/cli/commands/fix/FixOptions.scala
Outdated
Show resolved
Hide resolved
|
@Gedochao : Thanks for the comments. I have pushed the changes. I ended up ditching the regex approach entirely for a simple state machine tokenizer. It’s much more robust now and correctly ignores imports or usages inside strings and block comments. I also added some caching so we are not re-reading files multiple times, which should help with performance. As per your suggestion, I also moved the orchestration logic into BuiltInRules (cleaning up Fix.scala quite a bit) and renamed the flags to --check-unused-deps and --check-explicit-deps. Let me know what you think. Thanks again for being patient and reviewing my changes. |
4d53bc5 to
9cd1545
Compare
| def javaSemanticdb = "0.10.0" | ||
| def javaClassName = "0.1.9" | ||
| def bloop = "2.0.17" | ||
| def bloop = "2.0.18" |
There was a problem hiding this comment.
This bump is rather far from this simple, and out of scope here.
There are some tests are hanging for this Bloop version.
| val isCI: Boolean = System.getenv("CI") != null | ||
| val isM1: Boolean = sys.props.get("os.arch").contains("aarch64") | ||
| val cliPath: String = sys.props("test.scala-cli.path") | ||
| val cliPath: String = sys.props.getOrElse("test.scala-cli.path", "scala-cli") |
There was a problem hiding this comment.
In what circumstances is this necessary?
| object TestUtil { | ||
|
|
||
| val cliKind: String = sys.props("test.scala-cli.kind") | ||
| val cliKind: String = sys.props.getOrElse("test.scala-cli.kind", "jvm") |
There was a problem hiding this comment.
Again, in what circumstances is this necessary?
| logger.message("Running built-in rules...") | ||
| if options.check then | ||
| // TODO support --check for built-in rules: https://github.com/VirtusLab/scala-cli/issues/3423 | ||
| // built-in rules don't support --check yet |
There was a problem hiding this comment.
the old comment is more informative, as it references a ticket and is caught by tooling because of the TODO word
| ) | ||
| val scopedSources = crossSources.scopedSources(sharedOptions).orExit(logger) | ||
| val sources = scopedSources.sources( | ||
| Scope.Main, |
There was a problem hiding this comment.
A potential follow-up would be to respect the --test flag and if it's enabled, include the test scope in the analysis as well.
Doesn't have to be in this PR, can create a ticket to track it instead.
| // Regex to extract imports from a code line (already stripped of strings/comments) | ||
| private val importPattern: Regex = """^\s*import\s+([^\s{(]+).*""".r | ||
| // Regex to extract simple package/object usages | ||
| private val usagePattern: Regex = | ||
| """\b([a-z][a-zA-Z0-9_]*+(?:\.[a-z][a-zA-Z0-9_]*+)*+)\b""".r |
There was a problem hiding this comment.
I ended up ditching the regex approach entirely for a simple state machine tokenizer.
Uh... As far as I can tell, these regex patterns are still being used for detecing usage & imports.
Add Dependency Analysis to Fix Command
Overview
Implements dependency analysis for
scala-cli fixcommand to detect unused and missing explicit dependencies.Features
--with-unused-deps: Reports declared dependencies not directly imported--with-explicit-deps: Reports transitive dependencies used without explicit declarationChanges
DependencyAnalyzer.scalawith import analysisFixOptionsand integrated intoFix.scalafix.mddocumentationNotes
Closing issue
closes #3873