mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 18:31:54 +00:00
feat(codenav): Add symbol support for the Hack language (#64015)
Adds scip-ctags support for the Hack language. Noteworthy items 1. I did not add support for modules since they are [not supported](https://github.com/slackhq/tree-sitter-hack/issues/70) in the tree-sitter grammar right now. ## Screenshots  ## Test plan - [x] Update unit tests - [x] Manually validate symbol side bar for indexed commits - [x] Manually validate symbol side bar for unindexed commits - [x] Validate symbol search for indexed commits - [x] Validate symbol search for unindexed commits
This commit is contained in:
parent
70b31c9be7
commit
b2cd7e5fee
@ -0,0 +1,52 @@
|
||||
; Mark method/function parameters as local
|
||||
(parameters (parameter)) @local
|
||||
|
||||
(namespace_declaration
|
||||
name: (qualified_identifier (identifier)) @descriptor.namespace @kind.namespace) @scope
|
||||
|
||||
(class_declaration
|
||||
name: (identifier) @descriptor.type @kind.class) @scope
|
||||
|
||||
(interface_declaration
|
||||
name: (identifier) @descriptor.type @kind.interface) @scope
|
||||
|
||||
(trait_declaration
|
||||
name: (identifier) @descriptor.type @kind.trait) @scope
|
||||
|
||||
(function_declaration
|
||||
name: (identifier) @descriptor.method @kind.function
|
||||
body: (_) @local)
|
||||
|
||||
; Match interface declarations that do not have a body
|
||||
(method_declaration
|
||||
name: (identifier) @descriptor.method @kind.method
|
||||
!body)
|
||||
|
||||
(method_declaration
|
||||
name: (identifier) @descriptor.method @kind.constructor (#eq? @descriptor.method "__construct")
|
||||
body: (_) @local)
|
||||
|
||||
(method_declaration
|
||||
name: (identifier) @descriptor.method @kind.method (#not-eq? @descriptor.method "__construct")
|
||||
body: (_) @local)
|
||||
|
||||
(property_declaration
|
||||
(property_declarator name: (variable) @descriptor.term @kind.property)
|
||||
(#transform! "[$](.*)" "$1"))
|
||||
|
||||
(const_declaration
|
||||
(const_declarator name: (identifier) @descriptor.term @kind.constant))
|
||||
|
||||
(enum_declaration
|
||||
name: (identifier) @descriptor.type @kind.enum
|
||||
) @scope
|
||||
|
||||
(enum_class_declaration
|
||||
name: (identifier) @descriptor.type @kind.enum
|
||||
) @scope
|
||||
|
||||
(enumerator (identifier) @descriptor.term @kind.enummember)
|
||||
|
||||
(alias_declaration (identifier) @descriptor.type @kind.typealias)
|
||||
|
||||
(type_const_declaration name: (identifier) @descriptor.type @kind.typealias)
|
||||
@ -213,6 +213,7 @@ mod tags {
|
||||
create_tags_configuration!(go, ParserId::Go, "go");
|
||||
create_tags_configuration!(java, ParserId::Java, "java");
|
||||
create_tags_configuration!(javascript, ParserId::Javascript, "javascript");
|
||||
create_tags_configuration!(hack, ParserId::Hack, "hack");
|
||||
create_tags_configuration!(kotlin, ParserId::Kotlin, "kotlin");
|
||||
create_tags_configuration!(magik, ParserId::Magik, "magik");
|
||||
create_tags_configuration!(python, ParserId::Python, "python");
|
||||
@ -230,6 +231,7 @@ mod tags {
|
||||
ParserId::Go => Some(go()),
|
||||
ParserId::Java => Some(java()),
|
||||
ParserId::Javascript => Some(javascript()),
|
||||
ParserId::Hack => Some(hack()),
|
||||
ParserId::Kotlin => Some(kotlin()),
|
||||
ParserId::Magik => Some(magik()),
|
||||
ParserId::Python => Some(python()),
|
||||
|
||||
@ -134,4 +134,6 @@ mod test {
|
||||
generate_tags_and_snapshot!(Tags, test_tags_perl_example, "example.pl");
|
||||
|
||||
generate_tags_and_snapshot!(All, test_tags_magik, test_scip_magik, "globals.magik");
|
||||
|
||||
generate_tags_and_snapshot!(All, test_tags_hack, test_scip_hack, "globals.hack");
|
||||
}
|
||||
|
||||
@ -0,0 +1,122 @@
|
||||
---
|
||||
source: crates/syntax-analysis/src/lib.rs
|
||||
expression: dumped
|
||||
---
|
||||
namespace SomeNamespace {
|
||||
// ^^^^^^^^^^^^^ definition(Namespace) scip-ctags SomeNamespace/
|
||||
const int some_const = 100;
|
||||
// ^^^^^^^^^^ definition(Constant) scip-ctags SomeNamespace/some_const.
|
||||
trait SomeTrait {
|
||||
// ^^^^^^^^^ definition(Trait) scip-ctags SomeNamespace/SomeTrait#
|
||||
public $logLevel;
|
||||
// ^^^^^^^^^ definition(Property) scip-ctags SomeNamespace/SomeTrait#logLevel.
|
||||
protected $thing;
|
||||
// ^^^^^^ definition(Property) scip-ctags SomeNamespace/SomeTrait#thing.
|
||||
private $secretFromTrait;
|
||||
// ^^^^^^^^^^^^^^^^ definition(Property) scip-ctags SomeNamespace/SomeTrait#secretFromTrait.
|
||||
|
||||
public function setLogger(SomeInterface $thing) {
|
||||
// ^^^^^^^^^ definition(Method) scip-ctags SomeNamespace/SomeTrait#setLogger().
|
||||
$this->thing = $thing;
|
||||
}
|
||||
|
||||
public function log($message, $level) {
|
||||
// ^^^ definition(Method) scip-ctags SomeNamespace/SomeTrait#log().
|
||||
$this->thing->log($message, $level);
|
||||
}
|
||||
}
|
||||
|
||||
interface SomeInterface {
|
||||
// ^^^^^^^^^^^^^ definition(Interface) scip-ctags SomeNamespace/SomeInterface#
|
||||
const MAX_NUMBER_ITEMS = 1000;
|
||||
// ^^^^^^^^^^^^^^^^ definition(Constant) scip-ctags SomeNamespace/SomeInterface#MAX_NUMBER_ITEMS.
|
||||
protected int $secretFromInterface = 0;
|
||||
// ^^^^^^^^^^^^^^^^^^^^ definition(Property) scip-ctags SomeNamespace/SomeInterface#secretFromInterface.
|
||||
public function log($message, $level);
|
||||
// ^^^ definition(Method) scip-ctags SomeNamespace/SomeInterface#log().
|
||||
}
|
||||
|
||||
class SomeClass implements SomeInterface {
|
||||
// ^^^^^^^^^ definition(Class) scip-ctags SomeNamespace/SomeClass#
|
||||
const PI = 3.1415926;
|
||||
// ^^ definition(Constant) scip-ctags SomeNamespace/SomeClass#PI.
|
||||
private static int $secretFromClass = 0;
|
||||
// ^^^^^^^^^^^^^^^^ definition(Property) scip-ctags SomeNamespace/SomeClass#secretFromClass.
|
||||
public static int $hello = 11;
|
||||
// ^^^^^^ definition(Property) scip-ctags SomeNamespace/SomeClass#hello.
|
||||
public int $age = 39;
|
||||
// ^^^^ definition(Property) scip-ctags SomeNamespace/SomeClass#age.
|
||||
public function log($message, $level) {
|
||||
// ^^^ definition(Method) scip-ctags SomeNamespace/SomeClass#log().
|
||||
echo "Log $message of level $level";
|
||||
}
|
||||
}
|
||||
|
||||
class Foo implements SomeInterface {
|
||||
// ^^^ definition(Class) scip-ctags SomeNamespace/Foo#
|
||||
const type T = string;
|
||||
// ^ definition(TypeAlias) scip-ctags SomeNamespace/Foo#T#
|
||||
use SomeTrait;
|
||||
}
|
||||
|
||||
type Foo_alias = Foo;
|
||||
// ^^^^^^^^^ definition(TypeAlias) scip-ctags SomeNamespace/Foo_alias#
|
||||
newtype Foo_new = Foo::T;
|
||||
// ^^^^^^^ definition(TypeAlias) scip-ctags SomeNamespace/Foo_new#
|
||||
|
||||
// Top level function
|
||||
<<__EntryPoint>>
|
||||
function main() {
|
||||
// ^^^^ definition(Function) scip-ctags SomeNamespace/main().
|
||||
$foo = new Foo;
|
||||
$foo->setLogger(new SomeClass);
|
||||
$foo->log('It works', 1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace SomeNamespace\SubNamespace {
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^ definition(Namespace) scip-ctags `SomeNamespace\SubNamespace`/
|
||||
// Generic class and a constructor
|
||||
class Stack<T> {
|
||||
// ^^^^^ definition(Class) scip-ctags `SomeNamespace\SubNamespace`/Stack#
|
||||
private vec<T> $stack;
|
||||
// ^^^^^^ definition(Property) scip-ctags `SomeNamespace\SubNamespace`/Stack#stack.
|
||||
private int $stackPtr;
|
||||
// ^^^^^^^^^ definition(Property) scip-ctags `SomeNamespace\SubNamespace`/Stack#stackPtr.
|
||||
|
||||
public function __construct() {
|
||||
// ^^^^^^^^^^^ definition(Constructor) scip-ctags `SomeNamespace\SubNamespace`/Stack#__construct().
|
||||
$this->stackPtr = 0;
|
||||
$this->stack = vec[];
|
||||
}
|
||||
|
||||
public function __dispose(): void {}
|
||||
// ^^^^^^^^^ definition(Method) scip-ctags `SomeNamespace\SubNamespace`/Stack#__dispose().
|
||||
}
|
||||
|
||||
enum Colors: int {
|
||||
// ^^^^^^ definition(Enum) scip-ctags `SomeNamespace\SubNamespace`/Colors#
|
||||
Red = 1;
|
||||
// ^^^ definition(EnumMember) scip-ctags `SomeNamespace\SubNamespace`/Colors#Red.
|
||||
Green = 2;
|
||||
// ^^^^^ definition(EnumMember) scip-ctags `SomeNamespace\SubNamespace`/Colors#Green.
|
||||
Blue = 3;
|
||||
// ^^^^ definition(EnumMember) scip-ctags `SomeNamespace\SubNamespace`/Colors#Blue.
|
||||
Default = 4;
|
||||
// ^^^^^^^ definition(EnumMember) scip-ctags `SomeNamespace\SubNamespace`/Colors#Default.
|
||||
}
|
||||
|
||||
enum class Random: mixed {
|
||||
// ^^^^^^ definition(Enum) scip-ctags `SomeNamespace\SubNamespace`/Random#
|
||||
int X = 42;
|
||||
// ^ definition(EnumMember) scip-ctags `SomeNamespace\SubNamespace`/Random#X.
|
||||
string S = 'foo';
|
||||
// ^ definition(EnumMember) scip-ctags `SomeNamespace\SubNamespace`/Random#S.
|
||||
}
|
||||
}
|
||||
|
||||
// Validate anonymous namespace
|
||||
namespace {
|
||||
const int another_const = 88;
|
||||
// ^^^^^^^^^^^^^ definition(Constant) scip-ctags another_const.
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
---
|
||||
source: crates/syntax-analysis/src/lib.rs
|
||||
expression: "String::from_utf8_lossy(&output)"
|
||||
---
|
||||
{"_type":"tag","name":"SomeNamespace","path":"globals.hack","language":"hack","line":1,"kind":"namespace","scope":null}
|
||||
{"_type":"tag","name":"SomeTrait","path":"globals.hack","language":"hack","line":3,"kind":"trait","scope":"SomeNamespace"}
|
||||
{"_type":"tag","name":"log","path":"globals.hack","language":"hack","line":12,"kind":"method","scope":"SomeNamespace.SomeTrait"}
|
||||
{"_type":"tag","name":"setLogger","path":"globals.hack","language":"hack","line":8,"kind":"method","scope":"SomeNamespace.SomeTrait"}
|
||||
{"_type":"tag","name":"secretFromTrait","path":"globals.hack","language":"hack","line":6,"kind":"property","scope":"SomeNamespace.SomeTrait"}
|
||||
{"_type":"tag","name":"thing","path":"globals.hack","language":"hack","line":5,"kind":"property","scope":"SomeNamespace.SomeTrait"}
|
||||
{"_type":"tag","name":"logLevel","path":"globals.hack","language":"hack","line":4,"kind":"property","scope":"SomeNamespace.SomeTrait"}
|
||||
{"_type":"tag","name":"SomeInterface","path":"globals.hack","language":"hack","line":17,"kind":"interface","scope":"SomeNamespace"}
|
||||
{"_type":"tag","name":"log","path":"globals.hack","language":"hack","line":20,"kind":"method","scope":"SomeNamespace.SomeInterface"}
|
||||
{"_type":"tag","name":"secretFromInterface","path":"globals.hack","language":"hack","line":19,"kind":"property","scope":"SomeNamespace.SomeInterface"}
|
||||
{"_type":"tag","name":"MAX_NUMBER_ITEMS","path":"globals.hack","language":"hack","line":18,"kind":"constant","scope":"SomeNamespace.SomeInterface"}
|
||||
{"_type":"tag","name":"SomeClass","path":"globals.hack","language":"hack","line":23,"kind":"class","scope":"SomeNamespace"}
|
||||
{"_type":"tag","name":"log","path":"globals.hack","language":"hack","line":28,"kind":"method","scope":"SomeNamespace.SomeClass"}
|
||||
{"_type":"tag","name":"age","path":"globals.hack","language":"hack","line":27,"kind":"property","scope":"SomeNamespace.SomeClass"}
|
||||
{"_type":"tag","name":"hello","path":"globals.hack","language":"hack","line":26,"kind":"property","scope":"SomeNamespace.SomeClass"}
|
||||
{"_type":"tag","name":"secretFromClass","path":"globals.hack","language":"hack","line":25,"kind":"property","scope":"SomeNamespace.SomeClass"}
|
||||
{"_type":"tag","name":"PI","path":"globals.hack","language":"hack","line":24,"kind":"constant","scope":"SomeNamespace.SomeClass"}
|
||||
{"_type":"tag","name":"Foo","path":"globals.hack","language":"hack","line":33,"kind":"class","scope":"SomeNamespace"}
|
||||
{"_type":"tag","name":"T","path":"globals.hack","language":"hack","line":34,"kind":"typeAlias","scope":"SomeNamespace.Foo"}
|
||||
{"_type":"tag","name":"main","path":"globals.hack","language":"hack","line":43,"kind":"function","scope":"SomeNamespace"}
|
||||
{"_type":"tag","name":"Foo_new","path":"globals.hack","language":"hack","line":39,"kind":"typeAlias","scope":"SomeNamespace"}
|
||||
{"_type":"tag","name":"Foo_alias","path":"globals.hack","language":"hack","line":38,"kind":"typeAlias","scope":"SomeNamespace"}
|
||||
{"_type":"tag","name":"some_const","path":"globals.hack","language":"hack","line":2,"kind":"constant","scope":"SomeNamespace"}
|
||||
{"_type":"tag","name":"SomeNamespace\\SubNamespace","path":"globals.hack","language":"hack","line":50,"kind":"namespace","scope":null}
|
||||
{"_type":"tag","name":"Stack","path":"globals.hack","language":"hack","line":52,"kind":"class","scope":"SomeNamespace\\SubNamespace"}
|
||||
{"_type":"tag","name":"__dispose","path":"globals.hack","language":"hack","line":61,"kind":"method","scope":"SomeNamespace\\SubNamespace.Stack"}
|
||||
{"_type":"tag","name":"__construct","path":"globals.hack","language":"hack","line":56,"kind":"constructor","scope":"SomeNamespace\\SubNamespace.Stack"}
|
||||
{"_type":"tag","name":"stackPtr","path":"globals.hack","language":"hack","line":54,"kind":"property","scope":"SomeNamespace\\SubNamespace.Stack"}
|
||||
{"_type":"tag","name":"stack","path":"globals.hack","language":"hack","line":53,"kind":"property","scope":"SomeNamespace\\SubNamespace.Stack"}
|
||||
{"_type":"tag","name":"Colors","path":"globals.hack","language":"hack","line":64,"kind":"enum","scope":"SomeNamespace\\SubNamespace"}
|
||||
{"_type":"tag","name":"Default","path":"globals.hack","language":"hack","line":68,"kind":"enumMember","scope":"SomeNamespace\\SubNamespace.Colors"}
|
||||
{"_type":"tag","name":"Blue","path":"globals.hack","language":"hack","line":67,"kind":"enumMember","scope":"SomeNamespace\\SubNamespace.Colors"}
|
||||
{"_type":"tag","name":"Green","path":"globals.hack","language":"hack","line":66,"kind":"enumMember","scope":"SomeNamespace\\SubNamespace.Colors"}
|
||||
{"_type":"tag","name":"Red","path":"globals.hack","language":"hack","line":65,"kind":"enumMember","scope":"SomeNamespace\\SubNamespace.Colors"}
|
||||
{"_type":"tag","name":"Random","path":"globals.hack","language":"hack","line":71,"kind":"enum","scope":"SomeNamespace\\SubNamespace"}
|
||||
{"_type":"tag","name":"S","path":"globals.hack","language":"hack","line":73,"kind":"enumMember","scope":"SomeNamespace\\SubNamespace.Random"}
|
||||
{"_type":"tag","name":"X","path":"globals.hack","language":"hack","line":72,"kind":"enumMember","scope":"SomeNamespace\\SubNamespace.Random"}
|
||||
{"_type":"tag","name":"another_const","path":"globals.hack","language":"hack","line":79,"kind":"constant","scope":null}
|
||||
80
docker-images/syntax-highlighter/crates/syntax-analysis/testdata/globals.hack
vendored
Normal file
80
docker-images/syntax-highlighter/crates/syntax-analysis/testdata/globals.hack
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
namespace SomeNamespace {
|
||||
const int some_const = 100;
|
||||
trait SomeTrait {
|
||||
public $logLevel;
|
||||
protected $thing;
|
||||
private $secretFromTrait;
|
||||
|
||||
public function setLogger(SomeInterface $thing) {
|
||||
$this->thing = $thing;
|
||||
}
|
||||
|
||||
public function log($message, $level) {
|
||||
$this->thing->log($message, $level);
|
||||
}
|
||||
}
|
||||
|
||||
interface SomeInterface {
|
||||
const MAX_NUMBER_ITEMS = 1000;
|
||||
protected int $secretFromInterface = 0;
|
||||
public function log($message, $level);
|
||||
}
|
||||
|
||||
class SomeClass implements SomeInterface {
|
||||
const PI = 3.1415926;
|
||||
private static int $secretFromClass = 0;
|
||||
public static int $hello = 11;
|
||||
public int $age = 39;
|
||||
public function log($message, $level) {
|
||||
echo "Log $message of level $level";
|
||||
}
|
||||
}
|
||||
|
||||
class Foo implements SomeInterface {
|
||||
const type T = string;
|
||||
use SomeTrait;
|
||||
}
|
||||
|
||||
type Foo_alias = Foo;
|
||||
newtype Foo_new = Foo::T;
|
||||
|
||||
// Top level function
|
||||
<<__EntryPoint>>
|
||||
function main() {
|
||||
$foo = new Foo;
|
||||
$foo->setLogger(new SomeClass);
|
||||
$foo->log('It works', 1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace SomeNamespace\SubNamespace {
|
||||
// Generic class and a constructor
|
||||
class Stack<T> {
|
||||
private vec<T> $stack;
|
||||
private int $stackPtr;
|
||||
|
||||
public function __construct() {
|
||||
$this->stackPtr = 0;
|
||||
$this->stack = vec[];
|
||||
}
|
||||
|
||||
public function __dispose(): void {}
|
||||
}
|
||||
|
||||
enum Colors: int {
|
||||
Red = 1;
|
||||
Green = 2;
|
||||
Blue = 3;
|
||||
Default = 4;
|
||||
}
|
||||
|
||||
enum class Random: mixed {
|
||||
int X = 42;
|
||||
string S = 'foo';
|
||||
}
|
||||
}
|
||||
|
||||
// Validate anonymous namespace
|
||||
namespace {
|
||||
const int another_const = 88;
|
||||
}
|
||||
@ -65,6 +65,7 @@ var supportedLanguages = map[string]struct{}{
|
||||
"go": {},
|
||||
"java": {},
|
||||
"javascript": {},
|
||||
"hack": {},
|
||||
"kotlin": {},
|
||||
"magik": {},
|
||||
"python": {},
|
||||
@ -81,6 +82,7 @@ var DefaultEngines = map[string]ParserType{
|
||||
"c_sharp": ScipCtags,
|
||||
"go": ScipCtags,
|
||||
"javascript": ScipCtags,
|
||||
"hack": ScipCtags,
|
||||
"kotlin": ScipCtags,
|
||||
"magik": ScipCtags,
|
||||
"python": ScipCtags,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user