#[allow(unused_imports)]
use crate::clang::ast::*;
#[allow(unused_imports)]
use crate::clang::sema::*;
#[allow(unused_imports)]
use crate::x86::*;
use std::cmp::Ordering;
use std::collections::{BinaryHeap, HashMap, HashSet};
use std::fmt;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(u8)]
pub enum X86CompletionKind {
Function = 1,
Variable = 2,
Type = 3,
Macro = 4,
Keyword = 5,
Directive = 6,
Field = 7,
EnumMember = 8,
Namespace = 9,
Snippet = 10,
File = 11,
Label = 12,
Concept = 13,
Operator = 14,
TypeParameter = 15,
Intrinsic = 16,
Module = 17,
Constant = 18,
TemplateFunction = 19,
TemplateType = 20,
StaticMember = 21,
InheritedMember = 22,
UsingDeclaration = 23,
NamespaceAlias = 24,
Constructor = 25,
Destructor = 26,
ConversionFunction = 27,
LiteralOperator = 28,
UserDefinedLiteral = 29,
Parameter = 30,
LocalVariable = 31,
GlobalVariable = 32,
}
impl X86CompletionKind {
pub fn icon(&self) -> &'static str {
match self {
Self::Function => "f",
Self::Variable => "v",
Self::Type => "t",
Self::Macro => "m",
Self::Keyword => "k",
Self::Directive => "#",
Self::Field => ".",
Self::EnumMember => "e",
Self::Namespace => "n",
Self::Snippet => "~",
Self::File => "F",
Self::Label => "l",
Self::Concept => "c",
Self::Operator => "o",
Self::TypeParameter => "p",
Self::Intrinsic => "i",
Self::Module => "M",
Self::Constant => "C",
Self::TemplateFunction => "Tf",
Self::TemplateType => "Tt",
Self::StaticMember => "s.",
Self::InheritedMember => "i.",
Self::UsingDeclaration => "u",
Self::NamespaceAlias => "na",
Self::Constructor => "Ct",
Self::Destructor => "Dt",
Self::ConversionFunction => "cv",
Self::LiteralOperator => "lo",
Self::UserDefinedLiteral => "ud",
Self::Parameter => "p",
Self::LocalVariable => "lv",
Self::GlobalVariable => "gv",
}
}
pub fn lsp_kind(&self) -> u32 {
match self {
Self::Function | Self::TemplateFunction => 3,
Self::Variable | Self::LocalVariable | Self::GlobalVariable | Self::Parameter => 6,
Self::Type | Self::TemplateType | Self::TypeParameter => 7,
Self::Macro => 1,
Self::Keyword => 14,
Self::Directive => 1,
Self::Field | Self::StaticMember | Self::InheritedMember => 5,
Self::EnumMember => 13,
Self::Namespace | Self::NamespaceAlias => 8,
Self::Snippet => 15,
Self::File => 17,
Self::Label => 5,
Self::Concept => 8,
Self::Operator | Self::LiteralOperator => 11,
Self::Intrinsic => 3,
Self::Module => 9,
Self::Constant => 21,
Self::UsingDeclaration => 8,
Self::Constructor => 4,
Self::Destructor => 4,
Self::ConversionFunction => 3,
Self::UserDefinedLiteral => 1,
}
}
}
impl fmt::Display for X86CompletionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Self::Function => "function",
Self::Variable => "variable",
Self::Type => "type",
Self::Macro => "macro",
Self::Keyword => "keyword",
Self::Directive => "directive",
Self::Field => "field",
Self::EnumMember => "enum",
Self::Namespace => "namespace",
Self::Snippet => "snippet",
Self::File => "file",
Self::Label => "label",
Self::Concept => "concept",
Self::Operator => "operator",
Self::TypeParameter => "type-param",
Self::Intrinsic => "intrinsic",
Self::Module => "module",
Self::Constant => "constant",
Self::TemplateFunction => "template-function",
Self::TemplateType => "template-type",
Self::StaticMember => "static-member",
Self::InheritedMember => "inherited-member",
Self::UsingDeclaration => "using-decl",
Self::NamespaceAlias => "namespace-alias",
Self::Constructor => "constructor",
Self::Destructor => "destructor",
Self::ConversionFunction => "conversion-func",
Self::LiteralOperator => "literal-operator",
Self::UserDefinedLiteral => "user-defined-literal",
Self::Parameter => "parameter",
Self::LocalVariable => "local-variable",
Self::GlobalVariable => "global-variable",
};
write!(f, "{}", s)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum X86CompletionContext {
DotAccess {
receiver_type: Option<String>,
implicit_this: bool,
},
ArrowAccess {
receiver_type: Option<String>,
implicit_this: bool,
},
ScopeResolution {
scope_name: Option<String>,
nested: bool,
nested_specifiers: Vec<String>,
},
OpenParen { callee: Option<String> },
TypeContext {
template_argument: bool,
base_specifier: bool,
preceding_keyword: Option<String>,
},
DeclarationContext {
in_class_body: bool,
class_name: Option<String>,
in_namespace: bool,
at_top_level: bool,
},
DirectiveContext {
partial: String,
},
IncludeContext {
delimiter: IncludeDelimiter,
partial: String,
},
StringContext {
partial: String,
delimiter: char,
},
LabelContext,
EnumBody { enum_name: Option<String> },
UsingContext,
TemplateArgumentContext,
General,
ExpressionContext,
ReturnContext,
CaseContext,
GotoContext,
AccessSpecifierContext { access: X86AccessSpecifier },
InitializerListContext { class_name: Option<String> },
ThrowContext,
NoexceptContext,
CatchContext,
DecltypeContext,
SizeofContext,
AttributeContext,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum IncludeDelimiter {
Quote,
Angle,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum X86AccessSpecifier {
Public,
Protected,
Private,
Unspecified,
}
impl X86CompletionContext {
pub fn from_source_line(line: &str, column: usize) -> Self {
let prefix = if column <= line.len() {
&line[..column]
} else {
line
};
let trimmed = prefix.trim();
let trimmed_lower = trimmed.to_lowercase();
if let Some(quote_pos) = trimmed.rfind("#include \"") {
let partial = trimmed[quote_pos + 10..].to_string();
return Self::IncludeContext {
delimiter: IncludeDelimiter::Quote,
partial,
};
}
if let Some(angle_pos) = trimmed.rfind("#include <") {
let partial = trimmed[angle_pos + 10..].to_string();
return Self::IncludeContext {
delimiter: IncludeDelimiter::Angle,
partial,
};
}
if let Some(angle_pos) = trimmed.rfind("#include<") {
let partial = trimmed[angle_pos + 9..].to_string();
return Self::IncludeContext {
delimiter: IncludeDelimiter::Angle,
partial,
};
}
if trimmed == "#" {
return Self::DirectiveContext {
partial: String::new(),
};
}
if trimmed.starts_with('#')
&& !trimmed.starts_with("#include")
&& !trimmed.starts_with("#define")
&& !trimmed.starts_with("#if")
&& !trimmed.starts_with("#endif")
&& !trimmed.starts_with("#else")
&& !trimmed.starts_with("#elif")
&& !trimmed.starts_with("#pragma")
&& !trimmed.starts_with("#error")
&& !trimmed.starts_with("#warning")
&& !trimmed.starts_with("#undef")
&& !trimmed.starts_with("#line")
&& !trimmed.starts_with("#import")
&& !trimmed.starts_with("#include_next")
{
let partial = trimmed[1..].trim().to_string();
return Self::DirectiveContext { partial };
}
if trimmed.ends_with("::") {
let scope_part = &trimmed[..trimmed.len() - 2];
let scope_name = scope_part
.rsplit(|c: char| !c.is_alphanumeric() && c != '_' && c != ':')
.next()
.map(|s| s.to_string());
return Self::ScopeResolution {
scope_name,
nested: scope_part.contains("::"),
nested_specifiers: extract_nested_specifiers(scope_part),
};
}
if trimmed.ends_with('.') {
let before_dot = &trimmed[..trimmed.len() - 1];
if before_dot
.chars()
.last()
.map_or(true, |c| !c.is_ascii_digit())
{
return Self::DotAccess {
receiver_type: extract_receiver_type(trimmed),
implicit_this: false,
};
}
}
if trimmed.ends_with("->") {
return Self::ArrowAccess {
receiver_type: extract_receiver_type(trimmed),
implicit_this: false,
};
}
if trimmed.ends_with('(') {
return Self::OpenParen {
callee: extract_callee_name(trimmed),
};
}
let type_kws = [
"int",
"long",
"short",
"char",
"float",
"double",
"void",
"unsigned",
"signed",
"struct",
"enum",
"union",
"class",
"const",
"volatile",
"static",
"extern",
"typedef",
"auto",
"register",
"_Bool",
"_Complex",
"typename",
"mutable",
"thread_local",
"constexpr",
"inline",
"virtual",
"explicit",
"friend",
"export",
];
for kw in &type_kws {
if trimmed.ends_with(&format!("{} ", kw)) || trimmed.ends_with(&format!("{}\t", kw)) {
return Self::TypeContext {
template_argument: false,
base_specifier: false,
preceding_keyword: Some(kw.to_string()),
};
}
}
if trimmed.ends_with('<') || trimmed.ends_with('<') {
let before = &trimmed[..trimmed.len() - 1].trim();
if before
.chars()
.last()
.map_or(false, |c| c.is_alphanumeric() || c == '_')
{
return Self::TemplateArgumentContext;
}
}
let last_word = trimmed
.rsplit(|c: char| c.is_whitespace())
.next()
.unwrap_or("");
match last_word {
"return" => return Self::ReturnContext,
"case" => return Self::CaseContext,
"goto" => return Self::GotoContext,
"throw" => return Self::ThrowContext,
"noexcept" => return Self::NoexceptContext,
"decltype" => return Self::DecltypeContext,
"sizeof" | "alignof" | "alignas" => return Self::SizeofContext,
_ => {}
}
if trimmed.ends_with("public:") || trimmed_lower.ends_with("public :") {
return Self::AccessSpecifierContext {
access: X86AccessSpecifier::Public,
};
}
if trimmed.ends_with("protected:") || trimmed_lower.ends_with("protected :") {
return Self::AccessSpecifierContext {
access: X86AccessSpecifier::Protected,
};
}
if trimmed.ends_with("private:") || trimmed_lower.ends_with("private :") {
return Self::AccessSpecifierContext {
access: X86AccessSpecifier::Private,
};
}
if trimmed.is_empty() {
return Self::General;
}
if trimmed.ends_with(';') || trimmed.ends_with('{') || trimmed.ends_with('}') {
return Self::DeclarationContext {
in_class_body: false,
class_name: None,
in_namespace: false,
at_top_level: true,
};
}
if trimmed.ends_with("[[") || trimmed.ends_with("__attribute__((") {
return Self::AttributeContext;
}
if trimmed.ends_with('"') && !trimmed.ends_with("\\\"") {
let partial = extract_string_partial(trimmed);
if !partial.is_empty() && partial.contains('/') {
return Self::StringContext {
partial,
delimiter: '"',
};
}
}
if trimmed.ends_with("using ") || trimmed.ends_with("using namespace ") {
return Self::UsingContext;
}
if trimmed.ends_with(':') {
let before_colon = &trimmed[..trimmed.len() - 1].trim();
if before_colon.ends_with(')') {
return Self::InitializerListContext {
class_name: extract_class_from_ctor(before_colon),
};
}
}
let stmt_kws = ["if", "for", "while", "do", "switch"];
for kw in &stmt_kws {
if trimmed.ends_with(&format!("{} ", kw)) || trimmed.ends_with(&format!("{}\t", kw)) {
return Self::ExpressionContext;
}
}
Self::General
}
pub fn expects_type(&self) -> bool {
matches!(
self,
Self::TypeContext { .. }
| Self::TemplateArgumentContext
| Self::DecltypeContext
| Self::SizeofContext
| Self::ScopeResolution { .. }
)
}
pub fn expects_value(&self) -> bool {
matches!(
self,
Self::ExpressionContext
| Self::ReturnContext
| Self::CaseContext
| Self::GotoContext
| Self::ThrowContext
| Self::General
)
}
pub fn expects_member(&self) -> bool {
matches!(self, Self::DotAccess { .. } | Self::ArrowAccess { .. })
}
pub fn is_directive(&self) -> bool {
matches!(
self,
Self::DirectiveContext { .. } | Self::IncludeContext { .. }
)
}
}
fn extract_nested_specifiers(text: &str) -> Vec<String> {
text.split("::")
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect()
}
fn extract_receiver_type(text: &str) -> Option<String> {
let stripped = if text.ends_with("->") {
&text[..text.len() - 2]
} else {
&text[..text.len() - 1]
};
let ident = stripped
.rsplit(|c: char| !c.is_alphanumeric() && c != '_')
.next()?;
if ident.is_empty() {
None
} else {
Some(ident.to_string())
}
}
fn extract_callee_name(text: &str) -> Option<String> {
let before = &text[..text.len() - 1];
let ident = before
.rsplit(|c: char| !c.is_alphanumeric() && c != '_' && c != ':')
.next()?;
if ident.is_empty()
|| ident == "if"
|| ident == "for"
|| ident == "while"
|| ident == "switch"
|| ident == "return"
|| ident == "sizeof"
|| ident == "alignof"
|| ident == "decltype"
{
None
} else {
Some(ident.to_string())
}
}
fn extract_string_partial(text: &str) -> String {
if let Some(start) = text.rfind('"') {
let after_quote = &text[start + 1..];
after_quote.to_string()
} else {
String::new()
}
}
fn extract_class_from_ctor(text: &str) -> Option<String> {
let before_paren = &text[..text.len() - 1];
let ident = before_paren
.rsplit(|c: char| !c.is_alphanumeric() && c != '_' && c != ':')
.next()?;
if ident.is_empty() || ident == "if" || ident == "for" || ident == "while" {
None
} else {
Some(ident.to_string())
}
}
#[derive(Debug, Clone)]
pub struct X86CompletionResult {
pub display_text: String,
pub insert_text: String,
pub kind: X86CompletionKind,
pub priority: i32,
pub documentation: Option<String>,
pub detail: Option<String>,
pub additional_edits: Vec<X86AdditionalEdit>,
pub deprecated: bool,
pub is_snippet: bool,
pub sort_text: Option<String>,
pub filter_text: Option<String>,
pub required_header: Option<String>,
pub scope: Option<String>,
pub visibility: X86SymbolVisibility,
pub is_static: bool,
pub is_constexpr: bool,
pub is_virtual: bool,
pub is_override: bool,
pub is_noexcept: bool,
pub return_type: Option<String>,
pub parameters: Vec<X86ParameterInfo>,
pub template_params: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct X86AdditionalEdit {
pub file: Option<String>,
pub line: usize,
pub column: usize,
pub new_text: String,
}
#[derive(Debug, Clone)]
pub struct X86ParameterInfo {
pub name: String,
pub param_type: String,
pub default_value: Option<String>,
pub is_variadic: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum X86SymbolVisibility {
Public,
Protected,
Private,
Unspecified,
}
impl X86CompletionResult {
pub fn keyword(name: &str) -> Self {
Self {
display_text: name.to_string(),
insert_text: format!("{} ", name),
kind: X86CompletionKind::Keyword,
priority: 100,
documentation: Some(format!("Keyword: `{}`", name)),
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: None,
required_header: None,
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: None,
parameters: Vec::new(),
template_params: Vec::new(),
}
}
pub fn macro_(name: &str, doc: Option<&str>) -> Self {
Self {
display_text: name.to_string(),
insert_text: name.to_string(),
kind: X86CompletionKind::Macro,
priority: 90,
documentation: doc.map(|d| d.to_string()),
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: None,
required_header: None,
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: None,
parameters: Vec::new(),
template_params: Vec::new(),
}
}
pub fn directive(name: &str, doc: &str) -> Self {
Self {
display_text: name.to_string(),
insert_text: format!("{} ", name),
kind: X86CompletionKind::Directive,
priority: 95,
documentation: Some(doc.to_string()),
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: None,
required_header: None,
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: None,
parameters: Vec::new(),
template_params: Vec::new(),
}
}
pub fn type_(name: &str, doc: Option<&str>) -> Self {
Self {
display_text: name.to_string(),
insert_text: name.to_string(),
kind: X86CompletionKind::Type,
priority: 85,
documentation: doc.map(|d| d.to_string()),
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: None,
required_header: None,
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: None,
parameters: Vec::new(),
template_params: Vec::new(),
}
}
pub fn function(name: &str, ret: &str, params: &[(&str, &str)], doc: Option<&str>) -> Self {
let param_infos: Vec<X86ParameterInfo> = params
.iter()
.map(|(pt, pn)| X86ParameterInfo {
name: pn.to_string(),
param_type: pt.to_string(),
default_value: None,
is_variadic: false,
})
.collect();
let param_str: Vec<String> = params
.iter()
.map(|(pt, pn)| format!("{} {}", pt, pn))
.collect();
let detail = format!("{} {}({})", ret, name, param_str.join(", "));
Self {
display_text: format!("{} ({})", name, ret),
insert_text: format!("{}(", name),
kind: X86CompletionKind::Function,
priority: 80,
documentation: doc.map(|d| d.to_string()),
detail: Some(detail),
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: Some(name.to_string()),
required_header: None,
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: Some(ret.to_string()),
parameters: param_infos,
template_params: Vec::new(),
}
}
pub fn snippet(label: &str, insert: &str, doc: &str) -> Self {
Self {
display_text: label.to_string(),
insert_text: insert.to_string(),
kind: X86CompletionKind::Snippet,
priority: 70,
documentation: Some(doc.to_string()),
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: true,
sort_text: Some(format!("~{}", label)),
filter_text: None,
required_header: None,
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: None,
parameters: Vec::new(),
template_params: Vec::new(),
}
}
pub fn variable(name: &str, var_type: &str, doc: Option<&str>) -> Self {
Self {
display_text: format!("{} : {}", name, var_type),
insert_text: name.to_string(),
kind: X86CompletionKind::Variable,
priority: 75,
documentation: doc.map(|d| d.to_string()),
detail: Some(format!("{} {}", var_type, name)),
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: Some(name.to_string()),
required_header: None,
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: Some(var_type.to_string()),
parameters: Vec::new(),
template_params: Vec::new(),
}
}
pub fn field(name: &str, field_type: &str, doc: Option<&str>) -> Self {
Self {
display_text: format!("{} : {}", name, field_type),
insert_text: name.to_string(),
kind: X86CompletionKind::Field,
priority: 75,
documentation: doc.map(|d| d.to_string()),
detail: Some(format!("{} {}", field_type, name)),
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: Some(name.to_string()),
required_header: None,
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: Some(field_type.to_string()),
parameters: Vec::new(),
template_params: Vec::new(),
}
}
pub fn enum_member(name: &str, enum_name: &str, doc: Option<&str>) -> Self {
Self {
display_text: name.to_string(),
insert_text: name.to_string(),
kind: X86CompletionKind::EnumMember,
priority: 75,
documentation: doc.map(|d| d.to_string()),
detail: Some(format!("{}::{}", enum_name, name)),
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: Some(name.to_string()),
required_header: None,
scope: Some(enum_name.to_string()),
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: true,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: None,
parameters: Vec::new(),
template_params: Vec::new(),
}
}
pub fn namespace(name: &str, doc: Option<&str>) -> Self {
Self {
display_text: name.to_string(),
insert_text: format!("{}::", name),
kind: X86CompletionKind::Namespace,
priority: 85,
documentation: doc.map(|d| d.to_string()),
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: None,
required_header: None,
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: None,
parameters: Vec::new(),
template_params: Vec::new(),
}
}
pub fn file(name: &str, is_dir: bool) -> Self {
let suffix = if is_dir { "/" } else { "" };
Self {
display_text: format!("{}{}", name, suffix),
insert_text: format!("{}{}", name, suffix),
kind: X86CompletionKind::File,
priority: if is_dir { 60 } else { 55 },
documentation: if is_dir {
Some("Directory".to_string())
} else {
Some("Header file".to_string())
},
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: Some(format!("{}{}", if is_dir { "0" } else { "1" }, name)),
filter_text: Some(name.to_string()),
required_header: None,
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: None,
parameters: Vec::new(),
template_params: Vec::new(),
}
}
pub fn intrinsic(name: &str, params: &[(&str, &str)], ret: &str, header: &str) -> Self {
let param_infos: Vec<X86ParameterInfo> = params
.iter()
.map(|(pt, pn)| X86ParameterInfo {
name: pn.to_string(),
param_type: pt.to_string(),
default_value: None,
is_variadic: false,
})
.collect();
let param_str: Vec<String> = params
.iter()
.map(|(pt, pn)| format!("{} {}", pt, pn))
.collect();
let detail = format!(
"{} {}({}) — header: <{}>",
ret,
name,
param_str.join(", "),
header
);
Self {
display_text: format!("{} {}", ret, name),
insert_text: format!("{}(", name),
kind: X86CompletionKind::Intrinsic,
priority: 85,
documentation: Some(detail.clone()),
detail: Some(detail),
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: Some(name.to_string()),
required_header: Some(header.to_string()),
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: Some(ret.to_string()),
parameters: param_infos,
template_params: Vec::new(),
}
}
}
impl PartialEq for X86CompletionResult {
fn eq(&self, other: &Self) -> bool {
self.display_text == other.display_text
&& self.insert_text == other.insert_text
&& self.kind == other.kind
}
}
impl Eq for X86CompletionResult {}
impl PartialOrd for X86CompletionResult {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for X86CompletionResult {
fn cmp(&self, other: &Self) -> Ordering {
other
.priority
.cmp(&self.priority)
.then_with(|| self.display_text.cmp(&other.display_text))
}
}
#[derive(Debug, Clone)]
pub struct X86CompletionRanker {
type_compat_scores: HashMap<(String, String), f64>,
frequency_map: HashMap<String, u64>,
scope_depth_map: HashMap<String, u32>,
context_weights: X86RankerWeights,
fuzzy_enabled: bool,
fuzzy_threshold: f64,
}
#[derive(Debug, Clone)]
pub struct X86RankerWeights {
pub type_weight: f64,
pub scope_weight: f64,
pub frequency_weight: f64,
pub distance_weight: f64,
pub context_weight: f64,
}
impl Default for X86RankerWeights {
fn default() -> Self {
Self {
type_weight: 0.30,
scope_weight: 0.20,
frequency_weight: 0.15,
distance_weight: 0.10,
context_weight: 0.25,
}
}
}
impl Default for X86CompletionRanker {
fn default() -> Self {
Self {
type_compat_scores: HashMap::new(),
frequency_map: HashMap::new(),
scope_depth_map: HashMap::new(),
context_weights: X86RankerWeights::default(),
fuzzy_enabled: true,
fuzzy_threshold: 0.6,
}
}
}
impl X86CompletionRanker {
pub fn new() -> Self {
Self::default()
}
pub fn with_weights(weights: X86RankerWeights) -> Self {
Self {
context_weights: weights,
..Default::default()
}
}
pub fn set_fuzzy(&mut self, enabled: bool, threshold: f64) {
self.fuzzy_enabled = enabled;
self.fuzzy_threshold = threshold;
}
pub fn record_usage(&mut self, symbol: &str) {
*self.frequency_map.entry(symbol.to_string()).or_insert(0) += 1;
}
pub fn set_scope_depth(&mut self, symbol: &str, depth: u32) {
self.scope_depth_map.insert(symbol.to_string(), depth);
}
pub fn register_type_compatibility(&mut self, from: &str, to: &str, score: f64) {
self.type_compat_scores
.insert((from.to_string(), to.to_string()), score);
}
pub fn rank(
&self,
results: &mut [X86CompletionResult],
query: &str,
context: &X86CompletionContext,
expected_type: Option<&str>,
) {
for result in results.iter_mut() {
let mut score = 0.0;
if let Some(expected) = expected_type {
score += self.context_weights.type_weight * self.type_match_score(expected, result);
}
score += self.context_weights.scope_weight * self.scope_proximity_score(result);
score += self.context_weights.frequency_weight * self.frequency_score(result);
score += self.context_weights.distance_weight * self.distance_score(query, result);
score +=
self.context_weights.context_weight * self.context_relevance_score(result, context);
result.priority = (score * 100.0).round() as i32;
}
results.sort_by(|a, b| b.priority.cmp(&a.priority));
}
fn type_match_score(&self, expected: &str, result: &X86CompletionResult) -> f64 {
let result_type = result.return_type.as_deref().unwrap_or("");
if result_type.is_empty() {
return 0.3;
}
if result_type == expected {
return 1.0;
}
if let Some(score) = self
.type_compat_scores
.get(&(result_type.to_string(), expected.to_string()))
{
return *score;
}
if result_type.contains(expected) || expected.contains(result_type) {
return 0.7;
}
let strip_ref = |s: &str| {
s.trim_end_matches('&')
.trim_end_matches('*')
.trim()
.to_string()
};
if strip_ref(result_type) == strip_ref(expected) {
return 0.8;
}
if result_type.replace("const ", "") == expected.replace("const ", "") {
return 0.75;
}
0.1
}
fn scope_proximity_score(&self, result: &X86CompletionResult) -> f64 {
match result.kind {
X86CompletionKind::LocalVariable
| X86CompletionKind::Parameter
| X86CompletionKind::Label => 1.0,
X86CompletionKind::Field
| X86CompletionKind::StaticMember
| X86CompletionKind::InheritedMember => 0.8,
X86CompletionKind::Function
| X86CompletionKind::Constructor
| X86CompletionKind::Destructor => 0.6,
X86CompletionKind::EnumMember => 0.5,
X86CompletionKind::Type | X86CompletionKind::TemplateType => 0.4,
X86CompletionKind::Namespace | X86CompletionKind::NamespaceAlias => 0.3,
X86CompletionKind::GlobalVariable => 0.5,
X86CompletionKind::Macro => 0.35,
_ => 0.2,
}
}
fn frequency_score(&self, result: &X86CompletionResult) -> f64 {
let count = self
.frequency_map
.get(&result.insert_text)
.copied()
.unwrap_or(0);
if count == 0 {
return 0.2;
}
let score = (count as f64).ln() / 10.0;
score.min(1.0).max(0.0)
}
fn distance_score(&self, query: &str, result: &X86CompletionResult) -> f64 {
if query.is_empty() || !self.fuzzy_enabled {
return 0.5; }
let target = &result.display_text;
let edit_dist = levenshtein_distance(&query.to_lowercase(), &target.to_lowercase());
let max_len = query.len().max(target.len()).max(1) as f64;
let similarity = 1.0 - (edit_dist as f64 / max_len);
if similarity < self.fuzzy_threshold {
return 0.0;
}
similarity
}
fn context_relevance_score(
&self,
result: &X86CompletionResult,
context: &X86CompletionContext,
) -> f64 {
match context {
X86CompletionContext::DotAccess { .. } | X86CompletionContext::ArrowAccess { .. } => {
match result.kind {
X86CompletionKind::Field
| X86CompletionKind::StaticMember
| X86CompletionKind::InheritedMember => 1.0,
X86CompletionKind::Function => 0.6,
_ => 0.1,
}
}
X86CompletionContext::ScopeResolution { .. } => match result.kind {
X86CompletionKind::Type
| X86CompletionKind::Namespace
| X86CompletionKind::EnumMember
| X86CompletionKind::Function
| X86CompletionKind::Variable
| X86CompletionKind::Constant => 1.0,
_ => 0.3,
},
X86CompletionContext::TypeContext { .. }
| X86CompletionContext::TemplateArgumentContext => match result.kind {
X86CompletionKind::Type
| X86CompletionKind::TemplateType
| X86CompletionKind::TypeParameter
| X86CompletionKind::Namespace => 1.0,
_ => 0.1,
},
X86CompletionContext::DirectiveContext { .. } => {
if matches!(result.kind, X86CompletionKind::Directive) {
1.0
} else {
0.0
}
}
X86CompletionContext::IncludeContext { .. }
| X86CompletionContext::StringContext { .. } => {
if matches!(result.kind, X86CompletionKind::File) {
1.0
} else {
0.0
}
}
X86CompletionContext::ReturnContext => match result.kind {
X86CompletionKind::Variable
| X86CompletionKind::LocalVariable
| X86CompletionKind::GlobalVariable
| X86CompletionKind::Parameter
| X86CompletionKind::Function
| X86CompletionKind::Constant => 0.8,
_ => 0.2,
},
X86CompletionContext::CaseContext => {
if matches!(
result.kind,
X86CompletionKind::EnumMember | X86CompletionKind::Constant
) {
1.0
} else {
0.2
}
}
X86CompletionContext::EnumBody { .. } => {
if matches!(result.kind, X86CompletionKind::EnumMember) {
1.0
} else {
0.1
}
}
X86CompletionContext::DeclarationContext {
in_class_body: true,
..
} => match result.kind {
X86CompletionKind::Keyword
| X86CompletionKind::Type
| X86CompletionKind::Function
| X86CompletionKind::Constructor
| X86CompletionKind::Destructor
| X86CompletionKind::Field
| X86CompletionKind::Snippet
| X86CompletionKind::Operator => 0.8,
_ => 0.3,
},
_ => 0.5, }
}
}
pub fn levenshtein_distance(a: &str, b: &str) -> usize {
let a_chars: Vec<char> = a.chars().collect();
let b_chars: Vec<char> = b.chars().collect();
let a_len = a_chars.len();
let b_len = b_chars.len();
if a_len == 0 {
return b_len;
}
if b_len == 0 {
return a_len;
}
let mut prev_row: Vec<usize> = (0..=b_len).collect();
let mut curr_row = vec![0usize; b_len + 1];
for i in 1..=a_len {
curr_row[0] = i;
for j in 1..=b_len {
let cost = if a_chars[i - 1] == b_chars[j - 1] {
0
} else {
1
};
curr_row[j] = (prev_row[j] + 1) .min(curr_row[j - 1] + 1) .min(prev_row[j - 1] + cost); }
std::mem::swap(&mut prev_row, &mut curr_row);
}
prev_row[b_len]
}
pub fn damerau_levenshtein_distance(a: &str, b: &str) -> usize {
let a_chars: Vec<char> = a.chars().collect();
let b_chars: Vec<char> = b.chars().collect();
let a_len = a_chars.len();
let b_len = b_chars.len();
if a_len == 0 {
return b_len;
}
if b_len == 0 {
return a_len;
}
let mut d = vec![vec![0usize; b_len + 1]; a_len + 1];
for i in 0..=a_len {
d[i][0] = i;
}
for j in 0..=b_len {
d[0][j] = j;
}
for i in 1..=a_len {
for j in 1..=b_len {
let cost = if a_chars[i - 1] == b_chars[j - 1] {
0
} else {
1
};
d[i][j] = (d[i - 1][j] + 1) .min(d[i][j - 1] + 1) .min(d[i - 1][j - 1] + cost);
if i > 1
&& j > 1
&& a_chars[i - 1] == b_chars[j - 2]
&& a_chars[i - 2] == b_chars[j - 1]
{
d[i][j] = d[i][j].min(d[i - 2][j - 2] + cost);
}
}
}
d[a_len][b_len]
}
#[derive(Debug, Clone)]
pub struct X86KeywordDatabase {
c_keywords: Vec<(&'static str, &'static str)>,
cpp_keywords: Vec<(&'static str, &'static str)>,
type_specifiers: Vec<(&'static str, &'static str)>,
type_qualifiers: Vec<(&'static str, &'static str)>,
storage_class_specifiers: Vec<(&'static str, &'static str)>,
}
impl Default for X86KeywordDatabase {
fn default() -> Self {
Self {
c_keywords: vec![
("auto", "Automatic storage duration"),
("break", "Exit from loop or switch"),
("case", "Case label in switch statement"),
("const", "Const-qualified type"),
("continue", "Continue to next loop iteration"),
("default", "Default case label"),
("do", "Do-while loop"),
("else", "Alternative branch of if statement"),
("enum", "Enumeration type"),
("extern", "External linkage"),
("for", "For loop"),
("goto", "Unconditional jump"),
("if", "Conditional statement"),
("inline", "Inline function specifier (C99)"),
("register", "Register storage class"),
("restrict", "Restrict-qualified pointer (C99)"),
("return", "Return from function"),
("signed", "Signed integer type specifier"),
("sizeof", "Size of type or expression"),
("static", "Static storage duration"),
("struct", "Structure type"),
("switch", "Switch statement"),
("typedef", "Type definition"),
("union", "Union type"),
("unsigned", "Unsigned integer type specifier"),
("void", "Void type"),
("volatile", "Volatile-qualified type"),
("while", "While loop"),
("_Alignas", "Alignment specifier (C11)"),
("_Alignof", "Alignment query (C11)"),
("_Atomic", "Atomic type specifier (C11)"),
("_Bool", "Boolean type (C99)"),
("_Complex", "Complex type (C99)"),
("_Generic", "Generic selection (C11)"),
("_Imaginary", "Imaginary type (C99)"),
("_Noreturn", "No return specifier (C11)"),
("_Static_assert", "Static assertion (C11)"),
("_Thread_local", "Thread-local storage (C11)"),
],
cpp_keywords: vec![
("alignas", "Alignment specifier (C++11)"),
("alignof", "Alignment query (C++11)"),
("and", "Logical AND alternative token"),
("and_eq", "Bitwise AND assignment alternative"),
("asm", "Inline assembly"),
("bitand", "Bitwise AND alternative"),
("bitor", "Bitwise OR alternative"),
("bool", "Boolean type"),
("catch", "Exception handler"),
("char8_t", "UTF-8 character type (C++20)"),
("char16_t", "UTF-16 character type (C++11)"),
("char32_t", "UTF-32 character type (C++11)"),
("class", "Class type"),
("compl", "Bitwise complement alternative"),
("concept", "Concept definition (C++20)"),
("const_cast", "Const cast operator"),
("consteval", "Immediate function (C++20)"),
("constexpr", "Constant expression specifier (C++11)"),
("constinit", "Constant initialization (C++20)"),
("co_await", "Coroutine await (C++20)"),
("co_return", "Coroutine return (C++20)"),
("co_yield", "Coroutine yield (C++20)"),
("decltype", "Declared type specifier (C++11)"),
("delete", "Delete operator / deleted function"),
("dynamic_cast", "Dynamic cast operator"),
("explicit", "Explicit constructor"),
("export", "Export declaration"),
("false", "Boolean false literal"),
("friend", "Friend declaration"),
("mutable", "Mutable data member"),
("namespace", "Namespace declaration"),
("new", "New operator"),
("noexcept", "Noexcept specifier (C++11)"),
("not", "Logical NOT alternative"),
("not_eq", "Not equal alternative"),
("nullptr", "Null pointer literal (C++11)"),
("operator", "Operator function"),
("or", "Logical OR alternative"),
("or_eq", "Bitwise OR assignment alternative"),
("private", "Private access specifier"),
("protected", "Protected access specifier"),
("public", "Public access specifier"),
("reinterpret_cast", "Reinterpret cast operator"),
("requires", "Requires clause (C++20)"),
("static_assert", "Static assertion (C++11)"),
("static_cast", "Static cast operator"),
("template", "Template declaration"),
("this", "This pointer"),
("thread_local", "Thread-local storage (C++11)"),
("throw", "Throw exception"),
("true", "Boolean true literal"),
("try", "Try block"),
("typeid", "Type identification"),
("typename", "Type name specifier"),
("using", "Using declaration/directive"),
("virtual", "Virtual function specifier"),
("wchar_t", "Wide character type"),
("xor", "Bitwise XOR alternative"),
("xor_eq", "Bitwise XOR assignment alternative"),
],
type_specifiers: vec![
("char", "Character type (1 byte)"),
("signed char", "Signed character type"),
("unsigned char", "Unsigned character type"),
("short", "Short integer (usually 2 bytes)"),
("short int", "Short integer"),
("signed short", "Signed short integer"),
("signed short int", "Signed short integer"),
("unsigned short", "Unsigned short integer"),
("unsigned short int", "Unsigned short integer"),
("int", "Integer type (usually 4 bytes)"),
("signed", "Signed integer"),
("signed int", "Signed integer"),
("unsigned", "Unsigned integer"),
("unsigned int", "Unsigned integer"),
("long", "Long integer (4 or 8 bytes)"),
("long int", "Long integer"),
("signed long", "Signed long integer"),
("signed long int", "Signed long integer"),
("unsigned long", "Unsigned long integer"),
("unsigned long int", "Unsigned long integer"),
("long long", "Long long integer (8 bytes)"),
("long long int", "Long long integer"),
("signed long long", "Signed long long integer"),
("signed long long int", "Signed long long integer"),
("unsigned long long", "Unsigned long long integer"),
("unsigned long long int", "Unsigned long long integer"),
("float", "Single-precision floating point"),
("double", "Double-precision floating point"),
("long double", "Extended-precision floating point"),
("void", "Empty type"),
("bool", "Boolean type (C++ / C99 _Bool)"),
("_Bool", "Boolean type (C99)"),
("_Complex float", "Complex float type (C99)"),
("_Complex double", "Complex double type (C99)"),
("_Complex long double", "Complex long double type (C99)"),
("wchar_t", "Wide character type"),
("char16_t", "UTF-16 character type"),
("char32_t", "UTF-32 character type"),
("char8_t", "UTF-8 character type (C++20)"),
("size_t", "Unsigned integer result of sizeof"),
("ptrdiff_t", "Signed integer result of pointer subtraction"),
("intptr_t", "Signed integer capable of holding a pointer"),
("uintptr_t", "Unsigned integer capable of holding a pointer"),
("intmax_t", "Maximum-width signed integer"),
("uintmax_t", "Maximum-width unsigned integer"),
("int8_t", "Signed 8-bit integer"),
("int16_t", "Signed 16-bit integer"),
("int32_t", "Signed 32-bit integer"),
("int64_t", "Signed 64-bit integer"),
("uint8_t", "Unsigned 8-bit integer"),
("uint16_t", "Unsigned 16-bit integer"),
("uint32_t", "Unsigned 32-bit integer"),
("uint64_t", "Unsigned 64-bit integer"),
],
type_qualifiers: vec![
("const", "Constant type qualifier"),
("volatile", "Volatile type qualifier"),
("restrict", "Restrict pointer qualifier (C99)"),
(
"__restrict",
"Restrict pointer qualifier (compiler extension)",
),
("__restrict__", "Restrict pointer qualifier (GNU extension)"),
("_Atomic", "Atomic type qualifier (C11)"),
],
storage_class_specifiers: vec![
("auto", "Automatic storage duration (C++11: type deduction)"),
("register", "Register storage class hint"),
("static", "Static storage duration"),
("extern", "External linkage"),
("typedef", "Type alias definition"),
("_Thread_local", "Thread-local storage duration (C11)"),
("thread_local", "Thread-local storage duration (C++11)"),
("mutable", "Mutable data member (C++)"),
],
}
}
}
impl X86KeywordDatabase {
pub fn c_keywords(&self) -> Vec<X86CompletionResult> {
self.c_keywords
.iter()
.map(|(name, doc)| {
let mut item = X86CompletionResult::keyword(name);
item.documentation = Some(doc.to_string());
item
})
.collect()
}
pub fn cpp_keywords(&self) -> Vec<X86CompletionResult> {
self.cpp_keywords
.iter()
.map(|(name, doc)| {
let mut item = X86CompletionResult::keyword(name);
item.documentation = Some(doc.to_string());
item
})
.collect()
}
pub fn type_specifiers(&self) -> Vec<X86CompletionResult> {
self.type_specifiers
.iter()
.map(|(name, doc)| {
let mut item = X86CompletionResult::type_(name, Some(doc));
item.kind = X86CompletionKind::Type;
item
})
.collect()
}
pub fn type_qualifiers(&self) -> Vec<X86CompletionResult> {
self.type_qualifiers
.iter()
.map(|(name, doc)| {
let mut item = X86CompletionResult::keyword(name);
item.documentation = Some(doc.to_string());
item
})
.collect()
}
pub fn storage_classes(&self) -> Vec<X86CompletionResult> {
self.storage_class_specifiers
.iter()
.map(|(name, doc)| {
let mut item = X86CompletionResult::keyword(name);
item.documentation = Some(doc.to_string());
item
})
.collect()
}
pub fn all_keywords(&self) -> Vec<X86CompletionResult> {
let mut all = self.c_keywords();
all.extend(self.cpp_keywords());
all.extend(self.type_qualifiers());
all.extend(self.storage_classes());
all
}
}
#[derive(Debug, Clone, Default)]
pub struct X86DirectiveDatabase {
directives: Vec<(&'static str, &'static str)>,
}
impl X86DirectiveDatabase {
pub fn new() -> Self {
Self {
directives: vec![
("include", "#include — Include a header file"),
(
"include_next",
"#include_next — Include next matching header (GNU)",
),
("define", "#define — Define a macro"),
("undef", "#undef — Undefine a macro"),
("if", "#if — Conditional compilation"),
("ifdef", "#ifdef — Conditional on defined macro"),
("ifndef", "#ifndef — Conditional on undefined macro"),
("elif", "#elif — Else-if conditional"),
("elifdef", "#elifdef — Else-if defined (C++23)"),
("elifndef", "#elifndef — Else-if not defined (C++23)"),
("else", "#else — Alternative conditional branch"),
("endif", "#endif — End conditional block"),
("error", "#error — Emit compilation error"),
("warning", "#warning — Emit compilation warning (GNU)"),
("pragma", "#pragma — Compiler-specific directive"),
("line", "#line — Set line number and filename"),
("import", "#import — Import header (Objective-C / MSVC)"),
("using", "#using — Import metadata (C++/CLI)"),
],
}
}
pub fn all_directives(&self) -> Vec<X86CompletionResult> {
self.directives
.iter()
.map(|(name, doc)| X86CompletionResult::directive(name, doc))
.collect()
}
pub fn get(&self, name: &str) -> Option<X86CompletionResult> {
self.directives
.iter()
.find(|(n, _)| *n == name)
.map(|(name, doc)| X86CompletionResult::directive(name, doc))
}
}
#[derive(Debug, Clone, Default)]
pub struct X86BuiltinMacroDatabase {
macros: Vec<(&'static str, &'static str)>,
}
impl X86BuiltinMacroDatabase {
pub fn new() -> Self {
Self {
macros: vec![
(
"__cplusplus",
"Defined in C++ translation units (value is standard year)",
),
("__STDC__", "Defined in C conforming implementations"),
(
"__STDC_VERSION__",
"C standard version (e.g., 201112L for C11)",
),
("__STDC_HOSTED__", "1 for hosted, 0 for freestanding"),
("__FILE__", "Current source filename as a string literal"),
("__LINE__", "Current source line number as an integer"),
("__DATE__", "Compilation date as a string literal"),
("__TIME__", "Compilation time as a string literal"),
("__func__", "Current function name (C99)"),
("__FUNCTION__", "Current function name (GNU/MSVC)"),
("__PRETTY_FUNCTION__", "Decorated function name (GNU)"),
("__TIMESTAMP__", "Last modification timestamp (MSVC)"),
("__COUNTER__", "Incrementing counter (GNU/MSVC)"),
("__has_include", "Check header availability (C++17)"),
("__has_include_next", "Check next header availability"),
(
"__has_cpp_attribute",
"Check attribute availability (C++20)",
),
("__has_builtin", "Check builtin function availability"),
("__has_feature", "Check compiler feature (Clang)"),
("__has_extension", "Check compiler extension (Clang)"),
("__has_attribute", "Check attribute availability"),
("__has_declspec_attribute", "Check declspec attribute"),
("__has_warning", "Check warning flag availability (Clang)"),
("__BASE_FILE__", "Base source filename (GNU)"),
("__INCLUDE_LEVEL__", "Include nesting level (GNU)"),
("__ELF__", "Defined for ELF targets"),
("__x86_64__", "Defined for x86-64 targets"),
("__i386__", "Defined for x86 32-bit targets"),
("__i686__", "Defined for i686 targets"),
("__SSE__", "SSE support available"),
("__SSE2__", "SSE2 support available"),
("__SSE3__", "SSE3 support available"),
("__SSSE3__", "SSSE3 support available"),
("__SSE4_1__", "SSE4.1 support available"),
("__SSE4_2__", "SSE4.2 support available"),
("__AVX__", "AVX support available"),
("__AVX2__", "AVX2 support available"),
("__AVX512F__", "AVX-512 Foundation available"),
("__MMX__", "MMX support available"),
("__AES__", "AES-NI support available"),
("__PCLMUL__", "PCLMUL support available"),
("__RDRND__", "RDRAND support available"),
("__FMA__", "FMA support available"),
("__BMI__", "BMI support available"),
("__BMI2__", "BMI2 support available"),
("__LZCNT__", "LZCNT support available"),
("__POPCNT__", "POPCNT support available"),
],
}
}
pub fn all_macros(&self) -> Vec<X86CompletionResult> {
self.macros
.iter()
.map(|(name, doc)| X86CompletionResult::macro_(name, Some(doc)))
.collect()
}
}
#[derive(Debug, Clone, Default)]
pub struct X86SnippetDatabase {
snippets: Vec<X86SnippetDef>,
}
#[derive(Debug, Clone)]
struct X86SnippetDef {
label: &'static str,
insert: &'static str,
doc: &'static str,
}
impl X86SnippetDatabase {
pub fn new() -> Self {
Self {
snippets: vec${3: -> ${4:auto}} {\n\t${5:}\n}",
doc: "Lambda expression (C++11)",
},
X86SnippetDef {
label: "main function",
insert: "int main(int argc, char* argv[]) {\n\t${1:}\n\treturn 0;\n}",
doc: "Main function signature",
},
X86SnippetDef {
label: "include guard",
insert: "#ifndef ${1:HEADER_NAME}_H\n#define ${1:HEADER_NAME}_H\n\n${2:}\n\n#endif // ${1:HEADER_NAME}_H",
doc: "Header include guard",
},
X86SnippetDef {
label: "#pragma once",
insert: "#pragma once\n\n${1:}",
doc: "Pragma once header guard",
},
X86SnippetDef {
label: "operator overload",
insert: "${1:ReturnType} operator${2:+}(${3:const ${4:Type}& other}) {\n\t${5:}\n}",
doc: "Operator overload (C++)",
},
X86SnippetDef {
label: "static_assert",
insert: "static_assert(${1:condition}, \"${2:message}\");",
doc: "Static assertion (C++11)",
},
X86SnippetDef {
label: "typedef",
insert: "typedef ${1:existing_type} ${2:new_name};",
doc: "Type alias (C)",
},
X86SnippetDef {
label: "using alias (C++11)",
insert: "using ${1:new_name} = ${2:existing_type};",
doc: "Type alias (C++11)",
},
],
}
}
pub fn all_snippets(&self) -> Vec<X86CompletionResult> {
self.snippets
.iter()
.map(|s| X86CompletionResult::snippet(s.label, s.insert, s.doc))
.collect()
}
pub fn search(&self, query: &str) -> Vec<X86CompletionResult> {
let lower = query.to_lowercase();
self.snippets
.iter()
.filter(|s| s.label.to_lowercase().contains(&lower))
.map(|s| X86CompletionResult::snippet(s.label, s.insert, s.doc))
.collect()
}
}
#[derive(Debug, Clone)]
pub struct X86TypeCompletion {
types: Vec<X86TypeEntry>,
keyword_db: X86KeywordDatabase,
}
#[derive(Debug, Clone)]
struct X86TypeEntry {
name: String,
kind: X86CompletionKind,
doc: String,
header: Option<String>,
scope: Option<String>,
}
impl Default for X86TypeCompletion {
fn default() -> Self {
Self {
types: Vec::new(),
keyword_db: X86KeywordDatabase::default(),
}
}
}
impl X86TypeCompletion {
pub fn new() -> Self {
Self::default()
}
pub fn register_type(
&mut self,
name: &str,
kind: X86CompletionKind,
doc: &str,
header: Option<&str>,
scope: Option<&str>,
) {
self.types.push(X86TypeEntry {
name: name.to_string(),
kind,
doc: doc.to_string(),
header: header.map(|s| s.to_string()),
scope: scope.map(|s| s.to_string()),
});
}
pub fn register_struct(&mut self, name: &str, doc: &str) {
self.register_type(name, X86CompletionKind::Type, doc, None, None);
}
pub fn register_enum(&mut self, name: &str, doc: &str) {
self.register_type(name, X86CompletionKind::Type, doc, None, None);
}
pub fn register_union(&mut self, name: &str, doc: &str) {
self.register_type(name, X86CompletionKind::Type, doc, None, None);
}
pub fn register_template_type(&mut self, name: &str, doc: &str) {
self.register_type(name, X86CompletionKind::TemplateType, doc, None, None);
}
pub fn register_typedef(&mut self, name: &str, underlying: &str, header: Option<&str>) {
self.register_type(
name,
X86CompletionKind::Type,
&format!("typedef {} {}", underlying, name),
header,
None,
);
}
pub fn complete(&self, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
let mut results: Vec<X86CompletionResult> = Vec::new();
for item in self.keyword_db.type_specifiers() {
if lower.is_empty() || item.display_text.to_lowercase().starts_with(&lower) {
results.push(item);
}
}
for entry in &self.types {
if lower.is_empty() || entry.name.to_lowercase().starts_with(&lower) {
let mut item = X86CompletionResult::type_(&entry.name, Some(&entry.doc));
item.kind = entry.kind;
if let Some(ref h) = entry.header {
item.required_header = Some(h.clone());
}
if let Some(ref s) = entry.scope {
item.scope = Some(s.clone());
}
results.push(item);
}
}
results
}
pub fn complete_fuzzy(&self, prefix: &str) -> Vec<X86CompletionResult> {
let mut results = self.complete(prefix);
if prefix.len() >= 2 {
let lower = prefix.to_lowercase();
for item in self.keyword_db.type_specifiers() {
let item_lower = item.display_text.to_lowercase();
if !item_lower.starts_with(&lower) && levenshtein_distance(&lower, &item_lower) <= 2
{
results.push(item);
}
}
for entry in &self.types {
let entry_lower = entry.name.to_lowercase();
if !entry_lower.starts_with(&lower)
&& levenshtein_distance(&lower, &entry_lower) <= 2
{
let mut item = X86CompletionResult::type_(&entry.name, Some(&entry.doc));
item.kind = entry.kind;
item.priority -= 10; results.push(item);
}
}
}
results
}
}
#[derive(Debug, Clone, Default)]
pub struct X86MemberCompletion {
members: HashMap<String, Vec<X86MemberEntry>>,
inheritance: HashMap<String, Vec<String>>,
static_members: HashMap<String, Vec<X86MemberEntry>>,
}
#[derive(Debug, Clone)]
struct X86MemberEntry {
name: String,
member_type: String,
kind: X86CompletionKind,
doc: Option<String>,
is_static: bool,
visibility: X86SymbolVisibility,
is_virtual: bool,
is_const: bool,
parameters: Vec<X86ParameterInfo>,
return_type: Option<String>,
}
impl X86MemberCompletion {
pub fn new() -> Self {
Self::default()
}
pub fn register_field(
&mut self,
type_name: &str,
field_name: &str,
field_type: &str,
doc: Option<&str>,
visibility: X86SymbolVisibility,
) {
let entry = X86MemberEntry {
name: field_name.to_string(),
member_type: field_type.to_string(),
kind: X86CompletionKind::Field,
doc: doc.map(|s| s.to_string()),
is_static: false,
visibility,
is_virtual: false,
is_const: false,
parameters: Vec::new(),
return_type: Some(field_type.to_string()),
};
self.members
.entry(type_name.to_string())
.or_default()
.push(entry);
}
pub fn register_method(
&mut self,
type_name: &str,
method_name: &str,
ret: &str,
params: &[(&str, &str)],
doc: Option<&str>,
visibility: X86SymbolVisibility,
is_static: bool,
is_virtual: bool,
is_const: bool,
) {
let param_infos: Vec<X86ParameterInfo> = params
.iter()
.map(|(pt, pn)| X86ParameterInfo {
name: pn.to_string(),
param_type: pt.to_string(),
default_value: None,
is_variadic: false,
})
.collect();
let entry = X86MemberEntry {
name: method_name.to_string(),
member_type: "function".to_string(),
kind: if is_static {
X86CompletionKind::StaticMember
} else {
X86CompletionKind::Function
},
doc: doc.map(|s| s.to_string()),
is_static,
visibility,
is_virtual,
is_const,
parameters: param_infos,
return_type: Some(ret.to_string()),
};
if is_static {
self.static_members
.entry(type_name.to_string())
.or_default()
.push(entry);
} else {
self.members
.entry(type_name.to_string())
.or_default()
.push(entry);
}
}
pub fn register_inheritance(&mut self, derived: &str, base: &str) {
self.inheritance
.entry(derived.to_string())
.or_default()
.push(base.to_string());
}
pub fn complete_members(
&self,
type_name: &str,
_prefix: &str,
_is_pointer: bool,
) -> Vec<X86CompletionResult> {
let lower = _prefix.to_lowercase();
let mut results: Vec<X86CompletionResult> = Vec::new();
if let Some(members) = self.members.get(type_name) {
for entry in members {
if lower.is_empty() || entry.name.to_lowercase().starts_with(&lower) {
let mut item = if entry.kind == X86CompletionKind::Function
|| entry.kind == X86CompletionKind::StaticMember
{
let param_refs: Vec<(&str, &str)> = entry
.parameters
.iter()
.map(|p| (p.param_type.as_str(), p.name.as_str()))
.collect();
let mut f = X86CompletionResult::function(
&entry.name,
entry.return_type.as_deref().unwrap_or("void"),
¶m_refs,
entry.doc.as_deref(),
);
f.kind = entry.kind;
f.is_static = entry.is_static;
f.is_virtual = entry.is_virtual;
f.is_constexpr = entry.is_const;
f.visibility = entry.visibility;
f
} else {
let mut f = X86CompletionResult::field(
&entry.name,
&entry.member_type,
entry.doc.as_deref(),
);
f.visibility = entry.visibility;
f
};
results.push(item);
}
}
}
if let Some(bases) = self.inheritance.get(type_name) {
for base in bases {
let inherited = self.complete_members(base, _prefix, _is_pointer);
for mut item in inherited {
item.kind = if item.kind == X86CompletionKind::Field {
X86CompletionKind::InheritedMember
} else {
X86CompletionKind::InheritedMember
};
item.scope = Some(base.clone());
results.push(item);
}
}
}
if let Some(statics) = self.static_members.get(type_name) {
for entry in statics {
if lower.is_empty() || entry.name.to_lowercase().starts_with(&lower) {
let param_refs: Vec<(&str, &str)> = entry
.parameters
.iter()
.map(|p| (p.param_type.as_str(), p.name.as_str()))
.collect();
let mut item = X86CompletionResult::function(
&entry.name,
entry.return_type.as_deref().unwrap_or("void"),
¶m_refs,
entry.doc.as_deref(),
);
item.kind = X86CompletionKind::StaticMember;
item.is_static = true;
item.visibility = entry.visibility;
results.push(item);
}
}
}
results
}
pub fn complete_static_members(
&self,
type_name: &str,
_prefix: &str,
) -> Vec<X86CompletionResult> {
let lower = _prefix.to_lowercase();
let mut results: Vec<X86CompletionResult> = Vec::new();
if let Some(statics) = self.static_members.get(type_name) {
for entry in statics {
if lower.is_empty() || entry.name.to_lowercase().starts_with(&lower) {
let param_refs: Vec<(&str, &str)> = entry
.parameters
.iter()
.map(|p| (p.param_type.as_str(), p.name.as_str()))
.collect();
let mut item = X86CompletionResult::function(
&entry.name,
entry.return_type.as_deref().unwrap_or("void"),
¶m_refs,
entry.doc.as_deref(),
);
item.kind = X86CompletionKind::StaticMember;
item.is_static = true;
item.visibility = entry.visibility;
results.push(item);
}
}
}
results
}
}
#[derive(Debug, Clone, Default)]
pub struct X86FunctionCompletion {
functions: HashMap<String, Vec<X86FunctionEntry>>,
operators: HashMap<String, Vec<X86FunctionEntry>>,
}
#[derive(Debug, Clone)]
struct X86FunctionEntry {
name: String,
return_type: String,
params: Vec<(String, String)>,
doc: Option<String>,
header: Option<String>,
scope: Option<String>,
is_template: bool,
template_params: Vec<String>,
is_noexcept: bool,
is_const: bool,
is_virtual: bool,
}
impl X86FunctionCompletion {
pub fn new() -> Self {
Self::default()
}
pub fn register_function(
&mut self,
name: &str,
ret: &str,
params: &[(&str, &str)],
doc: Option<&str>,
header: Option<&str>,
scope: Option<&str>,
) {
let entry = X86FunctionEntry {
name: name.to_string(),
return_type: ret.to_string(),
params: params
.iter()
.map(|(t, n)| (t.to_string(), n.to_string()))
.collect(),
doc: doc.map(|s| s.to_string()),
header: header.map(|s| s.to_string()),
scope: scope.map(|s| s.to_string()),
is_template: false,
template_params: Vec::new(),
is_noexcept: false,
is_const: false,
is_virtual: false,
};
self.functions
.entry(name.to_string())
.or_default()
.push(entry);
}
pub fn register_template_function(
&mut self,
name: &str,
ret: &str,
params: &[(&str, &str)],
template_params: &[&str],
doc: Option<&str>,
header: Option<&str>,
) {
let entry = X86FunctionEntry {
name: name.to_string(),
return_type: ret.to_string(),
params: params
.iter()
.map(|(t, n)| (t.to_string(), n.to_string()))
.collect(),
doc: doc.map(|s| s.to_string()),
header: header.map(|s| s.to_string()),
scope: None,
is_template: true,
template_params: template_params.iter().map(|s| s.to_string()).collect(),
is_noexcept: false,
is_const: false,
is_virtual: false,
};
self.functions
.entry(name.to_string())
.or_default()
.push(entry);
}
pub fn register_operator(
&mut self,
op: &str,
ret: &str,
params: &[(&str, &str)],
doc: Option<&str>,
) {
let entry = X86FunctionEntry {
name: format!("operator{}", op),
return_type: ret.to_string(),
params: params
.iter()
.map(|(t, n)| (t.to_string(), n.to_string()))
.collect(),
doc: doc.map(|s| s.to_string()),
header: None,
scope: None,
is_template: false,
template_params: Vec::new(),
is_noexcept: false,
is_const: false,
is_virtual: false,
};
self.operators
.entry(op.to_string())
.or_default()
.push(entry);
}
pub fn register_std_functions(&mut self) {
self.register_function(
"printf",
"int",
&[("const char*", "format"), ("...", "...")],
Some("Print formatted output to stdout"),
Some("stdio.h"),
None,
);
self.register_function(
"scanf",
"int",
&[("const char*", "format"), ("...", "...")],
Some("Read formatted input from stdin"),
Some("stdio.h"),
None,
);
self.register_function(
"fopen",
"FILE*",
&[("const char*", "filename"), ("const char*", "mode")],
Some("Open a file"),
Some("stdio.h"),
None,
);
self.register_function(
"fclose",
"int",
&[("FILE*", "stream")],
Some("Close a file"),
Some("stdio.h"),
None,
);
self.register_function(
"fprintf",
"int",
&[
("FILE*", "stream"),
("const char*", "format"),
("...", "..."),
],
Some("Print formatted output to stream"),
Some("stdio.h"),
None,
);
self.register_function(
"sprintf",
"int",
&[("char*", "str"), ("const char*", "format"), ("...", "...")],
Some("Print formatted output to string"),
Some("stdio.h"),
None,
);
self.register_function(
"snprintf",
"int",
&[
("char*", "str"),
("size_t", "size"),
("const char*", "format"),
("...", "..."),
],
Some("Print formatted output to string with size limit"),
Some("stdio.h"),
None,
);
self.register_function(
"fgets",
"char*",
&[("char*", "str"), ("int", "n"), ("FILE*", "stream")],
Some("Get string from stream"),
Some("stdio.h"),
None,
);
self.register_function(
"fputs",
"int",
&[("const char*", "str"), ("FILE*", "stream")],
Some("Write string to stream"),
Some("stdio.h"),
None,
);
self.register_function(
"puts",
"int",
&[("const char*", "str")],
Some("Write string to stdout"),
Some("stdio.h"),
None,
);
self.register_function(
"gets",
"char*",
&[("char*", "str")],
Some("Read string from stdin (deprecated)"),
Some("stdio.h"),
None,
);
self.register_function(
"fread",
"size_t",
&[
("void*", "ptr"),
("size_t", "size"),
("size_t", "nmemb"),
("FILE*", "stream"),
],
Some("Read from stream"),
Some("stdio.h"),
None,
);
self.register_function(
"fwrite",
"size_t",
&[
("const void*", "ptr"),
("size_t", "size"),
("size_t", "nmemb"),
("FILE*", "stream"),
],
Some("Write to stream"),
Some("stdio.h"),
None,
);
self.register_function(
"malloc",
"void*",
&[("size_t", "size")],
Some("Allocate memory"),
Some("stdlib.h"),
None,
);
self.register_function(
"calloc",
"void*",
&[("size_t", "nmemb"), ("size_t", "size")],
Some("Allocate zero-initialized memory"),
Some("stdlib.h"),
None,
);
self.register_function(
"realloc",
"void*",
&[("void*", "ptr"), ("size_t", "size")],
Some("Reallocate memory"),
Some("stdlib.h"),
None,
);
self.register_function(
"free",
"void",
&[("void*", "ptr")],
Some("Free allocated memory"),
Some("stdlib.h"),
None,
);
self.register_function(
"atoi",
"int",
&[("const char*", "str")],
Some("Convert string to integer"),
Some("stdlib.h"),
None,
);
self.register_function(
"atol",
"long",
&[("const char*", "str")],
Some("Convert string to long"),
Some("stdlib.h"),
None,
);
self.register_function(
"atof",
"double",
&[("const char*", "str")],
Some("Convert string to double"),
Some("stdlib.h"),
None,
);
self.register_function(
"strtol",
"long",
&[
("const char*", "str"),
("char**", "endptr"),
("int", "base"),
],
Some("Convert string to long with error detection"),
Some("stdlib.h"),
None,
);
self.register_function(
"strtoul",
"unsigned long",
&[
("const char*", "str"),
("char**", "endptr"),
("int", "base"),
],
Some("Convert string to unsigned long"),
Some("stdlib.h"),
None,
);
self.register_function(
"strtod",
"double",
&[("const char*", "str"), ("char**", "endptr")],
Some("Convert string to double with error detection"),
Some("stdlib.h"),
None,
);
self.register_function(
"rand",
"int",
&[],
Some("Generate random number"),
Some("stdlib.h"),
None,
);
self.register_function(
"srand",
"void",
&[("unsigned int", "seed")],
Some("Seed random number generator"),
Some("stdlib.h"),
None,
);
self.register_function(
"qsort",
"void",
&[
("void*", "base"),
("size_t", "nmemb"),
("size_t", "size"),
("int (*)(const void*, const void*)", "compar"),
],
Some("Sort array"),
Some("stdlib.h"),
None,
);
self.register_function(
"bsearch",
"void*",
&[
("const void*", "key"),
("const void*", "base"),
("size_t", "nmemb"),
("size_t", "size"),
("int (*)(const void*, const void*)", "compar"),
],
Some("Binary search array"),
Some("stdlib.h"),
None,
);
self.register_function(
"exit",
"void",
&[("int", "status")],
Some("Terminate program"),
Some("stdlib.h"),
None,
);
self.register_function(
"abort",
"void",
&[],
Some("Abnormal program termination"),
Some("stdlib.h"),
None,
);
self.register_function(
"abs",
"int",
&[("int", "n")],
Some("Absolute value of int"),
Some("stdlib.h"),
None,
);
self.register_function(
"labs",
"long",
&[("long", "n")],
Some("Absolute value of long"),
Some("stdlib.h"),
None,
);
self.register_function(
"strcpy",
"char*",
&[("char*", "dest"), ("const char*", "src")],
Some("Copy string"),
Some("string.h"),
None,
);
self.register_function(
"strncpy",
"char*",
&[("char*", "dest"), ("const char*", "src"), ("size_t", "n")],
Some("Copy n characters of string"),
Some("string.h"),
None,
);
self.register_function(
"strcat",
"char*",
&[("char*", "dest"), ("const char*", "src")],
Some("Concatenate strings"),
Some("string.h"),
None,
);
self.register_function(
"strncat",
"char*",
&[("char*", "dest"), ("const char*", "src"), ("size_t", "n")],
Some("Concatenate n characters of string"),
Some("string.h"),
None,
);
self.register_function(
"strlen",
"size_t",
&[("const char*", "str")],
Some("Get string length"),
Some("string.h"),
None,
);
self.register_function(
"strcmp",
"int",
&[("const char*", "s1"), ("const char*", "s2")],
Some("Compare strings"),
Some("string.h"),
None,
);
self.register_function(
"strncmp",
"int",
&[
("const char*", "s1"),
("const char*", "s2"),
("size_t", "n"),
],
Some("Compare n characters of strings"),
Some("string.h"),
None,
);
self.register_function(
"strchr",
"char*",
&[("const char*", "str"), ("int", "c")],
Some("Find character in string"),
Some("string.h"),
None,
);
self.register_function(
"strrchr",
"char*",
&[("const char*", "str"), ("int", "c")],
Some("Find last character in string"),
Some("string.h"),
None,
);
self.register_function(
"strstr",
"char*",
&[("const char*", "haystack"), ("const char*", "needle")],
Some("Find substring"),
Some("string.h"),
None,
);
self.register_function(
"strtok",
"char*",
&[("char*", "str"), ("const char*", "delim")],
Some("Tokenize string"),
Some("string.h"),
None,
);
self.register_function(
"memset",
"void*",
&[("void*", "ptr"), ("int", "value"), ("size_t", "num")],
Some("Set memory to value"),
Some("string.h"),
None,
);
self.register_function(
"memcpy",
"void*",
&[("void*", "dest"), ("const void*", "src"), ("size_t", "num")],
Some("Copy memory"),
Some("string.h"),
None,
);
self.register_function(
"memmove",
"void*",
&[("void*", "dest"), ("const void*", "src"), ("size_t", "num")],
Some("Move memory (safe for overlap)"),
Some("string.h"),
None,
);
self.register_function(
"memcmp",
"int",
&[
("const void*", "ptr1"),
("const void*", "ptr2"),
("size_t", "num"),
],
Some("Compare memory"),
Some("string.h"),
None,
);
self.register_function(
"memchr",
"void*",
&[("const void*", "ptr"), ("int", "value"), ("size_t", "num")],
Some("Find value in memory"),
Some("string.h"),
None,
);
self.register_function(
"sin",
"double",
&[("double", "x")],
Some("Sine"),
Some("math.h"),
None,
);
self.register_function(
"cos",
"double",
&[("double", "x")],
Some("Cosine"),
Some("math.h"),
None,
);
self.register_function(
"tan",
"double",
&[("double", "x")],
Some("Tangent"),
Some("math.h"),
None,
);
self.register_function(
"asin",
"double",
&[("double", "x")],
Some("Arc sine"),
Some("math.h"),
None,
);
self.register_function(
"acos",
"double",
&[("double", "x")],
Some("Arc cosine"),
Some("math.h"),
None,
);
self.register_function(
"atan",
"double",
&[("double", "x")],
Some("Arc tangent"),
Some("math.h"),
None,
);
self.register_function(
"atan2",
"double",
&[("double", "y"), ("double", "x")],
Some("Arc tangent of y/x"),
Some("math.h"),
None,
);
self.register_function(
"sqrt",
"double",
&[("double", "x")],
Some("Square root"),
Some("math.h"),
None,
);
self.register_function(
"pow",
"double",
&[("double", "base"), ("double", "exp")],
Some("Power"),
Some("math.h"),
None,
);
self.register_function(
"exp",
"double",
&[("double", "x")],
Some("Exponential"),
Some("math.h"),
None,
);
self.register_function(
"log",
"double",
&[("double", "x")],
Some("Natural logarithm"),
Some("math.h"),
None,
);
self.register_function(
"log10",
"double",
&[("double", "x")],
Some("Base-10 logarithm"),
Some("math.h"),
None,
);
self.register_function(
"ceil",
"double",
&[("double", "x")],
Some("Ceiling"),
Some("math.h"),
None,
);
self.register_function(
"floor",
"double",
&[("double", "x")],
Some("Floor"),
Some("math.h"),
None,
);
self.register_function(
"fabs",
"double",
&[("double", "x")],
Some("Absolute value of double"),
Some("math.h"),
None,
);
self.register_function(
"fmod",
"double",
&[("double", "x"), ("double", "y")],
Some("Floating-point remainder"),
Some("math.h"),
None,
);
self.register_function(
"isalpha",
"int",
&[("int", "c")],
Some("Check if character is alphabetic"),
Some("ctype.h"),
None,
);
self.register_function(
"isdigit",
"int",
&[("int", "c")],
Some("Check if character is digit"),
Some("ctype.h"),
None,
);
self.register_function(
"isalnum",
"int",
&[("int", "c")],
Some("Check if character is alphanumeric"),
Some("ctype.h"),
None,
);
self.register_function(
"isspace",
"int",
&[("int", "c")],
Some("Check if character is whitespace"),
Some("ctype.h"),
None,
);
self.register_function(
"isupper",
"int",
&[("int", "c")],
Some("Check if character is uppercase"),
Some("ctype.h"),
None,
);
self.register_function(
"islower",
"int",
&[("int", "c")],
Some("Check if character is lowercase"),
Some("ctype.h"),
None,
);
self.register_function(
"toupper",
"int",
&[("int", "c")],
Some("Convert to uppercase"),
Some("ctype.h"),
None,
);
self.register_function(
"tolower",
"int",
&[("int", "c")],
Some("Convert to lowercase"),
Some("ctype.h"),
None,
);
self.register_function(
"time",
"time_t",
&[("time_t*", "t")],
Some("Get current time"),
Some("time.h"),
None,
);
self.register_function(
"clock",
"clock_t",
&[],
Some("Get processor time"),
Some("time.h"),
None,
);
self.register_function(
"difftime",
"double",
&[("time_t", "end"), ("time_t", "begin")],
Some("Compute time difference"),
Some("time.h"),
None,
);
self.register_function(
"signal",
"void (*)(int)",
&[("int", "sig"), ("void (*)(int)", "handler")],
Some("Set signal handler"),
Some("signal.h"),
None,
);
self.register_function(
"raise",
"int",
&[("int", "sig")],
Some("Raise signal"),
Some("signal.h"),
None,
);
self.register_function(
"assert",
"void",
&[("int", "expression")],
Some("Runtime assertion (macro)"),
Some("assert.h"),
None,
);
}
pub fn complete(&self, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
let mut results: Vec<X86CompletionResult> = Vec::new();
for (name, entries) in &self.functions {
if lower.is_empty() || name.to_lowercase().starts_with(&lower) {
for entry in entries {
let param_refs: Vec<(&str, &str)> = entry
.params
.iter()
.map(|(t, n)| (t.as_str(), n.as_str()))
.collect();
let mut item = X86CompletionResult::function(
name,
&entry.return_type,
¶m_refs,
entry.doc.as_deref(),
);
if entry.is_template {
item.kind = X86CompletionKind::TemplateFunction;
item.template_params = entry.template_params.clone();
}
if let Some(ref h) = entry.header {
item.required_header = Some(h.clone());
}
if let Some(ref s) = entry.scope {
item.scope = Some(s.clone());
}
if entry.is_noexcept {
item.is_noexcept = true;
}
results.push(item);
}
}
}
results
}
pub fn complete_operators(&self, op_prefix: &str) -> Vec<X86CompletionResult> {
let mut results: Vec<X86CompletionResult> = Vec::new();
for (op, entries) in &self.operators {
if op.starts_with(op_prefix) || op_prefix.is_empty() {
for entry in entries {
let param_refs: Vec<(&str, &str)> = entry
.params
.iter()
.map(|(t, n)| (t.as_str(), n.as_str()))
.collect();
let item = X86CompletionResult::function(
&entry.name,
&entry.return_type,
¶m_refs,
entry.doc.as_deref(),
);
results.push(item);
}
}
}
results
}
}
#[derive(Debug, Clone, Default)]
pub struct X86VariableCompletion {
variables: Vec<X86VariableEntry>,
}
#[derive(Debug, Clone)]
struct X86VariableEntry {
name: String,
var_type: String,
kind: X86CompletionKind,
doc: Option<String>,
scope: Option<String>,
is_const: bool,
is_static: bool,
}
impl X86VariableCompletion {
pub fn new() -> Self {
Self::default()
}
pub fn register_variable(
&mut self,
name: &str,
var_type: &str,
kind: X86CompletionKind,
doc: Option<&str>,
scope: Option<&str>,
is_const: bool,
is_static: bool,
) {
self.variables.push(X86VariableEntry {
name: name.to_string(),
var_type: var_type.to_string(),
kind,
doc: doc.map(|s| s.to_string()),
scope: scope.map(|s| s.to_string()),
is_const,
is_static,
});
}
pub fn register_local(&mut self, name: &str, var_type: &str, doc: Option<&str>) {
self.register_variable(
name,
var_type,
X86CompletionKind::LocalVariable,
doc,
None,
false,
false,
);
}
pub fn register_global(
&mut self,
name: &str,
var_type: &str,
doc: Option<&str>,
is_const: bool,
) {
self.register_variable(
name,
var_type,
X86CompletionKind::GlobalVariable,
doc,
None,
is_const,
false,
);
}
pub fn register_parameter(&mut self, name: &str, var_type: &str) {
self.register_variable(
name,
var_type,
X86CompletionKind::Parameter,
None,
None,
false,
false,
);
}
pub fn register_static(&mut self, name: &str, var_type: &str, doc: Option<&str>) {
self.register_variable(
name,
var_type,
X86CompletionKind::Variable,
doc,
None,
false,
true,
);
}
pub fn complete(&self, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
self.variables
.iter()
.filter(|v| lower.is_empty() || v.name.to_lowercase().starts_with(&lower))
.map(|v| {
let mut item =
X86CompletionResult::variable(&v.name, &v.var_type, v.doc.as_deref());
item.kind = v.kind;
item.is_static = v.is_static;
item.is_constexpr = v.is_const;
if let Some(ref s) = v.scope {
item.scope = Some(s.clone());
}
item
})
.collect()
}
pub fn complete_by_kind(
&self,
prefix: &str,
kind: X86CompletionKind,
) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
self.variables
.iter()
.filter(|v| {
(lower.is_empty() || v.name.to_lowercase().starts_with(&lower)) && v.kind == kind
})
.map(|v| {
let mut item =
X86CompletionResult::variable(&v.name, &v.var_type, v.doc.as_deref());
item.kind = v.kind;
item.is_static = v.is_static;
item.is_constexpr = v.is_const;
if let Some(ref s) = v.scope {
item.scope = Some(s.clone());
}
item
})
.collect()
}
}
#[derive(Debug, Clone, Default)]
pub struct X86NamespaceCompletion {
namespaces: HashMap<String, X86NamespaceEntry>,
}
#[derive(Debug, Clone, Default)]
struct X86NamespaceEntry {
name: String,
doc: Option<String>,
types: Vec<String>,
functions: Vec<String>,
variables: Vec<String>,
nested_namespaces: Vec<String>,
constants: Vec<String>,
}
impl X86NamespaceCompletion {
pub fn new() -> Self {
Self::default()
}
pub fn register_namespace(&mut self, name: &str, doc: Option<&str>) {
self.namespaces
.entry(name.to_string())
.or_insert(X86NamespaceEntry {
name: name.to_string(),
doc: doc.map(|s| s.to_string()),
types: Vec::new(),
functions: Vec::new(),
variables: Vec::new(),
nested_namespaces: Vec::new(),
constants: Vec::new(),
});
}
pub fn add_type(&mut self, ns: &str, name: &str) {
if let Some(entry) = self.namespaces.get_mut(ns) {
entry.types.push(name.to_string());
}
}
pub fn add_function(&mut self, ns: &str, name: &str) {
if let Some(entry) = self.namespaces.get_mut(ns) {
entry.functions.push(name.to_string());
}
}
pub fn add_variable(&mut self, ns: &str, name: &str) {
if let Some(entry) = self.namespaces.get_mut(ns) {
entry.variables.push(name.to_string());
}
}
pub fn add_nested_namespace(&mut self, ns: &str, child: &str) {
if let Some(entry) = self.namespaces.get_mut(ns) {
entry.nested_namespaces.push(child.to_string());
}
}
pub fn add_constant(&mut self, ns: &str, name: &str) {
if let Some(entry) = self.namespaces.get_mut(ns) {
entry.constants.push(name.to_string());
}
}
pub fn register_std_namespace(&mut self) {
self.register_namespace("std", Some("C++ Standard Library namespace"));
self.add_type("std", "string");
self.add_type("std", "wstring");
self.add_type("std", "u16string");
self.add_type("std", "u32string");
self.add_type("std", "vector");
self.add_type("std", "list");
self.add_type("std", "deque");
self.add_type("std", "forward_list");
self.add_type("std", "set");
self.add_type("std", "multiset");
self.add_type("std", "map");
self.add_type("std", "multimap");
self.add_type("std", "unordered_set");
self.add_type("std", "unordered_multiset");
self.add_type("std", "unordered_map");
self.add_type("std", "unordered_multimap");
self.add_type("std", "stack");
self.add_type("std", "queue");
self.add_type("std", "priority_queue");
self.add_type("std", "array");
self.add_type("std", "pair");
self.add_type("std", "tuple");
self.add_type("std", "optional");
self.add_type("std", "variant");
self.add_type("std", "any");
self.add_type("std", "shared_ptr");
self.add_type("std", "unique_ptr");
self.add_type("std", "weak_ptr");
self.add_type("std", "function");
self.add_type("std", "initializer_list");
self.add_type("std", "string_view");
self.add_type("std", "span");
self.add_type("std", "regex");
self.add_type("std", "thread");
self.add_type("std", "mutex");
self.add_type("std", "lock_guard");
self.add_type("std", "unique_lock");
self.add_type("std", "condition_variable");
self.add_type("std", "atomic");
self.add_type("std", "future");
self.add_type("std", "promise");
self.add_type("std", "istream");
self.add_type("std", "ostream");
self.add_type("std", "iostream");
self.add_type("std", "fstream");
self.add_type("std", "stringstream");
self.add_type("std", "ifstream");
self.add_type("std", "ofstream");
self.add_type("std", "filesystem::path");
self.add_type("std", "complex");
self.add_type("std", "valarray");
self.add_function("std", "move");
self.add_function("std", "forward");
self.add_function("std", "swap");
self.add_function("std", "make_shared");
self.add_function("std", "make_unique");
self.add_function("std", "make_pair");
self.add_function("std", "make_tuple");
self.add_function("std", "tie");
self.add_function("std", "get");
self.add_function("std", "getline");
self.add_function("std", "stoi");
self.add_function("std", "stol");
self.add_function("std", "stoul");
self.add_function("std", "stoll");
self.add_function("std", "stoull");
self.add_function("std", "stof");
self.add_function("std", "stod");
self.add_function("std", "stold");
self.add_function("std", "to_string");
self.add_function("std", "to_wstring");
self.add_constant("std", "nullopt");
self.add_constant("std", "nullptr_t");
self.add_nested_namespace("std", "chrono");
self.add_nested_namespace("std", "filesystem");
self.add_nested_namespace("std", "literals");
self.add_nested_namespace("std", "placeholders");
self.add_nested_namespace("std", "ranges");
self.add_nested_namespace("std", "views");
self.add_nested_namespace("std", "pmr");
self.add_nested_namespace("std", "execution");
}
pub fn complete_namespaces(&self, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
self.namespaces
.iter()
.filter(|(name, _)| lower.is_empty() || name.to_lowercase().starts_with(&lower))
.map(|(name, entry)| {
let mut item = X86CompletionResult::namespace(name, entry.doc.as_deref());
item
})
.collect()
}
pub fn complete_scope(&self, ns: &str, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
let mut results: Vec<X86CompletionResult> = Vec::new();
if let Some(entry) = self.namespaces.get(ns) {
for name in &entry.types {
if lower.is_empty() || name.to_lowercase().starts_with(&lower) {
results.push(X86CompletionResult::type_(name, None));
}
}
for name in &entry.functions {
if lower.is_empty() || name.to_lowercase().starts_with(&lower) {
let mut item = X86CompletionResult::function(name, "auto", &[], None);
item.scope = Some(ns.to_string());
results.push(item);
}
}
for name in &entry.variables {
if lower.is_empty() || name.to_lowercase().starts_with(&lower) {
results.push(X86CompletionResult::variable(name, "auto", None));
}
}
for name in &entry.nested_namespaces {
if lower.is_empty() || name.to_lowercase().starts_with(&lower) {
results.push(X86CompletionResult::namespace(name, None));
}
}
for name in &entry.constants {
if lower.is_empty() || name.to_lowercase().starts_with(&lower) {
let mut item = X86CompletionResult::variable(name, "auto", None);
item.kind = X86CompletionKind::Constant;
item.is_constexpr = true;
results.push(item);
}
}
}
results
}
}
#[derive(Debug, Clone, Default)]
pub struct X86MacroCompletion {
macros: Vec<X86MacroEntry>,
builtin_db: X86BuiltinMacroDatabase,
}
#[derive(Debug, Clone)]
struct X86MacroEntry {
name: String,
params: Option<Vec<String>>,
body: Option<String>,
doc: Option<String>,
header: Option<String>,
is_builtin: bool,
}
impl X86MacroCompletion {
pub fn new() -> Self {
Self {
macros: Vec::new(),
builtin_db: X86BuiltinMacroDatabase::new(),
}
}
pub fn register_macro(
&mut self,
name: &str,
params: Option<&[&str]>,
body: Option<&str>,
doc: Option<&str>,
header: Option<&str>,
) {
self.macros.push(X86MacroEntry {
name: name.to_string(),
params: params.map(|p| p.iter().map(|s| s.to_string()).collect()),
body: body.map(|s| s.to_string()),
doc: doc.map(|s| s.to_string()),
header: header.map(|s| s.to_string()),
is_builtin: false,
});
}
pub fn register_std_macros(&mut self) {
let std_macros: Vec<(&str, Option<&[&str]>, Option<&str>, &str, &str)> = vec![
(
"NULL",
None,
Some("((void*)0)"),
"Null pointer constant",
"stddef.h",
),
(
"EXIT_SUCCESS",
None,
Some("0"),
"Successful exit status",
"stdlib.h",
),
(
"EXIT_FAILURE",
None,
Some("1"),
"Failure exit status",
"stdlib.h",
),
(
"RAND_MAX",
None,
Some("32767"),
"Maximum rand() value",
"stdlib.h",
),
(
"MB_CUR_MAX",
None,
None,
"Max bytes in multibyte char",
"stdlib.h",
),
(
"EOF",
None,
Some("(-1)"),
"End-of-file indicator",
"stdio.h",
),
("BUFSIZ", None, None, "Buffer size for setbuf", "stdio.h"),
("FILENAME_MAX", None, None, "Max filename length", "stdio.h"),
("FOPEN_MAX", None, None, "Max open files", "stdio.h"),
(
"SEEK_SET",
None,
Some("0"),
"Seek from beginning",
"stdio.h",
),
(
"SEEK_CUR",
None,
Some("1"),
"Seek from current position",
"stdio.h",
),
("SEEK_END", None, Some("2"), "Seek from end", "stdio.h"),
(
"TMP_MAX",
None,
None,
"Max unique temp filenames",
"stdio.h",
),
("CHAR_BIT", None, Some("8"), "Bits in char", "limits.h"),
(
"SCHAR_MIN",
None,
Some("(-128)"),
"Min signed char",
"limits.h",
),
(
"SCHAR_MAX",
None,
Some("127"),
"Max signed char",
"limits.h",
),
(
"UCHAR_MAX",
None,
Some("255"),
"Max unsigned char",
"limits.h",
),
(
"INT_MIN",
None,
Some("(-2147483647-1)"),
"Min int",
"limits.h",
),
("INT_MAX", None, Some("2147483647"), "Max int", "limits.h"),
(
"UINT_MAX",
None,
Some("4294967295U"),
"Max unsigned int",
"limits.h",
),
("LONG_MIN", None, None, "Min long", "limits.h"),
("LONG_MAX", None, None, "Max long", "limits.h"),
("ULONG_MAX", None, None, "Max unsigned long", "limits.h"),
("LLONG_MIN", None, None, "Min long long", "limits.h"),
("LLONG_MAX", None, None, "Max long long", "limits.h"),
(
"ULLONG_MAX",
None,
None,
"Max unsigned long long",
"limits.h",
),
("FLT_MAX", None, None, "Max float", "float.h"),
("DBL_MAX", None, None, "Max double", "float.h"),
("LDBL_MAX", None, None, "Max long double", "float.h"),
(
"assert",
Some(&["expr"]),
None,
"Runtime assertion",
"assert.h",
),
(
"offsetof",
Some(&["type", "member"]),
None,
"Offset of member",
"stddef.h",
),
(
"va_start",
Some(&["ap", "last"]),
None,
"Start variadic args",
"stdarg.h",
),
(
"va_arg",
Some(&["ap", "type"]),
None,
"Get variadic arg",
"stdarg.h",
),
(
"va_end",
Some(&["ap"]),
None,
"End variadic args",
"stdarg.h",
),
(
"va_copy",
Some(&["dest", "src"]),
None,
"Copy variadic args",
"stdarg.h",
),
("errno", None, None, "Error number", "errno.h"),
("EDOM", None, None, "Domain error", "errno.h"),
("ERANGE", None, None, "Range error", "errno.h"),
("EILSEQ", None, None, "Illegal sequence", "errno.h"),
("SIG_DFL", None, None, "Default signal handler", "signal.h"),
("SIG_IGN", None, None, "Ignore signal", "signal.h"),
("SIG_ERR", None, None, "Signal error", "signal.h"),
("SIGINT", None, None, "Interrupt signal", "signal.h"),
("SIGABRT", None, None, "Abort signal", "signal.h"),
("SIGSEGV", None, None, "Segmentation violation", "signal.h"),
("SIGTERM", None, None, "Termination signal", "signal.h"),
(
"CLOCKS_PER_SEC",
None,
None,
"Clock ticks per second",
"time.h",
),
];
for (name, params, body, doc, header) in std_macros {
self.register_macro(name, params, body, Some(doc), Some(header));
}
}
pub fn complete(&self, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
let mut results: Vec<X86CompletionResult> = Vec::new();
for entry in &self.macros {
if lower.is_empty() || entry.name.to_lowercase().starts_with(&lower) {
let doc_str = entry
.doc
.as_deref()
.unwrap_or(entry.body.as_deref().unwrap_or(""));
let mut item = X86CompletionResult::macro_(&entry.name, Some(doc_str));
if let Some(ref h) = entry.header {
item.required_header = Some(h.clone());
}
results.push(item);
}
}
for mut item in self.builtin_db.all_macros() {
if lower.is_empty() || item.display_text.to_lowercase().starts_with(&lower) {
results.push(item.clone());
}
}
results
}
pub fn complete_fuzzy(&self, prefix: &str) -> Vec<X86CompletionResult> {
let mut results = self.complete(prefix);
if prefix.len() < 2 {
return results;
}
let lower = prefix.to_lowercase();
for entry in &self.macros {
let entry_lower = entry.name.to_lowercase();
if !entry_lower.starts_with(&lower) && levenshtein_distance(&lower, &entry_lower) <= 2 {
let doc_str = entry.doc.as_deref().unwrap_or("");
let mut item = X86CompletionResult::macro_(&entry.name, Some(doc_str));
item.priority -= 10;
results.push(item);
}
}
results
}
}
#[derive(Debug, Clone)]
pub struct X86KeywordCompletion {
keyword_db: X86KeywordDatabase,
}
impl Default for X86KeywordCompletion {
fn default() -> Self {
Self {
keyword_db: X86KeywordDatabase::default(),
}
}
}
impl X86KeywordCompletion {
pub fn new() -> Self {
Self::default()
}
pub fn complete_c_keywords(&self, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
self.keyword_db
.c_keywords()
.into_iter()
.filter(|k| lower.is_empty() || k.display_text.to_lowercase().starts_with(&lower))
.collect()
}
pub fn complete_cpp_keywords(&self, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
self.keyword_db
.cpp_keywords()
.into_iter()
.filter(|k| lower.is_empty() || k.display_text.to_lowercase().starts_with(&lower))
.collect()
}
pub fn complete_all(&self, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
self.keyword_db
.all_keywords()
.into_iter()
.filter(|k| lower.is_empty() || k.display_text.to_lowercase().starts_with(&lower))
.collect()
}
pub fn complete_types(&self, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
self.keyword_db
.type_specifiers()
.into_iter()
.filter(|t| lower.is_empty() || t.display_text.to_lowercase().starts_with(&lower))
.collect()
}
pub fn complete_storage_classes(&self, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
self.keyword_db
.storage_classes()
.into_iter()
.filter(|k| lower.is_empty() || k.display_text.to_lowercase().starts_with(&lower))
.collect()
}
}
#[derive(Debug, Clone)]
pub struct X86DirectiveCompletion {
directive_db: X86DirectiveDatabase,
}
impl Default for X86DirectiveCompletion {
fn default() -> Self {
Self {
directive_db: X86DirectiveDatabase::new(),
}
}
}
impl X86DirectiveCompletion {
pub fn new() -> Self {
Self::default()
}
pub fn complete(&self, partial: &str) -> Vec<X86CompletionResult> {
let lower = partial.to_lowercase();
let mut results: Vec<X86CompletionResult> = self
.directive_db
.all_directives()
.into_iter()
.filter(|d| {
lower.is_empty()
|| d.insert_text.to_lowercase().starts_with(&lower)
|| d.display_text.to_lowercase().starts_with(&lower)
})
.collect();
if lower.starts_with("pragma") || lower.is_empty() {
let pragma_sub: Vec<(&str, &str)> = vec![
(
"pragma once",
"Include guard — ensure header is included only once",
),
("pragma pack", "Set struct packing alignment"),
(
"pragma message",
"Emit a diagnostic message during compilation",
),
("pragma warning", "Control compiler warnings (MSVC)"),
("pragma GCC diagnostic", "Control GCC/Clang diagnostics"),
("pragma GCC optimize", "Set optimization level per-function"),
("pragma GCC target", "Set target ISA per-function"),
(
"pragma clang diagnostic",
"Control Clang-specific diagnostics",
),
("pragma omp parallel", "OpenMP parallel region"),
("pragma omp for", "OpenMP for-loop parallelization"),
("pragma omp simd", "OpenMP SIMD vectorization hint"),
("pragma unroll", "Loop unrolling hint"),
("pragma nounroll", "Disable loop unrolling hint"),
("pragma inline", "Force inline hint"),
("pragma noinline", "Disable inline hint"),
];
for (pragma, doc) in pragma_sub {
if lower.is_empty()
|| pragma.to_lowercase().starts_with(&lower)
|| format!("#{}", pragma).to_lowercase().starts_with(&lower)
{
results.push(X86CompletionResult::directive(pragma, doc));
}
}
}
results
}
pub fn get(&self, name: &str) -> Option<X86CompletionResult> {
self.directive_db.get(name)
}
}
#[derive(Debug, Clone)]
pub struct X86FilePathCompletion {
project_includes: Vec<String>,
system_includes: Vec<String>,
project_headers: HashMap<String, Vec<String>>,
system_headers: Vec<String>,
working_dir: Option<PathBuf>,
}
impl Default for X86FilePathCompletion {
fn default() -> Self {
Self {
project_includes: vec![
"./".to_string(),
"./include/".to_string(),
"./src/".to_string(),
],
system_includes: vec![
"/usr/include/".to_string(),
"/usr/local/include/".to_string(),
"/usr/include/c++/".to_string(),
"/usr/include/x86_64-linux-gnu/".to_string(),
],
project_headers: HashMap::new(),
system_headers: Vec::new(),
working_dir: None,
}
}
}
impl X86FilePathCompletion {
pub fn new() -> Self {
Self::default()
}
pub fn set_working_dir(&mut self, path: &Path) {
self.working_dir = Some(path.to_path_buf());
}
pub fn add_project_include_path(&mut self, path: &str) {
self.project_includes.push(path.to_string());
}
pub fn add_system_include_path(&mut self, path: &str) {
self.system_includes.push(path.to_string());
}
pub fn register_project_header(&mut self, dir: &str, filename: &str) {
self.project_headers
.entry(dir.to_string())
.or_default()
.push(filename.to_string());
}
pub fn register_system_header(&mut self, filename: &str) {
self.system_headers.push(filename.to_string());
}
pub fn register_common_headers(&mut self) {
let common_c_headers = vec![
"stdio.h",
"stdlib.h",
"string.h",
"math.h",
"ctype.h",
"time.h",
"signal.h",
"setjmp.h",
"locale.h",
"errno.h",
"stddef.h",
"stdarg.h",
"stdbool.h",
"stdint.h",
"stdalign.h",
"stdatomic.h",
"stdnoreturn.h",
"assert.h",
"complex.h",
"fenv.h",
"inttypes.h",
"iso646.h",
"limits.h",
"float.h",
"tgmath.h",
"wchar.h",
"wctype.h",
"threads.h",
"uchar.h",
];
for header in common_c_headers {
self.system_headers.push(header.to_string());
}
let common_cpp_headers = vec![
"algorithm",
"any",
"array",
"atomic",
"bitset",
"chrono",
"codecvt",
"complex",
"condition_variable",
"deque",
"exception",
"execution",
"filesystem",
"forward_list",
"fstream",
"functional",
"future",
"initializer_list",
"iomanip",
"ios",
"iosfwd",
"iostream",
"istream",
"iterator",
"limits",
"list",
"locale",
"map",
"memory",
"memory_resource",
"mutex",
"new",
"numeric",
"optional",
"ostream",
"queue",
"random",
"ratio",
"regex",
"scoped_allocator",
"set",
"shared_mutex",
"span",
"sstream",
"stack",
"stdexcept",
"streambuf",
"string",
"string_view",
"strstream",
"system_error",
"thread",
"tuple",
"type_traits",
"typeindex",
"typeinfo",
"unordered_map",
"unordered_set",
"utility",
"valarray",
"variant",
"vector",
"version",
];
for header in common_cpp_headers {
self.system_headers.push(format!("{}", header));
}
let c_wrapper_headers = vec![
"cassert", "cctype", "cerrno", "cfloat", "ciso646", "climits", "clocale", "cmath",
"csetjmp", "csignal", "cstdarg", "cstddef", "cstdint", "cstdio", "cstdlib", "cstring",
"ctime", "cwchar", "cwctype",
];
for header in c_wrapper_headers {
self.system_headers.push(format!("{}", header));
}
let x86_headers = vec![
"x86intrin.h",
"mmintrin.h",
"xmmintrin.h",
"emmintrin.h",
"pmmintrin.h",
"tmmintrin.h",
"smmintrin.h",
"nmmintrin.h",
"wmmintrin.h",
"immintrin.h",
"zmmintrin.h",
"ammintrin.h",
"bmiintrin.h",
"bmi2intrin.h",
"tbmintrin.h",
"lzcntintrin.h",
"popcntintrin.h",
"fmaintrin.h",
"f16cintrin.h",
"rdseedintrin.h",
"prfchwintrin.h",
"cpuid.h",
];
for header in x86_headers {
self.system_headers.push(header.to_string());
}
}
pub fn complete_path(
&self,
partial: &str,
delimiter: IncludeDelimiter,
) -> Vec<X86CompletionResult> {
let mut results: Vec<X86CompletionResult> = Vec::new();
match delimiter {
IncludeDelimiter::Quote => {
for dir in &self.project_includes {
if let Some(headers) = self.project_headers.get(dir) {
for header in headers {
let full = format!("{}/{}", dir, header);
if full.starts_with(partial) || header.starts_with(partial) {
results.push(X86CompletionResult::file(header, false));
}
}
}
}
for header in &self.system_headers {
if header.starts_with(partial) || partial.is_empty() {
results.push(X86CompletionResult::file(header, false));
}
}
}
IncludeDelimiter::Angle => {
for header in &self.system_headers {
if header.starts_with(partial) || partial.is_empty() {
results.push(X86CompletionResult::file(header, false));
}
}
}
}
let mut seen: HashSet<String> = HashSet::new();
results.retain(|r| seen.insert(r.display_text.clone()));
results
}
pub fn complete_string_path(&self, partial: &str) -> Vec<X86CompletionResult> {
let mut results: Vec<X86CompletionResult> = Vec::new();
let path = Path::new(partial);
let dir_part = path.parent().map(|p| p.to_string_lossy().to_string());
for dir in &self.project_includes {
if let Some(headers) = self.project_headers.get(dir) {
for header in headers {
if header.starts_with(partial) {
results.push(X86CompletionResult::file(header, false));
}
}
}
}
for header in &self.system_headers {
if header.starts_with(partial) {
results.push(X86CompletionResult::file(header, false));
}
}
let mut seen: HashSet<String> = HashSet::new();
results.retain(|r| seen.insert(r.display_text.clone()));
results
}
}
#[derive(Debug, Clone)]
pub struct X86SnippetCompletion {
snippet_db: X86SnippetDatabase,
}
impl Default for X86SnippetCompletion {
fn default() -> Self {
Self {
snippet_db: X86SnippetDatabase::new(),
}
}
}
impl X86SnippetCompletion {
pub fn new() -> Self {
Self::default()
}
pub fn all_snippets(&self) -> Vec<X86CompletionResult> {
self.snippet_db.all_snippets()
}
pub fn search(&self, query: &str) -> Vec<X86CompletionResult> {
self.snippet_db.search(query)
}
pub fn complete_for_context(&self, context: &X86CompletionContext) -> Vec<X86CompletionResult> {
match context {
X86CompletionContext::ExpressionContext => self
.snippet_db
.search("for loop")
.into_iter()
.chain(self.snippet_db.search("while"))
.chain(self.snippet_db.search("if"))
.chain(self.snippet_db.search("switch"))
.chain(self.snippet_db.search("try"))
.collect(),
X86CompletionContext::DeclarationContext {
in_class_body: true,
..
} => self
.snippet_db
.search("constructor")
.into_iter()
.chain(self.snippet_db.search("destructor"))
.chain(self.snippet_db.search("operator"))
.chain(self.snippet_db.search("function"))
.collect(),
X86CompletionContext::DeclarationContext {
at_top_level: true, ..
} => self
.snippet_db
.search("class")
.into_iter()
.chain(self.snippet_db.search("struct"))
.chain(self.snippet_db.search("enum"))
.chain(self.snippet_db.search("namespace"))
.chain(self.snippet_db.search("function"))
.chain(self.snippet_db.search("template"))
.chain(self.snippet_db.search("main"))
.chain(self.snippet_db.search("include"))
.collect(),
_ => self.snippet_db.all_snippets(),
}
}
}
#[derive(Debug, Clone)]
pub struct X86CodeCompleteDeep {
pub type_completion: X86TypeCompletion,
pub member_completion: X86MemberCompletion,
pub function_completion: X86FunctionCompletion,
pub variable_completion: X86VariableCompletion,
pub namespace_completion: X86NamespaceCompletion,
pub macro_completion: X86MacroCompletion,
pub keyword_completion: X86KeywordCompletion,
pub directive_completion: X86DirectiveCompletion,
pub file_path_completion: X86FilePathCompletion,
pub snippet_completion: X86SnippetCompletion,
pub ranker: X86CompletionRanker,
pub cpp_mode: bool,
pub x86_intrinsics: bool,
pub fuzzy: bool,
pub max_results: usize,
cache: HashMap<String, Vec<X86CompletionResult>>,
}
impl X86CodeCompleteDeep {
pub fn new() -> Self {
let mut func_comp = X86FunctionCompletion::new();
func_comp.register_std_functions();
let mut macro_comp = X86MacroCompletion::new();
macro_comp.register_std_macros();
let mut ns_comp = X86NamespaceCompletion::new();
ns_comp.register_std_namespace();
let mut file_comp = X86FilePathCompletion::new();
file_comp.register_common_headers();
Self {
type_completion: X86TypeCompletion::new(),
member_completion: X86MemberCompletion::new(),
function_completion: func_comp,
variable_completion: X86VariableCompletion::new(),
namespace_completion: ns_comp,
macro_completion: macro_comp,
keyword_completion: X86KeywordCompletion::new(),
directive_completion: X86DirectiveCompletion::new(),
file_path_completion: file_comp,
snippet_completion: X86SnippetCompletion::new(),
ranker: X86CompletionRanker::new(),
cpp_mode: true,
x86_intrinsics: true,
fuzzy: true,
max_results: 50,
cache: HashMap::new(),
}
}
pub fn new_c_mode() -> Self {
let mut engine = Self::new();
engine.cpp_mode = false;
engine
}
pub fn clear_cache(&mut self) {
self.cache.clear();
}
pub fn invalidate_cache(&mut self, key: &str) {
self.cache.remove(key);
}
pub fn complete(
&mut self,
source_line: &str,
column: usize,
prefix: &str,
) -> Vec<X86CompletionResult> {
let context = X86CompletionContext::from_source_line(source_line, column);
self.complete_with_context(&context, prefix, None)
}
pub fn complete_with_context(
&mut self,
context: &X86CompletionContext,
prefix: &str,
expected_type: Option<&str>,
) -> Vec<X86CompletionResult> {
let cache_key = format!("{:?}|{}|{}", context, prefix, expected_type.unwrap_or(""));
if let Some(cached) = self.cache.get(&cache_key) {
return cached.clone();
}
let mut results = self.collect_completions(context, prefix);
self.ranker.set_fuzzy(self.fuzzy, 0.6);
self.ranker
.rank(&mut results, prefix, context, expected_type);
results.truncate(self.max_results);
self.cache.insert(cache_key, results.clone());
results
}
fn collect_completions(
&self,
context: &X86CompletionContext,
prefix: &str,
) -> Vec<X86CompletionResult> {
let mut results: Vec<X86CompletionResult> = Vec::new();
match context {
X86CompletionContext::DotAccess {
receiver_type,
implicit_this,
}
| X86CompletionContext::ArrowAccess {
receiver_type,
implicit_this,
} => {
let is_arrow = matches!(context, X86CompletionContext::ArrowAccess { .. });
if let Some(type_name) = receiver_type {
results.extend(
self.member_completion
.complete_members(type_name, prefix, is_arrow),
);
}
}
X86CompletionContext::ScopeResolution {
scope_name, nested, ..
} => {
if let Some(scope) = scope_name {
results.extend(self.namespace_completion.complete_scope(scope, prefix));
results.extend(
self.member_completion
.complete_static_members(scope, prefix),
);
if results.is_empty() {
results.extend(
self.member_completion
.complete_members(scope, prefix, false),
);
}
} else {
results.extend(self.namespace_completion.complete_namespaces(prefix));
}
}
X86CompletionContext::TypeContext { .. }
| X86CompletionContext::TemplateArgumentContext => {
results.extend(self.type_completion.complete(prefix));
if self.cpp_mode {
results.extend(self.keyword_completion.complete_types(prefix));
}
}
X86CompletionContext::DirectiveContext { partial } => {
results.extend(self.directive_completion.complete(partial));
}
X86CompletionContext::IncludeContext { delimiter, partial } => {
results.extend(self.file_path_completion.complete_path(partial, *delimiter));
}
X86CompletionContext::StringContext { partial, .. } => {
results.extend(self.file_path_completion.complete_string_path(partial));
}
X86CompletionContext::ReturnContext => {
results.extend(self.variable_completion.complete(prefix));
results.extend(self.function_completion.complete(prefix));
}
X86CompletionContext::CaseContext => {
results.extend(
self.variable_completion
.complete_by_kind(prefix, X86CompletionKind::Constant),
);
}
X86CompletionContext::LabelContext | X86CompletionContext::GotoContext => {
}
X86CompletionContext::EnumBody { .. } => {
}
X86CompletionContext::DeclarationContext {
in_class_body,
at_top_level,
..
} => {
if *in_class_body && self.cpp_mode {
results.push(X86CompletionResult::keyword("public"));
results.push(X86CompletionResult::keyword("private"));
results.push(X86CompletionResult::keyword("protected"));
results.extend(self.snippet_completion.complete_for_context(context));
}
if *at_top_level || *in_class_body {
results.extend(self.type_completion.complete(prefix));
}
results.extend(self.keyword_completion.complete_all(prefix));
results.extend(self.snippet_completion.complete_for_context(context));
}
X86CompletionContext::ExpressionContext | X86CompletionContext::General => {
results.extend(self.keyword_completion.complete_all(prefix));
results.extend(self.function_completion.complete(prefix));
results.extend(self.variable_completion.complete(prefix));
results.extend(self.macro_completion.complete(prefix));
results.extend(self.type_completion.complete(prefix));
if self.cpp_mode {
results.extend(self.namespace_completion.complete_namespaces(prefix));
}
results.extend(self.snippet_completion.complete_for_context(context));
}
X86CompletionContext::UsingContext => {
results.extend(self.namespace_completion.complete_namespaces(prefix));
}
X86CompletionContext::AttributeContext => {
let attrs = vec![
("noreturn", "Function does not return"),
("deprecated", "Marked as deprecated"),
("nodiscard", "Return value should not be discarded"),
("maybe_unused", "May be unused without warning"),
("fallthrough", "Intentional switch fallthrough"),
("likely", "Branch is likely to be taken"),
("unlikely", "Branch is unlikely to be taken"),
("no_unique_address", "Member may overlap other members"),
];
for (name, doc) in attrs {
if name.starts_with(prefix) || prefix.is_empty() {
let mut item = X86CompletionResult::keyword(name);
item.documentation = Some(doc.to_string());
results.push(item);
}
}
}
X86CompletionContext::ThrowContext => {
results.extend(self.type_completion.complete(prefix));
results.extend(self.variable_completion.complete(prefix));
}
X86CompletionContext::NoexceptContext => {
let mut item = X86CompletionResult::keyword("true");
item.documentation = Some("noexcept(true) — function does not throw".into());
results.push(item);
let mut item = X86CompletionResult::keyword("false");
item.documentation = Some("noexcept(false) — function may throw".into());
results.push(item);
}
X86CompletionContext::SizeofContext | X86CompletionContext::DecltypeContext => {
results.extend(self.type_completion.complete(prefix));
results.extend(self.variable_completion.complete(prefix));
}
X86CompletionContext::InitializerListContext { class_name } => {
if let Some(class_name) = class_name {
results.extend(
self.member_completion
.complete_members(class_name, prefix, false),
);
}
}
_ => {
results.extend(self.keyword_completion.complete_all(prefix));
results.extend(self.type_completion.complete(prefix));
results.extend(self.function_completion.complete(prefix));
results.extend(self.variable_completion.complete(prefix));
results.extend(self.macro_completion.complete(prefix));
if self.cpp_mode {
results.extend(self.namespace_completion.complete_namespaces(prefix));
}
results.extend(self.snippet_completion.all_snippets());
}
}
let mut seen: HashSet<String> = HashSet::new();
results.retain(|r| seen.insert(r.display_text.clone()));
results
}
pub fn complete_dot_access(
&mut self,
receiver_type: &str,
prefix: &str,
is_arrow: bool,
) -> Vec<X86CompletionResult> {
let context = if is_arrow {
X86CompletionContext::ArrowAccess {
receiver_type: Some(receiver_type.to_string()),
implicit_this: false,
}
} else {
X86CompletionContext::DotAccess {
receiver_type: Some(receiver_type.to_string()),
implicit_this: false,
}
};
self.complete_with_context(&context, prefix, None)
}
pub fn complete_scope_resolution(
&mut self,
scope_name: Option<&str>,
prefix: &str,
) -> Vec<X86CompletionResult> {
let context = X86CompletionContext::ScopeResolution {
scope_name: scope_name.map(|s| s.to_string()),
nested: scope_name.map_or(false, |s| s.contains("::")),
nested_specifiers: scope_name
.map(|s| extract_nested_specifiers(s))
.unwrap_or_default(),
};
self.complete_with_context(&context, prefix, None)
}
pub fn complete_include(
&mut self,
partial: &str,
use_angle_brackets: bool,
) -> Vec<X86CompletionResult> {
let delimiter = if use_angle_brackets {
IncludeDelimiter::Angle
} else {
IncludeDelimiter::Quote
};
let context = X86CompletionContext::IncludeContext {
delimiter,
partial: partial.to_string(),
};
self.complete_with_context(&context, partial, None)
}
pub fn complete_directive(&mut self, partial: &str) -> Vec<X86CompletionResult> {
let context = X86CompletionContext::DirectiveContext {
partial: partial.to_string(),
};
self.complete_with_context(&context, partial, None)
}
pub fn complete_all(&mut self, prefix: &str) -> Vec<X86CompletionResult> {
self.complete_with_context(&X86CompletionContext::General, prefix, None)
}
pub fn complete_ranked(
&mut self,
context: &X86CompletionContext,
prefix: &str,
expected_type: Option<&str>,
weights: Option<X86RankerWeights>,
) -> Vec<X86CompletionResult> {
if let Some(w) = weights {
self.ranker = X86CompletionRanker::with_weights(w);
}
self.complete_with_context(context, prefix, expected_type)
}
pub fn record_symbol_usage(&mut self, symbol: &str) {
self.ranker.record_usage(symbol);
}
pub fn stats(&self) -> X86CompletionStats {
let mut total_types = 0u64;
let mut total_functions = 0u64;
let mut total_variables = 0u64;
let mut total_macros = 0u64;
total_types += self.type_completion.complete("").len() as u64;
total_functions += self.function_completion.complete("").len() as u64;
total_variables += self.variable_completion.complete("").len() as u64;
total_macros += self.macro_completion.complete("").len() as u64;
X86CompletionStats {
total_types,
total_functions,
total_variables,
total_macros,
total_snippets: self.snippet_completion.all_snippets().len() as u64,
cache_entries: self.cache.len() as u64,
is_cpp_mode: self.cpp_mode,
}
}
}
#[derive(Debug, Clone)]
pub struct X86CompletionStats {
pub total_types: u64,
pub total_functions: u64,
pub total_variables: u64,
pub total_macros: u64,
pub total_snippets: u64,
pub cache_entries: u64,
pub is_cpp_mode: bool,
}
impl fmt::Display for X86CompletionStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "X86CodeCompleteDeep Statistics:")?;
writeln!(
f,
" Mode: {}",
if self.is_cpp_mode { "C++" } else { "C" }
)?;
writeln!(f, " Known types: {}", self.total_types)?;
writeln!(f, " Known functions: {}", self.total_functions)?;
writeln!(f, " Known variables: {}", self.total_variables)?;
writeln!(f, " Known macros: {}", self.total_macros)?;
writeln!(f, " Available snippets: {}", self.total_snippets)?;
writeln!(f, " Cached queries: {}", self.cache_entries)?;
Ok(())
}
}
impl Default for X86CodeCompleteDeep {
fn default() -> Self {
Self::new()
}
}
pub fn make_x86_64_deep_codecomplete() -> X86CodeCompleteDeep {
let mut engine = X86CodeCompleteDeep::new();
engine.cpp_mode = true;
engine.x86_intrinsics = true;
engine
}
pub fn make_x86_32_deep_codecomplete() -> X86CodeCompleteDeep {
let mut engine = X86CodeCompleteDeep::new_c_mode();
engine.x86_intrinsics = true;
engine
}
pub fn make_x86_deep_codecomplete_cpp17() -> X86CodeCompleteDeep {
let mut engine = X86CodeCompleteDeep::new();
engine.cpp_mode = true;
engine.x86_intrinsics = true;
engine.fuzzy = true;
engine.max_results = 100;
engine
}
pub fn make_x86_deep_codecomplete_minimal() -> X86CodeCompleteDeep {
let mut engine = X86CodeCompleteDeep::new();
engine.cpp_mode = false;
engine.x86_intrinsics = false;
engine.fuzzy = false;
engine.max_results = 25;
engine
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_context_general() {
let ctx = X86CompletionContext::from_source_line("int x = ", 8);
assert_eq!(ctx, X86CompletionContext::General);
}
#[test]
fn test_context_dot_access() {
let ctx = X86CompletionContext::from_source_line("obj.", 4);
match ctx {
X86CompletionContext::DotAccess { receiver_type, .. } => {
assert_eq!(receiver_type, Some("obj".to_string()));
}
_ => panic!("Expected DotAccess, got {:?}", ctx),
}
}
#[test]
fn test_context_arrow_access() {
let ctx = X86CompletionContext::from_source_line("ptr->", 5);
match ctx {
X86CompletionContext::ArrowAccess { receiver_type, .. } => {
assert_eq!(receiver_type, Some("ptr".to_string()));
}
_ => panic!("Expected ArrowAccess, got {:?}", ctx),
}
}
#[test]
fn test_context_scope_resolution() {
let ctx = X86CompletionContext::from_source_line("std::", 5);
match ctx {
X86CompletionContext::ScopeResolution { scope_name, .. } => {
assert_eq!(scope_name, Some("std".to_string()));
}
_ => panic!("Expected ScopeResolution, got {:?}", ctx),
}
}
#[test]
fn test_context_nested_scope() {
let ctx = X86CompletionContext::from_source_line("std::chrono::", 14);
match ctx {
X86CompletionContext::ScopeResolution {
scope_name,
nested,
nested_specifiers,
} => {
assert_eq!(scope_name, Some("chrono".to_string()));
assert!(nested);
assert_eq!(nested_specifiers, vec!["std", "chrono"]);
}
_ => panic!("Expected nested ScopeResolution, got {:?}", ctx),
}
}
#[test]
fn test_context_directive() {
let ctx = X86CompletionContext::from_source_line("#", 1);
match ctx {
X86CompletionContext::DirectiveContext { partial } => {
assert_eq!(partial, "");
}
_ => panic!("Expected DirectiveContext, got {:?}", ctx),
}
}
#[test]
fn test_context_directive_partial() {
let ctx = X86CompletionContext::from_source_line("#incl", 5);
match ctx {
X86CompletionContext::DirectiveContext { partial } => {
assert_eq!(partial, "incl");
}
_ => panic!("Expected DirectiveContext, got {:?}", ctx),
}
}
#[test]
fn test_context_include_quote() {
let ctx = X86CompletionContext::from_source_line("#include \"std", 13);
match ctx {
X86CompletionContext::IncludeContext { delimiter, partial } => {
assert_eq!(delimiter, IncludeDelimiter::Quote);
assert_eq!(partial, "std");
}
_ => panic!("Expected IncludeContext, got {:?}", ctx),
}
}
#[test]
fn test_context_include_angle() {
let ctx = X86CompletionContext::from_source_line("#include <ios", 14);
match ctx {
X86CompletionContext::IncludeContext { delimiter, partial } => {
assert_eq!(delimiter, IncludeDelimiter::Angle);
assert_eq!(partial, "ios");
}
_ => panic!("Expected IncludeContext, got {:?}", ctx),
}
}
#[test]
fn test_context_type() {
let ctx = X86CompletionContext::from_source_line("int ", 4);
match ctx {
X86CompletionContext::TypeContext {
preceding_keyword, ..
} => {
assert_eq!(preceding_keyword, Some("int".to_string()));
}
_ => panic!("Expected TypeContext, got {:?}", ctx),
}
}
#[test]
fn test_context_struct_type() {
let ctx = X86CompletionContext::from_source_line("struct ", 7);
match ctx {
X86CompletionContext::TypeContext {
preceding_keyword, ..
} => {
assert_eq!(preceding_keyword, Some("struct".to_string()));
}
_ => panic!("Expected TypeContext, got {:?}", ctx),
}
}
#[test]
fn test_context_return() {
let ctx = X86CompletionContext::from_source_line("return ", 7);
assert_eq!(ctx, X86CompletionContext::ReturnContext);
}
#[test]
fn test_context_case() {
let ctx = X86CompletionContext::from_source_line("case ", 5);
assert_eq!(ctx, X86CompletionContext::CaseContext);
}
#[test]
fn test_context_goto() {
let ctx = X86CompletionContext::from_source_line("goto ", 5);
assert_eq!(ctx, X86CompletionContext::GotoContext);
}
#[test]
fn test_context_open_paren() {
let ctx = X86CompletionContext::from_source_line("func(", 5);
match ctx {
X86CompletionContext::OpenParen { callee } => {
assert_eq!(callee, Some("func".to_string()));
}
_ => panic!("Expected OpenParen, got {:?}", ctx),
}
}
#[test]
fn test_context_throw() {
let ctx = X86CompletionContext::from_source_line("throw ", 6);
assert_eq!(ctx, X86CompletionContext::ThrowContext);
}
#[test]
fn test_context_using() {
let ctx = X86CompletionContext::from_source_line("using namespace ", 16);
assert_eq!(ctx, X86CompletionContext::UsingContext);
}
#[test]
fn test_context_expects_type() {
let ctx = X86CompletionContext::TypeContext {
template_argument: false,
base_specifier: false,
preceding_keyword: Some("int".to_string()),
};
assert!(ctx.expects_type());
let ctx = X86CompletionContext::General;
assert!(!ctx.expects_type());
}
#[test]
fn test_context_expects_value() {
let ctx = X86CompletionContext::ReturnContext;
assert!(ctx.expects_value());
let ctx = X86CompletionContext::ExpressionContext;
assert!(ctx.expects_value());
let ctx = X86CompletionContext::TypeContext {
template_argument: false,
base_specifier: false,
preceding_keyword: None,
};
assert!(!ctx.expects_value());
}
#[test]
fn test_context_expects_member() {
let ctx = X86CompletionContext::DotAccess {
receiver_type: Some("obj".to_string()),
implicit_this: false,
};
assert!(ctx.expects_member());
let ctx = X86CompletionContext::ArrowAccess {
receiver_type: Some("ptr".to_string()),
implicit_this: false,
};
assert!(ctx.expects_member());
let ctx = X86CompletionContext::General;
assert!(!ctx.expects_member());
}
#[test]
fn test_context_is_directive() {
let ctx = X86CompletionContext::DirectiveContext {
partial: String::new(),
};
assert!(ctx.is_directive());
let ctx = X86CompletionContext::IncludeContext {
delimiter: IncludeDelimiter::Angle,
partial: String::new(),
};
assert!(ctx.is_directive());
let ctx = X86CompletionContext::General;
assert!(!ctx.is_directive());
}
#[test]
fn test_completion_result_keyword() {
let result = X86CompletionResult::keyword("for");
assert_eq!(result.display_text, "for");
assert_eq!(result.kind, X86CompletionKind::Keyword);
assert_eq!(result.priority, 100);
assert!(result.documentation.is_some());
}
#[test]
fn test_completion_result_macro() {
let result = X86CompletionResult::macro_("NULL", Some("Null pointer constant"));
assert_eq!(result.display_text, "NULL");
assert_eq!(result.kind, X86CompletionKind::Macro);
assert_eq!(result.priority, 90);
assert!(result.documentation.is_some());
}
#[test]
fn test_completion_result_directive() {
let result = X86CompletionResult::directive("include", "Include a header");
assert_eq!(result.display_text, "include");
assert_eq!(result.kind, X86CompletionKind::Directive);
assert_eq!(result.priority, 95);
}
#[test]
fn test_completion_result_function() {
let result = X86CompletionResult::function(
"printf",
"int",
&[("const char*", "format"), ("...", "...")],
Some("Print formatted"),
);
assert_eq!(result.kind, X86CompletionKind::Function);
assert_eq!(result.return_type, Some("int".to_string()));
assert_eq!(result.parameters.len(), 2);
assert!(result.detail.is_some());
}
#[test]
fn test_completion_result_snippet() {
let result = X86CompletionResult::snippet("for loop", "for (...)", "A for loop");
assert_eq!(result.kind, X86CompletionKind::Snippet);
assert!(result.is_snippet);
assert_eq!(result.priority, 70);
}
#[test]
fn test_completion_result_type() {
let result = X86CompletionResult::type_("int", Some("Integer type"));
assert_eq!(result.kind, X86CompletionKind::Type);
assert_eq!(result.priority, 85);
}
#[test]
fn test_completion_result_ordering() {
let a = X86CompletionResult::keyword("for");
let mut b = X86CompletionResult::type_("int", None);
assert!(a > b);
let c = X86CompletionResult::keyword("auto");
let d = X86CompletionResult::keyword("break");
assert!(c < d); }
#[test]
fn test_completion_result_equality() {
let a = X86CompletionResult::keyword("for");
let b = X86CompletionResult::keyword("for");
assert_eq!(a, b);
let c = X86CompletionResult::keyword("while");
assert_ne!(a, c);
}
#[test]
fn test_levenshtein_equal() {
assert_eq!(levenshtein_distance("hello", "hello"), 0);
}
#[test]
fn test_levenshtein_empty() {
assert_eq!(levenshtein_distance("", "hello"), 5);
assert_eq!(levenshtein_distance("hello", ""), 5);
assert_eq!(levenshtein_distance("", ""), 0);
}
#[test]
fn test_levenshtein_substitution() {
assert_eq!(levenshtein_distance("kitten", "sitten"), 1); assert_eq!(levenshtein_distance("sitten", "sittin"), 1); }
#[test]
fn test_levenshtein_insertion() {
assert_eq!(levenshtein_distance("cat", "cats"), 1);
assert_eq!(levenshtein_distance("abc", "abdc"), 1);
}
#[test]
fn test_levenshtein_deletion() {
assert_eq!(levenshtein_distance("cats", "cat"), 1);
assert_eq!(levenshtein_distance("abdc", "abc"), 1);
}
#[test]
fn test_levenshtein_complex() {
assert_eq!(levenshtein_distance("saturday", "sunday"), 3);
assert_eq!(levenshtein_distance("algorithm", "altruistic"), 6);
}
#[test]
fn test_levenshtein_case_sensitive() {
assert_eq!(levenshtein_distance("Hello", "hello"), 1);
}
#[test]
fn test_damerau_levenshtein_transposition() {
assert_eq!(damerau_levenshtein_distance("ab", "ba"), 1);
}
#[test]
fn test_damerau_levenshtein_same_as_levenshtein() {
let cases = vec![
("hello", "hello", 0),
("", "abc", 3),
("abc", "", 3),
("kitten", "sitting", 3),
];
for (a, b, expected) in cases {
let dl = damerau_levenshtein_distance(a, b);
let l = levenshtein_distance(a, b);
assert_eq!(dl, l, "Damerau-Levenshtein should equal Levenshtein for '{a}' vs '{b}' (transposition-free)");
}
}
#[test]
fn test_ranker_type_match() {
let ranker = X86CompletionRanker::new();
let mut results = vec![
{
let mut r = X86CompletionResult::function("foo", "int", &[], None);
r.priority = 0;
r
},
{
let mut r = X86CompletionResult::function("bar", "double", &[], None);
r.priority = 0;
r
},
{
let mut r = X86CompletionResult::function("baz", "int", &[], None);
r.priority = 0;
r
},
];
ranker.rank(
&mut results,
"f",
&X86CompletionContext::General,
Some("int"),
);
let int_results: Vec<_> = results
.iter()
.filter(|r| r.return_type.as_deref() == Some("int"))
.collect();
let double_results: Vec<_> = results
.iter()
.filter(|r| r.return_type.as_deref() == Some("double"))
.collect();
assert!(
int_results[0].priority > double_results[0].priority,
"int-returning functions should rank higher when expected type is int"
);
}
#[test]
fn test_ranker_scope_proximity() {
let ranker = X86CompletionRanker::new();
let mut results = vec![
{
let mut r = X86CompletionResult::variable("local_var", "int", None);
r.kind = X86CompletionKind::LocalVariable;
r
},
{
let mut r = X86CompletionResult::variable("global_var", "int", None);
r.kind = X86CompletionKind::GlobalVariable;
r
},
];
ranker.rank(&mut results, "", &X86CompletionContext::General, None);
let local = results
.iter()
.find(|r| r.display_text.contains("local_var"))
.unwrap();
let global = results
.iter()
.find(|r| r.display_text.contains("global_var"))
.unwrap();
assert!(local.priority > global.priority);
}
#[test]
fn test_ranker_frequency() {
let mut ranker = X86CompletionRanker::new();
ranker.record_usage("printf");
ranker.record_usage("printf");
ranker.record_usage("printf");
let mut results = vec![
{
let mut r = X86CompletionResult::function("printf", "int", &[], None);
r.priority = 0;
r
},
{
let mut r = X86CompletionResult::function("malloc", "void*", &[], None);
r.priority = 0;
r
},
];
ranker.rank(&mut results, "", &X86CompletionContext::General, None);
let printf_result = results
.iter()
.find(|r| r.display_text.contains("printf"))
.unwrap();
let malloc_result = results
.iter()
.find(|r| r.display_text.contains("malloc"))
.unwrap();
assert!(printf_result.priority > malloc_result.priority);
}
#[test]
fn test_ranker_fuzzy_matching() {
let ranker = X86CompletionRanker::new();
let mut results = vec![
{
let mut r = X86CompletionResult::keyword("printf");
r.priority = 0;
r.display_text = "printf".to_string();
r
},
{
let mut r = X86CompletionResult::keyword("prinf");
r.priority = 0;
r.display_text = "prinf".to_string();
r
},
];
ranker.rank(&mut results, "printf", &X86CompletionContext::General, None);
let exact = results.iter().find(|r| r.display_text == "printf").unwrap();
let fuzzy = results.iter().find(|r| r.display_text == "prinf").unwrap();
assert!(exact.priority > fuzzy.priority);
}
#[test]
fn test_ranker_context_dot_access() {
let ranker = X86CompletionRanker::new();
let mut results = vec![
{
let mut r = X86CompletionResult::field("member", "int", None);
r.priority = 0;
r
},
{
let mut r = X86CompletionResult::keyword("class");
r.priority = 0;
r
},
];
let ctx = X86CompletionContext::DotAccess {
receiver_type: Some("obj".to_string()),
implicit_this: false,
};
ranker.rank(&mut results, "", &ctx, None);
let field = results
.iter()
.find(|r| r.kind == X86CompletionKind::Field)
.unwrap();
let keyword = results
.iter()
.find(|r| r.kind == X86CompletionKind::Keyword)
.unwrap();
assert!(field.priority > keyword.priority);
}
#[test]
fn test_type_completion_builtin() {
let tc = X86TypeCompletion::new();
let results = tc.complete("");
assert!(!results.is_empty());
let has_int = results.iter().any(|r| r.display_text == "int");
assert!(has_int, "Type completion should include 'int'");
let has_float = results.iter().any(|r| r.display_text == "float");
assert!(has_float, "Type completion should include 'float'");
}
#[test]
fn test_type_completion_filtered() {
let tc = X86TypeCompletion::new();
let results = tc.complete("unsi");
assert!(!results.is_empty());
for r in &results {
assert!(
r.display_text.to_lowercase().starts_with("unsi"),
"Filtered result '{}' should start with 'unsi'",
r.display_text
);
}
}
#[test]
fn test_type_completion_user_defined() {
let mut tc = X86TypeCompletion::new();
tc.register_struct("MyStruct", "A custom struct");
tc.register_enum("MyEnum", "A custom enum");
tc.register_typedef("MyInt", "int", None);
let results = tc.complete("My");
assert!(results.iter().any(|r| r.display_text == "MyStruct"));
assert!(results.iter().any(|r| r.display_text == "MyEnum"));
assert!(results.iter().any(|r| r.display_text == "MyInt"));
}
#[test]
fn test_type_completion_fuzzy() {
let mut tc = X86TypeCompletion::new();
tc.register_struct("Vector3D", "3D vector type");
let results = tc.complete("Vec");
assert!(results.iter().any(|r| r.display_text == "Vector3D"));
let fuzzy_results = tc.complete_fuzzy("Vectro");
assert!(
fuzzy_results.iter().any(|r| r.display_text == "Vector3D"),
"Fuzzy completion should find 'Vector3D' for 'Vectro' (distance 2)"
);
}
#[test]
fn test_member_completion_fields() {
let mut mc = X86MemberCompletion::new();
mc.register_field("Point", "x", "int", None, X86SymbolVisibility::Public);
mc.register_field("Point", "y", "int", None, X86SymbolVisibility::Public);
mc.register_field("Point", "z", "int", None, X86SymbolVisibility::Public);
let results = mc.complete_members("Point", "", false);
assert_eq!(results.len(), 3);
assert!(results.iter().any(|r| r.display_text.contains("x")));
assert!(results.iter().any(|r| r.display_text.contains("y")));
assert!(results.iter().any(|r| r.display_text.contains("z")));
}
#[test]
fn test_member_completion_methods() {
let mut mc = X86MemberCompletion::new();
mc.register_method(
"Point",
"distance",
"double",
&[("const Point&", "other")],
Some("Compute distance"),
X86SymbolVisibility::Public,
false,
false,
true,
);
let results = mc.complete_members("Point", "", false);
assert!(results.iter().any(|r| r.display_text.contains("distance")));
}
#[test]
fn test_member_completion_inheritance() {
let mut mc = X86MemberCompletion::new();
mc.register_field(
"Shape",
"name",
"const char*",
None,
X86SymbolVisibility::Protected,
);
mc.register_inheritance("Circle", "Shape");
mc.register_field(
"Circle",
"radius",
"double",
None,
X86SymbolVisibility::Public,
);
let results = mc.complete_members("Circle", "", false);
assert!(results.iter().any(|r| r.display_text.contains("name")));
assert!(results.iter().any(|r| r.display_text.contains("radius")));
}
#[test]
fn test_member_completion_static() {
let mut mc = X86MemberCompletion::new();
mc.register_method(
"Math",
"sqrt",
"double",
&[("double", "x")],
Some("Square root"),
X86SymbolVisibility::Public,
true,
false,
false,
);
let results = mc.complete_static_members("Math", "");
assert!(results.iter().any(|r| r.display_text.contains("sqrt")));
}
#[test]
fn test_member_completion_filtered() {
let mut mc = X86MemberCompletion::new();
mc.register_field("Rect", "width", "int", None, X86SymbolVisibility::Public);
mc.register_field("Rect", "height", "int", None, X86SymbolVisibility::Public);
mc.register_field("Rect", "x", "int", None, X86SymbolVisibility::Public);
let results = mc.complete_members("Rect", "w", false);
assert_eq!(results.len(), 1);
assert!(results.iter().any(|r| r.display_text.contains("width")));
}
#[test]
fn test_function_completion_std() {
let fc = X86FunctionCompletion::new();
let results = fc.complete("printf");
assert!(results.is_empty());
let mut fc = X86FunctionCompletion::new();
fc.register_std_functions();
let results = fc.complete("printf");
assert!(results.iter().any(|r| r.display_text.contains("printf")));
}
#[test]
fn test_function_completion_filtered() {
let mut fc = X86FunctionCompletion::new();
fc.register_std_functions();
let results = fc.complete("str");
assert!(results.iter().any(|r| r.display_text.contains("strcpy")));
assert!(results.iter().any(|r| r.display_text.contains("strlen")));
for r in &results {
assert!(
r.display_text.to_lowercase().starts_with("str"),
"Result '{}' should start with 'str'",
r.display_text
);
}
}
#[test]
fn test_function_completion_user_defined() {
let mut fc = X86FunctionCompletion::new();
fc.register_function(
"my_func",
"int",
&[("int", "a"), ("int", "b")],
Some("A custom function"),
None,
None,
);
let results = fc.complete("my_func");
assert_eq!(results.len(), 1);
assert_eq!(results[0].return_type, Some("int".to_string()));
assert_eq!(results[0].parameters.len(), 2);
}
#[test]
fn test_function_completion_template() {
let mut fc = X86FunctionCompletion::new();
fc.register_template_function(
"max",
"T",
&[("const T&", "a"), ("const T&", "b")],
&["T"],
Some("Maximum of two values"),
None,
);
let results = fc.complete("max");
assert_eq!(results.len(), 1);
assert_eq!(results[0].kind, X86CompletionKind::TemplateFunction);
assert_eq!(results[0].template_params, vec!["T"]);
}
#[test]
fn test_function_completion_operator() {
let mut fc = X86FunctionCompletion::new();
fc.register_operator(
"+",
"Vec3",
&[("const Vec3&", "other")],
Some("Vector addition"),
);
let results = fc.complete_operators("+");
assert_eq!(results.len(), 1);
assert!(results[0].display_text.contains("operator"));
}
#[test]
fn test_variable_completion_local() {
let mut vc = X86VariableCompletion::new();
vc.register_local("counter", "int", Some("Loop counter"));
vc.register_local("index", "size_t", Some("Array index"));
let results = vc.complete("");
assert!(results.iter().any(|r| r.display_text.contains("counter")));
assert!(results.iter().any(|r| r.display_text.contains("index")));
}
#[test]
fn test_variable_completion_global() {
let mut vc = X86VariableCompletion::new();
vc.register_global("errno", "int", Some("Error number"), false);
vc.register_global("environ", "char**", Some("Environment variables"), true);
let results = vc.complete("err");
assert_eq!(results.len(), 1);
assert_eq!(results[0].kind, X86CompletionKind::GlobalVariable);
}
#[test]
fn test_variable_completion_by_kind() {
let mut vc = X86VariableCompletion::new();
vc.register_local("x", "int", None);
vc.register_global("PI", "const double", Some("Pi constant"), true);
let locals = vc.complete_by_kind("", X86CompletionKind::LocalVariable);
assert!(locals.iter().any(|r| r.display_text.contains("x")));
let globals = vc.complete_by_kind("", X86CompletionKind::GlobalVariable);
assert!(globals.iter().any(|r| r.display_text.contains("PI")));
}
#[test]
fn test_variable_completion_filtered() {
let mut vc = X86VariableCompletion::new();
vc.register_local("alpha", "int", None);
vc.register_local("beta", "int", None);
vc.register_local("alphabet", "int", None);
let results = vc.complete("alph");
assert_eq!(results.len(), 1);
assert!(results[0].display_text.contains("alphabet"));
}
#[test]
fn test_namespace_completion_list() {
let mut nc = X86NamespaceCompletion::new();
nc.register_std_namespace();
let results = nc.complete_namespaces("");
assert!(results.iter().any(|r| r.display_text == "std"));
}
#[test]
fn test_namespace_completion_scope() {
let mut nc = X86NamespaceCompletion::new();
nc.register_std_namespace();
let results = nc.complete_scope("std", "");
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.display_text.contains("string")));
assert!(results.iter().any(|r| r.display_text.contains("vector")));
assert!(results.iter().any(|r| r.display_text.contains("cout")));
}
#[test]
fn test_namespace_completion_filtered() {
let mut nc = X86NamespaceCompletion::new();
nc.register_std_namespace();
let results = nc.complete_scope("std", "str");
for r in &results {
assert!(
r.display_text.to_lowercase().starts_with("str"),
"Result '{}' should start with 'str'",
r.display_text
);
}
}
#[test]
fn test_namespace_completion_nested() {
let mut nc = X86NamespaceCompletion::new();
nc.register_std_namespace();
let results = nc.complete_namespaces("");
let has_nested = results.iter().any(|r| r.display_text == "std");
assert!(has_nested);
}
#[test]
fn test_macro_completion_std() {
let mut mc = X86MacroCompletion::new();
mc.register_std_macros();
let results = mc.complete("NULL");
assert!(results.iter().any(|r| r.display_text == "NULL"));
}
#[test]
fn test_macro_completion_builtin() {
let mc = X86MacroCompletion::new();
let results = mc.complete("__cplusplus");
assert!(results.iter().any(|r| r.display_text == "__cplusplus"));
}
#[test]
fn test_macro_completion_filtered() {
let mut mc = X86MacroCompletion::new();
mc.register_std_macros();
let results = mc.complete("SEEK");
assert!(results.iter().any(|r| r.display_text == "SEEK_SET"));
assert!(results.iter().any(|r| r.display_text == "SEEK_CUR"));
assert!(results.iter().any(|r| r.display_text == "SEEK_END"));
}
#[test]
fn test_macro_completion_user_defined() {
let mut mc = X86MacroCompletion::new();
mc.register_macro(
"MY_MACRO",
Some(&["x", "y"]),
Some("((x) + (y))"),
Some("Custom macro: adds x and y"),
None,
);
let results = mc.complete("MY_MACRO");
assert_eq!(results.len(), 1);
assert_eq!(results[0].display_text, "MY_MACRO");
assert!(results[0].documentation.is_some());
}
#[test]
fn test_macro_completion_fuzzy() {
let mut mc = X86MacroCompletion::new();
mc.register_std_macros();
let results = mc.complete_fuzzy("NULl");
assert!(
results.iter().any(|r| r.display_text == "NULL"),
"Fuzzy matching should find 'NULL' for 'NULl'"
);
}
#[test]
fn test_keyword_completion_c() {
let kc = X86KeywordCompletion::new();
let results = kc.complete_c_keywords("");
assert!(results.iter().any(|r| r.display_text == "if"));
assert!(results.iter().any(|r| r.display_text == "for"));
assert!(results.iter().any(|r| r.display_text == "while"));
assert!(results.iter().any(|r| r.display_text == "return"));
assert!(results.iter().any(|r| r.display_text == "struct"));
}
#[test]
fn test_keyword_completion_cpp() {
let kc = X86KeywordCompletion::new();
let results = kc.complete_cpp_keywords("");
assert!(results.iter().any(|r| r.display_text == "class"));
assert!(results.iter().any(|r| r.display_text == "namespace"));
assert!(results.iter().any(|r| r.display_text == "template"));
assert!(results.iter().any(|r| r.display_text == "virtual"));
}
#[test]
fn test_keyword_completion_type_specifiers() {
let kc = X86KeywordCompletion::new();
let results = kc.complete_types("");
assert!(results.iter().any(|r| r.display_text == "int"));
assert!(results.iter().any(|r| r.display_text == "double"));
assert!(results.iter().any(|r| r.display_text == "size_t"));
}
#[test]
fn test_keyword_completion_filtered() {
let kc = X86KeywordCompletion::new();
let results = kc.complete_all("stat");
assert!(results.iter().any(|r| r.display_text == "static"));
assert!(results
.iter()
.all(|r| r.display_text.to_lowercase().starts_with("stat")));
}
#[test]
fn test_directive_completion_all() {
let dc = X86DirectiveCompletion::new();
let results = dc.complete("");
assert!(results.iter().any(|r| r.display_text == "include"));
assert!(results.iter().any(|r| r.display_text == "define"));
assert!(results.iter().any(|r| r.display_text == "ifdef"));
assert!(results.iter().any(|r| r.display_text == "pragma"));
}
#[test]
fn test_directive_completion_filtered() {
let dc = X86DirectiveCompletion::new();
let results = dc.complete("if");
assert!(results.iter().any(|r| r.display_text == "if"));
assert!(results.iter().any(|r| r.display_text == "ifdef"));
assert!(results.iter().any(|r| r.display_text == "ifndef"));
}
#[test]
fn test_directive_completion_pragma() {
let dc = X86DirectiveCompletion::new();
let results = dc.complete("pragma");
assert!(!results.is_empty());
assert!(results
.iter()
.any(|r| r.display_text.contains("pragma once")));
}
#[test]
fn test_directive_completion_get() {
let dc = X86DirectiveCompletion::new();
let result = dc.get("include");
assert!(result.is_some());
assert_eq!(result.unwrap().display_text, "include");
}
#[test]
fn test_file_path_completion_system() {
let mut fc = X86FilePathCompletion::new();
fc.register_common_headers();
let results = fc.complete_path("stdio", IncludeDelimiter::Angle);
assert!(results.iter().any(|r| r.display_text == "stdio.h"));
}
#[test]
fn test_file_path_completion_cpp() {
let mut fc = X86FilePathCompletion::new();
fc.register_common_headers();
let results = fc.complete_path("iostream", IncludeDelimiter::Angle);
assert!(results.iter().any(|r| r.display_text == "iostream"));
}
#[test]
fn test_file_path_completion_project() {
let mut fc = X86FilePathCompletion::new();
fc.register_project_header("./include/", "my_header.h");
fc.register_project_header("./include/", "utils.h");
let results = fc.complete_path("my_", IncludeDelimiter::Quote);
assert!(results.iter().any(|r| r.display_text == "my_header.h"));
}
#[test]
fn test_file_path_completion_x86() {
let mut fc = X86FilePathCompletion::new();
fc.register_common_headers();
let results = fc.complete_path("xmm", IncludeDelimiter::Angle);
assert!(results.iter().any(|r| r.display_text == "xmmintrin.h"));
}
#[test]
fn test_snippet_completion_all() {
let sc = X86SnippetCompletion::new();
let results = sc.all_snippets();
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.display_text.contains("for loop")));
assert!(results.iter().any(|r| r.display_text.contains("if")));
assert!(results.iter().any(|r| r.display_text.contains("class")));
}
#[test]
fn test_snippet_completion_search() {
let sc = X86SnippetCompletion::new();
let results = sc.search("for");
assert!(results.iter().any(|r| r.display_text.contains("for loop")));
assert!(results.iter().any(|r| r.display_text.contains("for range")));
}
#[test]
fn test_snippet_completion_context_expression() {
let sc = X86SnippetCompletion::new();
let ctx = X86CompletionContext::ExpressionContext;
let results = sc.complete_for_context(&ctx);
assert!(!results.is_empty());
assert!(results.iter().any(|r| r.display_text.contains("for")));
assert!(results.iter().any(|r| r.display_text.contains("while")));
}
#[test]
fn test_snippet_completion_context_class_body() {
let sc = X86SnippetCompletion::new();
let ctx = X86CompletionContext::DeclarationContext {
in_class_body: true,
class_name: Some("MyClass".to_string()),
in_namespace: false,
at_top_level: false,
};
let results = sc.complete_for_context(&ctx);
assert!(!results.is_empty());
assert!(results
.iter()
.any(|r| r.display_text.contains("constructor")));
}
#[test]
fn test_snippet_completion_context_top_level() {
let sc = X86SnippetCompletion::new();
let ctx = X86CompletionContext::DeclarationContext {
in_class_body: false,
class_name: None,
in_namespace: false,
at_top_level: true,
};
let results = sc.complete_for_context(&ctx);
assert!(!results.is_empty());
}
#[test]
fn test_engine_creation() {
let engine = X86CodeCompleteDeep::new();
assert!(engine.cpp_mode);
assert!(engine.x86_intrinsics);
assert!(engine.fuzzy);
assert_eq!(engine.max_results, 50);
}
#[test]
fn test_engine_c_mode() {
let engine = X86CodeCompleteDeep::new_c_mode();
assert!(!engine.cpp_mode);
}
#[test]
fn test_engine_complete_keywords() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_all("for");
assert!(results.iter().any(|r| r.display_text == "for"));
}
#[test]
fn test_engine_complete_types() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_all("int");
assert!(results.iter().any(|r| r.display_text == "int"));
}
#[test]
fn test_engine_complete_functions() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_all("printf");
assert!(results.iter().any(|r| r.display_text.contains("printf")));
}
#[test]
fn test_engine_complete_directive() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_directive("incl");
assert!(results.iter().any(|r| r.display_text == "include"));
}
#[test]
fn test_engine_complete_include() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_include("stdio", true);
assert!(results.iter().any(|r| r.display_text == "stdio.h"));
}
#[test]
fn test_engine_complete_context_dot() {
let mut engine = X86CodeCompleteDeep::new();
engine.member_completion.register_field(
"MyStruct",
"value",
"int",
None,
X86SymbolVisibility::Public,
);
let results = engine.complete_dot_access("MyStruct", "", false);
assert!(results.iter().any(|r| r.display_text.contains("value")));
}
#[test]
fn test_engine_complete_context_scope() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_scope_resolution(Some("std"), "");
assert!(!results.is_empty());
assert!(
results.iter().any(|r| r.display_text.contains("string"))
|| results.iter().any(|r| r.display_text.contains("vector"))
);
}
#[test]
fn test_engine_complete_source_line() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete("obj.", 4, "");
assert!(results.len() <= engine.max_results);
}
#[test]
fn test_engine_caching() {
let mut engine = X86CodeCompleteDeep::new();
let results1 = engine.complete_all("int");
let results2 = engine.complete_all("int");
assert_eq!(results1.len(), results2.len());
}
#[test]
fn test_engine_cache_invalidation() {
let mut engine = X86CodeCompleteDeep::new();
let results1 = engine.complete_all("int");
engine.clear_cache();
let results2 = engine.complete_all("int");
assert_eq!(results1.len(), results2.len());
}
#[test]
fn test_engine_stats() {
let engine = X86CodeCompleteDeep::new();
let stats = engine.stats();
assert!(stats.total_types > 0);
assert!(stats.total_functions > 0);
assert!(stats.total_macros > 0);
assert!(stats.total_snippets > 0);
assert!(stats.is_cpp_mode);
assert_eq!(stats.cache_entries, 0);
}
#[test]
fn test_engine_stats_display() {
let engine = X86CodeCompleteDeep::new();
let stats = engine.stats();
let display = format!("{}", stats);
assert!(display.contains("X86CodeCompleteDeep Statistics"));
assert!(display.contains("C++"));
assert!(display.contains("Known types"));
}
#[test]
fn test_engine_ranked() {
let mut engine = X86CodeCompleteDeep::new();
let results =
engine.complete_ranked(&X86CompletionContext::General, "int", Some("int"), None);
assert!(!results.is_empty());
}
#[test]
fn test_engine_symbol_usage() {
let mut engine = X86CodeCompleteDeep::new();
engine.record_symbol_usage("printf");
engine.record_symbol_usage("printf");
let results = engine.complete_all("printf");
assert!(!results.is_empty());
}
#[test]
fn test_make_x86_64_deep_codecomplete() {
let engine = make_x86_64_deep_codecomplete();
assert!(engine.cpp_mode);
assert!(engine.x86_intrinsics);
}
#[test]
fn test_make_x86_32_deep_codecomplete() {
let engine = make_x86_32_deep_codecomplete();
assert!(!engine.cpp_mode);
assert!(engine.x86_intrinsics);
}
#[test]
fn test_make_x86_deep_codecomplete_cpp17() {
let engine = make_x86_deep_codecomplete_cpp17();
assert!(engine.cpp_mode);
assert!(engine.x86_intrinsics);
assert!(engine.fuzzy);
assert_eq!(engine.max_results, 100);
}
#[test]
fn test_make_x86_deep_codecomplete_minimal() {
let engine = make_x86_deep_codecomplete_minimal();
assert!(!engine.cpp_mode);
assert!(!engine.x86_intrinsics);
assert!(!engine.fuzzy);
assert_eq!(engine.max_results, 25);
}
#[test]
fn test_completion_kind_icon() {
assert_eq!(X86CompletionKind::Function.icon(), "f");
assert_eq!(X86CompletionKind::Type.icon(), "t");
assert_eq!(X86CompletionKind::Macro.icon(), "m");
assert_eq!(X86CompletionKind::Keyword.icon(), "k");
assert_eq!(X86CompletionKind::Snippet.icon(), "~");
assert_eq!(X86CompletionKind::Namespace.icon(), "n");
}
#[test]
fn test_completion_kind_lsp_kind() {
assert_eq!(X86CompletionKind::Function.lsp_kind(), 3);
assert_eq!(X86CompletionKind::Variable.lsp_kind(), 6);
assert_eq!(X86CompletionKind::Type.lsp_kind(), 7);
assert_eq!(X86CompletionKind::Keyword.lsp_kind(), 14);
assert_eq!(X86CompletionKind::Namespace.lsp_kind(), 8);
}
#[test]
fn test_completion_kind_display() {
let s = format!("{}", X86CompletionKind::Function);
assert_eq!(s, "function");
let s = format!("{}", X86CompletionKind::TemplateFunction);
assert_eq!(s, "template-function");
}
#[test]
fn test_include_delimiter_eq() {
assert_eq!(IncludeDelimiter::Quote, IncludeDelimiter::Quote);
assert_eq!(IncludeDelimiter::Angle, IncludeDelimiter::Angle);
assert_ne!(IncludeDelimiter::Quote, IncludeDelimiter::Angle);
}
#[test]
fn test_access_specifier_eq() {
assert_eq!(X86AccessSpecifier::Public, X86AccessSpecifier::Public);
assert_eq!(X86AccessSpecifier::Protected, X86AccessSpecifier::Protected);
assert_ne!(X86AccessSpecifier::Public, X86AccessSpecifier::Private);
}
#[test]
fn test_symbol_visibility_eq() {
assert_eq!(X86SymbolVisibility::Public, X86SymbolVisibility::Public);
assert_eq!(X86SymbolVisibility::Private, X86SymbolVisibility::Private);
assert_ne!(X86SymbolVisibility::Public, X86SymbolVisibility::Private);
}
#[test]
fn test_ranker_weights_default() {
let weights = X86RankerWeights::default();
assert!((weights.type_weight - 0.30).abs() < 0.001);
assert!((weights.scope_weight - 0.20).abs() < 0.001);
assert!((weights.frequency_weight - 0.15).abs() < 0.001);
assert!((weights.distance_weight - 0.10).abs() < 0.001);
assert!((weights.context_weight - 0.25).abs() < 0.001);
}
#[test]
fn test_empty_prefix_completes_all() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_all("");
assert!(!results.is_empty());
assert!(results.len() <= engine.max_results);
}
#[test]
fn test_nonexistent_prefix_returns_empty() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_all("zzzz_nonexistent_symbol_xyzzy");
assert!(results.is_empty());
}
#[test]
fn test_empty_source_line() {
let ctx = X86CompletionContext::from_source_line("", 0);
assert_eq!(ctx, X86CompletionContext::General);
}
#[test]
fn test_column_beyond_line() {
let ctx = X86CompletionContext::from_source_line("int x", 100);
assert!(matches!(
ctx,
X86CompletionContext::General
| X86CompletionContext::DeclarationContext { .. }
| X86CompletionContext::ExpressionContext
));
}
#[test]
fn test_multiple_calls_same_result() {
let mut engine = X86CodeCompleteDeep::new();
let results1 = engine.complete_all("int");
let results2 = engine.complete_all("int");
assert_eq!(results1, results2, "Cached results should be identical");
}
#[test]
fn test_large_completion_set() {
let mut engine = X86CodeCompleteDeep::new();
engine.max_results = 200;
let results = engine.complete_all("");
assert!(!results.is_empty());
assert!(results.len() <= 200);
}
#[test]
fn test_all_contexts_no_panic() {
let all_contexts: Vec<X86CompletionContext> = vec![
X86CompletionContext::DotAccess {
receiver_type: Some("obj".into()),
implicit_this: false,
},
X86CompletionContext::ArrowAccess {
receiver_type: Some("ptr".into()),
implicit_this: false,
},
X86CompletionContext::ScopeResolution {
scope_name: Some("std".into()),
nested: false,
nested_specifiers: vec![],
},
X86CompletionContext::OpenParen {
callee: Some("func".into()),
},
X86CompletionContext::TypeContext {
template_argument: false,
base_specifier: false,
preceding_keyword: None,
},
X86CompletionContext::DeclarationContext {
in_class_body: true,
class_name: Some("C".into()),
in_namespace: false,
at_top_level: false,
},
X86CompletionContext::DirectiveContext {
partial: "incl".into(),
},
X86CompletionContext::IncludeContext {
delimiter: IncludeDelimiter::Angle,
partial: "std".into(),
},
X86CompletionContext::StringContext {
partial: "path".into(),
delimiter: '"',
},
X86CompletionContext::LabelContext,
X86CompletionContext::EnumBody {
enum_name: Some("E".into()),
},
X86CompletionContext::UsingContext,
X86CompletionContext::TemplateArgumentContext,
X86CompletionContext::General,
X86CompletionContext::ExpressionContext,
X86CompletionContext::ReturnContext,
X86CompletionContext::CaseContext,
X86CompletionContext::GotoContext,
X86CompletionContext::AccessSpecifierContext {
access: X86AccessSpecifier::Public,
},
X86CompletionContext::InitializerListContext {
class_name: Some("C".into()),
},
X86CompletionContext::ThrowContext,
X86CompletionContext::NoexceptContext,
X86CompletionContext::CatchContext,
X86CompletionContext::DecltypeContext,
X86CompletionContext::SizeofContext,
X86CompletionContext::AttributeContext,
];
let mut engine = X86CodeCompleteDeep::new();
for ctx in &all_contexts {
let results = engine.complete_with_context(ctx, "", None);
assert!(
results.len() <= engine.max_results,
"Context {:?} returned more than max_results",
ctx
);
}
}
#[test]
fn test_x86_completion_kind_enum_values() {
let kinds = vec![
X86CompletionKind::Function,
X86CompletionKind::Variable,
X86CompletionKind::Type,
X86CompletionKind::Macro,
X86CompletionKind::Keyword,
X86CompletionKind::Directive,
X86CompletionKind::Field,
X86CompletionKind::EnumMember,
X86CompletionKind::Namespace,
X86CompletionKind::Snippet,
X86CompletionKind::File,
X86CompletionKind::Label,
X86CompletionKind::Concept,
X86CompletionKind::Operator,
X86CompletionKind::TypeParameter,
X86CompletionKind::Intrinsic,
X86CompletionKind::Module,
X86CompletionKind::Constant,
X86CompletionKind::TemplateFunction,
X86CompletionKind::TemplateType,
X86CompletionKind::StaticMember,
X86CompletionKind::InheritedMember,
X86CompletionKind::UsingDeclaration,
X86CompletionKind::NamespaceAlias,
X86CompletionKind::Constructor,
X86CompletionKind::Destructor,
X86CompletionKind::ConversionFunction,
X86CompletionKind::LiteralOperator,
X86CompletionKind::UserDefinedLiteral,
X86CompletionKind::Parameter,
X86CompletionKind::LocalVariable,
X86CompletionKind::GlobalVariable,
];
let mut seen = HashSet::new();
for kind in kinds {
let val = kind as u8;
assert!(
seen.insert(val),
"Duplicate discriminant value: {} for {:?}",
val,
kind
);
}
}
#[test]
fn test_type_completion_empty_registration() {
let tc = X86TypeCompletion::new();
let results = tc.complete("int");
assert!(results.iter().any(|r| r.display_text == "int"));
}
#[test]
fn test_member_completion_empty_type() {
let mc = X86MemberCompletion::new();
let results = mc.complete_members("NonExistentType", "", false);
assert!(results.is_empty());
}
#[test]
fn test_function_completion_duplicate_registration() {
let mut fc = X86FunctionCompletion::new();
fc.register_function("dup", "int", &[], None, None, None);
fc.register_function("dup", "int", &[("int", "x")], None, None, None);
let results = fc.complete("dup");
assert_eq!(results.len(), 2);
}
#[test]
fn test_variable_completion_duplicate() {
let mut vc = X86VariableCompletion::new();
vc.register_local("x", "int", None);
vc.register_local("x", "double", None);
let results = vc.complete("x");
assert_eq!(results.len(), 2);
}
#[test]
fn test_namespace_completion_double_register() {
let mut nc = X86NamespaceCompletion::new();
nc.register_namespace("test_ns", Some("First"));
nc.register_namespace("test_ns", Some("Second"));
let results = nc.complete_namespaces("test_ns");
assert_eq!(results.len(), 1);
}
#[test]
fn test_macro_completion_empty_string_body() {
let mut mc = X86MacroCompletion::new();
mc.register_macro("EMPTY_MACRO", None, Some(""), Some("Empty body"), None);
let results = mc.complete("EMPTY_MACRO");
assert_eq!(results.len(), 1);
assert_eq!(results[0].display_text, "EMPTY_MACRO");
}
#[test]
fn test_context_public_access_specifier() {
let ctx = X86CompletionContext::from_source_line("public:", 7);
match ctx {
X86CompletionContext::AccessSpecifierContext { access } => {
assert_eq!(access, X86AccessSpecifier::Public);
}
_ => panic!("Expected AccessSpecifierContext"),
}
}
#[test]
fn test_context_attribute_ctx() {
let ctx = X86CompletionContext::from_source_line("[[", 2);
assert_eq!(ctx, X86CompletionContext::AttributeContext);
}
#[test]
fn test_context_initializer_list() {
let ctx = X86CompletionContext::from_source_line("MyClass() : ", 12);
}
#[test]
fn test_context_template_argument() {
let ctx = X86CompletionContext::from_source_line("vector<", 7);
assert_eq!(ctx, X86CompletionContext::TemplateArgumentContext);
}
#[test]
fn test_context_using_namespace() {
let ctx = X86CompletionContext::from_source_line("using namespace ", 16);
assert_eq!(ctx, X86CompletionContext::UsingContext);
}
#[test]
fn test_context_sizeof() {
let ctx = X86CompletionContext::from_source_line("sizeof(", 7);
assert_eq!(ctx, X86CompletionContext::SizeofContext);
}
#[test]
fn test_context_noexcept() {
let ctx = X86CompletionContext::from_source_line("noexcept(", 9);
assert_eq!(ctx, X86CompletionContext::NoexceptContext);
}
#[test]
fn test_ranker_empty_results() {
let ranker = X86CompletionRanker::new();
let mut results: Vec<X86CompletionResult> = Vec::new();
ranker.rank(&mut results, "", &X86CompletionContext::General, None);
assert!(results.is_empty());
}
#[test]
fn test_ranker_fuzzy_disabled() {
let mut ranker = X86CompletionRanker::new();
ranker.set_fuzzy(false, 0.0);
let mut results = vec![{
let mut r = X86CompletionResult::keyword("hello");
r.display_text = "hello".to_string();
r
}];
ranker.rank(&mut results, "hallo", &X86CompletionContext::General, None);
assert_eq!(results.len(), 1);
}
#[test]
fn test_ranker_custom_weights() {
let weights = X86RankerWeights {
type_weight: 1.0,
scope_weight: 0.0,
frequency_weight: 0.0,
distance_weight: 0.0,
context_weight: 0.0,
};
let mut ranker = X86CompletionRanker::with_weights(weights);
let mut results = vec![
{
let mut r = X86CompletionResult::function("f_int", "int", &[], None);
r.priority = 0;
r
},
{
let mut r = X86CompletionResult::function("f_void", "void", &[], None);
r.priority = 0;
r
},
];
ranker.rank(
&mut results,
"",
&X86CompletionContext::General,
Some("int"),
);
let f_int = results
.iter()
.find(|r| r.display_text.contains("f_int"))
.unwrap();
let f_void = results
.iter()
.find(|r| r.display_text.contains("f_void"))
.unwrap();
assert!(f_int.priority > f_void.priority);
}
#[test]
fn test_engine_deduplicates_results() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_all("int");
let int_count = results.iter().filter(|r| r.display_text == "int").count();
assert!(int_count <= 1, "Should have at most one 'int' result");
}
#[test]
fn test_no_crash_on_unicode() {
let ctx = X86CompletionContext::from_source_line("变量.", 7);
let _ = ctx;
}
#[test]
fn test_levenshtein_unicode() {
let dist = levenshtein_distance("café", "cafe");
assert_eq!(dist, 1);
}
}
#[derive(Debug, Clone, Default)]
pub struct X86IntrinsicDatabase {
categories: HashMap<String, Vec<X86IntrinsicEntry>>,
all_intrinsics: Vec<X86IntrinsicEntry>,
}
#[derive(Debug, Clone)]
struct X86IntrinsicEntry {
name: String,
return_type: String,
params: Vec<(String, String)>,
header: String,
category: String,
doc: String,
isa: X86IsaLevel,
cpu_feature: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum X86IsaLevel {
Baseline = 0,
MMX = 1,
SSE = 2,
SSE2 = 3,
SSE3 = 4,
SSSE3 = 5,
SSE41 = 6,
SSE42 = 7,
AVX = 8,
AVX2 = 9,
AVX512F = 10,
AVX512CD = 11,
AVX512BW = 12,
AVX512DQ = 13,
AVX512VL = 14,
FMA = 15,
AES = 16,
PCLMUL = 17,
RDRAND = 18,
RDSEED = 19,
SHA = 20,
BMI = 21,
BMI2 = 22,
LZCNT = 23,
POPCNT = 24,
F16C = 25,
AVX512ER = 26,
AVX512PF = 27,
AVX512IFMA = 28,
AVX512VBMI = 29,
AVX5124FMAPS = 30,
AVX5124VNNIW = 31,
AVX512VPOPCNTDQ = 32,
AVX512BITALG = 33,
AVX512VNNI = 34,
AVX512BF16 = 35,
AVX512VP2INTERSECT = 36,
AMX = 37,
AMXBF16 = 38,
AMXINT8 = 39,
AMXTILE = 40,
AVXVNNI = 41,
AVXIFMA = 42,
}
impl X86IsaLevel {
pub fn compiler_flag(&self) -> &'static str {
match self {
Self::Baseline => "",
Self::MMX => "-mmmx",
Self::SSE => "-msse",
Self::SSE2 => "-msse2",
Self::SSE3 => "-msse3",
Self::SSSE3 => "-mssse3",
Self::SSE41 => "-msse4.1",
Self::SSE42 => "-msse4.2",
Self::AVX => "-mavx",
Self::AVX2 => "-mavx2",
Self::AVX512F => "-mavx512f",
Self::AVX512CD => "-mavx512cd",
Self::AVX512BW => "-mavx512bw",
Self::AVX512DQ => "-mavx512dq",
Self::AVX512VL => "-mavx512vl",
Self::FMA => "-mfma",
Self::AES => "-maes",
Self::PCLMUL => "-mpclmul",
Self::RDRAND => "-mrdrnd",
Self::RDSEED => "-mrdseed",
Self::SHA => "-msha",
Self::BMI => "-mbmi",
Self::BMI2 => "-mbmi2",
Self::LZCNT => "-mlzcnt",
Self::POPCNT => "-mpopcnt",
Self::F16C => "-mf16c",
Self::AVX512ER => "-mavx512er",
Self::AVX512PF => "-mavx512pf",
Self::AVX512IFMA => "-mavx512ifma",
Self::AVX512VBMI => "-mavx512vbmi",
Self::AVX5124FMAPS => "-mavx5124fmaps",
Self::AVX5124VNNIW => "-mavx5124vnniw",
Self::AVX512VPOPCNTDQ => "-mavx512vpopcntdq",
Self::AVX512BITALG => "-mavx512bitalg",
Self::AVX512VNNI => "-mavx512vnni",
Self::AVX512BF16 => "-mavx512bf16",
Self::AVX512VP2INTERSECT => "-mavx512vp2intersect",
Self::AMX => "-mamx-tile",
Self::AMXBF16 => "-mamx-bf16",
Self::AMXINT8 => "-mamx-int8",
Self::AMXTILE => "-mamx-tile",
Self::AVXVNNI => "-mavxvnni",
Self::AVXIFMA => "-mavxifma",
}
}
pub fn predefined_macro(&self) -> Option<&'static str> {
match self {
Self::MMX => Some("__MMX__"),
Self::SSE => Some("__SSE__"),
Self::SSE2 => Some("__SSE2__"),
Self::SSE3 => Some("__SSE3__"),
Self::SSSE3 => Some("__SSSE3__"),
Self::SSE41 => Some("__SSE4_1__"),
Self::SSE42 => Some("__SSE4_2__"),
Self::AVX => Some("__AVX__"),
Self::AVX2 => Some("__AVX2__"),
Self::AVX512F => Some("__AVX512F__"),
Self::AVX512CD => Some("__AVX512CD__"),
Self::AVX512BW => Some("__AVX512BW__"),
Self::AVX512DQ => Some("__AVX512DQ__"),
Self::AVX512VL => Some("__AVX512VL__"),
Self::FMA => Some("__FMA__"),
Self::AES => Some("__AES__"),
Self::PCLMUL => Some("__PCLMUL__"),
Self::RDRAND => Some("__RDRND__"),
Self::BMI => Some("__BMI__"),
Self::BMI2 => Some("__BMI2__"),
Self::LZCNT => Some("__LZCNT__"),
Self::POPCNT => Some("__POPCNT__"),
_ => None,
}
}
pub fn description(&self) -> &'static str {
match self {
Self::Baseline => "x86 Baseline (no extensions)",
Self::MMX => "MMX — MultiMedia eXtensions (64-bit integer SIMD)",
Self::SSE => "SSE — Streaming SIMD Extensions (128-bit float SIMD)",
Self::SSE2 => "SSE2 — SSE with double-precision and integer operations",
Self::SSE3 => "SSE3 — SSE with horizontal operations",
Self::SSSE3 => "SSSE3 — Supplemental SSE3",
Self::SSE41 => "SSE4.1 — SSE4 with dot products, rounding, blending",
Self::SSE42 => "SSE4.2 — SSE4 with string/text processing",
Self::AVX => "AVX — Advanced Vector Extensions (256-bit SIMD)",
Self::AVX2 => "AVX2 — AVX with integer SIMD and gather",
Self::AVX512F => "AVX-512 Foundation (512-bit SIMD)",
Self::AVX512CD => "AVX-512 Conflict Detection",
Self::AVX512BW => "AVX-512 Byte and Word",
Self::AVX512DQ => "AVX-512 Doubleword and Quadword",
Self::AVX512VL => "AVX-512 Vector Length extensions",
Self::FMA => "FMA — Fused Multiply-Add",
Self::AES => "AES-NI — Advanced Encryption Standard New Instructions",
Self::PCLMUL => "PCLMUL — Carry-Less Multiplication",
Self::RDRAND => "RDRAND — Hardware Random Number Generator",
Self::RDSEED => "RDSEED — Hardware Seed Generator",
Self::SHA => "SHA — Secure Hash Algorithm extensions",
Self::BMI => "BMI — Bit Manipulation Instructions",
Self::BMI2 => "BMI2 — Bit Manipulation Instructions 2",
Self::LZCNT => "LZCNT — Leading Zero Count",
Self::POPCNT => "POPCNT — Population Count",
Self::F16C => "F16C — 16-bit Floating-Point Conversion",
Self::AVX512ER => "AVX-512 Exponential and Reciprocal",
Self::AVX512PF => "AVX-512 Prefetch",
Self::AVX512IFMA => "AVX-512 Integer FMA",
Self::AVX512VBMI => "AVX-512 Vector Byte Manipulation",
Self::AVX5124FMAPS => "AVX-512 4-iteration FMA packed single",
Self::AVX5124VNNIW => "AVX-512 4-iteration Vector Neural Net",
Self::AVX512VPOPCNTDQ => "AVX-512 Vector POPCNT DWord/QWord",
Self::AVX512BITALG => "AVX-512 Bit Algorithms",
Self::AVX512VNNI => "AVX-512 Vector Neural Network Instructions",
Self::AVX512BF16 => "AVX-512 BFloat16",
Self::AVX512VP2INTERSECT => "AVX-512 VP2INTERSECT",
Self::AMX => "AMX — Advanced Matrix Extensions",
Self::AMXBF16 => "AMX BFloat16",
Self::AMXINT8 => "AMX INT8",
Self::AMXTILE => "AMX Tile",
Self::AVXVNNI => "AVX Vector Neural Network Instructions",
Self::AVXIFMA => "AVX Integer FMA",
}
}
}
impl X86IntrinsicDatabase {
pub fn new() -> Self {
let mut db = Self::default();
db.initialize();
db
}
fn initialize(&mut self) {
self.add_intrinsic(
"_mm_load_ps",
"__m128",
&[("float const*", "mem_addr")],
"xmmintrin.h",
"SSE",
"Load 128-bits (4 packed single-precision floats)",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_load_ss",
"__m128",
&[("float const*", "mem_addr")],
"xmmintrin.h",
"SSE",
"Load single-precision float into low element",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_store_ps",
"void",
&[("float*", "mem_addr"), ("__m128", "a")],
"xmmintrin.h",
"SSE",
"Store 128-bits (4 packed single-precision floats)",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_set_ps",
"__m128",
&[
("float", "e3"),
("float", "e2"),
("float", "e1"),
("float", "e0"),
],
"xmmintrin.h",
"SSE",
"Set packed single-precision floats",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_set1_ps",
"__m128",
&[("float", "a")],
"xmmintrin.h",
"SSE",
"Set all elements to same float value",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_setzero_ps",
"__m128",
&[],
"xmmintrin.h",
"SSE",
"Set all elements to zero",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_add_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b")],
"xmmintrin.h",
"SSE",
"Add packed single-precision floats",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_sub_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b")],
"xmmintrin.h",
"SSE",
"Subtract packed single-precision floats",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_mul_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b")],
"xmmintrin.h",
"SSE",
"Multiply packed single-precision floats",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_div_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b")],
"xmmintrin.h",
"SSE",
"Divide packed single-precision floats",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_sqrt_ps",
"__m128",
&[("__m128", "a")],
"xmmintrin.h",
"SSE",
"Square root of packed single-precision floats",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_rcp_ps",
"__m128",
&[("__m128", "a")],
"xmmintrin.h",
"SSE",
"Approximate reciprocal of packed floats",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_rsqrt_ps",
"__m128",
&[("__m128", "a")],
"xmmintrin.h",
"SSE",
"Approximate reciprocal sqrt of packed floats",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_min_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b")],
"xmmintrin.h",
"SSE",
"Minimum of packed single-precision floats",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_max_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b")],
"xmmintrin.h",
"SSE",
"Maximum of packed single-precision floats",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_mm_load_pd",
"__m128d",
&[("double const*", "mem_addr")],
"emmintrin.h",
"SSE2",
"Load 128-bits (2 packed double-precision floats)",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_add_pd",
"__m128d",
&[("__m128d", "a"), ("__m128d", "b")],
"emmintrin.h",
"SSE2",
"Add packed double-precision floats",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_sub_pd",
"__m128d",
&[("__m128d", "a"), ("__m128d", "b")],
"emmintrin.h",
"SSE2",
"Subtract packed double-precision floats",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_mul_pd",
"__m128d",
&[("__m128d", "a"), ("__m128d", "b")],
"emmintrin.h",
"SSE2",
"Multiply packed double-precision floats",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_div_pd",
"__m128d",
&[("__m128d", "a"), ("__m128d", "b")],
"emmintrin.h",
"SSE2",
"Divide packed double-precision floats",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_load_si128",
"__m128i",
&[("__m128i const*", "mem_addr")],
"emmintrin.h",
"SSE2",
"Load 128-bit integer data",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_set_epi32",
"__m128i",
&[("int", "e3"), ("int", "e2"), ("int", "e1"), ("int", "e0")],
"emmintrin.h",
"SSE2",
"Set packed 32-bit integers",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_add_epi32",
"__m128i",
&[("__m128i", "a"), ("__m128i", "b")],
"emmintrin.h",
"SSE2",
"Add packed 32-bit integers",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_slli_epi32",
"__m128i",
&[("__m128i", "a"), ("int", "imm8")],
"emmintrin.h",
"SSE2",
"Shift left logical packed 32-bit integers",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_srli_epi32",
"__m128i",
&[("__m128i", "a"), ("int", "imm8")],
"emmintrin.h",
"SSE2",
"Shift right logical packed 32-bit integers",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_shuffle_epi32",
"__m128i",
&[("__m128i", "a"), ("int", "imm8")],
"emmintrin.h",
"SSE2",
"Shuffle packed 32-bit integers",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_extract_epi16",
"int",
&[("__m128i", "a"), ("int", "imm8")],
"emmintrin.h",
"SSE2",
"Extract 16-bit integer",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_addsub_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b")],
"pmmintrin.h",
"SSE3",
"Alternating add/subtract packed floats",
X86IsaLevel::SSE3,
"sse3",
);
self.add_intrinsic(
"_mm_hadd_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b")],
"pmmintrin.h",
"SSE3",
"Horizontal add packed floats",
X86IsaLevel::SSE3,
"sse3",
);
self.add_intrinsic(
"_mm_hsub_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b")],
"pmmintrin.h",
"SSE3",
"Horizontal subtract packed floats",
X86IsaLevel::SSE3,
"sse3",
);
self.add_intrinsic(
"_mm_movehdup_ps",
"__m128",
&[("__m128", "a")],
"pmmintrin.h",
"SSE3",
"Duplicate high elements",
X86IsaLevel::SSE3,
"sse3",
);
self.add_intrinsic(
"_mm_moveldup_ps",
"__m128",
&[("__m128", "a")],
"pmmintrin.h",
"SSE3",
"Duplicate low elements",
X86IsaLevel::SSE3,
"sse3",
);
self.add_intrinsic(
"_mm_abs_epi8",
"__m128i",
&[("__m128i", "a")],
"tmmintrin.h",
"SSSE3",
"Absolute value of packed 8-bit integers",
X86IsaLevel::SSSE3,
"ssse3",
);
self.add_intrinsic(
"_mm_abs_epi32",
"__m128i",
&[("__m128i", "a")],
"tmmintrin.h",
"SSSE3",
"Absolute value of packed 32-bit integers",
X86IsaLevel::SSSE3,
"ssse3",
);
self.add_intrinsic(
"_mm_shuffle_epi8",
"__m128i",
&[("__m128i", "a"), ("__m128i", "b")],
"tmmintrin.h",
"SSSE3",
"Shuffle bytes using mask",
X86IsaLevel::SSSE3,
"ssse3",
);
self.add_intrinsic(
"_mm_alignr_epi8",
"__m128i",
&[("__m128i", "a"), ("__m128i", "b"), ("int", "count")],
"tmmintrin.h",
"SSSE3",
"Concatenate and right-shift bytes",
X86IsaLevel::SSSE3,
"ssse3",
);
self.add_intrinsic(
"_mm_dp_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b"), ("const int", "mask")],
"smmintrin.h",
"SSE4.1",
"Dot product of packed floats",
X86IsaLevel::SSE41,
"sse4.1",
);
self.add_intrinsic(
"_mm_blend_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b"), ("const int", "mask")],
"smmintrin.h",
"SSE4.1",
"Blend packed floats using mask",
X86IsaLevel::SSE41,
"sse4.1",
);
self.add_intrinsic(
"_mm_blendv_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b"), ("__m128", "mask")],
"smmintrin.h",
"SSE4.1",
"Variable blend packed floats",
X86IsaLevel::SSE41,
"sse4.1",
);
self.add_intrinsic(
"_mm_round_ps",
"__m128",
&[("__m128", "a"), ("int", "rounding")],
"smmintrin.h",
"SSE4.1",
"Round packed floats",
X86IsaLevel::SSE41,
"sse4.1",
);
self.add_intrinsic(
"_mm_ceil_ps",
"__m128",
&[("__m128", "a")],
"smmintrin.h",
"SSE4.1",
"Ceiling of packed floats",
X86IsaLevel::SSE41,
"sse4.1",
);
self.add_intrinsic(
"_mm_floor_ps",
"__m128",
&[("__m128", "a")],
"smmintrin.h",
"SSE4.1",
"Floor of packed floats",
X86IsaLevel::SSE41,
"sse4.1",
);
self.add_intrinsic(
"_mm_min_epi32",
"__m128i",
&[("__m128i", "a"), ("__m128i", "b")],
"smmintrin.h",
"SSE4.1",
"Minimum of packed 32-bit integers",
X86IsaLevel::SSE41,
"sse4.1",
);
self.add_intrinsic(
"_mm_max_epi32",
"__m128i",
&[("__m128i", "a"), ("__m128i", "b")],
"smmintrin.h",
"SSE4.1",
"Maximum of packed 32-bit integers",
X86IsaLevel::SSE41,
"sse4.1",
);
self.add_intrinsic(
"_mm_packus_epi32",
"__m128i",
&[("__m128i", "a"), ("__m128i", "b")],
"smmintrin.h",
"SSE4.1",
"Pack 32-bit integers to 16-bit unsigned with saturation",
X86IsaLevel::SSE41,
"sse4.1",
);
self.add_intrinsic(
"_mm_cmpestra",
"int",
&[
("__m128i", "a"),
("int", "la"),
("__m128i", "b"),
("int", "lb"),
("const int", "imm8"),
],
"nmmintrin.h",
"SSE4.2",
"Compare explicit-length strings, return index",
X86IsaLevel::SSE42,
"sse4.2",
);
self.add_intrinsic(
"_mm_cmpestrc",
"int",
&[
("__m128i", "a"),
("int", "la"),
("__m128i", "b"),
("int", "lb"),
("const int", "imm8"),
],
"nmmintrin.h",
"SSE4.2",
"Compare explicit-length strings, return mask",
X86IsaLevel::SSE42,
"sse4.2",
);
self.add_intrinsic(
"_mm_crc32_u8",
"unsigned int",
&[("unsigned int", "crc"), ("unsigned char", "v")],
"nmmintrin.h",
"SSE4.2",
"Accumulate CRC32C value",
X86IsaLevel::SSE42,
"sse4.2",
);
self.add_intrinsic(
"_mm_crc32_u32",
"unsigned int",
&[("unsigned int", "crc"), ("unsigned int", "v")],
"nmmintrin.h",
"SSE4.2",
"Accumulate CRC32C value",
X86IsaLevel::SSE42,
"sse4.2",
);
self.add_intrinsic(
"_mm256_load_ps",
"__m256",
&[("float const*", "mem_addr")],
"immintrin.h",
"AVX",
"Load 256-bits (8 packed single-precision floats)",
X86IsaLevel::AVX,
"avx",
);
self.add_intrinsic(
"_mm256_add_ps",
"__m256",
&[("__m256", "a"), ("__m256", "b")],
"immintrin.h",
"AVX",
"Add packed single-precision floats (256-bit)",
X86IsaLevel::AVX,
"avx",
);
self.add_intrinsic(
"_mm256_mul_ps",
"__m256",
&[("__m256", "a"), ("__m256", "b")],
"immintrin.h",
"AVX",
"Multiply packed single-precision floats (256-bit)",
X86IsaLevel::AVX,
"avx",
);
self.add_intrinsic(
"_mm256_hadd_ps",
"__m256",
&[("__m256", "a"), ("__m256", "b")],
"immintrin.h",
"AVX",
"Horizontal add packed floats (256-bit)",
X86IsaLevel::AVX,
"avx",
);
self.add_intrinsic(
"_mm256_broadcast_ss",
"__m256",
&[("float const*", "mem_addr")],
"immintrin.h",
"AVX",
"Broadcast single-precision float to all elements",
X86IsaLevel::AVX,
"avx",
);
self.add_intrinsic(
"_mm256_blend_ps",
"__m256",
&[("__m256", "a"), ("__m256", "b"), ("const int", "imm8")],
"immintrin.h",
"AVX",
"Blend packed floats (256-bit)",
X86IsaLevel::AVX,
"avx",
);
self.add_intrinsic(
"_mm256_permute_ps",
"__m256",
&[("__m256", "a"), ("int", "imm8")],
"immintrin.h",
"AVX",
"Permute single-precision floats (256-bit)",
X86IsaLevel::AVX,
"avx",
);
self.add_intrinsic(
"_mm256_i32gather_ps",
"__m256",
&[
("float const*", "base_addr"),
("__m256i", "vindex"),
("const int", "scale"),
],
"immintrin.h",
"AVX2",
"Gather single-precision floats using 32-bit indices",
X86IsaLevel::AVX2,
"avx2",
);
self.add_intrinsic(
"_mm256_mpsadbw_epu8",
"__m256i",
&[("__m256i", "a"), ("__m256i", "b"), ("const int", "imm8")],
"immintrin.h",
"AVX2",
"Compute multiple packed sum of absolute differences",
X86IsaLevel::AVX2,
"avx2",
);
self.add_intrinsic(
"_mm256_sllv_epi32",
"__m256i",
&[("__m256i", "a"), ("__m256i", "count")],
"immintrin.h",
"AVX2",
"Shift left logical variable packed 32-bit integers",
X86IsaLevel::AVX2,
"avx2",
);
self.add_intrinsic(
"_mm512_load_ps",
"__m512",
&[("void const*", "mem_addr")],
"zmmintrin.h",
"AVX-512",
"Load 512-bits (16 packed single-precision floats)",
X86IsaLevel::AVX512F,
"avx512f",
);
self.add_intrinsic(
"_mm512_add_ps",
"__m512",
&[("__m512", "a"), ("__m512", "b")],
"zmmintrin.h",
"AVX-512",
"Add packed single-precision floats (512-bit)",
X86IsaLevel::AVX512F,
"avx512f",
);
self.add_intrinsic(
"_mm512_fmadd_ps",
"__m512",
&[("__m512", "a"), ("__m512", "b"), ("__m512", "c")],
"zmmintrin.h",
"AVX-512",
"Fused multiply-add packed floats (512-bit)",
X86IsaLevel::AVX512F,
"avx512f",
);
self.add_intrinsic(
"_mm512_mask_add_ps",
"__m512",
&[
("__m512", "src"),
("__mmask16", "k"),
("__m512", "a"),
("__m512", "b"),
],
"zmmintrin.h",
"AVX-512",
"Masked add packed floats (512-bit)",
X86IsaLevel::AVX512F,
"avx512f",
);
self.add_intrinsic(
"_mm_aesenc_si128",
"__m128i",
&[("__m128i", "a"), ("__m128i", "round_key")],
"wmmintrin.h",
"AES-NI",
"Perform one round of AES encryption",
X86IsaLevel::AES,
"aes",
);
self.add_intrinsic(
"_mm_aesdec_si128",
"__m128i",
&[("__m128i", "a"), ("__m128i", "round_key")],
"wmmintrin.h",
"AES-NI",
"Perform one round of AES decryption",
X86IsaLevel::AES,
"aes",
);
self.add_intrinsic(
"_mm_aeskeygenassist_si128",
"__m128i",
&[("__m128i", "a"), ("const int", "imm8")],
"wmmintrin.h",
"AES-NI",
"Assist in AES key generation",
X86IsaLevel::AES,
"aes",
);
self.add_intrinsic(
"_mm_fmadd_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b"), ("__m128", "c")],
"immintrin.h",
"FMA",
"Fused multiply-add packed floats (128-bit)",
X86IsaLevel::FMA,
"fma",
);
self.add_intrinsic(
"_mm_fmsub_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b"), ("__m128", "c")],
"immintrin.h",
"FMA",
"Fused multiply-subtract packed floats (128-bit)",
X86IsaLevel::FMA,
"fma",
);
self.add_intrinsic(
"_mm_fnmadd_ps",
"__m128",
&[("__m128", "a"), ("__m128", "b"), ("__m128", "c")],
"immintrin.h",
"FMA",
"Fused negative multiply-add packed floats",
X86IsaLevel::FMA,
"fma",
);
self.add_intrinsic(
"_mm_tzcnt_32",
"int",
&[("unsigned int", "a")],
"bmiintrin.h",
"BMI",
"Count trailing zeros (32-bit)",
X86IsaLevel::BMI,
"bmi",
);
self.add_intrinsic(
"_mm_tzcnt_64",
"__int64",
&[("unsigned __int64", "a")],
"bmiintrin.h",
"BMI",
"Count trailing zeros (64-bit)",
X86IsaLevel::BMI,
"bmi",
);
self.add_intrinsic(
"_blsr_u32",
"unsigned int",
&[("unsigned int", "a")],
"bmiintrin.h",
"BMI",
"Reset lowest set bit",
X86IsaLevel::BMI,
"bmi",
);
self.add_intrinsic(
"_blsmsk_u32",
"unsigned int",
&[("unsigned int", "a")],
"bmiintrin.h",
"BMI",
"Get mask up to lowest set bit",
X86IsaLevel::BMI,
"bmi",
);
self.add_intrinsic(
"_mm_empty",
"void",
&[],
"mmintrin.h",
"MMX",
"Empty MMX state",
X86IsaLevel::MMX,
"mmx",
);
self.add_intrinsic(
"_m_paddb",
"__m64",
&[("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Add packed 8-bit integers",
X86IsaLevel::MMX,
"mmx",
);
self.add_intrinsic(
"_m_psubw",
"__m64",
&[("__m64", "a"), ("__m64", "b")],
"mmintrin.h",
"MMX",
"Subtract packed 16-bit integers",
X86IsaLevel::MMX,
"mmx",
);
self.add_intrinsic(
"_mm_pause",
"void",
&[],
"xmmintrin.h",
"SSE2",
"Pause hint for spin-wait loops",
X86IsaLevel::SSE2,
"sse2",
);
self.add_intrinsic(
"_mm_prefetch",
"void",
&[("char const*", "p"), ("int", "i")],
"xmmintrin.h",
"SSE",
"Prefetch data into cache",
X86IsaLevel::SSE,
"sse",
);
self.add_intrinsic(
"_ReadWriteBarrier",
"void",
&[],
"intrin.h",
"MSVC",
"Compiler memory barrier (MSVC)",
X86IsaLevel::Baseline,
"",
);
self.add_intrinsic(
"__rdtsc",
"unsigned __int64",
&[],
"x86intrin.h",
"x86",
"Read Time-Stamp Counter",
X86IsaLevel::Baseline,
"",
);
self.add_intrinsic(
"__rdtscp",
"unsigned __int64",
&[("unsigned int*", "aux")],
"x86intrin.h",
"x86",
"Read Time-Stamp Counter and Processor ID",
X86IsaLevel::Baseline,
"",
);
self.add_intrinsic(
"__cpuid",
"void",
&[("int[4]", "cpu_info"), ("int", "info_type")],
"cpuid.h",
"x86",
"Execute CPUID instruction",
X86IsaLevel::Baseline,
"",
);
self.add_intrinsic(
"_bswap",
"unsigned long",
&[("unsigned long", "val")],
"stdlib.h",
"MSVC",
"Byte swap (MSVC intrinsic)",
X86IsaLevel::Baseline,
"",
);
self.add_intrinsic(
"_bswap64",
"unsigned __int64",
&[("unsigned __int64", "val")],
"stdlib.h",
"MSVC",
"64-bit byte swap (MSVC intrinsic)",
X86IsaLevel::Baseline,
"",
);
self.add_intrinsic(
"_BitScanForward",
"unsigned char",
&[("unsigned long*", "index"), ("unsigned long", "mask")],
"intrin.h",
"MSVC",
"Bit scan forward (MSVC)",
X86IsaLevel::Baseline,
"",
);
self.add_intrinsic(
"_BitScanReverse",
"unsigned char",
&[("unsigned long*", "index"), ("unsigned long", "mask")],
"intrin.h",
"MSVC",
"Bit scan reverse (MSVC)",
X86IsaLevel::Baseline,
"",
);
self.add_intrinsic(
"_InterlockedIncrement",
"long",
&[("long volatile*", "addend")],
"intrin.h",
"MSVC",
"Atomic increment (MSVC)",
X86IsaLevel::Baseline,
"",
);
self.add_intrinsic(
"_InterlockedDecrement",
"long",
&[("long volatile*", "addend")],
"intrin.h",
"MSVC",
"Atomic decrement (MSVC)",
X86IsaLevel::Baseline,
"",
);
self.add_intrinsic(
"_InterlockedCompareExchange",
"long",
&[
("long volatile*", "dest"),
("long", "exchange"),
("long", "comperand"),
],
"intrin.h",
"MSVC",
"Atomic compare and exchange (MSVC)",
X86IsaLevel::Baseline,
"",
);
}
fn add_intrinsic(
&mut self,
name: &str,
return_type: &str,
params: &[(&str, &str)],
header: &str,
category: &str,
doc: &str,
isa: X86IsaLevel,
cpu_feature: &str,
) {
let entry = X86IntrinsicEntry {
name: name.to_string(),
return_type: return_type.to_string(),
params: params
.iter()
.map(|(t, n)| (t.to_string(), n.to_string()))
.collect(),
header: header.to_string(),
category: category.to_string(),
doc: doc.to_string(),
isa,
cpu_feature: cpu_feature.to_string(),
};
self.categories
.entry(category.to_string())
.or_default()
.push(entry.clone());
self.all_intrinsics.push(entry);
}
pub fn complete(&self, prefix: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
self.all_intrinsics
.iter()
.filter(|e| lower.is_empty() || e.name.to_lowercase().starts_with(&lower))
.map(|e| {
let param_refs: Vec<(&str, &str)> = e
.params
.iter()
.map(|(t, n)| (t.as_str(), n.as_str()))
.collect();
let mut item =
X86CompletionResult::intrinsic(&e.name, ¶m_refs, &e.return_type, &e.header);
item.documentation = Some(format!(
"{} ({} — {})",
e.doc,
e.category,
e.isa.description()
));
if item.detail.is_none() {
item.detail = Some(format!(
"{} {}({}) [{}]",
e.return_type,
e.name,
e.params
.iter()
.map(|(t, n)| format!("{} {}", t, n))
.collect::<Vec<_>>()
.join(", "),
e.header
));
}
item
})
.collect()
}
pub fn complete_by_isa(&self, prefix: &str, isa: X86IsaLevel) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
self.all_intrinsics
.iter()
.filter(|e| {
e.isa <= isa && (lower.is_empty() || e.name.to_lowercase().starts_with(&lower))
})
.map(|e| {
let param_refs: Vec<(&str, &str)> = e
.params
.iter()
.map(|(t, n)| (t.as_str(), n.as_str()))
.collect();
X86CompletionResult::intrinsic(&e.name, ¶m_refs, &e.return_type, &e.header)
})
.collect()
}
pub fn complete_by_category(&self, prefix: &str, category: &str) -> Vec<X86CompletionResult> {
let lower = prefix.to_lowercase();
self.categories
.get(category)
.map(|entries| {
entries
.iter()
.filter(|e| lower.is_empty() || e.name.to_lowercase().starts_with(&lower))
.map(|e| {
let param_refs: Vec<(&str, &str)> = e
.params
.iter()
.map(|(t, n)| (t.as_str(), n.as_str()))
.collect();
X86CompletionResult::intrinsic(
&e.name,
¶m_refs,
&e.return_type,
&e.header,
)
})
.collect()
})
.unwrap_or_default()
}
pub fn categories(&self) -> Vec<&String> {
self.categories.keys().collect()
}
pub fn category_counts(&self) -> HashMap<String, usize> {
self.categories
.iter()
.map(|(k, v)| (k.clone(), v.len()))
.collect()
}
}
#[derive(Debug, Clone)]
pub struct X86CompletionFilter {
pub hide_deprecated: bool,
pub enforce_access_control: bool,
pub type_filter: Option<String>,
pub min_priority: i32,
pub max_results: usize,
pub deduplicate: bool,
pub include_snippets: bool,
pub include_macros: bool,
pub allowed_kinds: HashSet<X86CompletionKind>,
pub blocked_kinds: HashSet<X86CompletionKind>,
}
impl Default for X86CompletionFilter {
fn default() -> Self {
Self {
hide_deprecated: true,
enforce_access_control: false,
type_filter: None,
min_priority: 0,
max_results: 50,
deduplicate: true,
include_snippets: true,
include_macros: true,
allowed_kinds: HashSet::new(),
blocked_kinds: HashSet::new(),
}
}
}
impl X86CompletionFilter {
pub fn new() -> Self {
Self::default()
}
pub fn filter(&self, results: Vec<X86CompletionResult>) -> Vec<X86CompletionResult> {
let mut filtered: Vec<X86CompletionResult> = results
.into_iter()
.filter(|r| self.pass_filter(r))
.collect();
if self.deduplicate {
let mut seen: HashSet<String> = HashSet::new();
filtered.retain(|r| seen.insert(r.insert_text.clone()));
}
filtered.truncate(self.max_results);
filtered
}
fn pass_filter(&self, result: &X86CompletionResult) -> bool {
if self.hide_deprecated && result.deprecated {
return false;
}
if result.priority < self.min_priority {
return false;
}
if !self.include_snippets && result.is_snippet {
return false;
}
if !self.include_macros && result.kind == X86CompletionKind::Macro {
return false;
}
if !self.allowed_kinds.is_empty() && !self.allowed_kinds.contains(&result.kind) {
return false;
}
if self.blocked_kinds.contains(&result.kind) {
return false;
}
if let Some(ref type_filter) = self.type_filter {
if let Some(ref return_type) = result.return_type {
if return_type != type_filter {
return false;
}
}
}
if self.enforce_access_control {
if result.visibility == X86SymbolVisibility::Private {
return false;
}
}
true
}
pub fn kinds_only(kinds: &[X86CompletionKind]) -> Self {
Self {
allowed_kinds: kinds.iter().copied().collect(),
..Default::default()
}
}
pub fn block_kinds(kinds: &[X86CompletionKind]) -> Self {
Self {
blocked_kinds: kinds.iter().copied().collect(),
..Default::default()
}
}
pub fn types_only() -> Self {
Self::kinds_only(&[
X86CompletionKind::Type,
X86CompletionKind::TemplateType,
X86CompletionKind::TypeParameter,
])
}
pub fn functions_only() -> Self {
Self::kinds_only(&[
X86CompletionKind::Function,
X86CompletionKind::TemplateFunction,
X86CompletionKind::Constructor,
X86CompletionKind::Destructor,
])
}
pub fn snippets_only() -> Self {
Self::kinds_only(&[X86CompletionKind::Snippet])
}
}
#[derive(Debug, Clone, Default)]
pub struct X86DocGenerator {
pub markdown: bool,
pub include_params: bool,
pub include_return: bool,
pub include_header: bool,
}
impl X86DocGenerator {
pub fn new() -> Self {
Self {
markdown: true,
include_params: true,
include_return: true,
include_header: true,
}
}
pub fn generate_doc(&self, result: &X86CompletionResult) -> String {
let mut doc = String::new();
if self.markdown {
doc.push_str(&format!("### {}\n\n", result.display_text));
doc.push_str(&format!("**Kind:** `{}` \n", result.kind));
if self.include_return {
if let Some(ref ret) = result.return_type {
doc.push_str(&format!("**Returns:** `{}` \n", ret));
}
}
if self.include_params && !result.parameters.is_empty() {
doc.push_str("\n**Parameters:**\n\n");
for param in &result.parameters {
doc.push_str(&format!(
"- `{}` — `{}`{}\n",
param.name,
param.param_type,
if let Some(ref default) = param.default_value {
format!(" (default: `{}`)", default)
} else {
String::new()
}
));
}
}
if !result.template_params.is_empty() {
doc.push_str(&format!(
"\n**Template params:** `{}`\n",
result.template_params.join(", ")
));
}
if self.include_header {
if let Some(ref header) = result.required_header {
doc.push_str(&format!("\n**Header:** `<{}>`\n", header));
}
}
if result.deprecated {
doc.push_str("\n> ⚠️ **Deprecated**\n");
}
match result.visibility {
X86SymbolVisibility::Public => {}
X86SymbolVisibility::Protected => {
doc.push_str("\n🔒 **Protected** \n");
}
X86SymbolVisibility::Private => {
doc.push_str("\n🔒 **Private** \n");
}
X86SymbolVisibility::Unspecified => {}
}
let mut flags = Vec::new();
if result.is_static {
flags.push("static");
}
if result.is_constexpr {
flags.push("constexpr");
}
if result.is_virtual {
flags.push("virtual");
}
if result.is_override {
flags.push("override");
}
if result.is_noexcept {
flags.push("noexcept");
}
if !flags.is_empty() {
doc.push_str(&format!("\n**Flags:** {}\n", flags.join(", ")));
}
if let Some(ref custom_doc) = result.documentation {
doc.push_str(&format!("\n---\n\n{}\n", custom_doc));
}
} else {
if let Some(ref detail) = result.detail {
doc.push_str(detail);
} else {
doc.push_str(&result.display_text);
}
if self.include_header {
if let Some(ref header) = result.required_header {
doc.push_str(&format!(" — requires <{}>", header));
}
}
}
doc
}
pub fn generate_label(&self, result: &X86CompletionResult) -> String {
let mut label = format!(
"{} {} {}",
result.kind.icon(),
result.display_text,
if let Some(ref detail) = result.detail {
format!(" — {}", detail)
} else {
String::new()
}
);
if result.deprecated {
label.push_str(" [deprecated]");
}
label
}
pub fn generate_lsp_doc(&self, result: &X86CompletionResult) -> X86LspMarkupContent {
X86LspMarkupContent {
kind: if self.markdown {
"markdown"
} else {
"plaintext"
}
.to_string(),
value: self.generate_doc(result),
}
}
}
#[derive(Debug, Clone)]
pub struct X86LspMarkupContent {
pub kind: String,
pub value: String,
}
#[derive(Debug, Clone, Default)]
pub struct X86SnippetEngine {
custom_snippets: HashMap<String, X86SnippetDef>,
}
impl X86SnippetEngine {
pub fn new() -> Self {
Self::default()
}
pub fn register_snippet(
&mut self,
name: &str,
label: &'static str,
insert: &'static str,
doc: &'static str,
) {
self.custom_snippets
.insert(name.to_string(), X86SnippetDef { label, insert, doc });
}
pub fn parse_tab_stops(snippet: &str) -> Vec<X86TabStop> {
let mut stops = Vec::new();
let mut chars: Vec<char> = snippet.chars().collect();
let len = chars.len();
let mut i = 0;
while i < len {
if chars[i] == '$' && i + 1 < len {
if chars[i + 1] == '{' {
let start = i + 2;
let mut num_str = String::new();
let mut j = start;
while j < len && chars[j].is_ascii_digit() {
num_str.push(chars[j]);
j += 1;
}
if let Ok(num) = num_str.parse::<u32>() {
let default = if j < len && chars[j] == ':' {
j += 1;
let mut default_str = String::new();
while j < len && chars[j] != '}' {
default_str.push(chars[j]);
j += 1;
}
Some(default_str)
} else if j < len && chars[j] == '}' {
j += 1;
None
} else {
None
};
stops.push(X86TabStop {
index: num,
default_text: default,
position: i,
});
i = j;
continue;
}
} else if chars[i + 1].is_ascii_digit() {
let num_str: String = chars[i + 1..]
.iter()
.take_while(|c| c.is_ascii_digit())
.collect();
if let Ok(num) = num_str.parse::<u32>() {
stops.push(X86TabStop {
index: num,
default_text: None,
position: i,
});
i += 1 + num_str.len();
continue;
}
}
}
i += 1;
}
stops.sort_by_key(|s| s.index);
stops
}
pub fn expand_snippet(snippet: &str) -> String {
let stops = Self::parse_tab_stops(snippet);
if stops.is_empty() {
return snippet.to_string();
}
let chars: Vec<char> = snippet.chars().collect();
let mut result = String::new();
let mut stop_iter = stops.iter().peekable();
let mut pos = 0;
while pos < chars.len() {
if let Some(stop) = stop_iter.peek() {
if pos == stop.position {
result.push_str(stop.default_text.as_deref().unwrap_or(""));
if pos + 1 < chars.len() && chars[pos + 1] == '{' {
let mut j = pos + 2;
while j < chars.len() && chars[j] != '}' {
if chars[j] == ':' {
j += 1;
while j < chars.len() && chars[j] != '}' {
j += 1;
}
break;
}
j += 1;
}
pos = (j + 1).min(chars.len());
} else if pos + 1 < chars.len() && chars[pos + 1].is_ascii_digit() {
let mut j = pos + 1;
while j < chars.len() && chars[j].is_ascii_digit() {
j += 1;
}
pos = j;
} else {
pos += 1;
}
stop_iter.next();
continue;
}
}
result.push(chars[pos]);
pos += 1;
}
result
}
pub fn get_snippet(&self, name: &str) -> Option<X86CompletionResult> {
self.custom_snippets
.get(name)
.map(|s| X86CompletionResult::snippet(&s.label, &s.insert, &s.doc))
}
pub fn list_snippets(&self) -> Vec<X86CompletionResult> {
self.custom_snippets
.values()
.map(|s| X86CompletionResult::snippet(&s.label, &s.insert, &s.doc))
.collect()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct X86TabStop {
pub index: u32,
pub default_text: Option<String>,
pub position: usize,
}
#[cfg(test)]
mod additional_tests {
use super::*;
#[test]
fn test_intrinsic_database_initialization() {
let db = X86IntrinsicDatabase::new();
let categories = db.categories();
assert!(!categories.is_empty(), "Should have categories");
let counts = db.category_counts();
assert!(counts.values().sum::<usize>() > 0, "Should have intrinsics");
}
#[test]
fn test_intrinsic_complete_mm_prefix() {
let db = X86IntrinsicDatabase::new();
let results = db.complete("_mm_");
assert!(!results.is_empty());
for r in &results {
assert!(
r.display_text.starts_with("_mm_"),
"Result should start with _mm_: {}",
r.display_text
);
}
}
#[test]
fn test_intrinsic_complete_load_ps() {
let db = X86IntrinsicDatabase::new();
let results = db.complete("_mm_load_ps");
assert_eq!(results.len(), 1);
assert!(results[0].display_text.contains("_mm_load_ps"));
}
#[test]
fn test_intrinsic_complete_by_isa_avx() {
let db = X86IntrinsicDatabase::new();
let results = db.complete_by_isa("_mm256_", X86IsaLevel::AVX);
assert!(!results.is_empty());
for r in &results {
assert!(!r.display_text.contains("_mm512_"));
}
}
#[test]
fn test_intrinsic_complete_sse_only() {
let db = X86IntrinsicDatabase::new();
let results = db.complete_by_isa("", X86IsaLevel::SSE);
for r in &results {
assert!(
!r.display_text.contains("_mm256_"),
"SSE filter should exclude AVX intrinsics"
);
assert!(
!r.display_text.contains("_mm_aes"),
"SSE filter should exclude AES intrinsics"
);
}
}
#[test]
fn test_intrinsic_complete_by_category() {
let db = X86IntrinsicDatabase::new();
let results = db.complete_by_category("", "SSE");
assert!(!results.is_empty());
assert!(results
.iter()
.any(|r| r.display_text.contains("_mm_add_ps")));
}
#[test]
fn test_isa_level_predefined_macros() {
assert_eq!(X86IsaLevel::SSE.predefined_macro(), Some("__SSE__"));
assert_eq!(X86IsaLevel::SSE2.predefined_macro(), Some("__SSE2__"));
assert_eq!(X86IsaLevel::AVX.predefined_macro(), Some("__AVX__"));
assert_eq!(X86IsaLevel::AVX2.predefined_macro(), Some("__AVX2__"));
assert_eq!(X86IsaLevel::AVX512F.predefined_macro(), Some("__AVX512F__"));
assert_eq!(X86IsaLevel::Baseline.predefined_macro(), None);
}
#[test]
fn test_isa_level_compiler_flags() {
assert_eq!(X86IsaLevel::SSE.compiler_flag(), "-msse");
assert_eq!(X86IsaLevel::AVX.compiler_flag(), "-mavx");
assert_eq!(X86IsaLevel::FMA.compiler_flag(), "-mfma");
assert_eq!(X86IsaLevel::Baseline.compiler_flag(), "");
}
#[test]
fn test_isa_level_description() {
let desc = X86IsaLevel::SSE.description();
assert!(desc.contains("SSE"));
assert!(desc.contains("128-bit"));
}
#[test]
fn test_filter_basic() {
let filter = X86CompletionFilter::new();
let results = vec![
X86CompletionResult::keyword("for"),
X86CompletionResult::keyword("while"),
X86CompletionResult::keyword("if"),
];
let filtered = filter.filter(results);
assert_eq!(filtered.len(), 3);
}
#[test]
fn test_filter_deprecated() {
let filter = X86CompletionFilter::new();
let mut deprecated_item = X86CompletionResult::keyword("old_func");
deprecated_item.deprecated = true;
let results = vec![X86CompletionResult::keyword("new_func"), deprecated_item];
let filtered = filter.filter(results);
assert_eq!(filtered.len(), 1);
assert_eq!(filtered[0].display_text, "new_func");
}
#[test]
fn test_filter_deduplicate() {
let filter = X86CompletionFilter::new();
let results = vec![
X86CompletionResult::keyword("for"),
X86CompletionResult::keyword("for"),
X86CompletionResult::keyword("while"),
];
let filtered = filter.filter(results);
assert_eq!(filtered.len(), 2);
}
#[test]
fn test_filter_type_only() {
let filter = X86CompletionFilter::types_only();
let results = vec![
X86CompletionResult::type_("int", None),
X86CompletionResult::keyword("for"),
X86CompletionResult::function("printf", "int", &[], None),
];
let filtered = filter.filter(results);
assert_eq!(filtered.len(), 1);
assert_eq!(filtered[0].kind, X86CompletionKind::Type);
}
#[test]
fn test_filter_functions_only() {
let filter = X86CompletionFilter::functions_only();
let results = vec![
X86CompletionResult::function("foo", "void", &[], None),
X86CompletionResult::keyword("class"),
X86CompletionResult::type_("int", None),
];
let filtered = filter.filter(results);
assert_eq!(filtered.len(), 1);
}
#[test]
fn test_filter_min_priority() {
let mut filter = X86CompletionFilter::new();
filter.min_priority = 80;
let mut hi = X86CompletionResult::keyword("hi");
hi.priority = 90;
let mut lo = X86CompletionResult::keyword("lo");
lo.priority = 50;
let results = vec![hi, lo];
let filtered = filter.filter(results);
assert_eq!(filtered.len(), 1);
assert!(filtered[0].priority >= 80);
}
#[test]
fn test_filter_max_results() {
let mut filter = X86CompletionFilter::new();
filter.max_results = 2;
filter.deduplicate = false;
let results = vec![
X86CompletionResult::keyword("a"),
X86CompletionResult::keyword("b"),
X86CompletionResult::keyword("c"),
X86CompletionResult::keyword("d"),
];
let filtered = filter.filter(results);
assert_eq!(filtered.len(), 2);
}
#[test]
fn test_filter_block_kinds() {
let filter = X86CompletionFilter::block_kinds(&[X86CompletionKind::Keyword]);
let results = vec![
X86CompletionResult::keyword("for"),
X86CompletionResult::type_("int", None),
];
let filtered = filter.filter(results);
assert_eq!(filtered.len(), 1);
assert_eq!(filtered[0].kind, X86CompletionKind::Type);
}
#[test]
fn test_doc_generator_basic() {
let r#gen = X86DocGenerator::new();
let result = X86CompletionResult::function(
"my_func",
"int",
&[("int", "a"), ("double", "b")],
Some("A test function"),
);
let doc = r#gen.generate_doc(&result);
assert!(doc.contains("my_func"));
assert!(doc.contains("int"));
assert!(doc.contains("Returns"));
assert!(doc.contains("Parameters"));
}
#[test]
fn test_doc_generator_plaintext() {
let mut r#gen = X86DocGenerator::new();
r#gen.markdown = false;
let result = X86CompletionResult::function("my_func", "int", &[("int", "a")], None);
let doc = r#gen.generate_doc(&result);
assert!(!doc.starts_with("###"));
}
#[test]
fn test_doc_generator_label() {
let r#gen = X86DocGenerator::new();
let result = X86CompletionResult::function("my_func", "int", &[("int", "a")], None);
let label = r#gen.generate_label(&result);
assert!(label.starts_with("f"));
assert!(label.contains("my_func"));
}
#[test]
fn test_doc_generator_deprecated_label() {
let r#gen = X86DocGenerator::new();
let mut result = X86CompletionResult::function("old_func", "void", &[], None);
result.deprecated = true;
let label = r#gen.generate_label(&result);
assert!(label.contains("deprecated"));
}
#[test]
fn test_doc_generator_lsp_content() {
let r#gen = X86DocGenerator::new();
let result = X86CompletionResult::keyword("for");
let lsp_doc = r#gen.generate_lsp_doc(&result);
assert_eq!(lsp_doc.kind, "markdown");
assert!(lsp_doc.value.contains("for"));
}
#[test]
fn test_snippet_engine_parse_tab_stops() {
let snippet = "for (${1:int} ${2:i} = ${3:0}; ${2:i} < ${4:n}; ${2:i}++) {\n\t${5:}\n}";
let stops = X86SnippetEngine::parse_tab_stops(snippet);
assert_eq!(stops.len(), 5);
assert_eq!(stops[0].index, 1);
assert_eq!(stops[0].default_text, Some("int".to_string()));
assert_eq!(stops[1].index, 2);
assert_eq!(stops[1].default_text, Some("i".to_string()));
}
#[test]
fn test_snippet_engine_parse_simple() {
let snippet = "${1}$0";
let stops = X86SnippetEngine::parse_tab_stops(snippet);
assert_eq!(stops.len(), 2);
}
#[test]
fn test_snippet_engine_expand() {
let snippet = "${1:default_value}";
let expanded = X86SnippetEngine::expand_snippet(snippet);
assert_eq!(expanded, "default_value");
}
#[test]
fn test_snippet_engine_expand_multiple() {
let snippet = "int ${1:x} = ${2:42};";
let expanded = X86SnippetEngine::expand_snippet(snippet);
assert_eq!(expanded, "int x = 42;");
}
#[test]
fn test_snippet_engine_no_placeholders() {
let snippet = "int main() { return 0; }";
let stops = X86SnippetEngine::parse_tab_stops(snippet);
assert!(stops.is_empty());
let expanded = X86SnippetEngine::expand_snippet(snippet);
assert_eq!(expanded, snippet);
}
#[test]
fn test_snippet_engine_register_custom() {
let mut engine = X86SnippetEngine::new();
engine.register_snippet("my_snippet", "My Snippet", "${1:hello}", "A test");
let result = engine.get_snippet("my_snippet");
assert!(result.is_some());
assert_eq!(result.unwrap().insert_text, "${1:hello}");
}
#[test]
fn test_snippet_engine_list() {
let mut engine = X86SnippetEngine::new();
engine.register_snippet("s1", "S1", "code1", "desc1");
engine.register_snippet("s2", "S2", "code2", "desc2");
let snippets = engine.list_snippets();
assert_eq!(snippets.len(), 2);
}
#[test]
fn test_engine_with_intrinsics() {
let mut engine = X86CodeCompleteDeep::new();
let db = X86IntrinsicDatabase::new();
let sse_results = db.complete("_mm_");
assert!(!sse_results.is_empty());
}
#[test]
fn test_filter_with_engine_results() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_all("");
let filter = X86CompletionFilter::types_only();
let filtered = filter.filter(results);
for r in &filtered {
assert!(
matches!(
r.kind,
X86CompletionKind::Type
| X86CompletionKind::TemplateType
| X86CompletionKind::TypeParameter
),
"Filtered result should be a type: {:?}",
r.kind
);
}
}
#[test]
fn test_filter_snippets_only() {
let filter = X86CompletionFilter::snippets_only();
let sc = X86SnippetCompletion::new();
let results = filter.filter(sc.all_snippets());
for r in &results {
assert_eq!(r.kind, X86CompletionKind::Snippet);
}
}
#[test]
fn test_empty_prefix_all_providers() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_all("");
assert!(!results.is_empty());
assert!(results.len() <= engine.max_results);
}
#[test]
fn test_very_long_prefix() {
let mut engine = X86CodeCompleteDeep::new();
let long_prefix = "this_is_a_very_long_function_name_that_probably_does_not_exist_anywhere_in_the_database_1234567890abcdef";
let results = engine.complete_all(long_prefix);
assert!(results.is_empty());
}
#[test]
fn test_special_chars_in_prefix() {
let mut engine = X86CodeCompleteDeep::new();
let results = engine.complete_all("!@#$%");
assert!(results.is_empty());
}
#[test]
fn test_context_detection_with_unicode() {
let ctx = X86CompletionContext::from_source_line("// 这是一个注释 int x = ", 30);
let _ = ctx; }
#[test]
fn test_levenshtein_identical_long() {
let a = "this_is_a_particularly_long_identifier_name_for_testing";
let dist = levenshtein_distance(a, a);
assert_eq!(dist, 0);
}
#[test]
fn test_levenshtein_completely_different() {
let dist = levenshtein_distance("abcdef", "ghijkl");
assert_eq!(dist, 6);
}
#[test]
fn test_levenshtein_substring() {
let dist = levenshtein_distance("abc", "abcdef");
assert_eq!(dist, 3); }
#[test]
fn test_damerau_levenshtein_multiple_transpositions() {
let dist = damerau_levenshtein_distance("abcd", "badc");
assert_eq!(dist, 2);
}
#[test]
fn test_doc_generator_empty_result() {
let r#gen = X86DocGenerator::new();
let result = X86CompletionResult::variable("x", "int", None);
let doc = r#gen.generate_doc(&result);
assert!(!doc.is_empty());
}
#[test]
fn test_doc_generator_with_template_params() {
let r#gen = X86DocGenerator::new();
let mut result = X86CompletionResult::function("max", "T", &[], None);
result.kind = X86CompletionKind::TemplateFunction;
result.template_params = vec!["T".to_string(), "U".to_string()];
let doc = r#gen.generate_doc(&result);
assert!(doc.contains("Template params"));
assert!(doc.contains("T"));
assert!(doc.contains("U"));
}
#[test]
fn test_doc_generator_with_visibility() {
let r#gen = X86DocGenerator::new();
let mut result = X86CompletionResult::field("secret", "int", None);
result.visibility = X86SymbolVisibility::Private;
let doc = r#gen.generate_doc(&result);
assert!(doc.contains("Private"));
}
#[test]
fn test_doc_generator_with_flags() {
let r#gen = X86DocGenerator::new();
let mut result = X86CompletionResult::function("get_value", "int", &[], None);
result.is_constexpr = true;
result.is_noexcept = true;
let doc = r#gen.generate_doc(&result);
assert!(doc.contains("constexpr"));
assert!(doc.contains("noexcept"));
}
#[test]
fn test_doc_generator_plaintext_with_header() {
let mut r#gen = X86DocGenerator::new();
r#gen.markdown = false;
let mut result = X86CompletionResult::function("printf", "int", &[], None);
result.required_header = Some("stdio.h".to_string());
let doc = r#gen.generate_doc(&result);
assert!(doc.contains("requires"));
assert!(doc.contains("stdio.h"));
}
#[test]
fn test_many_completions_sequential() {
let mut engine = X86CodeCompleteDeep::new();
let queries = vec![
"int",
"float",
"double",
"char",
"void",
"for",
"while",
"if",
"return",
"struct",
"class",
"namespace",
"template",
"virtual",
"printf",
"malloc",
"free",
"strlen",
"memcpy",
"std",
"vector",
"string",
"map",
"set",
];
for query in queries {
let results = engine.complete_all(query);
assert!(
!results.is_empty(),
"Query '{}' should return results",
query
);
}
}
#[test]
fn test_cache_consistency() {
let mut engine = X86CodeCompleteDeep::new();
let results1 = engine.complete_all("int");
let stats = engine.stats();
assert_eq!(stats.cache_entries, 1);
let results2 = engine.complete_all("int");
assert_eq!(results1, results2);
}
#[test]
fn test_ranker_type_registration() {
let mut ranker = X86CompletionRanker::new();
ranker.register_type_compatibility("int", "long", 0.8);
ranker.register_type_compatibility("int", "float", 0.5);
let mut results = vec![
{
let mut r = X86CompletionResult::function("f_long", "long", &[], None);
r.priority = 0;
r
},
{
let mut r = X86CompletionResult::function("f_float", "float", &[], None);
r.priority = 0;
r
},
];
ranker.rank(
&mut results,
"",
&X86CompletionContext::General,
Some("int"),
);
let long_result = results
.iter()
.find(|r| r.return_type.as_deref() == Some("long"))
.unwrap();
let float_result = results
.iter()
.find(|r| r.return_type.as_deref() == Some("float"))
.unwrap();
assert!(long_result.priority > float_result.priority);
}
#[test]
fn test_x86_completion_kind_full_coverage() {
let kinds = vec![
X86CompletionKind::Function,
X86CompletionKind::Variable,
X86CompletionKind::Type,
X86CompletionKind::Macro,
X86CompletionKind::Keyword,
X86CompletionKind::Directive,
X86CompletionKind::Field,
X86CompletionKind::EnumMember,
X86CompletionKind::Namespace,
X86CompletionKind::Snippet,
X86CompletionKind::File,
X86CompletionKind::Label,
X86CompletionKind::Concept,
X86CompletionKind::Operator,
X86CompletionKind::TypeParameter,
X86CompletionKind::Intrinsic,
X86CompletionKind::Module,
X86CompletionKind::Constant,
X86CompletionKind::TemplateFunction,
X86CompletionKind::TemplateType,
X86CompletionKind::StaticMember,
X86CompletionKind::InheritedMember,
X86CompletionKind::UsingDeclaration,
X86CompletionKind::NamespaceAlias,
X86CompletionKind::Constructor,
X86CompletionKind::Destructor,
X86CompletionKind::ConversionFunction,
X86CompletionKind::LiteralOperator,
X86CompletionKind::UserDefinedLiteral,
X86CompletionKind::Parameter,
X86CompletionKind::LocalVariable,
X86CompletionKind::GlobalVariable,
];
for kind in kinds {
assert!(
!kind.icon().is_empty(),
"Icon should not be empty for {:?}",
kind
);
assert!(
kind.lsp_kind() > 0,
"LSP kind should be positive for {:?}",
kind
);
let display = format!("{}", kind);
assert!(
!display.is_empty(),
"Display should not be empty for {:?}",
kind
);
}
}
#[test]
fn test_context_debug_formatting() {
let contexts = vec![
X86CompletionContext::DotAccess {
receiver_type: None,
implicit_this: false,
},
X86CompletionContext::ArrowAccess {
receiver_type: None,
implicit_this: false,
},
X86CompletionContext::General,
X86CompletionContext::DirectiveContext {
partial: String::new(),
},
X86CompletionContext::IncludeContext {
delimiter: IncludeDelimiter::Angle,
partial: String::new(),
},
];
for ctx in contexts {
let debug_str = format!("{:?}", ctx);
assert!(!debug_str.is_empty());
}
}
#[test]
fn test_completion_result_clone() {
let original = X86CompletionResult::function("test", "int", &[], None);
let cloned = original.clone();
assert_eq!(original, cloned);
assert_eq!(original.display_text, cloned.display_text);
assert_eq!(original.kind, cloned.kind);
}
#[test]
fn test_additional_edit_construction() {
let edit = X86AdditionalEdit {
file: Some("test.h".to_string()),
line: 1,
column: 10,
new_text: "#include <stdio.h>\n".to_string(),
};
assert_eq!(edit.file, Some("test.h".to_string()));
assert_eq!(edit.line, 1);
}
#[test]
fn test_parameter_info_default() {
let param = X86ParameterInfo {
name: "x".to_string(),
param_type: "int".to_string(),
default_value: Some("42".to_string()),
is_variadic: false,
};
assert_eq!(param.default_value, Some("42".to_string()));
let variadic = X86ParameterInfo {
name: "args".to_string(),
param_type: "...".to_string(),
default_value: None,
is_variadic: true,
};
assert!(variadic.is_variadic);
}
#[test]
fn test_symbol_visibility_ordering() {
assert!(X86SymbolVisibility::Public != X86SymbolVisibility::Private);
assert_eq!(X86SymbolVisibility::Public, X86SymbolVisibility::Public);
}
#[test]
fn test_include_delimiter_hash() {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut h1 = DefaultHasher::new();
IncludeDelimiter::Quote.hash(&mut h1);
let hash1 = h1.finish();
let mut h2 = DefaultHasher::new();
IncludeDelimiter::Quote.hash(&mut h2);
let hash2 = h2.finish();
assert_eq!(hash1, hash2);
}
#[test]
fn test_isa_level_ordering() {
assert!(X86IsaLevel::Baseline < X86IsaLevel::SSE);
assert!(X86IsaLevel::SSE < X86IsaLevel::SSE2);
assert!(X86IsaLevel::SSE2 < X86IsaLevel::AVX);
assert!(X86IsaLevel::AVX < X86IsaLevel::AVX2);
assert!(X86IsaLevel::AVX2 < X86IsaLevel::AVX512F);
}
#[test]
fn test_tab_stop_equality() {
let ts1 = X86TabStop {
index: 1,
default_text: Some("x".into()),
position: 0,
};
let ts2 = X86TabStop {
index: 1,
default_text: Some("x".into()),
position: 0,
};
assert_eq!(ts1, ts2);
let ts3 = X86TabStop {
index: 2,
default_text: None,
position: 5,
};
assert_ne!(ts2, ts3);
}
#[test]
fn test_snippet_parse_complex() {
let snippet = "if (${1:condition}) {\n\t${2:// body}\n} else {\n\t${3:// else body}\n}$0";
let stops = X86SnippetEngine::parse_tab_stops(snippet);
assert_eq!(stops.len(), 4);
assert_eq!(stops[0].index, 0);
assert_eq!(stops[1].index, 1);
assert_eq!(stops[2].index, 2);
assert_eq!(stops[3].index, 3);
}
#[test]
fn test_snippet_expand_empty_default() {
let snippet = "${1:}";
let expanded = X86SnippetEngine::expand_snippet(snippet);
assert_eq!(expanded, "");
}
#[test]
fn test_ranker_custom_weights_clone() {
let weights = X86RankerWeights {
type_weight: 0.5,
scope_weight: 0.2,
frequency_weight: 0.1,
distance_weight: 0.1,
context_weight: 0.1,
};
let cloned = weights.clone();
assert!((cloned.type_weight - 0.5).abs() < 0.001);
}
#[test]
fn test_completion_stats_display_lines() {
let stats = X86CompletionStats {
total_types: 10,
total_functions: 20,
total_variables: 5,
total_macros: 15,
total_snippets: 30,
cache_entries: 3,
is_cpp_mode: true,
};
let display = format!("{}", stats);
assert!(display.contains("10"));
assert!(display.contains("20"));
assert!(display.contains("C++"));
}
#[test]
fn test_completion_stats_c_mode() {
let stats = X86CompletionStats {
total_types: 0,
total_functions: 0,
total_variables: 0,
total_macros: 0,
total_snippets: 0,
cache_entries: 0,
is_cpp_mode: false,
};
let display = format!("{}", stats);
assert!(display.contains("C"));
assert!(!display.contains("C++"));
}
#[test]
fn test_file_path_completion_empty_database() {
let fc = X86FilePathCompletion::new();
let results = fc.complete_path("stdio", IncludeDelimiter::Angle);
assert!(results.is_empty());
}
#[test]
fn test_variable_completion_empty_database() {
let vc = X86VariableCompletion::new();
let results = vc.complete("");
assert!(results.is_empty());
}
#[test]
fn test_member_completion_empty_database() {
let mc = X86MemberCompletion::new();
let results = mc.complete_members("Nonexistent", "", false);
assert!(results.is_empty());
}
#[test]
fn test_filter_no_snippets() {
let mut filter = X86CompletionFilter::new();
filter.include_snippets = false;
let mut snippet = X86CompletionResult::snippet("for", "for(...)", "desc");
let keyword = X86CompletionResult::keyword("for");
let results = filter.filter(vec![snippet, keyword]);
assert_eq!(results.len(), 1);
assert_eq!(results[0].kind, X86CompletionKind::Keyword);
}
#[test]
fn test_filter_no_macros() {
let mut filter = X86CompletionFilter::new();
filter.include_macros = false;
let mac = X86CompletionResult::macro_("NULL", None);
let kw = X86CompletionResult::keyword("void");
let results = filter.filter(vec![mac, kw]);
assert_eq!(results.len(), 1);
assert_eq!(results[0].kind, X86CompletionKind::Keyword);
}
#[test]
fn test_filter_access_control() {
let mut filter = X86CompletionFilter::new();
filter.enforce_access_control = true;
let mut public_field = X86CompletionResult::field("pub", "int", None);
public_field.visibility = X86SymbolVisibility::Public;
let mut private_field = X86CompletionResult::field("priv", "int", None);
private_field.visibility = X86SymbolVisibility::Private;
let results = filter.filter(vec![public_field, private_field]);
assert_eq!(results.len(), 1);
assert_eq!(results[0].visibility, X86SymbolVisibility::Public);
}
#[test]
fn test_isa_level_all_have_descriptions() {
let levels = vec![
X86IsaLevel::Baseline,
X86IsaLevel::MMX,
X86IsaLevel::SSE,
X86IsaLevel::SSE2,
X86IsaLevel::SSE3,
X86IsaLevel::SSSE3,
X86IsaLevel::SSE41,
X86IsaLevel::SSE42,
X86IsaLevel::AVX,
X86IsaLevel::AVX2,
X86IsaLevel::AVX512F,
X86IsaLevel::AVX512CD,
X86IsaLevel::AVX512BW,
X86IsaLevel::AVX512DQ,
X86IsaLevel::AVX512VL,
X86IsaLevel::FMA,
X86IsaLevel::AES,
X86IsaLevel::PCLMUL,
X86IsaLevel::RDRAND,
X86IsaLevel::RDSEED,
X86IsaLevel::SHA,
X86IsaLevel::BMI,
X86IsaLevel::BMI2,
X86IsaLevel::LZCNT,
X86IsaLevel::POPCNT,
X86IsaLevel::F16C,
X86IsaLevel::AVX512ER,
X86IsaLevel::AVX512PF,
X86IsaLevel::AVX512IFMA,
X86IsaLevel::AVX512VBMI,
X86IsaLevel::AVX5124FMAPS,
X86IsaLevel::AVX5124VNNIW,
X86IsaLevel::AVX512VPOPCNTDQ,
X86IsaLevel::AVX512BITALG,
X86IsaLevel::AVX512VNNI,
X86IsaLevel::AVX512BF16,
X86IsaLevel::AVX512VP2INTERSECT,
X86IsaLevel::AMX,
X86IsaLevel::AMXBF16,
X86IsaLevel::AMXINT8,
X86IsaLevel::AMXTILE,
X86IsaLevel::AVXVNNI,
X86IsaLevel::AVXIFMA,
];
for level in levels {
let desc = level.description();
assert!(
!desc.is_empty(),
"ISA level {:?} should have description",
level
);
let flag = level.compiler_flag();
assert!(
flag.is_empty() || flag.starts_with("-m"),
"ISA level {:?} flag '{}' should start with -m or be empty",
level,
flag
);
}
}
}
#[derive(Debug, Clone)]
pub struct X86CompletionAggregator {
primary: X86CodeCompleteDeep,
include_secondary: bool,
secondary_results: Vec<X86CompletionResult>,
conflict_strategy: X86ConflictStrategy,
stats: X86AggregationStats,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86ConflictStrategy {
PreferPrimary,
PreferSecondary,
HighestPriority,
KeepBoth,
}
#[derive(Debug, Clone, Default)]
pub struct X86AggregationStats {
pub primary_count: usize,
pub secondary_count: usize,
pub merged_count: usize,
pub conflicts_resolved: usize,
pub total_queries: u64,
}
impl Default for X86CompletionAggregator {
fn default() -> Self {
Self {
primary: X86CodeCompleteDeep::new(),
include_secondary: true,
secondary_results: Vec::new(),
conflict_strategy: X86ConflictStrategy::HighestPriority,
stats: X86AggregationStats::default(),
}
}
}
impl X86CompletionAggregator {
pub fn new() -> Self {
Self::default()
}
pub fn with_primary(primary: X86CodeCompleteDeep) -> Self {
Self {
primary,
..Default::default()
}
}
pub fn set_secondary(&mut self, results: Vec<X86CompletionResult>) {
self.secondary_results = results;
}
pub fn add_secondary(&mut self, results: &[X86CompletionResult]) {
self.secondary_results.extend(results.iter().cloned());
}
pub fn clear_secondary(&mut self) {
self.secondary_results.clear();
}
pub fn set_conflict_strategy(&mut self, strategy: X86ConflictStrategy) {
self.conflict_strategy = strategy;
}
pub fn complete_aggregated(
&mut self,
context: &X86CompletionContext,
prefix: &str,
expected_type: Option<&str>,
) -> Vec<X86CompletionResult> {
let mut primary_results =
self.primary
.complete_with_context(context, prefix, expected_type);
self.stats.primary_count = primary_results.len();
self.stats.total_queries += 1;
if !self.include_secondary || self.secondary_results.is_empty() {
return primary_results;
}
let lower = prefix.to_lowercase();
let secondary_filtered: Vec<X86CompletionResult> = self
.secondary_results
.iter()
.filter(|r| lower.is_empty() || r.display_text.to_lowercase().starts_with(&lower))
.cloned()
.collect();
self.stats.secondary_count = secondary_filtered.len();
let merged = self.merge_results(primary_results, secondary_filtered);
let mut sorted = merged;
sorted.sort_by(|a, b| b.priority.cmp(&a.priority));
sorted
}
fn merge_results(
&mut self,
primary: Vec<X86CompletionResult>,
secondary: Vec<X86CompletionResult>,
) -> Vec<X86CompletionResult> {
let mut merged: HashMap<String, X86CompletionResult> = HashMap::new();
let mut conflicts = 0usize;
for result in primary {
merged.insert(result.insert_text.clone(), result);
}
for result in secondary {
let key = result.insert_text.clone();
if let Some(existing) = merged.get(&key) {
conflicts += 1;
match self.conflict_strategy {
X86ConflictStrategy::PreferPrimary => {
}
X86ConflictStrategy::PreferSecondary => {
merged.insert(key, result);
}
X86ConflictStrategy::HighestPriority => {
if result.priority > existing.priority {
merged.insert(key, result);
}
}
X86ConflictStrategy::KeepBoth => {
let alt_key = format!("{}__secondary", key);
merged.entry(alt_key).or_insert(result);
}
}
} else {
merged.insert(key, result);
}
}
self.stats.conflicts_resolved += conflicts;
self.stats.merged_count = merged.len();
merged.into_values().collect()
}
pub fn stats(&self) -> &X86AggregationStats {
&self.stats
}
pub fn reset_stats(&mut self) {
self.stats = X86AggregationStats::default();
}
pub fn primary_mut(&mut self) -> &mut X86CodeCompleteDeep {
&mut self.primary
}
pub fn primary(&self) -> &X86CodeCompleteDeep {
&self.primary
}
}
#[derive(Debug, Clone)]
pub struct X86CompletionCacheManager {
entries: Vec<X86CacheEntry>,
max_entries: usize,
enabled: bool,
hits: u64,
misses: u64,
}
#[derive(Debug, Clone)]
struct X86CacheEntry {
key: String,
results: Vec<X86CompletionResult>,
source_file: Option<String>,
scope_id: Option<String>,
timestamp: u64,
}
impl Default for X86CompletionCacheManager {
fn default() -> Self {
Self {
entries: Vec::new(),
max_entries: 256,
enabled: true,
hits: 0,
misses: 0,
}
}
}
impl X86CompletionCacheManager {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(max_entries: usize) -> Self {
Self {
max_entries,
..Default::default()
}
}
pub fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
pub fn get(&mut self, key: &str) -> Option<Vec<X86CompletionResult>> {
if !self.enabled {
return None;
}
if let Some(pos) = self.entries.iter().position(|e| e.key == key) {
self.hits += 1;
let mut entry = self.entries.remove(pos);
entry.timestamp = Self::now();
self.entries.insert(0, entry);
Some(self.entries[0].results.clone())
} else {
self.misses += 1;
None
}
}
pub fn insert(
&mut self,
key: &str,
results: Vec<X86CompletionResult>,
source_file: Option<&str>,
scope_id: Option<&str>,
) {
if !self.enabled {
return;
}
self.entries.retain(|e| e.key != key);
while self.entries.len() >= self.max_entries {
self.entries.pop();
}
self.entries.insert(
0,
X86CacheEntry {
key: key.to_string(),
results,
source_file: source_file.map(|s| s.to_string()),
scope_id: scope_id.map(|s| s.to_string()),
timestamp: Self::now(),
},
);
}
pub fn invalidate_file(&mut self, file_path: &str) {
self.entries
.retain(|e| e.source_file.as_deref() != Some(file_path));
}
pub fn invalidate_scope(&mut self, scope_id: &str) {
self.entries
.retain(|e| e.scope_id.as_deref() != Some(scope_id));
}
pub fn invalidate_key(&mut self, key: &str) {
self.entries.retain(|e| e.key != key);
}
pub fn clear(&mut self) {
self.entries.clear();
self.hits = 0;
self.misses = 0;
}
pub fn stats(&self) -> X86CacheStats {
X86CacheStats {
entries: self.entries.len(),
max_entries: self.max_entries,
hits: self.hits,
misses: self.misses,
hit_rate: if self.hits + self.misses > 0 {
self.hits as f64 / (self.hits + self.misses) as f64
} else {
0.0
},
enabled: self.enabled,
}
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn keys(&self) -> Vec<&str> {
self.entries.iter().map(|e| e.key.as_str()).collect()
}
fn now() -> u64 {
use std::sync::atomic::{AtomicU64, Ordering};
static COUNTER: AtomicU64 = AtomicU64::new(0);
COUNTER.fetch_add(1, Ordering::Relaxed)
}
}
#[derive(Debug, Clone)]
pub struct X86CacheStats {
pub entries: usize,
pub max_entries: usize,
pub hits: u64,
pub misses: u64,
pub hit_rate: f64,
pub enabled: bool,
}
impl fmt::Display for X86CacheStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Completion Cache Statistics:")?;
writeln!(
f,
" Status: {}",
if self.enabled { "enabled" } else { "disabled" }
)?;
writeln!(f, " Entries: {} / {}", self.entries, self.max_entries)?;
writeln!(f, " Hits: {}", self.hits)?;
writeln!(f, " Misses: {}", self.misses)?;
write!(f, " Hit rate: {:.1}%", self.hit_rate * 100.0)?;
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct X86CompletionBuilder {
display_text: String,
insert_text: String,
kind: X86CompletionKind,
priority: i32,
documentation: Option<String>,
detail: Option<String>,
additional_edits: Vec<X86AdditionalEdit>,
deprecated: bool,
is_snippet: bool,
sort_text: Option<String>,
filter_text: Option<String>,
required_header: Option<String>,
scope: Option<String>,
visibility: X86SymbolVisibility,
is_static: bool,
is_constexpr: bool,
is_virtual: bool,
is_override: bool,
is_noexcept: bool,
return_type: Option<String>,
parameters: Vec<X86ParameterInfo>,
template_params: Vec<String>,
}
impl X86CompletionBuilder {
pub fn new(name: &str, kind: X86CompletionKind) -> Self {
Self {
display_text: name.to_string(),
insert_text: name.to_string(),
kind,
priority: 50,
documentation: None,
detail: None,
additional_edits: Vec::new(),
deprecated: false,
is_snippet: false,
sort_text: None,
filter_text: None,
required_header: None,
scope: None,
visibility: X86SymbolVisibility::Unspecified,
is_static: false,
is_constexpr: false,
is_virtual: false,
is_override: false,
is_noexcept: false,
return_type: None,
parameters: Vec::new(),
template_params: Vec::new(),
}
}
pub fn insert_text(mut self, text: &str) -> Self {
self.insert_text = text.to_string();
self
}
pub fn priority(mut self, priority: i32) -> Self {
self.priority = priority;
self
}
pub fn doc(mut self, doc: &str) -> Self {
self.documentation = Some(doc.to_string());
self
}
pub fn detail(mut self, detail: &str) -> Self {
self.detail = Some(detail.to_string());
self
}
pub fn return_type(mut self, ret: &str) -> Self {
self.return_type = Some(ret.to_string());
self
}
pub fn param(mut self, name: &str, param_type: &str) -> Self {
self.parameters.push(X86ParameterInfo {
name: name.to_string(),
param_type: param_type.to_string(),
default_value: None,
is_variadic: false,
});
self
}
pub fn param_with_default(mut self, name: &str, param_type: &str, default: &str) -> Self {
self.parameters.push(X86ParameterInfo {
name: name.to_string(),
param_type: param_type.to_string(),
default_value: Some(default.to_string()),
is_variadic: false,
});
self
}
pub fn variadic_param(mut self, name: &str) -> Self {
self.parameters.push(X86ParameterInfo {
name: name.to_string(),
param_type: "...".to_string(),
default_value: None,
is_variadic: true,
});
self
}
pub fn header(mut self, header: &str) -> Self {
self.required_header = Some(header.to_string());
self
}
pub fn scope(mut self, scope: &str) -> Self {
self.scope = Some(scope.to_string());
self
}
pub fn deprecated(mut self) -> Self {
self.deprecated = true;
self
}
pub fn snippet(mut self) -> Self {
self.is_snippet = true;
self
}
pub fn visibility(mut self, vis: X86SymbolVisibility) -> Self {
self.visibility = vis;
self
}
pub fn static_(mut self) -> Self {
self.is_static = true;
self
}
pub fn constexpr(mut self) -> Self {
self.is_constexpr = true;
self
}
pub fn virtual_(mut self) -> Self {
self.is_virtual = true;
self
}
pub fn override_(mut self) -> Self {
self.is_override = true;
self
}
pub fn noexcept(mut self) -> Self {
self.is_noexcept = true;
self
}
pub fn template_param(mut self, param: &str) -> Self {
self.template_params.push(param.to_string());
self
}
pub fn sort_text(mut self, text: &str) -> Self {
self.sort_text = Some(text.to_string());
self
}
pub fn filter_text(mut self, text: &str) -> Self {
self.filter_text = Some(text.to_string());
self
}
pub fn add_edit(
mut self,
file: Option<&str>,
line: usize,
column: usize,
new_text: &str,
) -> Self {
self.additional_edits.push(X86AdditionalEdit {
file: file.map(|s| s.to_string()),
line,
column,
new_text: new_text.to_string(),
});
self
}
pub fn build(self) -> X86CompletionResult {
X86CompletionResult {
display_text: self.display_text,
insert_text: self.insert_text,
kind: self.kind,
priority: self.priority,
documentation: self.documentation,
detail: self.detail,
additional_edits: self.additional_edits,
deprecated: self.deprecated,
is_snippet: self.is_snippet,
sort_text: self.sort_text,
filter_text: self.filter_text,
required_header: self.required_header,
scope: self.scope,
visibility: self.visibility,
is_static: self.is_static,
is_constexpr: self.is_constexpr,
is_virtual: self.is_virtual,
is_override: self.is_override,
is_noexcept: self.is_noexcept,
return_type: self.return_type,
parameters: self.parameters,
template_params: self.template_params,
}
}
}
#[derive(Debug, Clone)]
pub struct X86CompletionReflection {
supported_contexts: Vec<String>,
supported_kinds: Vec<String>,
capabilities: X86CompletionCapabilities,
}
#[derive(Debug, Clone, Default)]
pub struct X86CompletionCapabilities {
pub snippet_support: bool,
pub fuzzy_matching: bool,
pub type_based_ranking: bool,
pub scope_based_ranking: bool,
pub frequency_based_ranking: bool,
pub context_aware_completion: bool,
pub x86_intrinsic_support: bool,
pub cpp_support: bool,
pub c_support: bool,
pub header_completion: bool,
pub macro_completion: bool,
pub member_completion: bool,
pub namespace_completion: bool,
pub cache_support: bool,
pub aggregation_support: bool,
pub max_completions_per_query: usize,
pub supported_lsp_version: String,
}
impl Default for X86CompletionReflection {
fn default() -> Self {
Self {
supported_contexts: vec![
"dot_access".into(),
"arrow_access".into(),
"scope_resolution".into(),
"open_paren".into(),
"type_context".into(),
"declaration_context".into(),
"directive_context".into(),
"include_context".into(),
"string_context".into(),
"label_context".into(),
"enum_body".into(),
"using_context".into(),
"template_argument".into(),
"general".into(),
"expression".into(),
"return".into(),
"case".into(),
"goto".into(),
"access_specifier".into(),
"initializer_list".into(),
"throw".into(),
"noexcept".into(),
"catch".into(),
"decltype".into(),
"sizeof".into(),
"attribute".into(),
],
supported_kinds: vec![
"function".into(),
"variable".into(),
"type".into(),
"macro".into(),
"keyword".into(),
"directive".into(),
"field".into(),
"enum_member".into(),
"namespace".into(),
"snippet".into(),
"file".into(),
"label".into(),
"concept".into(),
"operator".into(),
"type_parameter".into(),
"intrinsic".into(),
"module".into(),
"constant".into(),
"template_function".into(),
"template_type".into(),
"static_member".into(),
"inherited_member".into(),
"using_declaration".into(),
"namespace_alias".into(),
"constructor".into(),
"destructor".into(),
"conversion_function".into(),
"literal_operator".into(),
"user_defined_literal".into(),
"parameter".into(),
"local_variable".into(),
"global_variable".into(),
],
capabilities: X86CompletionCapabilities {
snippet_support: true,
fuzzy_matching: true,
type_based_ranking: true,
scope_based_ranking: true,
frequency_based_ranking: true,
context_aware_completion: true,
x86_intrinsic_support: true,
cpp_support: true,
c_support: true,
header_completion: true,
macro_completion: true,
member_completion: true,
namespace_completion: true,
cache_support: true,
aggregation_support: true,
max_completions_per_query: 100,
supported_lsp_version: "3.17".into(),
},
}
}
}
impl X86CompletionReflection {
pub fn new() -> Self {
Self::default()
}
pub fn supported_contexts(&self) -> &[String] {
&self.supported_contexts
}
pub fn supported_kinds(&self) -> &[String] {
&self.supported_kinds
}
pub fn capabilities(&self) -> &X86CompletionCapabilities {
&self.capabilities
}
pub fn supports_kind(&self, kind: X86CompletionKind) -> bool {
let kind_str = format!("{}", kind);
self.supported_kinds.iter().any(|k| *k == kind_str)
}
pub fn supports_context(&self, context_name: &str) -> bool {
self.supported_contexts
.iter()
.any(|c| c.as_str() == context_name)
}
pub fn capabilities_report(&self) -> String {
let c = &self.capabilities;
let mut report = String::new();
report.push_str("X86 CodeCompletion Engine Capabilities\n");
report.push_str("=====================================\n");
report.push_str(&format!("LSP Version: {}\n", c.supported_lsp_version));
report.push_str(&format!("C support: {}\n", c.c_support));
report.push_str(&format!("C++ support: {}\n", c.cpp_support));
report.push_str(&format!("Snippets: {}\n", c.snippet_support));
report.push_str(&format!("Fuzzy matching: {}\n", c.fuzzy_matching));
report.push_str(&format!("X86 intrinsics: {}\n", c.x86_intrinsic_support));
report.push_str(&format!("Header complete: {}\n", c.header_completion));
report.push_str(&format!("Macro complete: {}\n", c.macro_completion));
report.push_str(&format!("Member complete: {}\n", c.member_completion));
report.push_str(&format!("Namespace comp.: {}\n", c.namespace_completion));
report.push_str(&format!("Type ranking: {}\n", c.type_based_ranking));
report.push_str(&format!("Scope ranking: {}\n", c.scope_based_ranking));
report.push_str(&format!("Freq. ranking: {}\n", c.frequency_based_ranking));
report.push_str(&format!(
"Context aware: {}\n",
c.context_aware_completion
));
report.push_str(&format!("Cache: {}\n", c.cache_support));
report.push_str(&format!("Aggregation: {}\n", c.aggregation_support));
report.push_str(&format!(
"Max/query: {}\n",
c.max_completions_per_query
));
report.push_str(&format!(
"Contexts: {}\n",
self.supported_contexts.len()
));
report.push_str(&format!(
"Item kinds: {}\n",
self.supported_kinds.len()
));
report
}
}
#[cfg(test)]
mod aggregator_cache_builder_tests {
use super::*;
#[test]
fn test_aggregator_default() {
let agg = X86CompletionAggregator::new();
assert!(agg.include_secondary);
assert_eq!(agg.stats.total_queries, 0);
}
#[test]
fn test_aggregator_primary_only() {
let mut agg = X86CompletionAggregator::new();
let results = agg.complete_aggregated(&X86CompletionContext::General, "int", None);
assert!(!results.is_empty());
assert_eq!(agg.stats.primary_count, results.len());
}
#[test]
fn test_aggregator_with_secondary() {
let mut agg = X86CompletionAggregator::new();
agg.set_secondary(vec![
X86CompletionResult::function("remote_func", "void", &[], None),
X86CompletionResult::type_("RemoteType", None),
]);
let results = agg.complete_aggregated(&X86CompletionContext::General, "remote", None);
assert!(results
.iter()
.any(|r| r.display_text.contains("remote_func")));
assert!(results
.iter()
.any(|r| r.display_text.contains("RemoteType")));
}
#[test]
fn test_aggregator_conflict_prefer_primary() {
let mut agg = X86CompletionAggregator::new();
agg.set_conflict_strategy(X86ConflictStrategy::PreferPrimary);
agg.primary_mut().type_completion.register_type(
"int",
X86CompletionKind::Type,
"Primary int",
None,
None,
);
agg.set_secondary(vec![{
let mut item = X86CompletionResult::type_("int", Some("Secondary int"));
item.priority = 90;
item
}]);
let results = agg.complete_aggregated(&X86CompletionContext::General, "int", None);
let int_result = results.iter().find(|r| r.display_text == "int").unwrap();
assert_eq!(int_result.priority, 80);
}
#[test]
fn test_aggregator_conflict_highest_priority() {
let mut agg = X86CompletionAggregator::new();
agg.set_conflict_strategy(X86ConflictStrategy::HighestPriority);
agg.primary_mut().type_completion.register_type(
"int",
X86CompletionKind::Type,
"Primary int",
None,
None,
);
agg.set_secondary(vec![{
let mut item = X86CompletionResult::type_("int", Some("Secondary int"));
item.priority = 95;
item
}]);
let results = agg.complete_aggregated(&X86CompletionContext::General, "int", None);
let int_result = results.iter().find(|r| r.display_text == "int").unwrap();
assert_eq!(int_result.priority, 95);
}
#[test]
fn test_aggregator_disable_secondary() {
let mut agg = X86CompletionAggregator::new();
agg.include_secondary = false;
agg.set_secondary(vec![X86CompletionResult::keyword("secondary_kw")]);
let results = agg.complete_aggregated(&X86CompletionContext::General, "secondary", None);
assert!(!results
.iter()
.any(|r| r.display_text.contains("secondary_kw")));
}
#[test]
fn test_aggregator_clear_secondary() {
let mut agg = X86CompletionAggregator::new();
agg.set_secondary(vec![X86CompletionResult::keyword("test")]);
agg.clear_secondary();
let results = agg.complete_aggregated(&X86CompletionContext::General, "test", None);
assert!(!results.iter().any(|r| r.display_text == "test"));
}
#[test]
fn test_aggregator_stats() {
let mut agg = X86CompletionAggregator::new();
agg.complete_aggregated(&X86CompletionContext::General, "int", None);
agg.complete_aggregated(&X86CompletionContext::General, "float", None);
let stats = agg.stats();
assert_eq!(stats.total_queries, 2);
}
#[test]
fn test_aggregator_reset_stats() {
let mut agg = X86CompletionAggregator::new();
agg.complete_aggregated(&X86CompletionContext::General, "int", None);
agg.reset_stats();
let stats = agg.stats();
assert_eq!(stats.total_queries, 0);
}
#[test]
fn test_cache_manager_basic() {
let mut cache = X86CompletionCacheManager::new();
let results = vec![X86CompletionResult::keyword("for")];
cache.insert("key1", results.clone(), None, None);
let cached = cache.get("key1");
assert!(cached.is_some());
assert_eq!(cached.unwrap().len(), 1);
}
#[test]
fn test_cache_manager_miss() {
let mut cache = X86CompletionCacheManager::new();
let result = cache.get("nonexistent");
assert!(result.is_none());
}
#[test]
fn test_cache_manager_disabled() {
let mut cache = X86CompletionCacheManager::new();
cache.set_enabled(false);
let results = vec![X86CompletionResult::keyword("for")];
cache.insert("key", results, None, None);
let cached = cache.get("key");
assert!(cached.is_none());
}
#[test]
fn test_cache_manager_eviction() {
let mut cache = X86CompletionCacheManager::with_capacity(2);
cache.insert("a", vec![], None, None);
cache.insert("b", vec![], None, None);
cache.insert("c", vec![], None, None);
assert!(cache.get("a").is_none());
assert!(cache.get("b").is_some());
assert!(cache.get("c").is_some());
}
#[test]
fn test_cache_manager_lru() {
let mut cache = X86CompletionCacheManager::with_capacity(2);
cache.insert("a", vec![], None, None);
cache.insert("b", vec![], None, None);
cache.get("a");
cache.insert("c", vec![], None, None);
assert!(cache.get("a").is_some());
assert!(cache.get("b").is_none());
assert!(cache.get("c").is_some());
}
#[test]
fn test_cache_manager_invalidate_file() {
let mut cache = X86CompletionCacheManager::new();
cache.insert("k1", vec![], Some("file_a.c"), None);
cache.insert("k2", vec![], Some("file_b.c"), None);
cache.invalidate_file("file_a.c");
assert!(cache.get("k1").is_none());
assert!(cache.get("k2").is_some());
}
#[test]
fn test_cache_manager_invalidate_scope() {
let mut cache = X86CompletionCacheManager::new();
cache.insert("k1", vec![], None, Some("scope_a"));
cache.insert("k2", vec![], None, Some("scope_b"));
cache.invalidate_scope("scope_a");
assert!(cache.get("k1").is_none());
assert!(cache.get("k2").is_some());
}
#[test]
fn test_cache_manager_stats() {
let mut cache = X86CompletionCacheManager::new();
cache.insert("k", vec![], None, None);
cache.get("k"); cache.get("miss");
let stats = cache.stats();
assert_eq!(stats.hits, 1);
assert_eq!(stats.misses, 1);
assert_eq!(stats.entries, 1);
assert!(stats.hit_rate > 0.0);
}
#[test]
fn test_cache_manager_clear() {
let mut cache = X86CompletionCacheManager::new();
cache.insert("k", vec![], None, None);
cache.clear();
assert!(cache.is_empty());
assert_eq!(cache.stats().hits, 0);
}
#[test]
fn test_cache_manager_keys() {
let mut cache = X86CompletionCacheManager::new();
cache.insert("alpha", vec![], None, None);
cache.insert("beta", vec![], None, None);
let keys = cache.keys();
assert_eq!(keys.len(), 2);
}
#[test]
fn test_cache_stats_display() {
let stats = X86CacheStats {
entries: 10,
max_entries: 100,
hits: 95,
misses: 5,
hit_rate: 0.95,
enabled: true,
};
let display = format!("{}", stats);
assert!(display.contains("95"));
assert!(display.contains("95.0%"));
}
#[test]
fn test_builder_basic() {
let result = X86CompletionBuilder::new("my_func", X86CompletionKind::Function)
.return_type("int")
.param("x", "int")
.param("y", "double")
.doc("A test function")
.priority(90)
.build();
assert_eq!(result.display_text, "my_func");
assert_eq!(result.kind, X86CompletionKind::Function);
assert_eq!(result.return_type, Some("int".to_string()));
assert_eq!(result.parameters.len(), 2);
assert_eq!(result.priority, 90);
}
#[test]
fn test_builder_full() {
let result = X86CompletionBuilder::new("full_func", X86CompletionKind::Function)
.insert_text("full_func(")
.return_type("void")
.param_with_default("a", "int", "42")
.variadic_param("rest")
.doc("Fully featured function")
.detail("void full_func(int a, ...)")
.header("myheader.h")
.scope("ns::inner")
.visibility(X86SymbolVisibility::Public)
.static_()
.constexpr()
.noexcept()
.template_param("T")
.sort_text("z_full")
.filter_text("full")
.add_edit(None, 0, 0, "#include <myheader.h>\n")
.priority(75)
.build();
assert_eq!(result.insert_text, "full_func(");
assert_eq!(result.return_type, Some("void".to_string()));
assert_eq!(result.parameters.len(), 2);
assert!(result.parameters[0].default_value.is_some());
assert!(result.parameters[1].is_variadic);
assert!(result.is_static);
assert!(result.is_constexpr);
assert!(result.is_noexcept);
assert_eq!(result.template_params, vec!["T"]);
assert_eq!(result.visibility, X86SymbolVisibility::Public);
assert_eq!(result.required_header, Some("myheader.h".to_string()));
assert_eq!(result.scope, Some("ns::inner".to_string()));
assert_eq!(result.sort_text, Some("z_full".to_string()));
assert_eq!(result.filter_text, Some("full".to_string()));
assert_eq!(result.additional_edits.len(), 1);
}
#[test]
fn test_builder_deprecated() {
let result = X86CompletionBuilder::new("old", X86CompletionKind::Function)
.deprecated()
.build();
assert!(result.deprecated);
}
#[test]
fn test_builder_snippet() {
let result = X86CompletionBuilder::new("for", X86CompletionKind::Snippet)
.snippet()
.build();
assert!(result.is_snippet);
}
#[test]
fn test_builder_virtual_override() {
let result = X86CompletionBuilder::new("do_work", X86CompletionKind::Function)
.virtual_()
.override_()
.build();
assert!(result.is_virtual);
assert!(result.is_override);
}
#[test]
fn test_reflection_defaults() {
let refl = X86CompletionReflection::new();
assert!(!refl.supported_contexts().is_empty());
assert!(!refl.supported_kinds().is_empty());
}
#[test]
fn test_reflection_supports_kind() {
let refl = X86CompletionReflection::new();
assert!(refl.supports_kind(X86CompletionKind::Function));
assert!(refl.supports_kind(X86CompletionKind::Type));
}
#[test]
fn test_reflection_supports_context() {
let refl = X86CompletionReflection::new();
assert!(refl.supports_context("dot_access"));
assert!(refl.supports_context("template_argument"));
}
#[test]
fn test_reflection_capabilities() {
let refl = X86CompletionReflection::new();
let caps = refl.capabilities();
assert!(caps.snippet_support);
assert!(caps.fuzzy_matching);
assert!(caps.x86_intrinsic_support);
assert_eq!(caps.supported_lsp_version, "3.17");
}
#[test]
fn test_reflection_capabilities_report() {
let refl = X86CompletionReflection::new();
let report = refl.capabilities_report();
assert!(report.contains("X86 CodeCompletion"));
assert!(report.contains("LSP Version"));
assert!(report.contains("Snippets"));
assert!(report.contains("Fuzzy matching"));
assert!(report.contains("Cache"));
}
}