code-moniker-core 0.6.0

Core symbol-graph types and per-language extractors for code-moniker.
Documentation
use crate::core::moniker::Moniker;

use super::super::kinds;

pub(super) fn is_libc_function(name: &[u8]) -> bool {
	LIBC_FUNCTIONS
		.binary_search_by(|candidate| candidate.as_bytes().cmp(name))
		.is_ok()
}

pub(super) fn libc_function_target(root: &Moniker, name: &[u8]) -> Moniker {
	let mut builder = crate::lang::sdk::sdk_target_builder(root.as_view().project(), b"c");
	builder.segment(kinds::PATH, b"libc");
	builder.segment(kinds::FUNC, name);
	builder.build()
}

pub(super) fn is_stdlib_header_path(path: &str) -> bool {
	let root = path
		.split('/')
		.find(|piece| !piece.is_empty())
		.map(super::syntax::strip_header_suffix)
		.unwrap_or_default();
	STDLIB_HEADER_ROOTS.binary_search(&root).is_ok()
}

// First path piece of C and common POSIX header includes. The extractor uses
// this set to emit canonical `sdk:c` targets rather than unknown externals.
pub(super) const STDLIB_HEADER_ROOTS: &[&str] = &[
	"arpa",
	"assert",
	"complex",
	"ctype",
	"dirent",
	"dlfcn",
	"errno",
	"fcntl",
	"fenv",
	"float",
	"glob",
	"grp",
	"iconv",
	"inttypes",
	"iso646",
	"langinfo",
	"libgen",
	"limits",
	"locale",
	"math",
	"netdb",
	"netinet",
	"poll",
	"pthread",
	"pwd",
	"regex",
	"sched",
	"semaphore",
	"setjmp",
	"signal",
	"stdalign",
	"stdarg",
	"stdatomic",
	"stdbool",
	"stddef",
	"stdint",
	"stdio",
	"stdlib",
	"stdnoreturn",
	"string",
	"strings",
	"sys",
	"syslog",
	"termios",
	"tgmath",
	"threads",
	"time",
	"uchar",
	"unistd",
	"utime",
	"wchar",
	"wctype",
];

// Universe of libc/POSIX functions a C file may call without any project
// definition being expected; kept to unambiguous, widespread names.
const LIBC_FUNCTIONS: &[&str] = &[
	"abort",
	"abs",
	"accept",
	"access",
	"asprintf",
	"assert",
	"atexit",
	"atof",
	"atoi",
	"atol",
	"atoll",
	"bind",
	"bsearch",
	"calloc",
	"ceil",
	"chdir",
	"chmod",
	"chown",
	"clearerr",
	"clock",
	"clock_gettime",
	"close",
	"closedir",
	"connect",
	"cos",
	"difftime",
	"dlclose",
	"dlerror",
	"dlopen",
	"dlsym",
	"dup",
	"dup2",
	"execve",
	"exit",
	"exp",
	"fabs",
	"fchmod",
	"fclose",
	"fcntl",
	"fdopen",
	"feof",
	"ferror",
	"fflush",
	"fgetc",
	"fgets",
	"fileno",
	"floor",
	"fmod",
	"fopen",
	"fork",
	"fprintf",
	"fputc",
	"fputs",
	"fread",
	"free",
	"freeaddrinfo",
	"fscanf",
	"fseek",
	"fseeko",
	"fstat",
	"fsync",
	"ftell",
	"ftello",
	"ftruncate",
	"fwrite",
	"getaddrinfo",
	"getc",
	"getchar",
	"getcwd",
	"getenv",
	"getline",
	"getpeername",
	"getpid",
	"getppid",
	"getrlimit",
	"getrusage",
	"getsockname",
	"getsockopt",
	"gettimeofday",
	"getuid",
	"gmtime",
	"gmtime_r",
	"isalnum",
	"isalpha",
	"isdigit",
	"islower",
	"isprint",
	"isspace",
	"isupper",
	"isxdigit",
	"kill",
	"labs",
	"listen",
	"localtime",
	"localtime_r",
	"log",
	"log10",
	"longjmp",
	"lseek",
	"lstat",
	"malloc",
	"memchr",
	"memcmp",
	"memcpy",
	"memmem",
	"memmove",
	"memset",
	"mkdir",
	"mkstemp",
	"mktime",
	"mmap",
	"munmap",
	"nanosleep",
	"open",
	"opendir",
	"perror",
	"pipe",
	"poll",
	"pow",
	"printf",
	"pthread_cond_broadcast",
	"pthread_cond_destroy",
	"pthread_cond_init",
	"pthread_cond_signal",
	"pthread_cond_wait",
	"pthread_create",
	"pthread_detach",
	"pthread_join",
	"pthread_mutex_destroy",
	"pthread_mutex_init",
	"pthread_mutex_lock",
	"pthread_mutex_trylock",
	"pthread_mutex_unlock",
	"pthread_self",
	"putc",
	"putchar",
	"puts",
	"qsort",
	"raise",
	"rand",
	"random",
	"read",
	"readdir",
	"readlink",
	"realloc",
	"recv",
	"regcomp",
	"regerror",
	"regexec",
	"regfree",
	"remove",
	"rename",
	"rewind",
	"rmdir",
	"round",
	"select",
	"send",
	"setenv",
	"setjmp",
	"setlocale",
	"setrlimit",
	"setsockopt",
	"setvbuf",
	"shutdown",
	"sigaction",
	"sigemptyset",
	"signal",
	"sin",
	"sleep",
	"snprintf",
	"socket",
	"sprintf",
	"sqrt",
	"srand",
	"srandom",
	"sscanf",
	"stat",
	"strcasecmp",
	"strcasestr",
	"strcat",
	"strchr",
	"strcmp",
	"strcoll",
	"strcpy",
	"strcspn",
	"strdup",
	"strerror",
	"strftime",
	"strlen",
	"strncasecmp",
	"strncat",
	"strncmp",
	"strncpy",
	"strndup",
	"strpbrk",
	"strrchr",
	"strspn",
	"strstr",
	"strtod",
	"strtok",
	"strtok_r",
	"strtol",
	"strtoll",
	"strtoul",
	"strtoull",
	"symlink",
	"sysconf",
	"system",
	"tan",
	"time",
	"tolower",
	"toupper",
	"ungetc",
	"unlink",
	"unsetenv",
	"usleep",
	"vasprintf",
	"vfprintf",
	"vprintf",
	"vsnprintf",
	"vsprintf",
	"waitpid",
	"write",
];

#[cfg(test)]
mod tests {
	use super::*;

	#[test]
	fn stdlib_header_roots_sorted_unique() {
		for pair in STDLIB_HEADER_ROOTS.windows(2) {
			assert!(
				pair[0] < pair[1],
				"expected sorted unique header roots, got `{}` before `{}`",
				pair[0],
				pair[1]
			);
		}
	}

	#[test]
	fn libc_functions_sorted_unique() {
		for pair in LIBC_FUNCTIONS.windows(2) {
			assert!(
				pair[0] < pair[1],
				"expected sorted unique libc list, got `{}` before `{}`",
				pair[0],
				pair[1]
			);
		}
	}

	#[test]
	fn libc_functions_are_language_contract() {
		for name in [
			b"assert".as_slice(),
			b"malloc".as_slice(),
			b"free",
			b"printf",
			b"memcpy",
			b"strlen",
			b"open",
			b"close",
			b"pthread_create",
		] {
			assert!(is_libc_function(name));
		}
		assert!(!is_libc_function(b"listCreate"));
		assert!(!is_libc_function(b"zmalloc"));
	}
}