use crate::cpp_data::CppBaseSpecifier;
use crate::cpp_data::CppClassField;
use crate::cpp_data::CppEnumValue;
use crate::cpp_data::CppOriginLocation;
use crate::cpp_data::CppTypeData;
use crate::cpp_data::CppTypeDataKind;
use ritual_common::target::Target;
use crate::cpp_data::CppVisibility;
use crate::cpp_function::CppFunction;
use crate::cpp_data::CppPath;
use crate::cpp_data::CppTemplateInstantiation;
use crate::cpp_ffi_data::CppFfiFunction;
use crate::cpp_ffi_data::QtSlotWrapper;
use crate::cpp_type::CppType;
use crate::rust_type::RustPath;
use itertools::Itertools;
use serde_derive::{Deserialize, Serialize};
use std::fmt::Display;
use std::fmt::Formatter;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CppCheckerEnv {
pub target: Target,
pub cpp_library_version: Option<String>,
}
impl CppCheckerEnv {
pub fn short_text(&self) -> String {
format!(
"{}/{:?}-{:?}-{:?}-{:?}",
self.cpp_library_version
.as_ref()
.map(|s| s.as_str())
.unwrap_or("None"),
self.target.arch,
self.target.os,
self.target.family,
self.target.env
)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DatabaseItemSource {
CppParser {
include_file: String,
origin_location: CppOriginLocation,
},
ImplicitDestructor,
TemplateInstantiation,
NamespaceInfering,
QtSignalArguments,
}
impl DatabaseItemSource {
pub fn is_parser(&self) -> bool {
match *self {
DatabaseItemSource::CppParser { .. } => true,
_ => false,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CppCheckerInfo {
pub env: CppCheckerEnv,
pub error: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct CppCheckerInfoList {
pub items: Vec<CppCheckerInfo>,
}
pub enum CppCheckerAddResult {
Added,
Changed { old: Option<String> },
Unchanged,
}
impl CppCheckerInfoList {
pub fn add(&mut self, env: &CppCheckerEnv, error: Option<String>) -> CppCheckerAddResult {
if let Some(item) = self.items.iter_mut().find(|i| &i.env == env) {
let r = if item.error == error {
CppCheckerAddResult::Unchanged
} else {
CppCheckerAddResult::Changed {
old: item.error.clone(),
}
};
item.error = error;
return r;
}
self.items.push(CppCheckerInfo {
env: env.clone(),
error,
});
CppCheckerAddResult::Added
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
pub enum CppItemData {
Namespace(CppPath),
Type(CppTypeData),
EnumValue(CppEnumValue),
Function(CppFunction),
ClassField(CppClassField),
ClassBase(CppBaseSpecifier),
TemplateInstantiation(CppTemplateInstantiation),
QtSignalArguments(Vec<CppType>),
}
impl CppItemData {
pub fn is_same(&self, other: &CppItemData) -> bool {
match (self, other) {
(&CppItemData::Type(ref v), &CppItemData::Type(ref v2)) => v.is_same(v2),
(&CppItemData::EnumValue(ref v), &CppItemData::EnumValue(ref v2)) => v.is_same(v2),
(&CppItemData::Function(ref v), &CppItemData::Function(ref v2)) => v.is_same(v2),
(&CppItemData::ClassField(ref v), &CppItemData::ClassField(ref v2)) => v.is_same(v2),
(&CppItemData::ClassBase(ref v), &CppItemData::ClassBase(ref v2)) => v == v2,
(
&CppItemData::TemplateInstantiation(ref v),
&CppItemData::TemplateInstantiation(ref v2),
) => v == v2,
(&CppItemData::QtSignalArguments(ref v), &CppItemData::QtSignalArguments(ref v2)) => {
v == v2
}
_ => false,
}
}
pub fn all_involved_types(&self) -> Vec<CppType> {
match *self {
CppItemData::Type(ref t) => match t.kind {
CppTypeDataKind::Enum => vec![CppType::Enum {
path: t.path.clone(),
}],
CppTypeDataKind::Class => vec![CppType::Class(t.path.clone())],
},
CppItemData::EnumValue(ref enum_value) => vec![CppType::Enum {
path: enum_value.enum_path.clone(),
}],
CppItemData::Namespace(_) => Vec::new(),
CppItemData::Function(ref function) => function.all_involved_types(),
CppItemData::ClassField(ref field) => {
let class_type = CppType::Class(field.class_type.clone());
vec![class_type, field.field_type.clone()]
}
CppItemData::ClassBase(ref base) => vec![
CppType::Class(base.base_class_type.clone()),
CppType::Class(base.derived_class_type.clone()),
],
CppItemData::QtSignalArguments(ref args) => args.clone(),
CppItemData::TemplateInstantiation(ref data) => data.template_arguments.clone(),
}
}
pub fn as_namespace_ref(&self) -> Option<&CppPath> {
if let CppItemData::Namespace(ref data) = *self {
Some(data)
} else {
None
}
}
pub fn as_function_ref(&self) -> Option<&CppFunction> {
if let CppItemData::Function(ref data) = *self {
Some(data)
} else {
None
}
}
pub fn as_field_ref(&self) -> Option<&CppClassField> {
if let CppItemData::ClassField(ref data) = *self {
Some(data)
} else {
None
}
}
pub fn as_enum_value_ref(&self) -> Option<&CppEnumValue> {
if let CppItemData::EnumValue(ref data) = *self {
Some(data)
} else {
None
}
}
pub fn as_base_ref(&self) -> Option<&CppBaseSpecifier> {
if let CppItemData::ClassBase(ref data) = *self {
Some(data)
} else {
None
}
}
pub fn as_type_ref(&self) -> Option<&CppTypeData> {
if let CppItemData::Type(ref data) = *self {
Some(data)
} else {
None
}
}
pub fn as_template_instantiation_ref(&self) -> Option<&CppTemplateInstantiation> {
if let CppItemData::TemplateInstantiation(ref data) = *self {
Some(data)
} else {
None
}
}
pub fn as_signal_arguments_ref(&self) -> Option<&[CppType]> {
if let CppItemData::QtSignalArguments(ref data) = *self {
Some(data)
} else {
None
}
}
}
impl Display for CppItemData {
fn fmt(&self, f: &mut Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
let s = match *self {
CppItemData::Namespace(ref path) => format!("namespace {}", path),
CppItemData::Type(ref type1) => match type1.kind {
CppTypeDataKind::Enum => format!("enum {}", type1.path.to_cpp_pseudo_code()),
CppTypeDataKind::Class => format!("class {}", type1.path.to_cpp_pseudo_code()),
},
CppItemData::Function(ref method) => method.short_text(),
CppItemData::EnumValue(ref value) => format!(
"enum {} {{ {} = {}, ... }}",
value.enum_path, value.name, value.value
),
CppItemData::ClassField(ref field) => field.short_text(),
CppItemData::ClassBase(ref class_base) => {
let virtual_text = if class_base.is_virtual {
"virtual "
} else {
""
};
let visibility_text = match class_base.visibility {
CppVisibility::Public => "public",
CppVisibility::Protected => "protected",
CppVisibility::Private => "private",
};
let index_text = if class_base.base_index > 0 {
format!(" (index: {}", class_base.base_index)
} else {
String::new()
};
format!(
"class {} : {}{} {}{}",
class_base.derived_class_type.to_cpp_pseudo_code(),
virtual_text,
visibility_text,
class_base.base_class_type.to_cpp_pseudo_code(),
index_text
)
}
CppItemData::QtSignalArguments(ref args) => format!(
"Qt signal args ({})",
args.iter().map(|arg| arg.to_cpp_pseudo_code()).join(", ")
),
CppItemData::TemplateInstantiation(ref data) => format!(
"template instantiation: {}<{}>",
data.class_name,
data.template_arguments
.iter()
.map(|arg| arg.to_cpp_pseudo_code())
.join(", ")
),
};
f.write_str(&s)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RustPathScope {
path: RustPath,
prefix: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RustClassPath {
TemplateClass {
instantiated: RustPathScope,
},
ConcreteClass {
path: RustPath,
nested: RustPathScope,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RustFunctionPath {
Inherent(RustPath),
Free(RustPath),
TraitImpl,
}
impl RustFunctionPath {
fn rust_path(&self) -> Option<&RustPath> {
match *self {
RustFunctionPath::Inherent(ref path) => Some(path),
RustFunctionPath::Free(ref path) => Some(path),
RustFunctionPath::TraitImpl => None,
}
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RustItem {
Function {
cpp_ffi_function: CppFfiFunction,
checks: CppCheckerInfoList,
rust_path: Option<RustFunctionPath>,
},
Enum {
rust_path: Option<RustPath>,
},
EnumValue {
rust_path: Option<RustPath>,
},
Class {
qt_slot_wrapper: Option<QtSlotWrapper>,
checks: CppCheckerInfoList,
rust_path: Option<RustClassPath>,
},
Namespace {
rust_path: Option<RustPathScope>,
},
QtPublicSlotWrapper {
some_things: (),
rust_path: Option<RustPath>,
},
}
impl RustItem {
pub fn from_function(cpp_ffi_function: CppFfiFunction) -> Self {
RustItem::Function {
cpp_ffi_function,
checks: Default::default(),
rust_path: None,
}
}
pub fn from_qt_slot_wrapper(wrapper: QtSlotWrapper) -> Self {
RustItem::Class {
qt_slot_wrapper: Some(wrapper),
checks: Default::default(),
rust_path: None,
}
}
pub fn has_rust_path_resolved(&self) -> bool {
match *self {
RustItem::Function { ref rust_path, .. } => rust_path.is_some(),
RustItem::Enum { ref rust_path, .. } => rust_path.is_some(),
RustItem::EnumValue { ref rust_path, .. } => rust_path.is_some(),
RustItem::Class { ref rust_path, .. } => rust_path.is_some(),
RustItem::Namespace { ref rust_path, .. } => rust_path.is_some(),
RustItem::QtPublicSlotWrapper { ref rust_path, .. } => rust_path.is_some(),
}
}
pub fn checks_mut(&mut self) -> Option<&mut CppCheckerInfoList> {
match *self {
RustItem::Function { ref mut checks, .. } | RustItem::Class { ref mut checks, .. } => {
Some(checks)
}
_ => None,
}
}
pub fn rust_path(&self) -> Option<&RustPath> {
match *self {
RustItem::Function { ref rust_path, .. } => rust_path
.as_ref()
.and_then(|function_path| function_path.rust_path()),
RustItem::Enum { ref rust_path, .. } => rust_path.as_ref(),
RustItem::EnumValue { ref rust_path, .. } => rust_path.as_ref(),
RustItem::Class { ref rust_path, .. } => {
if let Some(RustClassPath::ConcreteClass { ref path, .. }) = rust_path {
Some(path)
} else {
None
}
}
RustItem::Namespace { .. } => None,
RustItem::QtPublicSlotWrapper { ref rust_path, .. } => rust_path.as_ref(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseItem {
pub cpp_data: CppItemData,
pub source: DatabaseItemSource,
pub rust_items: Option<Vec<RustItem>>, }
#[derive(Debug, Serialize, Deserialize)]
pub struct Database {
pub crate_name: String,
pub crate_version: String,
pub items: Vec<DatabaseItem>,
pub environments: Vec<CppCheckerEnv>,
pub next_ffi_id: u64,
}
impl Database {
pub fn empty(crate_name: impl Into<String>) -> Database {
Database {
crate_name: crate_name.into(),
crate_version: "0.0.0".into(),
items: Vec::new(),
environments: Vec::new(),
next_ffi_id: 0,
}
}
pub fn items(&self) -> &[DatabaseItem] {
&self.items
}
pub fn clear(&mut self) {
self.items.clear();
self.environments.clear();
self.next_ffi_id = 0;
}
pub fn crate_name(&self) -> &str {
&self.crate_name
}
pub fn add_cpp_data(&mut self, source: DatabaseItemSource, data: CppItemData) -> bool {
if let Some(item) = self
.items
.iter_mut()
.find(|item| item.cpp_data.is_same(&data))
{
if source.is_parser() && !item.source.is_parser() {
item.source = source;
}
return false;
}
self.items.push(DatabaseItem {
cpp_data: data,
source,
rust_items: None,
});
true
}
}