Skip to content

Commit

Permalink
fix(gazelle): support deps between local projects (#2696)
Browse files Browse the repository at this point in the history
GitOrigin-RevId: 7c2ab434235c42a4bd32bdd0aba3ecdf2bd0b87a
  • Loading branch information
jbedard authored and gregmagolan committed Jun 29, 2023
1 parent 9721278 commit 6abb4bf
Show file tree
Hide file tree
Showing 19 changed files with 119 additions and 42 deletions.
2 changes: 1 addition & 1 deletion gazelle/kotlin/kotlin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package gazelle
import "strings"

func IsNativeImport(impt string) bool {
return strings.HasPrefix(impt, "kotlin.") || strings.HasPrefix(impt, "java.") || strings.HasPrefix(impt, "javax.")
return strings.HasPrefix(impt, "kotlin.") || strings.HasPrefix(impt, "kotlinx.") || strings.HasPrefix(impt, "java.") || strings.HasPrefix(impt, "javax.")
}
25 changes: 19 additions & 6 deletions gazelle/kotlin/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (p *treeSitterParser) ParsePackage(filePath, source string) (string, []erro
os.Exit(1)
}

pkg = readIdentifier(getLoneChild(nodeI, "identifier"), sourceCode)
pkg = readIdentifier(getLoneChild(nodeI, "identifier"), sourceCode, false)
}
}

