5100: Add support for include_str r=edwin0cheng a=lnicola

r? @edwin0cheng 

Co-authored-by: Laurențiu Nicola <lnicola@dend.ro>
This commit is contained in:
bors[bot] 2020-06-27 16:36:38 +00:00 committed by GitHub
commit 446fd3f515
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 75 additions and 34 deletions

View File

@ -99,6 +99,7 @@ register_builtin! {
EAGER: EAGER:
(concat, Concat) => concat_expand, (concat, Concat) => concat_expand,
(include, Include) => include_expand, (include, Include) => include_expand,
(include_str, IncludeStr) => include_str_expand,
(env, Env) => env_expand, (env, Env) => env_expand,
(option_env, OptionEnv) => option_env_expand (option_env, OptionEnv) => option_env_expand
} }
@ -292,11 +293,16 @@ fn concat_expand(
Ok((quote!(#text), FragmentKind::Expr)) Ok((quote!(#text), FragmentKind::Expr))
} }
fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { fn relative_file(
db: &dyn AstDatabase,
call_id: MacroCallId,
path: &str,
allow_recursion: bool,
) -> Option<FileId> {
let call_site = call_id.as_file().original_file(db); let call_site = call_id.as_file().original_file(db);
let res = db.resolve_path(call_site, path)?; let res = db.resolve_path(call_site, path)?;
// Prevent include itself // Prevent include itself
if res == call_site { if res == call_site && !allow_recursion {
None None
} else { } else {
Some(res) Some(res)
@ -319,8 +325,8 @@ fn include_expand(
tt: &tt::Subtree, tt: &tt::Subtree,
) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> {
let path = parse_string(tt)?; let path = parse_string(tt)?;
let file_id = let file_id = relative_file(db, arg_id.into(), &path, false)
relative_file(db, arg_id.into(), &path).ok_or_else(|| mbe::ExpandError::ConversionError)?; .ok_or_else(|| mbe::ExpandError::ConversionError)?;
// FIXME: // FIXME:
// Handle include as expression // Handle include as expression
@ -331,6 +337,30 @@ fn include_expand(
Ok((res, FragmentKind::Items)) Ok((res, FragmentKind::Items))
} }
fn include_str_expand(
db: &dyn AstDatabase,
arg_id: EagerMacroId,
tt: &tt::Subtree,
) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> {
let path = parse_string(tt)?;
// FIXME: we're not able to read excluded files (which is most of them because
// it's unusual to `include_str!` a Rust file), but we can return an empty string.
// Ideally, we'd be able to offer a precise expansion if the user asks for macro
// expansion.
let file_id = match relative_file(db, arg_id.into(), &path, true) {
Some(file_id) => file_id,
None => {
return Ok((quote!(""), FragmentKind::Expr));
}
};
let text = db.file_text(file_id);
let text = &*text;
Ok((quote!(#text), FragmentKind::Expr))
}
fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> {
let krate = db.lookup_intern_eager_expansion(arg_id).krate; let krate = db.lookup_intern_eager_expansion(arg_id).krate;
db.crate_graph()[krate].env.get(key) db.crate_graph()[krate].env.get(key)

View File

@ -191,6 +191,7 @@ pub mod known {
stringify, stringify,
concat, concat,
include, include,
include_str,
format_args, format_args,
format_args_nl, format_args_nl,
env, env,

View File

@ -494,6 +494,7 @@ fn main() {
} }
//- /src/main.rs //- /src/main.rs
#[rustc_builtin_macro] macro_rules! include {} #[rustc_builtin_macro] macro_rules! include {}
#[rustc_builtin_macro] macro_rules! include_str {}
#[rustc_builtin_macro] macro_rules! concat {} #[rustc_builtin_macro] macro_rules! concat {}
#[rustc_builtin_macro] macro_rules! env {} #[rustc_builtin_macro] macro_rules! env {}
@ -512,6 +513,7 @@ fn main() {
let va = A; let va = A;
let vb = B; let vb = B;
let should_be_str = message(); let should_be_str = message();
let another_str = include_str!("main.rs");
} }
"###, "###,
) )
@ -523,36 +525,19 @@ fn main() {
let res = server.send_request::<HoverRequest>(HoverParams { let res = server.send_request::<HoverRequest>(HoverParams {
text_document_position_params: TextDocumentPositionParams::new( text_document_position_params: TextDocumentPositionParams::new(
server.doc_id("src/main.rs"), server.doc_id("src/main.rs"),
Position::new(18, 10), Position::new(19, 10),
),
work_done_progress_params: Default::default(),
});
assert!(res.to_string().contains("&str"));
let res = server.send_request::<HoverRequest>(HoverParams {
text_document_position_params: TextDocumentPositionParams::new(
server.doc_id("src/main.rs"),
Position::new(20, 10),
), ),
work_done_progress_params: Default::default(), work_done_progress_params: Default::default(),
}); });
assert!(res.to_string().contains("&str")); assert!(res.to_string().contains("&str"));
server.request::<GotoTypeDefinition>(
GotoDefinitionParams {
text_document_position_params: TextDocumentPositionParams::new(
server.doc_id("src/main.rs"),
Position::new(16, 9),
),
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
},
json!([{
"originSelectionRange": {
"end": { "character": 10, "line": 16 },
"start": { "character": 8, "line": 16 }
},
"targetRange": {
"end": { "character": 9, "line": 7 },
"start": { "character": 0, "line": 6 }
},
"targetSelectionRange": {
"end": { "character": 8, "line": 7 },
"start": { "character": 7, "line": 7 }
},
"targetUri": "file:///[..]src/main.rs"
}]),
);
server.request::<GotoTypeDefinition>( server.request::<GotoTypeDefinition>(
GotoDefinitionParams { GotoDefinitionParams {
text_document_position_params: TextDocumentPositionParams::new( text_document_position_params: TextDocumentPositionParams::new(
@ -568,12 +553,37 @@ fn main() {
"start": { "character": 8, "line": 17 } "start": { "character": 8, "line": 17 }
}, },
"targetRange": { "targetRange": {
"end": { "character": 9, "line": 11 }, "end": { "character": 9, "line": 8 },
"start": { "character": 0, "line":10 } "start": { "character": 0, "line": 7 }
}, },
"targetSelectionRange": { "targetSelectionRange": {
"end": { "character": 8, "line": 11 }, "end": { "character": 8, "line": 8 },
"start": { "character": 7, "line": 11 } "start": { "character": 7, "line": 8 }
},
"targetUri": "file:///[..]src/main.rs"
}]),
);
server.request::<GotoTypeDefinition>(
GotoDefinitionParams {
text_document_position_params: TextDocumentPositionParams::new(
server.doc_id("src/main.rs"),
Position::new(18, 9),
),
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
},
json!([{
"originSelectionRange": {
"end": { "character": 10, "line": 18 },
"start": { "character": 8, "line": 18 }
},
"targetRange": {
"end": { "character": 9, "line": 12 },
"start": { "character": 0, "line":11 }
},
"targetSelectionRange": {
"end": { "character": 8, "line": 12 },
"start": { "character": 7, "line": 12 }
}, },
"targetUri": "file:///[..]src/main.rs" "targetUri": "file:///[..]src/main.rs"
}]), }]),