Skip to content

Commit 4b577e2

Browse files
committed
Support c string literals
1 parent 099b5b3 commit 4b577e2

File tree

21 files changed

+176
-34
lines changed

21 files changed

+176
-34
lines changed

crates/hir-def/src/body/pretty.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,7 @@ impl<'a> Printer<'a> {
611611
match literal {
612612
Literal::String(it) => w!(self, "{:?}", it),
613613
Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
614+
Literal::CString(it) => w!(self, "\"{}\\0\"", it),
614615
Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
615616
Literal::Bool(it) => w!(self, "{}", it),
616617
Literal::Int(i, suffix) => {

crates/hir-def/src/hir.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ impl fmt::Display for FloatTypeWrapper {
8585
pub enum Literal {
8686
String(Box<str>),
8787
ByteString(Box<[u8]>),
88+
CString(Box<str>),
8889
Char(char),
8990
Bool(bool),
9091
Int(i128, Option<BuiltinInt>),
@@ -135,6 +136,10 @@ impl From<ast::LiteralKind> for Literal {
135136
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
136137
Literal::String(text)
137138
}
139+
LiteralKind::CString(s) => {
140+
let text = s.value().map(Box::from).unwrap_or_else(Default::default);
141+
Literal::CString(text)
142+
}
138143
LiteralKind::Byte(b) => {
139144
Literal::Uint(b.value().unwrap_or_default() as u128, Some(BuiltinUint::U8))
140145
}

crates/hir-ty/src/infer/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,7 @@ impl<'a> InferenceContext<'a> {
815815
Expr::Array(array) => self.infer_expr_array(array, expected),
816816
Expr::Literal(lit) => match lit {
817817
Literal::Bool(..) => self.result.standard_types.bool_.clone(),
818-
Literal::String(..) => {
818+
Literal::String(..) | Literal::CString(..) => {
819819
TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner))
820820
.intern(Interner)
821821
}

crates/hir-ty/src/infer/pat.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -428,9 +428,10 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
428428
// FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
429429
Pat::Path(..) => true,
430430
Pat::ConstBlock(..) => true,
431-
Pat::Lit(expr) => {
432-
!matches!(body[*expr], Expr::Literal(Literal::String(..) | Literal::ByteString(..)))
433-
}
431+
Pat::Lit(expr) => !matches!(
432+
body[*expr],
433+
Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
434+
),
434435
Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
435436
}
436437
}

crates/hir-ty/src/mir/lower.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,15 +1112,24 @@ impl<'ctx> MirLowerCtx<'ctx> {
11121112
let bytes = match l {
11131113
hir_def::hir::Literal::String(b) => {
11141114
let b = b.as_bytes();
1115-
let mut data = vec![];
1115+
let mut data = Vec::with_capacity(mem::size_of::<usize>() * 2);
11161116
data.extend(0usize.to_le_bytes());
11171117
data.extend(b.len().to_le_bytes());
11181118
let mut mm = MemoryMap::default();
11191119
mm.insert(0, b.to_vec());
11201120
return Ok(Operand::from_concrete_const(data, mm, ty));
11211121
}
1122+
hir_def::hir::Literal::CString(b) => {
1123+
let b = b.as_bytes();
1124+
let mut data = Vec::with_capacity(mem::size_of::<usize>() * 2);
1125+
data.extend(0usize.to_le_bytes());
1126+
data.extend(b.len().to_le_bytes());
1127+
let mut mm = MemoryMap::default();
1128+
mm.insert(0, b.iter().copied().chain(iter::once(0)).collect::<Vec<_>>());
1129+
return Ok(Operand::from_concrete_const(data, mm, ty));
1130+
}
11221131
hir_def::hir::Literal::ByteString(b) => {
1123-
let mut data = vec![];
1132+
let mut data = Vec::with_capacity(mem::size_of::<usize>() * 2);
11241133
data.extend(0usize.to_le_bytes());
11251134
data.extend(b.len().to_le_bytes());
11261135
let mut mm = MemoryMap::default();

crates/ide-assists/src/handlers/raw_string.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{utils::required_hashes, AssistContext, AssistId, AssistKind, Assists
2020
// }
2121
// ```
2222
pub(crate) fn make_raw_string(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
23+
// FIXME: This should support byte and c strings as well.
2324
let token = ctx.find_token_at_offset::<ast::String>()?;
2425
if token.is_raw() {
2526
return None;

crates/ide/src/extend_selection.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn try_extend_selection(
3939
) -> Option<TextRange> {
4040
let range = frange.range;
4141

42-
let string_kinds = [COMMENT, STRING, BYTE_STRING];
42+
let string_kinds = [COMMENT, STRING, BYTE_STRING, C_STRING];
4343
let list_kinds = [
4444
RECORD_PAT_FIELD_LIST,
4545
MATCH_ARM_LIST,

crates/ide/src/syntax_highlighting.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ mod tests;
1616
use hir::{Name, Semantics};
1717
use ide_db::{FxHashMap, RootDatabase, SymbolKind};
1818
use syntax::{
19-
ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T,
19+
ast::{self, IsString},
20+
AstNode, AstToken, NodeOrToken,
21+
SyntaxKind::*,
22+
SyntaxNode, TextRange, WalkEvent, T,
2023
};
2124

2225
use crate::{
@@ -440,7 +443,17 @@ fn traverse(
440443
&& ast::ByteString::can_cast(descended_token.kind())
441444
{
442445
if let Some(byte_string) = ast::ByteString::cast(token) {
443-
highlight_escape_string(hl, &byte_string, range.start());
446+
if !byte_string.is_raw() {
447+
highlight_escape_string(hl, &byte_string, range.start());
448+
}
449+
}
450+
} else if ast::CString::can_cast(token.kind())
451+
&& ast::CString::can_cast(descended_token.kind())
452+
{
453+
if let Some(c_string) = ast::CString::cast(token) {
454+
if !c_string.is_raw() {
455+
highlight_escape_string(hl, &c_string, range.start());
456+
}
444457
}
445458
} else if ast::Char::can_cast(token.kind())
446459
&& ast::Char::can_cast(descended_token.kind())

crates/ide/src/syntax_highlighting/highlight.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub(super) fn token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> O
2626
}
2727

2828
let highlight: Highlight = match token.kind() {
29-
STRING | BYTE_STRING => HlTag::StringLiteral.into(),
29+
STRING | BYTE_STRING | C_STRING => HlTag::StringLiteral.into(),
3030
INT_NUMBER if token.parent_ancestors().nth(1).map(|it| it.kind()) == Some(FIELD_EXPR) => {
3131
SymbolKind::Field.into()
3232
}

crates/ide/src/syntax_tree.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
use ide_db::base_db::{FileId, SourceDatabase};
2-
use ide_db::RootDatabase;
1+
use ide_db::{
2+
base_db::{FileId, SourceDatabase},
3+
RootDatabase,
4+
};
35
use syntax::{
46
AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize,
57
};

0 commit comments

Comments
 (0)