Repository: rust-analyzer/rust-analyzer
Pull request #2355 (2019-11-22 13:49:16)

Expand column!()

matklad: r? @edwin0cheng 
bjorn3: Can we also have `file!()`?
kjeremy: > 
> 
> Can we also have `file!()`?

I think that deserves a separate PR.
matklad: We also can't really have `file!()` at the moment, as rust-analyzer
(purposefully) lacks the knowledge about absolute file paths. I think, for
starters, we should expand file to just `""`.

On Fri, 22 Nov 2019 at 16:57, Jeremy Kolb <notifications@github.com> wrote:

> Can we also have file!()?
>
> I think that deserves a separate PR.
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <https://github.com/rust-analyzer/rust-analyzer/pull/2355?email_source=notifications&email_token=AANB3M2Q5W77PMEQW6J6G6DQU7QMHA5CNFSM4JQQ5UQKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEE5WPVI#issuecomment-557541333>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AANB3M5IV74NSF5M7FBPX4LQU7QMHANCNFSM4JQQ5UQA>
> .
>

kjeremy: I'll rebase this ones #2357 merges.

Patch:
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index d7057e0054..4da56529de 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -10,6 +10,7 @@ use crate::quote;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum BuiltinExpander {
+    Column,
     File,
     Line,
     Stringify,
@@ -23,6 +24,7 @@ impl BuiltinExpander {
         tt: &tt::Subtree,
     ) -> Result<tt::Subtree, mbe::ExpandError> {
         match self {
+            BuiltinExpander::Column => column_expand(db, id, tt),
             BuiltinExpander::File => file_expand(db, id, tt),
             BuiltinExpander::Line => line_expand(db, id, tt),
             BuiltinExpander::Stringify => stringify_expand(db, id, tt),
@@ -36,7 +38,9 @@ pub fn find_builtin_macro(
     ast_id: AstId<ast::MacroCall>,
 ) -> Option<MacroDefId> {
     // FIXME: Better registering method
-    if ident == &name::FILE_MACRO {
+    if ident == &name::COLUMN_MACRO {
+        Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Column) })
+    } else if ident == &name::FILE_MACRO {
         Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::File) })
     } else if ident == &name::LINE_MACRO {
         Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Line) })
@@ -110,6 +114,43 @@ fn stringify_expand(
     Ok(expanded)
 }
 
+fn to_col_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
+    // FIXME: Use expansion info
+    let file_id = file.original_file(db);
+    let text = db.file_text(file_id);
+    let mut col_num = 1;
+
+    for c in text[..pos.to_usize()].chars().rev() {
+        if c == '\n' {
+            break;
+        }
+        col_num = col_num + 1;
+    }
+
+    col_num
+}
+
+fn column_expand(
+    db: &dyn AstDatabase,
+    id: MacroCallId,
+    _tt: &tt::Subtree,
+) -> Result<tt::Subtree, mbe::ExpandError> {
+    let loc = db.lookup_intern_macro(id);
+    let macro_call = loc.ast_id.to_node(db);
+
+    let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
+    let col_start = macro_call.syntax().text_range().start();
+
+    let file = id.as_file(MacroFileKind::Expr);
+    let col_num = to_col_number(db, file, col_start);
+
+    let expanded = quote! {
+        #col_num
+    };
+
+    Ok(expanded)
+}
+
 fn file_expand(
     db: &dyn AstDatabase,
     id: MacroCallId,
@@ -117,6 +158,7 @@ fn file_expand(
 ) -> Result<tt::Subtree, mbe::ExpandError> {
     let loc = db.lookup_intern_macro(id);
     let macro_call = loc.ast_id.to_node(db);
+
     let _ = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
 
     // FIXME: RA purposefully lacks knowledge of absolute file names
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 05fe6afd9b..eaea7a6a86 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -143,5 +143,6 @@ pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box");
 
 // Builtin Macros
 pub const FILE_MACRO: Name = Name::new_inline_ascii(4, b"file");
+pub const COLUMN_MACRO: Name = Name::new_inline_ascii(6, b"column");
 pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line");
 pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify");


Test patch:
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index b4bdd81f64..17a50cf741 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -4876,3 +4876,22 @@ fn main() {
     "###
     );
 }
+
+#[test]
+fn infer_builtin_macros_column() {
+    assert_snapshot!(
+        infer(r#"
+#[rustc_builtin_macro]
+macro_rules! column {() => {}}
+
+fn main() {
+    let x = column!();
+}
+"#),
+        @r###"
+    ![0; 2) '13': i32
+    [66; 92) '{     ...!(); }': ()
+    [76; 77) 'x': i32
+    "###
+    );
+}