1use crate::cpp_data::CppBaseSpecifier;
2use crate::cpp_data::CppClassField;
3use crate::cpp_data::CppEnumValue;
4use crate::cpp_data::CppOriginLocation;
5use crate::cpp_data::CppTypeData;
6use crate::cpp_data::CppTypeDataKind;
7use ritual_common::target::Target;
8
9use crate::cpp_data::CppVisibility;
10use crate::cpp_function::CppFunction;
11
12use crate::cpp_data::CppPath;
13use crate::cpp_data::CppTemplateInstantiation;
14use crate::cpp_ffi_data::CppFfiFunction;
15use crate::cpp_ffi_data::QtSlotWrapper;
16use crate::cpp_type::CppType;
17use crate::rust_type::RustPath;
18use itertools::Itertools;
19use serde_derive::{Deserialize, Serialize};
20use std::fmt::Display;
21use std::fmt::Formatter;
22
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
24pub struct CppCheckerEnv {
25 pub target: Target,
26 pub cpp_library_version: Option<String>,
27}
28
29impl CppCheckerEnv {
30 pub fn short_text(&self) -> String {
31 format!(
32 "{}/{:?}-{:?}-{:?}-{:?}",
33 self.cpp_library_version
34 .as_ref()
35 .map(|s| s.as_str())
36 .unwrap_or("None"),
37 self.target.arch,
38 self.target.os,
39 self.target.family,
40 self.target.env
41 )
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46pub enum DatabaseItemSource {
47 CppParser {
48 include_file: String,
50 origin_location: CppOriginLocation,
52 },
53 ImplicitDestructor,
54 TemplateInstantiation,
55 NamespaceInfering,
56 QtSignalArguments,
57}
58
59impl DatabaseItemSource {
60 pub fn is_parser(&self) -> bool {
61 match *self {
62 DatabaseItemSource::CppParser { .. } => true,
63 _ => false,
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
69pub struct CppCheckerInfo {
70 pub env: CppCheckerEnv,
71 pub error: Option<String>,
72}
73
74#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
75pub struct CppCheckerInfoList {
76 pub items: Vec<CppCheckerInfo>,
77}
78
79pub enum CppCheckerAddResult {
80 Added,
81 Changed { old: Option<String> },
82 Unchanged,
83}
84
85impl CppCheckerInfoList {
86 pub fn add(&mut self, env: &CppCheckerEnv, error: Option<String>) -> CppCheckerAddResult {
87 if let Some(item) = self.items.iter_mut().find(|i| &i.env == env) {
88 let r = if item.error == error {
89 CppCheckerAddResult::Unchanged
90 } else {
91 CppCheckerAddResult::Changed {
92 old: item.error.clone(),
93 }
94 };
95 item.error = error;
96 return r;
97 }
98 self.items.push(CppCheckerInfo {
99 env: env.clone(),
100 error,
101 });
102 CppCheckerAddResult::Added
103 }
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
107#[allow(clippy::large_enum_variant)]
108pub enum CppItemData {
109 Namespace(CppPath),
110 Type(CppTypeData),
111 EnumValue(CppEnumValue),
112 Function(CppFunction),
113 ClassField(CppClassField),
114 ClassBase(CppBaseSpecifier),
115 TemplateInstantiation(CppTemplateInstantiation),
116 QtSignalArguments(Vec<CppType>),
117}
118
119impl CppItemData {
120 pub fn is_same(&self, other: &CppItemData) -> bool {
121 match (self, other) {
122 (&CppItemData::Type(ref v), &CppItemData::Type(ref v2)) => v.is_same(v2),
123 (&CppItemData::EnumValue(ref v), &CppItemData::EnumValue(ref v2)) => v.is_same(v2),
124 (&CppItemData::Function(ref v), &CppItemData::Function(ref v2)) => v.is_same(v2),
125 (&CppItemData::ClassField(ref v), &CppItemData::ClassField(ref v2)) => v.is_same(v2),
126 (&CppItemData::ClassBase(ref v), &CppItemData::ClassBase(ref v2)) => v == v2,
127 (
128 &CppItemData::TemplateInstantiation(ref v),
129 &CppItemData::TemplateInstantiation(ref v2),
130 ) => v == v2,
131 (&CppItemData::QtSignalArguments(ref v), &CppItemData::QtSignalArguments(ref v2)) => {
132 v == v2
133 }
134 _ => false,
135 }
136 }
137
138 pub fn all_involved_types(&self) -> Vec<CppType> {
139 match *self {
140 CppItemData::Type(ref t) => match t.kind {
141 CppTypeDataKind::Enum => vec![CppType::Enum {
142 path: t.path.clone(),
143 }],
144 CppTypeDataKind::Class => vec![CppType::Class(t.path.clone())],
145 },
146 CppItemData::EnumValue(ref enum_value) => vec![CppType::Enum {
147 path: enum_value.enum_path.clone(),
148 }],
149 CppItemData::Namespace(_) => Vec::new(),
150 CppItemData::Function(ref function) => function.all_involved_types(),
151 CppItemData::ClassField(ref field) => {
152 let class_type = CppType::Class(field.class_type.clone());
153 vec![class_type, field.field_type.clone()]
154 }
155 CppItemData::ClassBase(ref base) => vec![
156 CppType::Class(base.base_class_type.clone()),
157 CppType::Class(base.derived_class_type.clone()),
158 ],
159 CppItemData::QtSignalArguments(ref args) => args.clone(),
160 CppItemData::TemplateInstantiation(ref data) => data.template_arguments.clone(),
161 }
162 }
163
164 pub fn as_namespace_ref(&self) -> Option<&CppPath> {
165 if let CppItemData::Namespace(ref data) = *self {
166 Some(data)
167 } else {
168 None
169 }
170 }
171 pub fn as_function_ref(&self) -> Option<&CppFunction> {
172 if let CppItemData::Function(ref data) = *self {
173 Some(data)
174 } else {
175 None
176 }
177 }
178 pub fn as_field_ref(&self) -> Option<&CppClassField> {
179 if let CppItemData::ClassField(ref data) = *self {
180 Some(data)
181 } else {
182 None
183 }
184 }
185 pub fn as_enum_value_ref(&self) -> Option<&CppEnumValue> {
186 if let CppItemData::EnumValue(ref data) = *self {
187 Some(data)
188 } else {
189 None
190 }
191 }
192 pub fn as_base_ref(&self) -> Option<&CppBaseSpecifier> {
193 if let CppItemData::ClassBase(ref data) = *self {
194 Some(data)
195 } else {
196 None
197 }
198 }
199 pub fn as_type_ref(&self) -> Option<&CppTypeData> {
200 if let CppItemData::Type(ref data) = *self {
201 Some(data)
202 } else {
203 None
204 }
205 }
206
207 pub fn as_template_instantiation_ref(&self) -> Option<&CppTemplateInstantiation> {
208 if let CppItemData::TemplateInstantiation(ref data) = *self {
209 Some(data)
210 } else {
211 None
212 }
213 }
214 pub fn as_signal_arguments_ref(&self) -> Option<&[CppType]> {
215 if let CppItemData::QtSignalArguments(ref data) = *self {
216 Some(data)
217 } else {
218 None
219 }
220 }
221
222 }
226
227impl Display for CppItemData {
228 fn fmt(&self, f: &mut Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
229 let s = match *self {
230 CppItemData::Namespace(ref path) => format!("namespace {}", path),
231 CppItemData::Type(ref type1) => match type1.kind {
232 CppTypeDataKind::Enum => format!("enum {}", type1.path.to_cpp_pseudo_code()),
233 CppTypeDataKind::Class => format!("class {}", type1.path.to_cpp_pseudo_code()),
234 },
235 CppItemData::Function(ref method) => method.short_text(),
236 CppItemData::EnumValue(ref value) => format!(
237 "enum {} {{ {} = {}, ... }}",
238 value.enum_path, value.name, value.value
239 ),
240 CppItemData::ClassField(ref field) => field.short_text(),
241 CppItemData::ClassBase(ref class_base) => {
242 let virtual_text = if class_base.is_virtual {
243 "virtual "
244 } else {
245 ""
246 };
247 let visibility_text = match class_base.visibility {
248 CppVisibility::Public => "public",
249 CppVisibility::Protected => "protected",
250 CppVisibility::Private => "private",
251 };
252 let index_text = if class_base.base_index > 0 {
253 format!(" (index: {}", class_base.base_index)
254 } else {
255 String::new()
256 };
257 format!(
258 "class {} : {}{} {}{}",
259 class_base.derived_class_type.to_cpp_pseudo_code(),
260 virtual_text,
261 visibility_text,
262 class_base.base_class_type.to_cpp_pseudo_code(),
263 index_text
264 )
265 }
266 CppItemData::QtSignalArguments(ref args) => format!(
267 "Qt signal args ({})",
268 args.iter().map(|arg| arg.to_cpp_pseudo_code()).join(", ")
269 ),
270 CppItemData::TemplateInstantiation(ref data) => format!(
271 "template instantiation: {}<{}>",
272 data.class_name,
273 data.template_arguments
274 .iter()
275 .map(|arg| arg.to_cpp_pseudo_code())
276 .join(", ")
277 ),
278 };
279
280 f.write_str(&s)
281 }
282}
283
284#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct RustPathScope {
286 path: RustPath,
287 prefix: Option<String>,
288}
289
290#[derive(Debug, Clone, Serialize, Deserialize)]
291pub enum RustClassPath {
292 TemplateClass {
293 instantiated: RustPathScope,
294 },
295 ConcreteClass {
296 path: RustPath,
297 nested: RustPathScope,
298 },
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
302pub enum RustFunctionPath {
303 Inherent(RustPath),
304 Free(RustPath),
305 TraitImpl,
306}
307
308impl RustFunctionPath {
309 fn rust_path(&self) -> Option<&RustPath> {
310 match *self {
311 RustFunctionPath::Inherent(ref path) => Some(path),
312 RustFunctionPath::Free(ref path) => Some(path),
313 RustFunctionPath::TraitImpl => None,
314 }
315 }
316}
317
318#[allow(clippy::large_enum_variant)]
319#[derive(Debug, Clone, Serialize, Deserialize)]
320pub enum RustItem {
321 Function {
322 cpp_ffi_function: CppFfiFunction,
323 checks: CppCheckerInfoList,
324 rust_path: Option<RustFunctionPath>,
325 },
326 Enum {
327 rust_path: Option<RustPath>,
328 },
329 EnumValue {
330 rust_path: Option<RustPath>,
331 },
332 Class {
333 qt_slot_wrapper: Option<QtSlotWrapper>,
334 checks: CppCheckerInfoList,
335 rust_path: Option<RustClassPath>,
336 },
337 Namespace {
338 rust_path: Option<RustPathScope>,
339 },
340 QtPublicSlotWrapper {
341 some_things: (),
342 rust_path: Option<RustPath>,
343 },
344}
345
346impl RustItem {
347 pub fn from_function(cpp_ffi_function: CppFfiFunction) -> Self {
348 RustItem::Function {
349 cpp_ffi_function,
350 checks: Default::default(),
351 rust_path: None,
352 }
353 }
354
355 pub fn from_qt_slot_wrapper(wrapper: QtSlotWrapper) -> Self {
356 RustItem::Class {
357 qt_slot_wrapper: Some(wrapper),
358 checks: Default::default(),
359 rust_path: None,
360 }
361 }
362
363 pub fn has_rust_path_resolved(&self) -> bool {
364 match *self {
365 RustItem::Function { ref rust_path, .. } => rust_path.is_some(),
366 RustItem::Enum { ref rust_path, .. } => rust_path.is_some(),
367 RustItem::EnumValue { ref rust_path, .. } => rust_path.is_some(),
368 RustItem::Class { ref rust_path, .. } => rust_path.is_some(),
369 RustItem::Namespace { ref rust_path, .. } => rust_path.is_some(),
370 RustItem::QtPublicSlotWrapper { ref rust_path, .. } => rust_path.is_some(),
371 }
372 }
373
374 pub fn checks_mut(&mut self) -> Option<&mut CppCheckerInfoList> {
375 match *self {
376 RustItem::Function { ref mut checks, .. } | RustItem::Class { ref mut checks, .. } => {
377 Some(checks)
378 }
379 _ => None,
380 }
381 }
382
383 pub fn rust_path(&self) -> Option<&RustPath> {
384 match *self {
385 RustItem::Function { ref rust_path, .. } => rust_path
386 .as_ref()
387 .and_then(|function_path| function_path.rust_path()),
388 RustItem::Enum { ref rust_path, .. } => rust_path.as_ref(),
389 RustItem::EnumValue { ref rust_path, .. } => rust_path.as_ref(),
390 RustItem::Class { ref rust_path, .. } => {
391 if let Some(RustClassPath::ConcreteClass { ref path, .. }) = rust_path {
392 Some(path)
393 } else {
394 None
395 }
396 }
397 RustItem::Namespace { .. } => None,
398 RustItem::QtPublicSlotWrapper { ref rust_path, .. } => rust_path.as_ref(),
399 }
400 }
401}
402
403#[derive(Debug, Clone, Serialize, Deserialize)]
404pub struct DatabaseItem {
405 pub cpp_data: CppItemData,
406
407 pub source: DatabaseItemSource,
408 pub rust_items: Option<Vec<RustItem>>, }
410
411#[derive(Debug, Serialize, Deserialize)]
413pub struct Database {
414 pub crate_name: String,
415 pub crate_version: String,
416 pub items: Vec<DatabaseItem>,
417 pub environments: Vec<CppCheckerEnv>,
418 pub next_ffi_id: u64,
419}
420
421impl Database {
422 pub fn empty(crate_name: impl Into<String>) -> Database {
423 Database {
424 crate_name: crate_name.into(),
425 crate_version: "0.0.0".into(),
426 items: Vec::new(),
427 environments: Vec::new(),
428 next_ffi_id: 0,
429 }
430 }
431
432 pub fn items(&self) -> &[DatabaseItem] {
433 &self.items
434 }
435
436 pub fn clear(&mut self) {
437 self.items.clear();
438 self.environments.clear();
439 self.next_ffi_id = 0;
440 }
441
442 pub fn crate_name(&self) -> &str {
443 &self.crate_name
444 }
445
446 pub fn add_cpp_data(&mut self, source: DatabaseItemSource, data: CppItemData) -> bool {
447 if let Some(item) = self
448 .items
449 .iter_mut()
450 .find(|item| item.cpp_data.is_same(&data))
451 {
452 if source.is_parser() && !item.source.is_parser() {
454 item.source = source;
455 }
456 return false;
457 }
458 self.items.push(DatabaseItem {
459 cpp_data: data,
460 source,
461 rust_items: None,
462 });
463 true
464 }
465
466 }