Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions hphp/hack/src/parser/core/declaration_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,9 +440,12 @@ where
is_backslash || parser.peek_token_kind() == TokenKind::LeftBrace
}
TokenKind::Name => {
let has_trailing_newline =
token.has_trailing_trivia_kind(TriviaKind::EndOfLine);
let token = parser.sc_mut().make_token(token);
let token_ref = &token as *const _;
let (name, is_backslash) = parser.scan_remaining_qualified_name_extended(token);
let (name, is_backslash) =
parser.scan_remaining_qualified_name_extended(token, has_trailing_newline);
// Here we rely on the implementation details of
// scan_remaining_qualified_name_extended. It's returning
// *exactly* token if there is nothing except it in the name.
Expand Down Expand Up @@ -576,8 +579,10 @@ where
let name = match self.peek_token_kind() {
TokenKind::Name => {
let token = self.next_token();
let has_trailing_newline =
token.has_trailing_trivia_kind(TriviaKind::EndOfLine);
let token = self.sc_mut().make_token(token);
self.scan_remaining_qualified_name(token)
self.scan_remaining_qualified_name(token, has_trailing_newline)
}
TokenKind::LeftBrace => {
let pos = self.pos();
Expand Down
13 changes: 10 additions & 3 deletions hphp/hack/src/parser/core/expression_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use parser_core_types::syntax_error::SyntaxQuickfix;
use parser_core_types::syntax_error::{self as Errors};
use parser_core_types::token_factory::TokenFactory;
use parser_core_types::token_kind::TokenKind;
use parser_core_types::trivia_kind::TriviaKind;

use crate::declaration_parser::DeclarationParser;
use crate::lexer::Lexer;
Expand Down Expand Up @@ -302,8 +303,10 @@ where
match token.kind() {
TokenKind::Namespace | TokenKind::Name => {
self.continue_from(parser1);
let has_trailing_newline =
token.has_trailing_trivia_kind(TriviaKind::EndOfLine);
let token = self.sc_mut().make_token(token);
let name = self.scan_remaining_qualified_name(token);
let name = self.scan_remaining_qualified_name(token, has_trailing_newline);
self.parse_name_or_collection_literal_expression(name)
}
kind if self.expects_here(kind) => {
Expand Down Expand Up @@ -525,8 +528,10 @@ where
}

fn parse_name(&mut self, token: Token<S>) -> S::Output {
let has_trailing_newline =
token.has_trailing_trivia_kind(TriviaKind::EndOfLine);
let token = self.sc_mut().make_token(token);
let qualified_name = self.scan_remaining_qualified_name(token);
let qualified_name = self.scan_remaining_qualified_name(token, has_trailing_newline);
let mut parser1 = self.clone();
let str_maybe = parser1.next_token_no_trailing();
match str_maybe.kind() {
Expand Down Expand Up @@ -1654,8 +1659,10 @@ where
let backslash = self.sc_mut().make_token(start_token);
self.scan_qualified_name(missing, backslash)
} else {
let has_trailing_newline =
start_token.has_trailing_trivia_kind(TriviaKind::EndOfLine);
let start_token = self.sc_mut().make_token(start_token);
self.scan_remaining_qualified_name(start_token)
self.scan_remaining_qualified_name(start_token, has_trailing_newline)
};
match self.peek_token_kind_with_possible_attributized_type_list() {
TokenKind::LeftParen | TokenKind::LessThan => Some(name),
Expand Down
39 changes: 29 additions & 10 deletions hphp/hack/src/parser/core/parser_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use parser_core_types::syntax_error::{self as Errors};
use parser_core_types::token_factory::TokenFactory;
use parser_core_types::token_kind::TokenKind;
use parser_core_types::trivia_factory::TriviaFactory;
use parser_core_types::trivia_kind::TriviaKind;

use crate::lexer;
use crate::lexer::Lexer;
Expand Down Expand Up @@ -251,8 +252,10 @@ where
let token = self.next_xhp_class_name_or_other_token();
match token.kind() {
TokenKind::Namespace | TokenKind::Name => {
let has_trailing_newline =
token.has_trailing_trivia_kind(TriviaKind::EndOfLine);
let name_token = self.sc_mut().make_token(token);
self.scan_remaining_qualified_name(name_token)
self.scan_remaining_qualified_name(name_token, has_trailing_newline)
}
TokenKind::Backslash => {
let pos = self.pos();
Expand Down Expand Up @@ -416,6 +419,7 @@ where
mut name_opt: Option<S::Output>,
mut parts: Vec<S::Output>,
mut has_backslash: bool,
mut name_has_trailing_newline: bool,
) -> (Vec<S::Output>, Option<S::Output>, bool) {
loop {
let mut parser1 = self.clone();
Expand All @@ -425,18 +429,21 @@ where
parser1.next_token_as_name()
};
match (name_opt.is_some(), token.kind()) {
(true, TokenKind::Backslash) => {
// found backslash, create item and recurse
(true, TokenKind::Backslash) if !name_has_trailing_newline => {
// found backslash on the same line, create item and recurse
self.continue_from(parser1);
let token = self.sc_mut().make_token(token);
let part = self.sc_mut().make_list_item(name_opt.unwrap(), token);
parts.push(part);
has_backslash = true;
name_opt = None;
name_has_trailing_newline = false;
}
(false, TokenKind::Name) => {
// found a name, recurse to look for backslash
self.continue_from(parser1);
name_has_trailing_newline =
token.has_trailing_trivia_kind(TriviaKind::EndOfLine);
let token = self.sc_mut().make_token(token);
name_opt = Some(token);
has_backslash = false;
Expand Down Expand Up @@ -467,9 +474,10 @@ where
fn scan_remaining_qualified_name_extended(
&mut self,
name_token: S::Output,
name_has_trailing_newline: bool,
) -> (S::Output, bool) {
let (parts, name_token_opt, is_backslash) =
self.scan_qualified_name_worker(Some(name_token), vec![], false);
self.scan_qualified_name_worker(Some(name_token), vec![], false, name_has_trailing_newline);
if parts.is_empty() {
(name_token_opt.unwrap(), is_backslash)
} else {
Expand All @@ -487,7 +495,7 @@ where
) -> (S::Output, bool) {
let head = self.sc_mut().make_list_item(missing, backslash);
let parts = vec![head];
let (parts, _, is_backslash) = self.scan_qualified_name_worker(None, parts, false);
let (parts, _, is_backslash) = self.scan_qualified_name_worker(None, parts, false, false);
let pos = self.pos();
let list_node = self.sc_mut().make_list(parts, pos);
let name = self.sc_mut().make_qualified_name(list_node);
Expand Down Expand Up @@ -531,8 +539,10 @@ where
match token.kind() {
TokenKind::Namespace | TokenKind::Name => {
self.continue_from(parser1);
let has_trailing_newline =
token.has_trailing_trivia_kind(TriviaKind::EndOfLine);
let token = self.sc_mut().make_token(token);
self.scan_remaining_qualified_name(token)
self.scan_remaining_qualified_name(token, has_trailing_newline)
}
TokenKind::Backslash => {
self.continue_from(parser1);
Expand Down Expand Up @@ -604,8 +614,10 @@ where
match name.kind() {
TokenKind::Namespace | TokenKind::Name | TokenKind::XHPClassName => {
self.continue_from(parser1);
let has_trailing_newline =
name.has_trailing_trivia_kind(TriviaKind::EndOfLine);
let token = self.sc_mut().make_token(name);
self.scan_remaining_qualified_name(token)
self.scan_remaining_qualified_name(token, has_trailing_newline)
}
TokenKind::Backslash => {
self.continue_from(parser1);
Expand Down Expand Up @@ -787,8 +799,10 @@ where
match token.kind() {
TokenKind::Namespace | TokenKind::Name => {
self.continue_from(parser1);
let has_trailing_newline =
token.has_trailing_trivia_kind(TriviaKind::EndOfLine);
let token = self.sc_mut().make_token(token);
self.scan_remaining_qualified_name(token)
self.scan_remaining_qualified_name(token, has_trailing_newline)
}
TokenKind::Variable => {
self.continue_from(parser1);
Expand Down Expand Up @@ -1382,8 +1396,13 @@ where
self.parse_double_angled_list(parse_items)
}

fn scan_remaining_qualified_name(&mut self, name_token: S::Output) -> S::Output {
let (name, _) = self.scan_remaining_qualified_name_extended(name_token);
fn scan_remaining_qualified_name(
&mut self,
name_token: S::Output,
name_has_trailing_newline: bool,
) -> S::Output {
let (name, _) =
self.scan_remaining_qualified_name_extended(name_token, name_has_trailing_newline);
name
}

Expand Down
2 changes: 1 addition & 1 deletion hphp/hack/src/parser/core/pattern_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ where

fn parse_constructor_or_refinement_pattern(&mut self) -> S::Output {
let name = self.assert_token(TokenKind::Name);
let name = self.scan_remaining_qualified_name(name);
let name = self.scan_remaining_qualified_name(name, false);

match self.peek_token_kind() {
// NB: This is only a valid refinement pattern if `name` is a `Name`
Expand Down
11 changes: 11 additions & 0 deletions hphp/hack/test/autocomplete/before_imported_function.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?hh

namespace N;

function my_favorite(): void {
}

function f(): void {
my_AUTO332
\some_function_in_root_ns();
}
4 changes: 4 additions & 0 deletions hphp/hack/test/autocomplete/before_imported_function.php.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
my_favorite
INSERT my_favorite
function
SORT TEXT: none
13 changes: 13 additions & 0 deletions hphp/hack/test/nast/qualified_name_newline_boundary.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?hh

namespace N;

function my_function(): void {}

function f(): void {
my_function();
\some_root_ns_function();

my_function
\some_root_ns_function();
}
36 changes: 36 additions & 0 deletions hphp/hack/test/nast/qualified_name_newline_boundary.php.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[(Fun
{ fd_namespace =
{ Namespace_env.ns_ns_uses = <opaque>; ns_class_uses = <opaque>;
ns_fun_uses = <opaque>; ns_const_uses = <opaque>; ns_name = (Some "N");
ns_mode = Namespace_env.ForTypecheck; ns_disable_xhp_element_mangling = false };
fd_file_attributes = []; fd_mode = Mstrict; fd_name = ([5:10-21], "\\N\\my_function");
fd_fun =
{ f_span = [5:1-32]; f_readonly_this = None; f_annotation = ();
f_readonly_ret = None; f_tparams = []; f_ret = ((), (Some ([5:25-29], (Hprim Tvoid))));
f_params = []; f_ctxs = None; f_unsafe_ctxs = None; f_body = { fb_ast = [([Pos.none], Noop)] };
f_fun_kind = FSync; f_user_attributes = [{ ua_name = ([5:10-21], "__SupportDynamicType"); ua_params = [] }];
f_external = false; f_hidden = false; f_doc_comment = None };
fd_internal = false; fd_module = None; fd_tparams = []; fd_where_constraints = [];
fd_package = None });
(Fun
{ fd_namespace =
{ Namespace_env.ns_ns_uses = <opaque>; ns_class_uses = <opaque>;
ns_fun_uses = <opaque>; ns_const_uses = <opaque>; ns_name = (Some "N");
ns_mode = Namespace_env.ForTypecheck; ns_disable_xhp_element_mangling = false };
fd_file_attributes = []; fd_mode = Mstrict; fd_name = ([7:10-11], "\\N\\f");
fd_fun =
{ f_span = [7:1-13:2]; f_readonly_this = None; f_annotation = ();
f_readonly_ret = None; f_tparams = []; f_ret = ((), (Some ([7:15-19], (Hprim Tvoid))));
f_params = []; f_ctxs = None; f_unsafe_ctxs = None;
f_body =
{ fb_ast =
[([8:3-17], (Expr ((), [8:3-16], (Call { func = ((), [8:3-14], (Id ([8:3-14], "\\N\\my_function"))); targs = []; args = []; unpacked_arg = None }))));
([9:3-28], (Expr ((), [9:3-27], (Call { func = ((), [9:3-25], (Id ([9:3-25], "\\some_root_ns_function"))); targs = []; args = []; unpacked_arg = None }))));
([11:3-14], (Expr ((), [11:3-14], (Id ([11:3-14], "\\N\\my_function")))));
([12:3-28], (Expr ((), [12:3-27], (Call { func = ((), [12:3-25], (Id ([12:3-25], "\\some_root_ns_function"))); targs = []; args = []; unpacked_arg = None }))))]
};
f_fun_kind = FSync; f_user_attributes = [{ ua_name = ([7:10-11], "__SupportDynamicType"); ua_params = [] }];
f_external = false; f_hidden = false; f_doc_comment = None };
fd_internal = false; fd_module = None; fd_tparams = []; fd_where_constraints = [];
fd_package = None })
]