Files
codeql/rust/ql/lib/codeql/files/FileSystem.qll
Paolo Tranquilli 4aef1ba9d1 Rust: clean up
2025-10-16 17:20:41 +02:00

111 lines
3.2 KiB
Plaintext

/** Provides classes for working with files and folders. */
private import codeql.Locations
private import codeql.util.FileSystem
private import codeql.rust.elements.SourceFile
private import codeql.rust.elements.AstNode
private import codeql.rust.elements.Comment
private import codeql.rust.Diagnostics
private import codeql.rust.elements.internal.ExtractorStep
private module Input implements InputSig {
abstract class ContainerBase extends @container {
abstract string getAbsolutePath();
ContainerBase getParentContainer() { containerparent(result, this) }
string toString() { result = this.getAbsolutePath() }
}
class FolderBase extends ContainerBase, @folder {
override string getAbsolutePath() { folders(this, result) }
}
class FileBase extends ContainerBase, @file {
override string getAbsolutePath() { files(this, result) }
}
predicate hasSourceLocationPrefix = sourceLocationPrefix/1;
}
private module Impl = Make<Input>;
class Container = Impl::Container;
class Folder = Impl::Folder;
module Folder = Impl::Folder;
/** A file. */
class File extends Container, Impl::File {
/** Holds if this file was extracted from ordinary source code. */
predicate fromSource() {
exists(ExtractorStep s | s.getAction() = "Extract" and s.getFile() = this)
}
/**
* Gets the number of lines containing code in this file. This value
* is approximate.
*/
int getNumberOfLinesOfCode() {
result =
count(int line |
exists(AstNode node, Location loc |
not node instanceof Comment and
not node instanceof SourceFile and
loc = node.getLocation()
|
node.getFile() = this and
line = [/*loc.getStartLine(), */ loc.getEndLine()] and // ignore start locations for now as we're getting them wrong for things with a comment attached
not loc instanceof EmptyLocation and
line > 0
)
)
}
}
/**
* A source file that was extracted.
*
* TODO: rename `SourceFile` from the generated AST to give that name to this class.
*/
class ExtractedFile extends File {
ExtractedFile() { this.fromSource() }
private Diagnostic getNoSemanticsDiagnostic() {
result.getTag() = "semantics" and result.getLocation().getFile() = this
}
/**
* Holds if we have semantical information about this file, which means
* we should be able to
* * expand any macros
* * skip any blocks that are conditionally compiled out
*/
predicate hasSemantics() { not exists(this.getNoSemanticsDiagnostic()) }
/**
* Holds if we know this file was skipped by conditional compilation.
* This is not the same as `not this.hasSemantics()`, as a file
* might not have semantics because of some error.
*/
predicate isSkippedByCompilation() { this.getNoSemanticsDiagnostic().getSeverityText() = "Info" }
}
/**
* A successfully extracted file, that is, a file that was extracted and
* contains no extraction errors or warnings.
*/
class SuccessfullyExtractedFile extends ExtractedFile {
SuccessfullyExtractedFile() {
not exists(Diagnostic d |
d.getLocation().getFile() = this and
(
d instanceof ExtractionError
or
d instanceof ExtractionWarning
)
)
}
}