use super::resolution::CppResolutionContext;
use crate::FileId;
use crate::Visibility;
use crate::parsing::behavior_state::{BehaviorState, StatefulBehavior};
use crate::parsing::{LanguageBehavior, ResolutionScope};
use std::path::PathBuf;
use tree_sitter::Language;
#[derive(Clone)]
pub struct CppBehavior {
language: Language,
state: BehaviorState,
}
impl CppBehavior {
pub fn new() -> Self {
Self {
language: tree_sitter_cpp::LANGUAGE.into(),
state: BehaviorState::new(),
}
}
}
impl StatefulBehavior for CppBehavior {
fn state(&self) -> &BehaviorState {
&self.state
}
}
impl Default for CppBehavior {
fn default() -> Self {
Self::new()
}
}
impl LanguageBehavior for CppBehavior {
fn language_id(&self) -> crate::parsing::registry::LanguageId {
crate::parsing::registry::LanguageId::new("cpp")
}
fn format_module_path(&self, base_path: &str, symbol_name: &str) -> String {
format!("{base_path}::{symbol_name}")
}
fn parse_visibility(&self, signature: &str) -> Visibility {
if signature.contains("public:") {
Visibility::Public
} else if signature.contains("protected:") {
Visibility::Module
} else if signature.contains("private:") {
Visibility::Private
} else {
Visibility::Public
}
}
fn module_separator(&self) -> &'static str {
"::"
}
fn supports_traits(&self) -> bool {
true
}
fn supports_inherent_methods(&self) -> bool {
true
}
fn get_language(&self) -> Language {
self.language.clone()
}
fn format_path_as_module(&self, components: &[&str]) -> Option<String> {
if components.is_empty() {
Some("root".to_string())
} else {
Some(components.join("::"))
}
}
fn create_resolution_context(&self, file_id: FileId) -> Box<dyn ResolutionScope> {
Box::new(CppResolutionContext::new(file_id))
}
fn create_inheritance_resolver(&self) -> Box<dyn crate::parsing::InheritanceResolver> {
Box::new(crate::parsing::resolution::GenericInheritanceResolver::new())
}
fn is_resolvable_symbol(&self, symbol: &crate::Symbol) -> bool {
use crate::SymbolKind;
use crate::symbol::ScopeContext;
if let Some(ref scope_context) = symbol.scope_context {
match scope_context {
ScopeContext::Module | ScopeContext::Global | ScopeContext::Package => true,
ScopeContext::Local { .. } | ScopeContext::Parameter => false,
ScopeContext::ClassMember { .. } => {
matches!(symbol.kind, SymbolKind::Method)
|| matches!(symbol.visibility, crate::Visibility::Public)
}
}
} else {
matches!(
symbol.kind,
SymbolKind::Function
| SymbolKind::Method
| SymbolKind::Struct
| SymbolKind::Class
| SymbolKind::Enum
| SymbolKind::Constant
)
}
}
fn format_method_call(&self, receiver: &str, method: &str) -> String {
format!("{receiver}.{method}")
}
fn inheritance_relation_name(&self) -> &'static str {
"inherits"
}
fn map_relationship(&self, language_specific: &str) -> crate::relationship::RelationKind {
use crate::relationship::RelationKind;
match language_specific {
"inherits" => RelationKind::Implements,
"uses" => RelationKind::Uses,
"calls" => RelationKind::Calls,
"defines" => RelationKind::Defines,
"references" => RelationKind::References,
_ => RelationKind::References,
}
}
fn register_file(&self, path: PathBuf, file_id: FileId, module_path: String) {
self.register_file_with_state(path, file_id, module_path);
}
fn add_import(&self, import: crate::parsing::Import) {
self.add_import_with_state(import);
}
fn get_imports_for_file(&self, file_id: FileId) -> Vec<crate::parsing::Import> {
self.get_imports_from_state(file_id)
}
fn is_symbol_visible_from_file(&self, symbol: &crate::Symbol, from_file: FileId) -> bool {
if symbol.file_id == from_file {
return true;
}
match symbol.visibility {
Visibility::Public => true,
Visibility::Crate => true,
Visibility::Module => false,
Visibility::Private => false,
}
}
fn get_module_path_for_file(&self, file_id: FileId) -> Option<String> {
self.state.get_module_path(file_id)
}
fn import_matches_symbol(
&self,
import_path: &str,
symbol_module_path: &str,
_importing_module: Option<&str>,
) -> bool {
import_path == symbol_module_path
}
}