Expand Down Expand Up @@ -104,10 +104,18 @@ func (p *treeSitterParser) ParseImports(filePath, source string) ([]string, []er
for j := 0; j < int(nodeI.NamedChildCount()); j++ {
nodeJ := nodeI.NamedChild(j)
if nodeJ.Type() == "import_header" {
for k := 0; k < int(nodeJ.NamedChildCount()); k++ {
nodeK := nodeJ.NamedChild(k)
for k := 0; k < int(nodeJ.ChildCount()); k++ {
nodeK := nodeJ.Child(k)
if nodeK.Type() == "identifier" {
imports.Add(readIdentifier(nodeK, sourceCode))
isStar := false
for l := k + 1; l < int(nodeJ.ChildCount()); l++ {
if nodeJ.Child(l).Type() == ".*" {
isStar = true
break
}
}

imports.Add(readIdentifier(nodeK, sourceCode, !isStar))
}
}
}
Expand Down Expand Up @@ -140,15 +148,20 @@ func getLoneChild(node *sitter.Node, name string) *sitter.Node {
return nil
}

func readIdentifier(node *sitter.Node, sourceCode []byte) string {
func readIdentifier(node *sitter.Node, sourceCode []byte, ignoreLast bool) string {
if node.Type() != "identifier" {
fmt.Printf("Must be type 'identifier': %v - %s", node.Type(), node.Content(sourceCode))
os.Exit(1)
}

var s strings.Builder

for c := 0; c < int(node.NamedChildCount()); c++ {
total := int(node.NamedChildCount())
if ignoreLast {
total = total - 1
}

for c := 0; c < total; c++ {
nodeC := node.NamedChild(c)

// TODO: are there any other node types under an "identifier"
Expand Down
49 changes: 30 additions & 19 deletions gazelle/kotlin/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,39 @@ var testCases = []struct {
imports: []string{},
},
{
desc: "simple",
kt: "import a.b",
desc: "simple",
kt: `
import a.B
import c.D as E
`,
filename: "simple.kt",
pkg: "",
imports: []string{"a.b"},
imports: []string{"a", "c"},
},
{
desc: "stars",
kt: `package a.b.c
import d.y.*
`,
filename: "stars.kt",
pkg: "a.b.c",
imports: []string{"d.y"},
},
{
desc: "comments",
kt: `
/*dlfkj*/ package /*dlfkj*/ x // x
/*dlfkj*/package /*dlfkj*/ x // x
//z
import a.b // y
import a.B // y
//z
/* asdf */ import /* asdf */ c./* asdf */d // w
`,
filename: "empty.kt",
/* asdf */ import /* asdf */ c./* asdf */D // w
import /* fdsa */ d/* asdf */.* // w
`,
filename: "comments.kt",
pkg: "x",
imports: []string{"a.b", "c.d"},
},
{
desc: "stars",
kt: `package a.b.c
import d.y.*`,
filename: "stars.kt",
pkg: "a.b.c",
imports: []string{"d.y"},
imports: []string{"a", "c", "d"},
},
}

Expand All @@ -57,7 +62,13 @@ func TestTreesitterParser(t *testing.T) {
actualImports, _ := NewParser().ParseImports(tc.filename, tc.kt)

if !equal(actualImports, tc.imports) {
t.Errorf("Inequality.\nactual: %#v;\nimports: %#v\nkotlin code:\n%v", actualImports, tc.imports, tc.kt)
t.Errorf("Imports...\nactual: %#v;\nexpected: %#v\nkotlin code:\n%v", actualImports, tc.imports, tc.kt)
}

actualPackage, _ := NewParser().ParsePackage(tc.filename, tc.kt)

if actualPackage != tc.pkg {
t.Errorf("Package....\nactual: %#v;\nexpected: %#v\nkotlin code:\n%v", actualPackage, tc.pkg, tc.kt)
}
})
}
Expand Down
29 changes: 19 additions & 10 deletions gazelle/kotlin/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ type Resolver struct {
}

const (
Resolution_Error = -1
Resolution_None = 0
Resolution_NotFound = 1
Resolution_Label = 2
Resolution_NativeNode = 3
Resolution_Error = -1
Resolution_None = 0
Resolution_NotFound = 1
Resolution_Label = 2
Resolution_NativeKotlin = 3
)

type ResolutionType = int
Expand Down Expand Up @@ -83,7 +83,7 @@ func (kt *Resolver) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repo.Re
start := time.Now()
BazelLog.Infof("Resolve '%s' dependencies", from.String())

if r.Kind() != KtJvmLibrary {
if r.Kind() == KtJvmLibrary {
deps, err := kt.resolveImports(c, ix, importData.(*KotlinImports).imports, from)
if err != nil {
log.Fatal("Resolution Error: ", err)
Expand Down Expand Up @@ -115,12 +115,21 @@ func (kt *Resolver) resolveImports(
return nil, err
}

if resolutionType == Resolution_NativeNode || resolutionType == Resolution_None {
if resolutionType == Resolution_NotFound {
BazelLog.Debugf("import '%s' for target '%s' not found", mod.Imp, from.String())

notFound := fmt.Errorf(
"Import %[1]q from %[2]q is an unknown dependency. Possible solutions:\n"+
"\t1. Instruct Gazelle to resolve to a known dependency using a directive:\n"+
"\t\t# gazelle:resolve [src-lang] kotlin import-string label\n",
mod.Imp, mod.SourcePath,
)

fmt.Printf("Resolution error %v\n", notFound)
continue
}

if resolutionType == Resolution_NotFound {
// TODO: collect errors
if resolutionType == Resolution_NativeKotlin || resolutionType == Resolution_None {
continue
}

Expand Down Expand Up @@ -176,7 +185,7 @@ func (kt *Resolver) resolveImport(

// Native kotlin imports
if IsNativeImport(impt.Imp) {
return Resolution_NativeNode, nil, nil
return Resolution_NativeKotlin, nil, nil
}

// TODO: maven imports
Expand Down
4 changes: 4 additions & 0 deletions gazelle/kotlin/tests/local_deps/BUILD.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
kt_jvm_library(
name = "local_deps",
srcs = ["main.kt"],
deps = [
"//impt",
"//impt-star",
],
)
7 changes: 7 additions & 0 deletions gazelle/kotlin/tests/local_deps/impt-star/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")

kt_jvm_library(
name = "impt-star",
srcs = ["S.kt"],
deps = ["//sub1"],
)
7 changes: 7 additions & 0 deletions gazelle/kotlin/tests/local_deps/impt-star/S.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package test.imptstar

import test.a.*

class Rectangle2(var height: Double, var length: Double): Shape() {
var perimeter = (height + length) * 2
}
7 changes: 7 additions & 0 deletions gazelle/kotlin/tests/local_deps/impt/B.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package test.impt

import test.a.Shape

class Rectangle(var height: Double, var length: Double): Shape() {
var perimeter = (height + length) * 2
}
Empty file.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")

kt_jvm_library(
name = "sub2",
name = "impt",
srcs = ["B.kt"],
deps = ["//sub1"],
)
6 changes: 3 additions & 3 deletions gazelle/kotlin/tests/local_deps/main.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package test.root

// Basic
import test.A
import test.B
import test.impt.Rectangle
import test.imptstar.*

fun main() {
A.f()
B.f()
Rectangle.f()
}
4 changes: 3 additions & 1 deletion gazelle/kotlin/tests/local_deps/sub1/A.kt
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
package test.a
package test.a

open class Shape
1 change: 0 additions & 1 deletion gazelle/kotlin/tests/local_deps/sub2/B.kt

This file was deleted.

Empty file.
6 changes: 6 additions & 0 deletions gazelle/kotlin/tests/unknown_imports/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")

kt_jvm_library(
name = "simple_file",
srcs = ["main.kt"],
)
2 changes: 2 additions & 0 deletions gazelle/kotlin/tests/unknown_imports/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This is a Bazel workspace for the Gazelle test data.
workspace(name = "simple_file")
4 changes: 4 additions & 0 deletions gazelle/kotlin/tests/unknown_imports/expectedStdout.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Resolution error Import "foo" from "main.kt" is an unknown dependency. Possible solutions:
1. Instruct Gazelle to resolve to a known dependency using a directive:
# gazelle:resolve [src-lang] kotlin import-string label

5 changes: 5 additions & 0 deletions gazelle/kotlin/tests/unknown_imports/main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import foo.bar

fun main() {
println("Hello world!")
}

0 comments on commit 6abb4bf

Please sign in to comment.