Skip to content

Commit 4bfbf62

Browse files
authored
Merge pull request #296 from github/hvitved/empty-location
Extract a special empty location
2 parents 916b844 + 1393dc9 commit 4bfbf62

File tree

5 files changed

+87
-61
lines changed

5 files changed

+87
-61
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ jobs:
203203
shell: bash
204204
run: |
205205
echo "import ruby select count(File f)" > "test.ql"
206-
echo "| 3 |" > "test.expected"
206+
echo "| 4 |" > "test.expected"
207207
echo 'name: sample-tests
208208
version: 0.0.0
209209
dependencies:

extractor/src/extractor.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,22 @@ impl TrapWriter {
7575
file_label
7676
}
7777

78+
fn populate_empty_file(&mut self) -> Label {
79+
let (file_label, fresh) = self.global_id("empty;sourcefile");
80+
if fresh {
81+
self.add_tuple(
82+
"files",
83+
vec![Arg::Label(file_label), Arg::String("".to_string())],
84+
);
85+
}
86+
file_label
87+
}
88+
89+
pub fn populate_empty_location(&mut self) {
90+
let file_label = self.populate_empty_file();
91+
self.location(file_label, 0, 0, 0, 0);
92+
}
93+
7894
fn populate_parent_folders(&mut self, child_label: Label, path: Option<&Path>) {
7995
let mut path = path;
8096
let mut child_label = child_label;

extractor/src/main.rs

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -129,57 +129,74 @@ fn main() -> std::io::Result<()> {
129129
node_types::read_node_types_str("erb", tree_sitter_embedded_template::NODE_TYPES)?;
130130
let lines: std::io::Result<Vec<String>> = std::io::BufReader::new(file_list).lines().collect();
131131
let lines = lines?;
132-
lines.par_iter().try_for_each(|line| {
133-
let path = PathBuf::from(line).canonicalize()?;
134-
let trap_file = path_for(&trap_dir, &path, trap_compression.extension());
135-
let src_archive_file = path_for(&src_archive_dir, &path, "");
136-
let mut source = std::fs::read(&path)?;
137-
let code_ranges;
138-
let mut trap_writer = extractor::new_trap_writer();
139-
if path.extension().map_or(false, |x| x == "erb") {
140-
tracing::info!("scanning: {}", path.display());
132+
lines
133+
.par_iter()
134+
.try_for_each(|line| {
135+
let path = PathBuf::from(line).canonicalize()?;
136+
let src_archive_file = path_for(&src_archive_dir, &path, "");
137+
let mut source = std::fs::read(&path)?;
138+
let code_ranges;
139+
let mut trap_writer = extractor::new_trap_writer();
140+
if path.extension().map_or(false, |x| x == "erb") {
141+
tracing::info!("scanning: {}", path.display());
142+
extractor::extract(
143+
erb,
144+
"erb",
145+
&erb_schema,
146+
&mut trap_writer,
147+
&path,
148+
&source,
149+
&[],
150+
)?;
151+
152+
let (ranges, line_breaks) = scan_erb(erb, &source);
153+
for i in line_breaks {
154+
if i < source.len() {
155+
source[i] = b'\n';
156+
}
157+
}
158+
code_ranges = ranges;
159+
} else {
160+
code_ranges = vec![];
161+
}
141162
extractor::extract(
142-
erb,
143-
"erb",
144-
&erb_schema,
163+
language,
164+
"ruby",
165+
&schema,
145166
&mut trap_writer,
146167
&path,
147168
&source,
148-
&[],
169+
&code_ranges,
149170
)?;
171+
std::fs::create_dir_all(&src_archive_file.parent().unwrap())?;
172+
std::fs::copy(&path, &src_archive_file)?;
173+
write_trap(&trap_dir, path, trap_writer, &trap_compression)
174+
})
175+
.expect("failed to extract files");
150176

151-
let (ranges, line_breaks) = scan_erb(erb, &source);
152-
for i in line_breaks {
153-
if i < source.len() {
154-
source[i] = b'\n';
155-
}
156-
}
157-
code_ranges = ranges;
158-
} else {
159-
code_ranges = vec![];
160-
}
161-
extractor::extract(
162-
language,
163-
"ruby",
164-
&schema,
165-
&mut trap_writer,
166-
&path,
167-
&source,
168-
&code_ranges,
169-
)?;
170-
std::fs::create_dir_all(&src_archive_file.parent().unwrap())?;
171-
std::fs::copy(&path, &src_archive_file)?;
172-
std::fs::create_dir_all(&trap_file.parent().unwrap())?;
173-
let trap_file = std::fs::File::create(&trap_file)?;
174-
let mut trap_file = BufWriter::new(trap_file);
175-
match trap_compression {
176-
TrapCompression::None => trap_writer.output(&mut trap_file),
177-
TrapCompression::Gzip => {
178-
let mut compressed_writer = GzEncoder::new(trap_file, flate2::Compression::fast());
179-
trap_writer.output(&mut compressed_writer)
180-
}
177+
let path = PathBuf::from("extras");
178+
let mut trap_writer = extractor::new_trap_writer();
179+
trap_writer.populate_empty_location();
180+
write_trap(&trap_dir, path, trap_writer, &trap_compression)
181+
}
182+
183+
fn write_trap(
184+
trap_dir: &PathBuf,
185+
path: PathBuf,
186+
trap_writer: extractor::TrapWriter,
187+
trap_compression: &TrapCompression,
188+
) -> std::io::Result<()> {
189+
let trap_file = path_for(&trap_dir, &path, trap_compression.extension());
190+
std::fs::create_dir_all(&trap_file.parent().unwrap())?;
191+
let trap_file = std::fs::File::create(&trap_file)?;
192+
let mut trap_file = BufWriter::new(trap_file);
193+
match trap_compression {
194+
TrapCompression::None => trap_writer.output(&mut trap_file),
195+
TrapCompression::Gzip => {
196+
let mut compressed_writer = GzEncoder::new(trap_file, flate2::Compression::fast());
197+
trap_writer.output(&mut compressed_writer)
181198
}
182-
})
199+
}
183200
}
184201

185202
fn scan_erb(erb: Language, source: &std::vec::Vec<u8>) -> (Vec<Range>, Vec<usize>) {

ql/lib/codeql/Locations.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,8 @@ class Location extends @location {
5959
this.getStartLine() = other.getStartLine() and this.getStartColumn() < other.getStartColumn()
6060
}
6161
}
62+
63+
/** An entity representing an empty location. */
64+
class EmptyLocation extends Location {
65+
EmptyLocation() { this.hasLocationInfo("", 0, 0, 0, 0) }
66+
}

ql/lib/codeql/ruby/ApiGraphs.qll

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -140,26 +140,14 @@ module API {
140140
*/
141141
DataFlow::Node getInducingNode() { this = Impl::MkUse(result) }
142142

143-
/**
144-
* Holds if this element is at the specified location.
145-
* The location spans column `startcolumn` of line `startline` to
146-
* column `endcolumn` of line `endline` in file `filepath`.
147-
* For more information, see
148-
* [Locations](https://help.semmle.com/QL/learn-ql/locations.html).
149-
*/
150-
predicate hasLocationInfo(
151-
string filepath, int startline, int startcolumn, int endline, int endcolumn
152-
) {
153-
getInducingNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
143+
/** Gets the location of this node. */
144+
Location getLocation() {
145+
result = this.getInducingNode().getLocation()
154146
or
155147
// For nodes that do not have a meaningful location, `path` is the empty string and all other
156148
// parameters are zero.
157149
not exists(getInducingNode()) and
158-
filepath = "" and
159-
startline = 0 and
160-
startcolumn = 0 and
161-
endline = 0 and
162-
endcolumn = 0
150+
result instanceof EmptyLocation
163151
}
164152

165153
/**

0 commit comments

Comments
 (0)