microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.2.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

compiler/qsc/src/location.rs

264lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use std::sync::Arc;
5
6use qsc_data_structures::{
7 line_column::{Encoding, Range},
8 span::Span,
9};
10use qsc_frontend::compile::PackageStore;
11use qsc_hir::hir::PackageId;
12
13pub const QSHARP_LIBRARY_URI_SCHEME: &str = "qsharp-library-source";
14
15/// Describes a location in source code in terms of a source name and [`Range`].
16#[derive(Debug, PartialEq, Clone)]
17pub struct Location {
18 pub source: Arc<str>,
19 pub range: Range,
20}
21
22impl Location {
23 /// Creates a [`Location`] from a package ID and a SourceMap-relative span.
24 ///
25 /// To differentiate user sources from library sources, this function takes
26 /// a `user_package_id` parameter which denotes the user package.
27 /// All other packages in the package store are assumed to be library packages.
28 /// Source names from library packages are prepended with a unique URI scheme.
29 #[must_use]
30 pub fn from(
31 span: Span,
32 package_id: PackageId,
33 package_store: &PackageStore,
34 user_package_id: PackageId,
35 position_encoding: Encoding,
36 ) -> Self {
37 let source = package_store
38 .get(package_id)
39 .expect("package id must exist in store")
40 .sources
41 .find_by_offset(span.lo)
42 .expect("source should exist for offset");
43
44 let source_name = if package_id == user_package_id {
45 source.name.clone()
46 } else {
47 // Currently the only supported external packages are our library packages,
48 // URI's to which need to include our custom library scheme.
49 format!("{}:{}", QSHARP_LIBRARY_URI_SCHEME, source.name).into()
50 };
51
52 Location {
53 source: source_name,
54 range: Range::from_span(position_encoding, &source.contents, &(span - source.offset)),
55 }
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use crate::compile;
62 use expect_test::expect;
63 use qsc_data_structures::{
64 language_features::LanguageFeatures, line_column::Encoding, span::Span,
65 };
66 use qsc_frontend::compile::{PackageStore, RuntimeCapabilityFlags, SourceMap};
67 use qsc_hir::hir::PackageId;
68 use qsc_passes::PackageType;
69
70 use super::Location;
71
72 #[test]
73 fn from_std_span() {
74 let (store, std_package_id, user_package_id) = compile_package();
75
76 let location = Location::from(
77 Span { lo: 0, hi: 1 },
78 std_package_id,
79 &store,
80 user_package_id,
81 Encoding::Utf8,
82 );
83
84 expect![[r#"
85 Location {
86 source: "qsharp-library-source:arrays.qs",
87 range: Range {
88 start: Position {
89 line: 0,
90 column: 0,
91 },
92 end: Position {
93 line: 0,
94 column: 1,
95 },
96 },
97 }
98 "#]]
99 .assert_debug_eq(&location);
100 }
101
102 #[test]
103 fn from_core_span() {
104 let (store, _, user_package_id) = compile_package();
105
106 let location = Location::from(
107 Span { lo: 0, hi: 1 },
108 PackageId::CORE,
109 &store,
110 user_package_id,
111 Encoding::Utf8,
112 );
113
114 expect![[r#"
115 Location {
116 source: "qsharp-library-source:core/core.qs",
117 range: Range {
118 start: Position {
119 line: 0,
120 column: 0,
121 },
122 end: Position {
123 line: 0,
124 column: 1,
125 },
126 },
127 }
128 "#]]
129 .assert_debug_eq(&location);
130 }
131
132 #[test]
133 fn from_user_span() {
134 let (store, _, user_package_id) = compile_package();
135
136 let bar_start_offset = store
137 .get(user_package_id)
138 .expect("expected to find user package")
139 .sources
140 .find_by_name("bar.qs")
141 .expect("expected to find source")
142 .offset;
143
144 let location = Location::from(
145 Span {
146 lo: bar_start_offset,
147 hi: bar_start_offset + 1,
148 },
149 user_package_id,
150 &store,
151 user_package_id,
152 Encoding::Utf8,
153 );
154
155 expect![[r#"
156 Location {
157 source: "bar.qs",
158 range: Range {
159 start: Position {
160 line: 0,
161 column: 0,
162 },
163 end: Position {
164 line: 0,
165 column: 1,
166 },
167 },
168 }
169 "#]]
170 .assert_debug_eq(&location);
171 }
172
173 #[test]
174 fn from_out_of_bounds_lo() {
175 let (store, _, user_package_id) = compile_package();
176
177 let location = Location::from(
178 Span { lo: 1000, hi: 2000 },
179 user_package_id,
180 &store,
181 user_package_id,
182 Encoding::Utf8,
183 );
184
185 // Per [`Range`] spec, out of bounds positions map to EOF
186 expect![[r#"
187 Location {
188 source: "bar.qs",
189 range: Range {
190 start: Position {
191 line: 0,
192 column: 17,
193 },
194 end: Position {
195 line: 0,
196 column: 17,
197 },
198 },
199 }
200 "#]]
201 .assert_debug_eq(&location);
202 }
203
204 #[test]
205 fn from_out_of_bounds_hi() {
206 let (store, _, user_package_id) = compile_package();
207
208 let location = Location::from(
209 Span { lo: 0, hi: 2000 },
210 user_package_id,
211 &store,
212 user_package_id,
213 Encoding::Utf8,
214 );
215
216 // Per [`Range`] spec, out of bounds positions map to EOF
217 expect![[r#"
218 Location {
219 source: "foo.qs",
220 range: Range {
221 start: Position {
222 line: 0,
223 column: 0,
224 },
225 end: Position {
226 line: 0,
227 column: 17,
228 },
229 },
230 }
231 "#]]
232 .assert_debug_eq(&location);
233 }
234
235 fn compile_package() -> (PackageStore, PackageId, PackageId) {
236 let mut store = PackageStore::new(compile::core());
237 let mut dependencies = Vec::new();
238
239 let (package_type, capabilities) = (PackageType::Lib, RuntimeCapabilityFlags::all());
240
241 let std = compile::std(&store, capabilities);
242 let std_package_id = store.insert(std);
243
244 dependencies.push(std_package_id);
245 let sources = SourceMap::new(
246 [
247 ("foo.qs".into(), "namespace Foo { }".into()),
248 ("bar.qs".into(), "namespace Bar { }".into()),
249 ],
250 None,
251 );
252 let (unit, _) = compile::compile(
253 &store,
254 &dependencies,
255 sources,
256 package_type,
257 capabilities,
258 LanguageFeatures::default(),
259 );
260 let user_package_id = store.insert(unit);
261
262 (store, std_package_id, user_package_id)
263 }
264}
265