1use std::borrow::Cow;
4use std::collections::HashMap;
5use std::collections::HashSet;
6use std::collections::hash_map::Entry;
7use std::path::Path;
8use std::sync::Arc;
9
10use arrayvec::ArrayString;
11use indexmap::IndexMap;
12use indexmap::IndexSet;
13use petgraph::graph::NodeIndex;
14use rowan::GreenNode;
15use rowan::TextRange;
16use rowan::TextSize;
17use url::Url;
18use uuid::Uuid;
19use wdl_ast::Ast;
20use wdl_ast::AstNode;
21use wdl_ast::AstToken;
22use wdl_ast::Diagnostic;
23use wdl_ast::Severity;
24use wdl_ast::Span;
25use wdl_ast::SupportedVersion;
26use wdl_ast::SyntaxNode;
27
28use crate::AnalysisCache;
29use crate::Diagnostics;
30use crate::EnumRef;
31use crate::StructRef;
32use crate::TaskRef;
33use crate::WorkflowRef;
34use crate::config::Config;
35use crate::diagnostics::Context;
36use crate::diagnostics::no_common_type;
37use crate::graph::DocumentGraph;
38use crate::graph::ParseState;
39use crate::types::CallType;
40use crate::types::EnumChoiceCacheKey;
41use crate::types::Optional;
42use crate::types::Type;
43
44pub mod cache;
45pub mod v1;
46
47pub const TASK_VAR_NAME: &str = "task";
50
51#[derive(Debug, Clone, PartialEq)]
53pub struct Namespace {
54 name: String,
56 pub(crate) span: Span,
58 source: Arc<Url>,
60 document: Document,
62 pub(crate) used: bool,
64 pub(in crate::document) imported_structs: IndexMap<String, ImportedStruct>,
70 pub(in crate::document) imported_enums: IndexMap<String, ImportedEnum>,
72}
73
74impl Namespace {
75 pub fn name(&self) -> &str {
77 &self.name
78 }
79
80 pub fn span(&self) -> Span {
82 self.span
83 }
84
85 pub fn source(&self) -> Arc<Url> {
87 self.source.clone()
88 }
89
90 pub fn document(&self) -> &Document {
92 &self.document
93 }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
98pub struct Struct {
99 name: String,
101 pub(in crate::document) name_span: Span,
103 offset: usize,
108 node: rowan::GreenNode,
112 ty: Option<Type>,
116}
117
118impl Struct {
119 pub fn name(&self) -> &str {
121 &self.name
122 }
123
124 pub fn name_span(&self) -> Span {
126 self.name_span
127 }
128
129 pub fn offset(&self) -> usize {
131 self.offset
132 }
133
134 pub fn node(&self) -> &rowan::GreenNode {
136 &self.node
137 }
138
139 pub fn definition(&self) -> wdl_ast::v1::StructDefinition {
141 wdl_ast::v1::StructDefinition::cast(wdl_ast::SyntaxNode::new_root(self.node.clone()))
142 .expect("stored node should be a valid struct definition")
143 }
144
145 pub fn ty(&self) -> Option<&Type> {
150 self.ty.as_ref()
151 }
152}
153
154#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct Enum {
157 name: String,
159 pub(in crate::document) name_span: Span,
161 offset: usize,
166 node: rowan::GreenNode,
171 ty: Option<Type>,
175}
176
177impl Enum {
178 pub fn name(&self) -> &str {
180 &self.name
181 }
182
183 pub fn name_span(&self) -> Span {
185 self.name_span
186 }
187
188 pub fn offset(&self) -> usize {
190 self.offset
191 }
192
193 pub fn node(&self) -> &rowan::GreenNode {
195 &self.node
196 }
197
198 pub fn definition(&self) -> wdl_ast::v1::EnumDefinition {
202 wdl_ast::v1::EnumDefinition::cast(wdl_ast::SyntaxNode::new_root(self.node.clone()))
203 .expect("stored node should be a valid enum definition")
204 }
205
206 pub fn ty(&self) -> Option<&Type> {
208 self.ty.as_ref()
209 }
210}
211
212#[derive(Debug, Clone, PartialEq, Eq)]
214pub struct Name {
215 pub(in crate::document) span: Span,
217 ty: Type,
219}
220
221impl Name {
222 pub fn span(&self) -> Span {
224 self.span
225 }
226
227 pub fn ty(&self) -> &Type {
229 &self.ty
230 }
231}
232
233#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
235pub struct ScopeIndex(usize);
236
237#[derive(Debug, Clone, PartialEq, Eq)]
239pub struct Scope {
240 parent: Option<ScopeIndex>,
244 pub(in crate::document) span: Span,
246 pub(in crate::document) names: IndexMap<String, Name>,
248}
249
250impl Scope {
251 fn new(parent: Option<ScopeIndex>, span: Span) -> Self {
253 Self {
254 parent,
255 span,
256 names: Default::default(),
257 }
258 }
259
260 pub fn insert(&mut self, name: impl Into<String>, span: Span, ty: Type) {
262 self.names.insert(name.into(), Name { span, ty });
263 }
264}
265
266#[derive(Debug, Clone, Copy)]
268pub struct ScopeRef<'a> {
269 scopes: &'a [Scope],
271 index: ScopeIndex,
273}
274
275impl<'a> ScopeRef<'a> {
276 fn new(scopes: &'a [Scope], index: ScopeIndex) -> Self {
278 Self { scopes, index }
279 }
280
281 pub fn span(&self) -> Span {
283 self.scopes[self.index.0].span
284 }
285
286 pub fn parent(&self) -> Option<Self> {
290 self.scopes[self.index.0].parent.map(|p| Self {
291 scopes: self.scopes,
292 index: p,
293 })
294 }
295
296 pub fn names(&self) -> impl Iterator<Item = (&str, &Name)> + use<'_> {
298 self.scopes[self.index.0]
299 .names
300 .iter()
301 .map(|(name, n)| (name.as_str(), n))
302 }
303
304 pub fn local(&self, name: &str) -> Option<&Name> {
308 self.scopes[self.index.0].names.get(name)
309 }
310
311 pub fn lookup(&self, name: &str) -> Option<&Name> {
315 let mut current = Some(self.index);
316
317 while let Some(index) = current {
318 if let Some(name) = self.scopes[index.0].names.get(name) {
319 return Some(name);
320 }
321
322 current = self.scopes[index.0].parent;
323 }
324
325 None
326 }
327}
328
329#[derive(Debug)]
331struct ScopeRefMut<'a> {
332 scopes: &'a mut [Scope],
334 index: ScopeIndex,
336}
337
338impl<'a> ScopeRefMut<'a> {
339 fn new(scopes: &'a mut [Scope], index: ScopeIndex) -> Self {
341 Self { scopes, index }
342 }
343
344 pub fn lookup(&self, name: &str) -> Option<&Name> {
348 let mut current = Some(self.index);
349
350 while let Some(index) = current {
351 if let Some(name) = self.scopes[index.0].names.get(name) {
352 return Some(name);
353 }
354
355 current = self.scopes[index.0].parent;
356 }
357
358 None
359 }
360
361 pub fn insert(&mut self, name: impl Into<String>, span: Span, ty: Type) {
363 self.scopes[self.index.0]
364 .names
365 .insert(name.into(), Name { span, ty });
366 }
367
368 pub fn as_scope_ref(&'a self) -> ScopeRef<'a> {
370 ScopeRef {
371 scopes: self.scopes,
372 index: self.index,
373 }
374 }
375}
376
377#[derive(Debug)]
382pub struct ScopeUnion<'a> {
383 scope_refs: Vec<(ScopeRef<'a>, bool)>,
385}
386
387impl<'a> ScopeUnion<'a> {
388 pub fn new() -> Self {
390 Self {
391 scope_refs: Vec::new(),
392 }
393 }
394
395 pub fn insert(&mut self, scope_ref: ScopeRef<'a>, exhaustive: bool) {
397 self.scope_refs.push((scope_ref, exhaustive));
398 }
399
400 pub fn resolve(self) -> Result<HashMap<String, Name>, Vec<Diagnostic>> {
405 let mut errors = Vec::new();
406 let mut ignored: HashSet<String> = HashSet::new();
407
408 let mut names: HashMap<String, Name> = HashMap::new();
410 for (scope_ref, _) in &self.scope_refs {
411 for (name, info) in scope_ref.names() {
412 if ignored.contains(name) {
413 continue;
414 }
415
416 match names.entry(name.to_string()) {
417 Entry::Vacant(entry) => {
418 entry.insert(info.clone());
419 }
420 Entry::Occupied(mut entry) => {
421 let Some(ty) = entry.get().ty.common_type(&info.ty) else {
422 errors.push(no_common_type(
423 &entry.get().ty,
424 entry.get().span,
425 &info.ty,
426 info.span,
427 ));
428 names.remove(name);
429 ignored.insert(name.to_string());
430 continue;
431 };
432
433 entry.get_mut().ty = ty;
434 }
435 }
436 }
437 }
438
439 for (scope_ref, _) in &self.scope_refs {
441 for (name, info) in &mut names {
442 if ignored.contains(name) {
443 continue;
444 }
445
446 if scope_ref.local(name).is_none() {
449 info.ty = info.ty.optional();
450 }
451 }
452 }
453
454 let has_exhaustive = self.scope_refs.iter().any(|(_, exhaustive)| *exhaustive);
456 if !has_exhaustive {
457 for info in names.values_mut() {
458 info.ty = info.ty.optional();
459 }
460 }
461
462 if !errors.is_empty() {
463 return Err(errors);
464 }
465
466 Ok(names)
467 }
468}
469
470#[derive(Debug, Clone, PartialEq, Eq)]
472pub struct Input {
473 ty: Type,
475 required: bool,
480}
481
482impl Input {
483 pub fn ty(&self) -> &Type {
485 &self.ty
486 }
487
488 pub fn required(&self) -> bool {
490 self.required
491 }
492}
493
494#[derive(Debug, Clone, PartialEq, Eq)]
496pub struct Output {
497 ty: Type,
499 pub(in crate::document) name_span: Span,
501}
502
503impl Output {
504 pub(crate) fn new(ty: Type, name_span: Span) -> Self {
506 Self { ty, name_span }
507 }
508
509 pub fn ty(&self) -> &Type {
511 &self.ty
512 }
513
514 pub fn name_span(&self) -> Span {
516 self.name_span
517 }
518}
519
520#[derive(Debug, Clone, PartialEq, Eq)]
522pub struct Task {
523 pub(in crate::document) name_span: Span,
525 pub(in crate::document) name: String,
527 pub(in crate::document) span: Span,
529 pub(in crate::document) scopes: Vec<Scope>,
535 pub(in crate::document) inputs: Arc<IndexMap<String, Input>>,
537 pub(in crate::document) outputs: Arc<IndexMap<String, Output>>,
539}
540
541impl Task {
542 pub fn name(&self) -> &str {
544 &self.name
545 }
546
547 pub fn name_span(&self) -> Span {
549 self.name_span
550 }
551
552 pub fn span(&self) -> Span {
554 self.span
555 }
556
557 pub fn scope(&self) -> ScopeRef<'_> {
559 ScopeRef::new(&self.scopes, ScopeIndex(0))
560 }
561
562 pub fn inputs(&self) -> &IndexMap<String, Input> {
564 &self.inputs
565 }
566
567 pub fn outputs(&self) -> &IndexMap<String, Output> {
569 &self.outputs
570 }
571}
572
573#[derive(Debug, Clone, PartialEq, Eq)]
575pub struct Workflow {
576 pub(in crate::document) name_span: Span,
578 pub(in crate::document) name: String,
580 pub(in crate::document) span: Span,
582 pub(in crate::document) scopes: Vec<Scope>,
588 pub(in crate::document) inputs: Arc<IndexMap<String, Input>>,
590 pub(in crate::document) outputs: Arc<IndexMap<String, Output>>,
592 pub(in crate::document) calls: HashMap<String, CallType>,
594 pub(in crate::document) allows_nested_inputs: bool,
596}
597
598impl Workflow {
599 pub fn name(&self) -> &str {
601 &self.name
602 }
603
604 pub fn name_span(&self) -> Span {
606 self.name_span
607 }
608
609 pub fn span(&self) -> Span {
611 self.span
612 }
613
614 pub fn scope(&self) -> ScopeRef<'_> {
616 ScopeRef::new(&self.scopes, ScopeIndex(0))
617 }
618
619 pub fn inputs(&self) -> &IndexMap<String, Input> {
621 &self.inputs
622 }
623
624 pub fn outputs(&self) -> &IndexMap<String, Output> {
626 &self.outputs
627 }
628
629 pub fn calls(&self) -> &HashMap<String, CallType> {
631 &self.calls
632 }
633
634 pub fn allows_nested_inputs(&self) -> bool {
636 self.allows_nested_inputs
637 }
638}
639
640#[derive(Debug, Clone, PartialEq)]
642pub struct ImportedStruct {
643 pub local_name: String,
645 offset: usize,
650 node: rowan::GreenNode,
654 pub span: Span,
656 pub document: Document,
658 ty: Option<Type>,
662}
663
664impl ImportedStruct {
665 pub fn node(&self) -> &rowan::GreenNode {
667 &self.node
668 }
669
670 pub fn offset(&self) -> usize {
672 self.offset
673 }
674
675 pub fn source(&self) -> Arc<Url> {
677 self.document.uri()
678 }
679
680 pub fn definition(&self) -> wdl_ast::v1::StructDefinition {
684 wdl_ast::v1::StructDefinition::cast(wdl_ast::SyntaxNode::new_root(self.node.clone()))
685 .expect("stored node should be a valid struct definition")
686 }
687
688 pub fn ty(&self) -> Option<&Type> {
693 self.ty.as_ref()
694 }
695}
696
697#[derive(Debug, Clone, PartialEq)]
699pub struct ImportedEnum {
700 pub local_name: String,
702 offset: usize,
707 node: rowan::GreenNode,
712 pub span: Span,
714 pub document: Document,
716 ty: Option<Type>,
720}
721
722impl ImportedEnum {
723 pub fn node(&self) -> &rowan::GreenNode {
725 &self.node
726 }
727
728 pub fn offset(&self) -> usize {
730 self.offset
731 }
732
733 pub fn source(&self) -> Arc<Url> {
735 self.document.uri()
736 }
737
738 pub fn definition(&self) -> wdl_ast::v1::EnumDefinition {
742 wdl_ast::v1::EnumDefinition::cast(wdl_ast::SyntaxNode::new_root(self.node.clone()))
743 .expect("stored node should be a valid enum definition")
744 }
745
746 pub fn ty(&self) -> Option<&Type> {
748 self.ty.as_ref()
749 }
750}
751
752#[derive(Debug, Clone, PartialEq)]
754pub struct ImportedTask {
755 pub local_name: String,
757 pub name: String,
759 pub span: Span,
761 pub document: Document,
763 pub inputs: Arc<IndexMap<String, Input>>,
765 pub outputs: Arc<IndexMap<String, Output>>,
767}
768
769impl ImportedTask {
770 pub fn name(&self) -> &str {
772 &self.name
773 }
774
775 pub fn document(&self) -> &Document {
777 &self.document
778 }
779
780 pub(crate) fn source(&self) -> Arc<Url> {
782 self.document.uri()
783 }
784}
785
786#[derive(Debug, Clone, PartialEq)]
788pub struct ImportedWorkflow {
789 pub local_name: String,
791 pub name: String,
793 pub span: Span,
795 pub document: Document,
797 pub inputs: Arc<IndexMap<String, Input>>,
799 pub outputs: Arc<IndexMap<String, Output>>,
801}
802
803impl ImportedWorkflow {
804 pub fn name(&self) -> &str {
806 &self.name
807 }
808
809 pub fn document(&self) -> &Document {
811 &self.document
812 }
813
814 pub(crate) fn source(&self) -> Arc<Url> {
816 self.document.uri()
817 }
818}
819
820#[derive(Copy, Clone, Debug)]
822pub enum Callable<'a> {
823 Workflow(WorkflowRef<'a>),
825 Task(TaskRef<'a>),
827}
828
829impl Callable<'_> {
830 pub fn name(&self) -> &str {
832 match self {
833 Callable::Workflow(w) => w.name(),
834 Callable::Task(t) => t.name(),
835 }
836 }
837
838 pub fn name_span(&self) -> Span {
840 match self {
841 Callable::Workflow(w) => w.name_span(),
842 Callable::Task(t) => t.name_span(),
843 }
844 }
845
846 pub fn is_workflow(&self) -> bool {
848 matches!(self, Callable::Workflow(_))
849 }
850
851 pub fn is_task(&self) -> bool {
853 matches!(self, Callable::Task(_))
854 }
855
856 pub fn inputs(&self) -> Arc<IndexMap<String, Input>> {
858 match self {
859 Callable::Workflow(w) => w.inputs(),
860 Callable::Task(t) => t.inputs(),
861 }
862 }
863
864 pub fn outputs(&self) -> Arc<IndexMap<String, Output>> {
866 match self {
867 Callable::Workflow(w) => w.outputs(),
868 Callable::Task(t) => t.outputs(),
869 }
870 }
871}
872
873#[derive(Debug)]
875pub(crate) struct DocumentData {
876 config: Config,
878 root: Option<GreenNode>,
882 id: Arc<String>,
886 uri: Arc<Url>,
888 version: Option<SupportedVersion>,
890 failed_imports: IndexMap<String, Span>,
896 cache: Arc<AnalysisCache>,
898 failed_wildcard_import: bool,
903 failed_selected_imports: IndexSet<String>,
905 parse_diagnostics: Vec<Diagnostic>,
907 pub(crate) analysis_diagnostics: Diagnostics,
909}
910
911impl PartialEq for DocumentData {
912 fn eq(&self, other: &Self) -> bool {
913 let Self {
914 config,
915 root,
916 id: _,
917 uri,
918 version,
919 failed_imports,
920 cache,
921 failed_wildcard_import,
922 failed_selected_imports,
923 parse_diagnostics,
924 analysis_diagnostics,
925 } = self;
926
927 config == &other.config
928 && root == &other.root
929 && uri == &other.uri
930 && version == &other.version
931 && failed_imports == &other.failed_imports
932 && cache == &other.cache
933 && failed_wildcard_import == &other.failed_wildcard_import
934 && failed_selected_imports == &other.failed_selected_imports
935 && parse_diagnostics == &other.parse_diagnostics
936 && analysis_diagnostics == &other.analysis_diagnostics
937 }
938}
939
940impl DocumentData {
941 fn new(
943 config: Config,
944 uri: Arc<Url>,
945 root: Option<GreenNode>,
946 version: Option<SupportedVersion>,
947 parse_diagnostics: Vec<Diagnostic>,
948 ) -> Self {
949 Self {
950 config,
951 root,
952 id: Uuid::new_v4().to_string().into(),
953 uri,
954 version,
955 failed_imports: Default::default(),
956 cache: Default::default(), failed_wildcard_import: false,
958 failed_selected_imports: Default::default(),
959 parse_diagnostics,
960 analysis_diagnostics: Default::default(),
961 }
962 }
963
964 fn context(&self, cache: &AnalysisCache, name: &str) -> Option<Context> {
970 if let Some((_hash, ns)) = cache.namespace_by_name(name) {
972 Some(Context::Namespace(ns.span))
973 } else if let Some(span) = self.failed_imports.get(name) {
974 Some(Context::Namespace(*span))
975 } else if let Some((_idx, _hash, task)) = cache.local_task_by_name(name) {
976 Some(Context::Task(task.name_span()))
977 } else if let Some(wf) = cache.workflow().filter(|w| w.name() == name) {
978 Some(Context::Workflow(wf.name_span()))
979 } else if let Some((_idx, _hash, s)) = cache.local_struct_by_name(name) {
980 Some(Context::Struct(s.name_span()))
981 } else {
982 cache
984 .local_enum_by_name(name)
985 .map(|(_idx, _hash, e)| Context::Enum(e.name_span()))
986 }
987 }
988}
989
990#[derive(Debug, Clone, PartialEq)]
994pub struct Document {
995 data: Arc<DocumentData>,
997}
998
999impl Document {
1000 #[cfg(test)]
1002 pub(crate) fn data(&self) -> &Arc<DocumentData> {
1003 &self.data
1004 }
1005}
1006
1007impl Document {
1008 pub(crate) fn default_from_uri(uri: Arc<Url>) -> Self {
1010 Self {
1011 data: Arc::new(DocumentData::new(
1012 Default::default(),
1013 uri,
1014 None,
1015 None,
1016 Default::default(),
1017 )),
1018 }
1019 }
1020
1021 pub(crate) fn from_graph_node(
1023 config: &Config,
1024 graph: &DocumentGraph,
1025 index: NodeIndex,
1026 existing_cache: Option<Arc<AnalysisCache>>,
1027 ) -> Self {
1028 let node = graph.get(index);
1029 let (wdl_version, parse_diagnostics, edits) = match node.parse_state() {
1030 ParseState::NotParsed => panic!("node should have been parsed"),
1031 ParseState::Error(_) => {
1032 return Self::default_from_uri(node.uri().clone());
1033 }
1034 ParseState::Parsed {
1035 wdl_version,
1036 diagnostics,
1037 edits,
1038 ..
1039 } => (*wdl_version, diagnostics.clone(), edits.clone()),
1040 };
1041
1042 let root = node.root().expect("node should have been parsed");
1043 let config = if let Some(stmt) = root.version_statement() {
1044 config.with_diagnostics_config(
1045 config.diagnostics_config().excepted_for_node(stmt.inner()),
1046 )
1047 } else {
1048 config.clone()
1049 };
1050
1051 let mut data = DocumentData::new(
1052 config.clone(),
1053 node.uri().clone(),
1054 Some(root.inner().green().to_owned()),
1055 wdl_version,
1056 parse_diagnostics,
1057 );
1058
1059 let _ = node;
1060 match root.ast_with_version_fallback(config.fallback_version()) {
1061 Ast::Unsupported => {
1062 }
1066 Ast::V1(ast) => v1::populate_document(
1067 &mut data,
1068 existing_cache,
1069 &config,
1070 graph,
1071 index,
1072 &ast,
1073 &edits,
1074 ),
1075 };
1076
1077 Self {
1078 data: Arc::new(data),
1079 }
1080 }
1081
1082 pub fn config(&self) -> &Config {
1084 &self.data.config
1085 }
1086
1087 pub fn root(&self) -> wdl_ast::Document {
1093 wdl_ast::Document::cast(SyntaxNode::new_root(
1094 self.data.root.clone().expect("should have a root"),
1095 ))
1096 .expect("should cast")
1097 }
1098
1099 pub fn id(&self) -> &Arc<String> {
1103 &self.data.id
1104 }
1105
1106 pub fn uri(&self) -> Arc<Url> {
1108 self.data.uri.clone()
1109 }
1110
1111 pub fn path(&self) -> Cow<'_, str> {
1118 if let Ok(path) = self.data.uri.to_file_path() {
1119 if let Some(path) = std::env::current_dir()
1120 .ok()
1121 .and_then(|cwd| path.strip_prefix(cwd).ok().and_then(Path::to_str))
1122 {
1123 return path.to_string().into();
1124 }
1125
1126 if let Ok(path) = path.into_os_string().into_string() {
1127 return path.into();
1128 }
1129 }
1130
1131 self.data.uri.as_str().into()
1132 }
1133
1134 pub fn hash_span(&self, span: Span) -> Option<ArrayString<64>> {
1142 let text = self.root().inner().text();
1143 let text_len = usize::from(text.len());
1144 if span.end() > text_len {
1145 return None;
1146 }
1147 let range = TextRange::new(
1148 TextSize::new(span.start() as u32),
1149 TextSize::new(span.end() as u32),
1150 );
1151 let slice = text.slice(range);
1152 let mut hasher = blake3::Hasher::new();
1153 slice.for_each_chunk(|chunk| {
1154 hasher.update(chunk.as_bytes());
1155 });
1156 Some(hasher.finalize().to_hex())
1157 }
1158
1159 pub fn version(&self) -> Option<SupportedVersion> {
1164 self.data.version
1165 }
1166
1167 pub(crate) fn cache(&self) -> Arc<AnalysisCache> {
1169 self.data.cache.clone()
1170 }
1171
1172 pub fn namespaces(&self) -> impl Iterator<Item = &Namespace> {
1174 self.data.cache.namespaces().map(|(_, ns)| ns)
1175 }
1176
1177 pub fn namespace(&self, name: &str) -> Option<&Namespace> {
1179 self.data.cache.namespace_by_name(name).map(|(_, ns)| ns)
1180 }
1181
1182 pub fn tasks(&self) -> impl Iterator<Item = TaskRef<'_>> {
1184 self.data.cache.tasks()
1185 }
1186
1187 pub(crate) fn local_tasks(&self) -> impl Iterator<Item = &Task> {
1189 self.data.cache.local_tasks().map(|(_, _, task)| task)
1190 }
1191
1192 pub fn local_task_by_name(&self, name: &str) -> Option<&Task> {
1194 self.data
1195 .cache
1196 .local_task_by_name(name)
1197 .map(|(_idx, _hash, task)| task)
1198 }
1199
1200 pub fn task_by_name(&self, name: &str) -> Option<TaskRef<'_>> {
1202 self.data.cache.task_by_name(name).map(|(_hash, task)| task)
1203 }
1204
1205 pub fn imported_task_by_name(&self, name: &str) -> Option<&ImportedTask> {
1210 self.data.cache.imported_task_by_name(name).map(|(_, t)| t)
1211 }
1212
1213 pub fn workflow(&self) -> Option<&Workflow> {
1217 self.data.cache.workflow()
1218 }
1219
1220 pub fn imported_workflow_by_name(&self, name: &str) -> Option<&ImportedWorkflow> {
1225 self.data
1226 .cache
1227 .imported_workflow_by_name(name)
1228 .map(|(_, w)| w)
1229 }
1230
1231 pub fn workflow_by_name(&self, name: &str) -> Option<WorkflowRef<'_>> {
1233 self.data.cache.workflow_by_name(name).map(|(_, w)| w)
1234 }
1235
1236 pub fn callable_by_name(&self, name: &str) -> Option<Callable<'_>> {
1244 if let Some(workflow) = self.workflow_by_name(name) {
1245 return Some(Callable::Workflow(workflow));
1246 }
1247
1248 if let Some(task) = self.task_by_name(name) {
1249 return Some(Callable::Task(task));
1250 }
1251
1252 None
1253 }
1254
1255 pub fn callables(&self) -> impl Iterator<Item = Callable<'_>> {
1259 self.local_callables()
1260 .chain(
1261 self.data
1262 .cache
1263 .imported_workflows()
1264 .map(|(_hash, w)| Callable::Workflow(WorkflowRef::Imported(w))),
1265 )
1266 .chain(
1267 self.data
1268 .cache
1269 .imported_tasks()
1270 .map(|(_hash, t)| Callable::Task(TaskRef::Imported(t))),
1271 )
1272 }
1273
1274 pub fn local_callable_by_name(&self, name: &str) -> Option<Callable<'_>> {
1282 if let Some(workflow) = self.workflow()
1283 && workflow.name == name
1284 {
1285 return Some(Callable::Workflow(WorkflowRef::Local(workflow)));
1286 }
1287
1288 if let Some(task) = self.local_task_by_name(name) {
1289 return Some(Callable::Task(TaskRef::Local(task)));
1290 }
1291
1292 None
1293 }
1294
1295 pub fn local_callables(&self) -> impl Iterator<Item = Callable<'_>> {
1299 self.workflow()
1300 .map(WorkflowRef::Local)
1301 .map(Callable::Workflow)
1302 .into_iter()
1303 .chain(self.local_tasks().map(TaskRef::Local).map(Callable::Task))
1304 }
1305
1306 pub fn structs(&self) -> impl Iterator<Item = StructRef<'_>> {
1308 self.data.cache.structs()
1309 }
1310
1311 pub fn local_struct_by_name(&self, name: &str) -> Option<&Struct> {
1313 self.data
1314 .cache
1315 .local_struct_by_name(name)
1316 .map(|(_idx, _hash, s)| s)
1317 }
1318
1319 pub fn imported_struct_by_name(&self, name: &str) -> Option<&ImportedStruct> {
1321 self.data
1322 .cache
1323 .imported_struct_by_name(name)
1324 .map(|(_hash, s)| s)
1325 }
1326
1327 pub fn struct_by_name(&self, name: &str) -> Option<StructRef<'_>> {
1329 self.data.cache.struct_by_name(name).map(|(_hash, s)| s)
1330 }
1331
1332 pub fn local_enums(&self) -> impl Iterator<Item = &Enum> {
1334 self.data.cache.local_enums().map(|(_idx, _hash, e)| e)
1335 }
1336
1337 pub fn local_enum_by_name(&self, name: &str) -> Option<&Enum> {
1339 self.data
1340 .cache
1341 .local_enum_by_name(name)
1342 .map(|(_idx, _hash, e)| e)
1343 }
1344
1345 pub fn enums(&self) -> impl Iterator<Item = EnumRef<'_>> {
1347 self.data.cache.enums()
1348 }
1349
1350 pub fn imported_enum_by_name(&self, name: &str) -> Option<&ImportedEnum> {
1352 self.data
1353 .cache
1354 .imported_enum_by_name(name)
1355 .map(|(_hash, e)| e)
1356 }
1357
1358 pub fn enum_by_name(&self, name: &str) -> Option<EnumRef<'_>> {
1360 self.data.cache.enum_by_name(name).map(|(_hash, e)| e)
1361 }
1362
1363 pub fn get_custom_type(&self, name: &str) -> Option<&Type> {
1365 if let Some(s) = self.struct_by_name(name) {
1366 return s.ty();
1367 }
1368
1369 if let Some(e) = self.enum_by_name(name) {
1370 return e.ty();
1371 }
1372
1373 None
1374 }
1375
1376 pub fn get_choice_cache_key(&self, name: &str, choice: &str) -> Option<EnumChoiceCacheKey> {
1378 let (source_uri, enum_index, r#enum) =
1379 if let Some((enum_index, _, r#enum)) = self.data.cache.local_enum_by_name(name) {
1380 (self.data.uri.clone(), enum_index, r#enum)
1381 } else {
1382 let (_, imported) = self.data.cache.imported_enum_by_name(name)?;
1383 let (enum_index, _, r#enum) = imported
1384 .document
1385 .data
1386 .cache
1387 .local_enum_by_name(imported.definition().name().text())?;
1388 (imported.document.uri(), enum_index, r#enum)
1389 };
1390
1391 let enum_ty = r#enum.ty()?.as_enum()?;
1392 let choice_index = enum_ty.choices().iter().position(|v| v == choice)?;
1393 Some(EnumChoiceCacheKey::new(
1394 source_uri,
1395 enum_index,
1396 choice_index,
1397 ))
1398 }
1399
1400 pub fn parse_diagnostics(&self) -> &[Diagnostic] {
1402 &self.data.parse_diagnostics
1403 }
1404
1405 pub fn analysis_diagnostics(&self) -> &Diagnostics {
1407 &self.data.analysis_diagnostics
1408 }
1409
1410 pub fn diagnostics(&self) -> impl Iterator<Item = &Diagnostic> {
1412 self.data
1413 .parse_diagnostics
1414 .iter()
1415 .chain(self.data.analysis_diagnostics.diagnostics.iter())
1416 }
1417
1418 pub fn sort_diagnostics(&mut self) -> Self {
1424 let data = &mut self.data;
1425 let inner = Arc::get_mut(data).expect("should only have one reference");
1426 inner.parse_diagnostics.sort();
1427 inner.analysis_diagnostics.sort();
1428 Self { data: data.clone() }
1429 }
1430
1431 pub fn extend_diagnostics(&mut self, diagnostics: Diagnostics) -> Self {
1437 let data = &mut self.data;
1438 let inner = Arc::get_mut(data).expect("should only have one reference");
1439 inner.analysis_diagnostics.extend(diagnostics.diagnostics);
1440 Self { data: data.clone() }
1441 }
1442
1443 pub fn find_scope_by_position(&self, position: usize) -> Option<ScopeRef<'_>> {
1445 fn find_scope(scopes: &[Scope], position: usize) -> Option<ScopeRef<'_>> {
1447 let mut index = match scopes.binary_search_by_key(&position, |s| s.span.start()) {
1448 Ok(index) => index,
1449 Err(index) => {
1450 if index == 0 {
1454 return None;
1455 }
1456
1457 index - 1
1458 }
1459 };
1460
1461 loop {
1465 let scope = &scopes[index];
1466 if scope.span.contains(position) {
1467 return Some(ScopeRef::new(scopes, ScopeIndex(index)));
1468 }
1469
1470 if index == 0 {
1471 return None;
1472 }
1473
1474 index -= 1;
1475 }
1476 }
1477
1478 if let Some(workflow) = self.data.cache.workflow()
1480 && workflow.scope().span().contains(position)
1481 {
1482 return find_scope(&workflow.scopes, position);
1483 }
1484
1485 let task = self
1487 .data
1488 .cache
1489 .local_tasks()
1490 .filter_map(|(_idx, _hash, t)| {
1491 if t.scope().span().start() <= position {
1492 Some(t)
1493 } else {
1494 None
1495 }
1496 })
1497 .max_by_key(|t| t.scope().span().start())?;
1498
1499 if task.scope().span().contains(position) {
1500 return find_scope(&task.scopes, position);
1501 }
1502
1503 None
1504 }
1505
1506 pub fn has_errors(&self) -> bool {
1515 if self.diagnostics().any(|d| d.severity() == Severity::Error) {
1517 return true;
1518 }
1519
1520 for ns in self.namespaces() {
1522 if ns.document().has_errors() {
1523 return true;
1524 }
1525 }
1526
1527 false
1528 }
1529
1530 pub fn visit<V: crate::Visitor>(&self, diagnostics: &mut crate::Diagnostics, visitor: &mut V) {
1533 crate::visit(self, diagnostics, visitor)
1534 }
1535}