Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gazelle/kotln: Fix import resolution to use ancestor packages #753

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
48 changes: 47 additions & 1 deletion gazelle/kotlin/imports.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,65 @@
package gazelle

import (
"strings"

"github.com/bazelbuild/bazel-gazelle/resolve"
godsutils "github.com/emirpasic/gods/utils"
)

// TODO: drop? still used?
// ImportStatement corresponds to a single Kotlin import. Only the package
// information is retained in this representation of the import.
type ImportStatement struct {
resolve.ImportSpec

// The path of the file containing the import
SourcePath string
}

// packageFullyQualifiedName returns a [javaFullyQualifiedName] of package of the import.
//
// for "import foo.Bar as X", returns "foo"
// for "import foo.* as X", returns "foo"
func (is *ImportStatement) packageFullyQualifiedName() *javaFullyQualifiedName {
return &javaFullyQualifiedName{strings.Split(is.Imp, ".")}
}

// importStatementComparator compares modules by name.
func importStatementComparator(a, b interface{}) int {
return godsutils.StringComparator(a.(ImportStatement).Imp, b.(ImportStatement).Imp)
}

// javaFullyQualifiedName represents a fully-qualified name in Java, which is
// a dot-delimited list of [identifiers].
//
// [identifiers]: https://docs.oracle.com/javase/specs/jls/se23/html/jls-3.html#jls-Identifier
type javaFullyQualifiedName struct {
// Each component of the path is an identifier.
// https://kotlinlang.org/spec/syntax-and-grammar.html#grammar-rule-importList.
//
// A Java identifier that should mostly correspond to [3.8. Identifiers] from
// the Java spec.
//
// [3.8. Identifiers]: https://docs.oracle.com/javase/specs/jls/se23/html/jls-3.html#jls-JavaLetter
//
// [L letter class]: https://stackoverflow.com/questions/5969440/what-is-the-l-unicode-category
parts []string
}

// String returns the dot-delimited java package name as it would appear in
// source code.
func (jpn *javaFullyQualifiedName) String() string {
return strings.Join(jpn.parts, ".")
}

// Parent returns the parent package.
func (jpn *javaFullyQualifiedName) Parent() *javaFullyQualifiedName {
if jpn == nil || len(jpn.parts) <= 1 {
return nil
}
return &javaFullyQualifiedName{jpn.parts[0 : len(jpn.parts)-1]}
}

func importAsFQN(is *ImportStatement) *javaFullyQualifiedName {
return &javaFullyQualifiedName{strings.Split(is.Imp, ".")}
}
13 changes: 11 additions & 2 deletions gazelle/kotlin/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,20 @@ func (kt *kotlinLang) resolveImport(
if l, mavenError := (*mavenResolver).Resolve(jvm_import, cfg.ExcludedArtifacts(), cfg.MavenRepositoryName()); mavenError == nil {
return Resolution_Label, &l, nil
} else {
BazelLog.Debugf("Maven resolution error: %v", mavenError)
BazelLog.Debugf("Maven resolution failed: %v", mavenError)
}
}

return Resolution_NotFound, nil, nil
// The original import, like "x.y.z" might be a subpackage within a package that resolves,
// so try to resolve the original identifer, then try to resolve the parent
// identifier, etc.
importParent := impt.packageFullyQualifiedName().Parent()
if importParent == nil {
return Resolution_NotFound, nil, nil
}
parentImportSpec := impt
parentImportSpec.Imp = importParent.String()
return kt.resolveImport(c, ix, parentImportSpec, from)
}

// targetListFromResults returns a string with the human-readable list of
Expand Down
1 change: 1 addition & 0 deletions gazelle/kotlin/tests/deep_import/BUILD.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# TODO(gazelle:)java_maven_repository_name vendor_java
1 change: 1 addition & 0 deletions gazelle/kotlin/tests/deep_import/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# TODO(gazelle:)java_maven_repository_name vendor_java
8 changes: 8 additions & 0 deletions gazelle/kotlin/tests/deep_import/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Copied from
[rules_jvm "maven" test](https://github.com/bazel-contrib/rules_jvm/tree/v0.17.0/java/gazelle/testdata/maven).

Created by ~ following steps:

1. Copy the rules_jvm "maven" test
2. Rename .java to .kt
3. Modify .kt files to Kotlin syntax with a minimal diff
27 changes: 27 additions & 0 deletions gazelle/kotlin/tests/deep_import/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
name = "rules_jvm_external",
sha256 = "23fe83890a77ac1a3ee143e2306ec12da4a845285b14ea13cb0df1b1e23658fe",
strip_prefix = "rules_jvm_external-4.3",
urls = ["https://github.com/bazelbuild/rules_jvm_external/archive/refs/tags/4.3.tar.gz"],
)

load("@rules_jvm_external//:defs.bzl", "maven_install")

maven_install(
artifacts = [
"junit:junit:4.13.1",
"com.google.guava:guava:30.0-jre",
],
fetch_sources = True,
maven_install_json = "//:maven_install.json",
repositories = [
"http://uk.maven.org/maven2",
"https://jcenter.bintray.com/",
],
)

load("@maven//:defs.bzl", "pinned_maven_install")

pinned_maven_install()
Loading
Loading