mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-09 22:33:39 +00:00
refactor: split global BUILT_IN_NAMES into per-language provider fields (#523)
* refactor: make isBuiltInOrNoise provider-aware, remove global BUILT_IN_NAMES Add builtInNames field to LanguageProviderConfig. Rewrite noise-filter.ts to accept a LanguageProvider and check provider.builtInNames instead of a global Set. Update all 3 call sites to pass their existing provider. Built-in entries will be added per-language in subsequent commits. * refactor(js/ts): add per-language builtInNames to JS/TS providers * refactor(python): add per-language builtInNames * refactor(kotlin): add per-language builtInNames * refactor(c/cpp): add per-language builtInNames * refactor(csharp): add per-language builtInNames * refactor(php): add per-language builtInNames * refactor(swift): add per-language builtInNames * refactor(rust): add per-language builtInNames * refactor(ruby): add per-language builtInNames * refactor(dart): add per-language builtInNames * test: update noise-filter tests for per-language API, add isolation tests - Update ingestion-utils.test.ts to pass provider to isBuiltInOrNoise - Add noise-filter.test.ts with 15 cross-language isolation tests - Fix Java heritage test: serialize() is now correctly unfiltered for Java (was false-positive noise from global PHP serialize entry) * refactor: remove noise-filter.ts, add provider.isBuiltInName() method Per review feedback: delete noise-filter.ts entirely and move the check into LanguageProvider as isBuiltInName(name) method, generated by defineLanguage() from the builtInNames set. Call sites now use provider.isBuiltInName(calledName) directly.
This commit is contained in:
parent
c6ed25de8b
commit
546128cdcb
19 changed files with 414 additions and 295 deletions
|
|
@ -11,7 +11,6 @@ import { getLanguageFromFilename } from './utils/language-detection.js';
|
|||
import { isVerboseIngestionEnabled } from './utils/verbose.js';
|
||||
import { yieldToEventLoop } from './utils/event-loop.js';
|
||||
import { FUNCTION_NODE_TYPES, extractFunctionName, findEnclosingClassId } from './utils/ast-helpers.js';
|
||||
import { isBuiltInOrNoise } from './utils/noise-filter.js';
|
||||
import {
|
||||
countCallArguments,
|
||||
inferCallForm,
|
||||
|
|
@ -497,7 +496,7 @@ export const processCalls = async (
|
|||
}
|
||||
}
|
||||
|
||||
if (isBuiltInOrNoise(calledName)) return;
|
||||
if (provider.isBuiltInName(calledName)) return;
|
||||
|
||||
const callNode = captureMap['call'];
|
||||
const callForm = inferCallForm(callNode, nameNode);
|
||||
|
|
|
|||
|
|
@ -110,6 +110,11 @@ interface LanguageProviderConfig {
|
|||
* When true, the worker extracts routes via the language's route extraction logic.
|
||||
* Default: undefined (no route files). */
|
||||
readonly isRouteFile?: (filePath: string) => boolean;
|
||||
|
||||
// ── Noise filtering ────────────────────────────────────────────────
|
||||
/** Built-in/stdlib names that should be filtered from the call graph for this language.
|
||||
* Default: undefined (no language-specific filtering). */
|
||||
readonly builtInNames?: ReadonlySet<string>;
|
||||
}
|
||||
|
||||
/** Runtime type — same as LanguageProviderConfig but with defaults guaranteed present. */
|
||||
|
|
@ -119,6 +124,8 @@ export interface LanguageProvider extends Omit<LanguageProviderConfig,
|
|||
readonly importSemantics: ImportSemantics;
|
||||
readonly heritageDefaultEdge: 'EXTENDS' | 'IMPLEMENTS';
|
||||
readonly mroStrategy: MroStrategy;
|
||||
/** Check if a name is a built-in/stdlib function that should be filtered from the call graph. */
|
||||
readonly isBuiltInName: (name: string) => boolean;
|
||||
}
|
||||
|
||||
const DEFAULTS: Pick<LanguageProvider, 'importSemantics' | 'heritageDefaultEdge' | 'mroStrategy'> = {
|
||||
|
|
@ -129,5 +136,10 @@ const DEFAULTS: Pick<LanguageProvider, 'importSemantics' | 'heritageDefaultEdge'
|
|||
|
||||
/** Define a language provider — required fields must be supplied, optional fields get sensible defaults. */
|
||||
export function defineLanguage(config: LanguageProviderConfig): LanguageProvider {
|
||||
return { ...DEFAULTS, ...config };
|
||||
const builtIns = config.builtInNames;
|
||||
return {
|
||||
...DEFAULTS,
|
||||
...config,
|
||||
isBuiltInName: builtIns ? (name: string) => builtIns.has(name) : () => false,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,28 @@ import { C_QUERIES, CPP_QUERIES } from '../tree-sitter-queries.js';
|
|||
import { isCppInsideClassOrStruct } from '../utils/ast-helpers.js';
|
||||
import type { LanguageProvider } from '../language-provider.js';
|
||||
|
||||
const C_BUILT_INS: ReadonlySet<string> = new Set([
|
||||
'printf', 'fprintf', 'sprintf', 'snprintf', 'vprintf', 'vfprintf', 'vsprintf', 'vsnprintf',
|
||||
'scanf', 'fscanf', 'sscanf',
|
||||
'malloc', 'calloc', 'realloc', 'free', 'memcpy', 'memmove', 'memset', 'memcmp',
|
||||
'strlen', 'strcpy', 'strncpy', 'strcat', 'strncat', 'strcmp', 'strncmp', 'strstr', 'strchr', 'strrchr',
|
||||
'atoi', 'atol', 'atof', 'strtol', 'strtoul', 'strtoll', 'strtoull', 'strtod',
|
||||
'sizeof', 'offsetof', 'typeof',
|
||||
'assert', 'abort', 'exit', '_exit',
|
||||
'fopen', 'fclose', 'fread', 'fwrite', 'fseek', 'ftell', 'rewind', 'fflush', 'fgets', 'fputs',
|
||||
'likely', 'unlikely', 'BUG', 'BUG_ON', 'WARN', 'WARN_ON', 'WARN_ONCE',
|
||||
'IS_ERR', 'PTR_ERR', 'ERR_PTR', 'IS_ERR_OR_NULL',
|
||||
'ARRAY_SIZE', 'container_of', 'list_for_each_entry', 'list_for_each_entry_safe',
|
||||
'min', 'max', 'clamp', 'abs', 'swap',
|
||||
'pr_info', 'pr_warn', 'pr_err', 'pr_debug', 'pr_notice', 'pr_crit', 'pr_emerg',
|
||||
'printk', 'dev_info', 'dev_warn', 'dev_err', 'dev_dbg',
|
||||
'GFP_KERNEL', 'GFP_ATOMIC',
|
||||
'spin_lock', 'spin_unlock', 'spin_lock_irqsave', 'spin_unlock_irqrestore',
|
||||
'mutex_lock', 'mutex_unlock', 'mutex_init',
|
||||
'kfree', 'kmalloc', 'kzalloc', 'kcalloc', 'krealloc', 'kvmalloc', 'kvfree',
|
||||
'get', 'put',
|
||||
]);
|
||||
|
||||
/** Label override shared by C and C++: skip function_definition captures inside class/struct
|
||||
* bodies (they're duplicates of definition.method captures). */
|
||||
const cppLabelOverride: NonNullable<LanguageProvider['labelOverride']> = (functionNode, defaultLabel) => {
|
||||
|
|
@ -34,6 +56,7 @@ export const cProvider = defineLanguage({
|
|||
importResolver: resolveCImport,
|
||||
importSemantics: 'wildcard',
|
||||
labelOverride: cppLabelOverride,
|
||||
builtInNames: C_BUILT_INS,
|
||||
});
|
||||
|
||||
export const cppProvider = defineLanguage({
|
||||
|
|
@ -46,4 +69,5 @@ export const cppProvider = defineLanguage({
|
|||
importSemantics: 'wildcard',
|
||||
mroStrategy: 'leftmost-base',
|
||||
labelOverride: cppLabelOverride,
|
||||
builtInNames: C_BUILT_INS,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,6 +14,27 @@ import { resolveCSharpImport } from '../import-resolvers/csharp.js';
|
|||
import { extractCSharpNamedBindings } from '../named-bindings/csharp.js';
|
||||
import { CSHARP_QUERIES } from '../tree-sitter-queries.js';
|
||||
|
||||
const BUILT_INS: ReadonlySet<string> = new Set([
|
||||
'Console', 'WriteLine', 'ReadLine', 'Write',
|
||||
'Task', 'Run', 'Wait', 'WhenAll', 'WhenAny', 'FromResult', 'Delay', 'ContinueWith',
|
||||
'ConfigureAwait', 'GetAwaiter', 'GetResult',
|
||||
'ToString', 'GetType', 'Equals', 'GetHashCode', 'ReferenceEquals',
|
||||
'Add', 'Remove', 'Contains', 'Clear', 'Count', 'Any', 'All',
|
||||
'Where', 'Select', 'SelectMany', 'OrderBy', 'OrderByDescending', 'GroupBy',
|
||||
'First', 'FirstOrDefault', 'Single', 'SingleOrDefault', 'Last', 'LastOrDefault',
|
||||
'ToList', 'ToArray', 'ToDictionary', 'AsEnumerable', 'AsQueryable',
|
||||
'Aggregate', 'Sum', 'Average', 'Min', 'Max', 'Distinct', 'Skip', 'Take',
|
||||
'String', 'Format', 'IsNullOrEmpty', 'IsNullOrWhiteSpace', 'Concat', 'Join',
|
||||
'Trim', 'TrimStart', 'TrimEnd', 'Split', 'Replace', 'StartsWith', 'EndsWith',
|
||||
'Convert', 'ToInt32', 'ToDouble', 'ToBoolean', 'ToByte',
|
||||
'Math', 'Abs', 'Ceiling', 'Floor', 'Round', 'Pow', 'Sqrt',
|
||||
'Dispose', 'Close',
|
||||
'TryParse', 'Parse',
|
||||
'AddRange', 'RemoveAt', 'RemoveAll', 'FindAll', 'Exists', 'TrueForAll',
|
||||
'ContainsKey', 'TryGetValue', 'AddOrUpdate',
|
||||
'Throw', 'ThrowIfNull',
|
||||
]);
|
||||
|
||||
export const csharpProvider = defineLanguage({
|
||||
id: SupportedLanguages.CSharp,
|
||||
extensions: ['.cs'],
|
||||
|
|
@ -24,4 +45,5 @@ export const csharpProvider = defineLanguage({
|
|||
namedBindingExtractor: extractCSharpNamedBindings,
|
||||
interfaceNamePattern: /^I[A-Z]/,
|
||||
mroStrategy: 'implements-split',
|
||||
builtInNames: BUILT_INS,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,6 +14,15 @@ import { dartExportChecker } from '../export-detection.js';
|
|||
import { resolveDartImport } from '../import-resolvers/dart.js';
|
||||
import { DART_QUERIES } from '../tree-sitter-queries.js';
|
||||
|
||||
const BUILT_INS: ReadonlySet<string> = new Set([
|
||||
'setState', 'mounted', 'debugPrint',
|
||||
'runApp', 'showDialog', 'showModalBottomSheet',
|
||||
'Navigator', 'push', 'pushNamed', 'pushReplacement', 'pop', 'maybePop',
|
||||
'ScaffoldMessenger', 'showSnackBar',
|
||||
'deactivate', 'reassemble', 'debugDumpApp', 'debugDumpRenderTree',
|
||||
'then', 'catchError', 'whenComplete', 'listen',
|
||||
]);
|
||||
|
||||
export const dartProvider = defineLanguage({
|
||||
id: SupportedLanguages.Dart,
|
||||
extensions: ['.dart'],
|
||||
|
|
@ -22,4 +31,5 @@ export const dartProvider = defineLanguage({
|
|||
exportChecker: dartExportChecker,
|
||||
importResolver: resolveDartImport,
|
||||
importSemantics: 'wildcard',
|
||||
builtInNames: BUILT_INS,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,6 +17,21 @@ import { appendKotlinWildcard } from '../import-resolvers/jvm.js';
|
|||
import { KOTLIN_QUERIES } from '../tree-sitter-queries.js';
|
||||
import { isKotlinClassMethod } from '../utils/ast-helpers.js';
|
||||
|
||||
const BUILT_INS: ReadonlySet<string> = new Set([
|
||||
'println', 'print', 'readLine', 'require', 'requireNotNull', 'check', 'assert', 'lazy', 'error',
|
||||
'listOf', 'mapOf', 'setOf', 'mutableListOf', 'mutableMapOf', 'mutableSetOf',
|
||||
'arrayOf', 'sequenceOf', 'also', 'apply', 'run', 'with', 'takeIf', 'takeUnless',
|
||||
'TODO', 'buildString', 'buildList', 'buildMap', 'buildSet',
|
||||
'repeat', 'synchronized',
|
||||
'launch', 'async', 'runBlocking', 'withContext', 'coroutineScope',
|
||||
'supervisorScope', 'delay',
|
||||
'flow', 'flowOf', 'collect', 'emit', 'onEach', 'catch',
|
||||
'buffer', 'conflate', 'distinctUntilChanged',
|
||||
'flatMapLatest', 'flatMapMerge', 'combine',
|
||||
'stateIn', 'shareIn', 'launchIn',
|
||||
'to', 'until', 'downTo', 'step',
|
||||
]);
|
||||
|
||||
export const kotlinProvider = defineLanguage({
|
||||
id: SupportedLanguages.Kotlin,
|
||||
extensions: ['.kt', '.kts'],
|
||||
|
|
@ -27,6 +42,7 @@ export const kotlinProvider = defineLanguage({
|
|||
namedBindingExtractor: extractKotlinNamedBindings,
|
||||
importPathPreprocessor: appendKotlinWildcard,
|
||||
mroStrategy: 'implements-split',
|
||||
builtInNames: BUILT_INS,
|
||||
labelOverride: (functionNode, defaultLabel) => {
|
||||
if (defaultLabel !== 'Function') return defaultLabel;
|
||||
if (isKotlinClassMethod(functionNode)) return 'Method';
|
||||
|
|
|
|||
|
|
@ -16,6 +16,25 @@ import { PHP_QUERIES } from '../tree-sitter-queries.js';
|
|||
import { findDescendant, extractStringContent } from '../utils/ast-helpers.js';
|
||||
import type { NodeLabel } from '../../graph/types.js';
|
||||
|
||||
const BUILT_INS: ReadonlySet<string> = new Set([
|
||||
'echo', 'isset', 'empty', 'unset', 'list', 'array', 'compact', 'extract',
|
||||
'count', 'strlen', 'strpos', 'strrpos', 'substr', 'strtolower', 'strtoupper', 'trim',
|
||||
'ltrim', 'rtrim', 'str_replace', 'str_contains', 'str_starts_with', 'str_ends_with',
|
||||
'sprintf', 'vsprintf', 'printf', 'number_format',
|
||||
'array_map', 'array_filter', 'array_reduce', 'array_push', 'array_pop', 'array_shift',
|
||||
'array_unshift', 'array_slice', 'array_splice', 'array_merge', 'array_keys', 'array_values',
|
||||
'array_key_exists', 'in_array', 'array_search', 'array_unique', 'usort', 'rsort',
|
||||
'json_encode', 'json_decode', 'serialize', 'unserialize',
|
||||
'intval', 'floatval', 'strval', 'boolval', 'is_null', 'is_string', 'is_int', 'is_array',
|
||||
'is_object', 'is_numeric', 'is_bool', 'is_float',
|
||||
'var_dump', 'print_r', 'var_export',
|
||||
'date', 'time', 'strtotime', 'mktime', 'microtime',
|
||||
'file_exists', 'file_get_contents', 'file_put_contents', 'is_file', 'is_dir',
|
||||
'preg_match', 'preg_match_all', 'preg_replace', 'preg_split',
|
||||
'header', 'session_start', 'session_destroy', 'ob_start', 'ob_end_clean', 'ob_get_clean',
|
||||
'dd', 'dump',
|
||||
]);
|
||||
|
||||
/** Eloquent model properties whose array values are worth indexing. */
|
||||
const ELOQUENT_ARRAY_PROPS = new Set(['fillable', 'casts', 'hidden', 'guarded', 'with', 'appends']);
|
||||
|
||||
|
|
@ -130,4 +149,5 @@ export const phpProvider = defineLanguage({
|
|||
namedBindingExtractor: extractPhpNamedBindings,
|
||||
descriptionExtractor: phpDescriptionExtractor,
|
||||
isRouteFile: isPhpRouteFile,
|
||||
builtInNames: BUILT_INS,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,6 +18,13 @@ import { resolvePythonImport } from '../import-resolvers/python.js';
|
|||
import { extractPythonNamedBindings } from '../named-bindings/python.js';
|
||||
import { PYTHON_QUERIES } from '../tree-sitter-queries.js';
|
||||
|
||||
const BUILT_INS: ReadonlySet<string> = new Set([
|
||||
'print', 'len', 'range', 'str', 'int', 'float', 'list', 'dict', 'set', 'tuple',
|
||||
'append', 'extend', 'update',
|
||||
'type', 'isinstance', 'issubclass', 'getattr', 'setattr', 'hasattr',
|
||||
'enumerate', 'zip', 'sorted', 'reversed', 'min', 'max', 'sum', 'abs',
|
||||
]);
|
||||
|
||||
export const pythonProvider = defineLanguage({
|
||||
id: SupportedLanguages.Python,
|
||||
extensions: ['.py'],
|
||||
|
|
@ -28,4 +35,5 @@ export const pythonProvider = defineLanguage({
|
|||
namedBindingExtractor: extractPythonNamedBindings,
|
||||
importSemantics: 'namespace',
|
||||
mroStrategy: 'c3',
|
||||
builtInNames: BUILT_INS,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,6 +15,22 @@ import { rubyExportChecker } from '../export-detection.js';
|
|||
import { resolveRubyImport } from '../import-resolvers/ruby.js';
|
||||
import { RUBY_QUERIES } from '../tree-sitter-queries.js';
|
||||
|
||||
const BUILT_INS: ReadonlySet<string> = new Set([
|
||||
'puts', 'p', 'pp', 'raise', 'fail',
|
||||
'require', 'require_relative', 'load', 'autoload',
|
||||
'include', 'extend', 'prepend',
|
||||
'attr_accessor', 'attr_reader', 'attr_writer',
|
||||
'public', 'private', 'protected', 'module_function',
|
||||
'lambda', 'proc', 'block_given?',
|
||||
'nil?', 'is_a?', 'kind_of?', 'instance_of?', 'respond_to?',
|
||||
'freeze', 'frozen?', 'dup', 'tap', 'yield_self',
|
||||
'each', 'select', 'reject', 'detect', 'collect',
|
||||
'inject', 'flat_map', 'each_with_object', 'each_with_index',
|
||||
'any?', 'all?', 'none?', 'count', 'first', 'last',
|
||||
'sort_by', 'min_by', 'max_by',
|
||||
'group_by', 'partition', 'compact', 'flatten', 'uniq',
|
||||
]);
|
||||
|
||||
export const rubyProvider = defineLanguage({
|
||||
id: SupportedLanguages.Ruby,
|
||||
extensions: ['.rb', '.rake', '.gemspec'],
|
||||
|
|
@ -24,4 +40,5 @@ export const rubyProvider = defineLanguage({
|
|||
importResolver: resolveRubyImport,
|
||||
callRouter: routeRubyCall,
|
||||
importSemantics: 'wildcard',
|
||||
builtInNames: BUILT_INS,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,6 +18,19 @@ import { resolveRustImport } from '../import-resolvers/rust.js';
|
|||
import { extractRustNamedBindings } from '../named-bindings/rust.js';
|
||||
import { RUST_QUERIES } from '../tree-sitter-queries.js';
|
||||
|
||||
const BUILT_INS: ReadonlySet<string> = new Set([
|
||||
'unwrap', 'expect', 'unwrap_or', 'unwrap_or_else', 'unwrap_or_default',
|
||||
'ok', 'err', 'is_ok', 'is_err', 'map', 'map_err', 'and_then', 'or_else',
|
||||
'clone', 'to_string', 'to_owned', 'into', 'from', 'as_ref', 'as_mut',
|
||||
'iter', 'into_iter', 'collect', 'filter', 'fold', 'for_each',
|
||||
'len', 'is_empty', 'push', 'pop', 'insert', 'remove', 'contains',
|
||||
'format', 'write', 'writeln', 'panic', 'unreachable', 'todo', 'unimplemented',
|
||||
'vec', 'println', 'eprintln', 'dbg',
|
||||
'lock', 'read', 'try_lock',
|
||||
'spawn', 'join', 'sleep',
|
||||
'Some', 'None', 'Ok', 'Err',
|
||||
]);
|
||||
|
||||
export const rustProvider = defineLanguage({
|
||||
id: SupportedLanguages.Rust,
|
||||
extensions: ['.rs'],
|
||||
|
|
@ -27,4 +40,5 @@ export const rustProvider = defineLanguage({
|
|||
importResolver: resolveRustImport,
|
||||
namedBindingExtractor: extractRustNamedBindings,
|
||||
mroStrategy: 'qualified-syntax',
|
||||
builtInNames: BUILT_INS,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -101,6 +101,34 @@ function wireSwiftImplicitImports(
|
|||
}
|
||||
}
|
||||
|
||||
const BUILT_INS: ReadonlySet<string> = new Set([
|
||||
'print', 'debugPrint', 'dump', 'fatalError', 'precondition', 'preconditionFailure',
|
||||
'assert', 'assertionFailure', 'NSLog',
|
||||
'abs', 'min', 'max', 'zip', 'stride', 'sequence', 'repeatElement',
|
||||
'swap', 'withUnsafePointer', 'withUnsafeMutablePointer', 'withUnsafeBytes',
|
||||
'autoreleasepool', 'unsafeBitCast', 'unsafeDowncast', 'numericCast',
|
||||
'type', 'MemoryLayout',
|
||||
'map', 'flatMap', 'compactMap', 'filter', 'reduce', 'forEach', 'contains',
|
||||
'first', 'last', 'prefix', 'suffix', 'dropFirst', 'dropLast',
|
||||
'sorted', 'reversed', 'enumerated', 'joined', 'split',
|
||||
'append', 'insert', 'remove', 'removeAll', 'removeFirst', 'removeLast',
|
||||
'isEmpty', 'count', 'index', 'startIndex', 'endIndex',
|
||||
'addSubview', 'removeFromSuperview', 'layoutSubviews', 'setNeedsLayout',
|
||||
'layoutIfNeeded', 'setNeedsDisplay', 'invalidateIntrinsicContentSize',
|
||||
'addTarget', 'removeTarget', 'addGestureRecognizer',
|
||||
'addConstraint', 'addConstraints', 'removeConstraint', 'removeConstraints',
|
||||
'NSLocalizedString', 'Bundle',
|
||||
'reloadData', 'reloadSections', 'reloadRows', 'performBatchUpdates',
|
||||
'register', 'dequeueReusableCell', 'dequeueReusableSupplementaryView',
|
||||
'beginUpdates', 'endUpdates', 'insertRows', 'deleteRows', 'insertSections', 'deleteSections',
|
||||
'present', 'dismiss', 'pushViewController', 'popViewController', 'popToRootViewController',
|
||||
'performSegue', 'prepare',
|
||||
'DispatchQueue', 'async', 'sync', 'asyncAfter',
|
||||
'Task', 'withCheckedContinuation', 'withCheckedThrowingContinuation',
|
||||
'sink', 'store', 'assign', 'receive', 'subscribe',
|
||||
'addObserver', 'removeObserver', 'post', 'NotificationCenter',
|
||||
]);
|
||||
|
||||
export const swiftProvider = defineLanguage({
|
||||
id: SupportedLanguages.Swift,
|
||||
extensions: ['.swift'],
|
||||
|
|
@ -111,4 +139,5 @@ export const swiftProvider = defineLanguage({
|
|||
importSemantics: 'wildcard',
|
||||
heritageDefaultEdge: 'IMPLEMENTS',
|
||||
implicitImportWirer: wireSwiftImplicitImports,
|
||||
builtInNames: BUILT_INS,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,6 +15,27 @@ import { resolveTypescriptImport, resolveJavascriptImport } from '../import-reso
|
|||
import { extractTsNamedBindings } from '../named-bindings/typescript.js';
|
||||
import { TYPESCRIPT_QUERIES, JAVASCRIPT_QUERIES } from '../tree-sitter-queries.js';
|
||||
|
||||
const BUILT_INS: ReadonlySet<string> = new Set([
|
||||
'console', 'log', 'warn', 'error', 'info', 'debug',
|
||||
'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
|
||||
'parseInt', 'parseFloat', 'isNaN', 'isFinite',
|
||||
'encodeURI', 'decodeURI', 'encodeURIComponent', 'decodeURIComponent',
|
||||
'JSON', 'parse', 'stringify',
|
||||
'Object', 'Array', 'String', 'Number', 'Boolean', 'Symbol', 'BigInt',
|
||||
'Map', 'Set', 'WeakMap', 'WeakSet',
|
||||
'Promise', 'resolve', 'reject', 'then', 'catch', 'finally',
|
||||
'Math', 'Date', 'RegExp', 'Error',
|
||||
'require', 'import', 'export', 'fetch', 'Response', 'Request',
|
||||
'useState', 'useEffect', 'useCallback', 'useMemo', 'useRef', 'useContext',
|
||||
'useReducer', 'useLayoutEffect', 'useImperativeHandle', 'useDebugValue',
|
||||
'createElement', 'createContext', 'createRef', 'forwardRef', 'memo', 'lazy',
|
||||
'map', 'filter', 'reduce', 'forEach', 'find', 'findIndex', 'some', 'every',
|
||||
'includes', 'indexOf', 'slice', 'splice', 'concat', 'join', 'split',
|
||||
'push', 'pop', 'shift', 'unshift', 'sort', 'reverse',
|
||||
'keys', 'values', 'entries', 'assign', 'freeze', 'seal',
|
||||
'hasOwnProperty', 'toString', 'valueOf',
|
||||
]);
|
||||
|
||||
export const typescriptProvider = defineLanguage({
|
||||
id: SupportedLanguages.TypeScript,
|
||||
extensions: ['.ts', '.tsx'],
|
||||
|
|
@ -23,6 +44,7 @@ export const typescriptProvider = defineLanguage({
|
|||
exportChecker: tsExportChecker,
|
||||
importResolver: resolveTypescriptImport,
|
||||
namedBindingExtractor: extractTsNamedBindings,
|
||||
builtInNames: BUILT_INS,
|
||||
});
|
||||
|
||||
export const javascriptProvider = defineLanguage({
|
||||
|
|
@ -33,4 +55,5 @@ export const javascriptProvider = defineLanguage({
|
|||
exportChecker: tsExportChecker,
|
||||
importResolver: resolveJavascriptImport,
|
||||
namedBindingExtractor: extractTsNamedBindings,
|
||||
builtInNames: BUILT_INS,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -808,7 +808,7 @@ export const RUBY_QUERIES = `
|
|||
; NOTE: This may over-capture variable reads as calls (e.g. 'result' at
|
||||
; statement level). Ruby's grammar makes bare identifiers ambiguous — they
|
||||
; could be local variables or zero-arity method calls. Post-processing via
|
||||
; isBuiltInOrNoise and symbol resolution filtering suppresses most false
|
||||
; provider.isBuiltInName and symbol resolution filtering suppresses most false
|
||||
; positives, but a variable name that coincidentally matches a method name
|
||||
; elsewhere may produce a false CALLS edge.
|
||||
(body_statement
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { type SyntaxNode, FUNCTION_NODE_TYPES, extractFunctionName, CLASS_CONTAINER_TYPES } from './utils/ast-helpers.js';
|
||||
import { CALL_EXPRESSION_TYPES } from './utils/call-analysis.js';
|
||||
import { isBuiltInOrNoise } from './utils/noise-filter.js';
|
||||
import { SupportedLanguages } from '../../config/supported-languages.js';
|
||||
import { TYPED_PARAMETER_TYPES } from './type-extractors/shared.js';
|
||||
import { getProvider } from './languages/index.js';
|
||||
|
|
@ -729,7 +728,7 @@ export const buildTypeEnv = (
|
|||
lookupReturnType(callee: string): string | undefined {
|
||||
// SymbolTable is authoritative when it has an unambiguous match
|
||||
if (symbolTable) {
|
||||
if (isBuiltInOrNoise(callee)) return undefined;
|
||||
if (provider.isBuiltInName(callee)) return undefined;
|
||||
const callables = symbolTable.lookupFuzzyCallable(callee);
|
||||
if (callables.length === 1) {
|
||||
const rawReturn = callables[0].returnType;
|
||||
|
|
@ -743,7 +742,7 @@ export const buildTypeEnv = (
|
|||
},
|
||||
lookupRawReturnType(callee: string): string | undefined {
|
||||
if (symbolTable) {
|
||||
if (isBuiltInOrNoise(callee)) return undefined;
|
||||
if (provider.isBuiltInName(callee)) return undefined;
|
||||
const callables = symbolTable.lookupFuzzyCallable(callee);
|
||||
if (callables.length === 1) return callables[0].returnType;
|
||||
// Ambiguous (2+) → return undefined (conservative, no cross-file fallback)
|
||||
|
|
|
|||
|
|
@ -1,175 +0,0 @@
|
|||
/**
|
||||
* Built-in name filtering — identifies standard library functions and common noise
|
||||
* that should not be tracked as call targets in the knowledge graph.
|
||||
*
|
||||
* Covers: JS/TS, Python, Kotlin, C/C++, C#, PHP, Swift, Rust, Ruby, Dart/Flutter standard libraries.
|
||||
*/
|
||||
|
||||
export const BUILT_IN_NAMES = new Set([
|
||||
// JavaScript/TypeScript
|
||||
'console', 'log', 'warn', 'error', 'info', 'debug',
|
||||
'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
|
||||
'parseInt', 'parseFloat', 'isNaN', 'isFinite',
|
||||
'encodeURI', 'decodeURI', 'encodeURIComponent', 'decodeURIComponent',
|
||||
'JSON', 'parse', 'stringify',
|
||||
'Object', 'Array', 'String', 'Number', 'Boolean', 'Symbol', 'BigInt',
|
||||
'Map', 'Set', 'WeakMap', 'WeakSet',
|
||||
'Promise', 'resolve', 'reject', 'then', 'catch', 'finally',
|
||||
'Math', 'Date', 'RegExp', 'Error',
|
||||
'require', 'import', 'export', 'fetch', 'Response', 'Request',
|
||||
'useState', 'useEffect', 'useCallback', 'useMemo', 'useRef', 'useContext',
|
||||
'useReducer', 'useLayoutEffect', 'useImperativeHandle', 'useDebugValue',
|
||||
'createElement', 'createContext', 'createRef', 'forwardRef', 'memo', 'lazy',
|
||||
'map', 'filter', 'reduce', 'forEach', 'find', 'findIndex', 'some', 'every',
|
||||
'includes', 'indexOf', 'slice', 'splice', 'concat', 'join', 'split',
|
||||
'push', 'pop', 'shift', 'unshift', 'sort', 'reverse',
|
||||
'keys', 'values', 'entries', 'assign', 'freeze', 'seal',
|
||||
'hasOwnProperty', 'toString', 'valueOf',
|
||||
// Python
|
||||
'print', 'len', 'range', 'str', 'int', 'float', 'list', 'dict', 'set', 'tuple',
|
||||
'append', 'extend', 'update',
|
||||
// NOTE: 'open', 'read', 'write', 'close' removed — these are real C POSIX syscalls
|
||||
'type', 'isinstance', 'issubclass', 'getattr', 'setattr', 'hasattr',
|
||||
'enumerate', 'zip', 'sorted', 'reversed', 'min', 'max', 'sum', 'abs',
|
||||
// Kotlin stdlib
|
||||
'println', 'print', 'readLine', 'require', 'requireNotNull', 'check', 'assert', 'lazy', 'error',
|
||||
'listOf', 'mapOf', 'setOf', 'mutableListOf', 'mutableMapOf', 'mutableSetOf',
|
||||
'arrayOf', 'sequenceOf', 'also', 'apply', 'run', 'with', 'takeIf', 'takeUnless',
|
||||
'TODO', 'buildString', 'buildList', 'buildMap', 'buildSet',
|
||||
'repeat', 'synchronized',
|
||||
// Kotlin coroutine builders & scope functions
|
||||
'launch', 'async', 'runBlocking', 'withContext', 'coroutineScope',
|
||||
'supervisorScope', 'delay',
|
||||
// Kotlin Flow operators
|
||||
'flow', 'flowOf', 'collect', 'emit', 'onEach', 'catch',
|
||||
'buffer', 'conflate', 'distinctUntilChanged',
|
||||
'flatMapLatest', 'flatMapMerge', 'combine',
|
||||
'stateIn', 'shareIn', 'launchIn',
|
||||
// Kotlin infix stdlib functions
|
||||
'to', 'until', 'downTo', 'step',
|
||||
// C/C++ standard library
|
||||
'printf', 'fprintf', 'sprintf', 'snprintf', 'vprintf', 'vfprintf', 'vsprintf', 'vsnprintf',
|
||||
'scanf', 'fscanf', 'sscanf',
|
||||
'malloc', 'calloc', 'realloc', 'free', 'memcpy', 'memmove', 'memset', 'memcmp',
|
||||
'strlen', 'strcpy', 'strncpy', 'strcat', 'strncat', 'strcmp', 'strncmp', 'strstr', 'strchr', 'strrchr',
|
||||
'atoi', 'atol', 'atof', 'strtol', 'strtoul', 'strtoll', 'strtoull', 'strtod',
|
||||
'sizeof', 'offsetof', 'typeof',
|
||||
'assert', 'abort', 'exit', '_exit',
|
||||
'fopen', 'fclose', 'fread', 'fwrite', 'fseek', 'ftell', 'rewind', 'fflush', 'fgets', 'fputs',
|
||||
// Linux kernel common macros/helpers (not real call targets)
|
||||
'likely', 'unlikely', 'BUG', 'BUG_ON', 'WARN', 'WARN_ON', 'WARN_ONCE',
|
||||
'IS_ERR', 'PTR_ERR', 'ERR_PTR', 'IS_ERR_OR_NULL',
|
||||
'ARRAY_SIZE', 'container_of', 'list_for_each_entry', 'list_for_each_entry_safe',
|
||||
'min', 'max', 'clamp', 'abs', 'swap',
|
||||
'pr_info', 'pr_warn', 'pr_err', 'pr_debug', 'pr_notice', 'pr_crit', 'pr_emerg',
|
||||
'printk', 'dev_info', 'dev_warn', 'dev_err', 'dev_dbg',
|
||||
'GFP_KERNEL', 'GFP_ATOMIC',
|
||||
'spin_lock', 'spin_unlock', 'spin_lock_irqsave', 'spin_unlock_irqrestore',
|
||||
'mutex_lock', 'mutex_unlock', 'mutex_init',
|
||||
'kfree', 'kmalloc', 'kzalloc', 'kcalloc', 'krealloc', 'kvmalloc', 'kvfree',
|
||||
'get', 'put',
|
||||
// C# / .NET built-ins
|
||||
'Console', 'WriteLine', 'ReadLine', 'Write',
|
||||
'Task', 'Run', 'Wait', 'WhenAll', 'WhenAny', 'FromResult', 'Delay', 'ContinueWith',
|
||||
'ConfigureAwait', 'GetAwaiter', 'GetResult',
|
||||
'ToString', 'GetType', 'Equals', 'GetHashCode', 'ReferenceEquals',
|
||||
'Add', 'Remove', 'Contains', 'Clear', 'Count', 'Any', 'All',
|
||||
'Where', 'Select', 'SelectMany', 'OrderBy', 'OrderByDescending', 'GroupBy',
|
||||
'First', 'FirstOrDefault', 'Single', 'SingleOrDefault', 'Last', 'LastOrDefault',
|
||||
'ToList', 'ToArray', 'ToDictionary', 'AsEnumerable', 'AsQueryable',
|
||||
'Aggregate', 'Sum', 'Average', 'Min', 'Max', 'Distinct', 'Skip', 'Take',
|
||||
'String', 'Format', 'IsNullOrEmpty', 'IsNullOrWhiteSpace', 'Concat', 'Join',
|
||||
'Trim', 'TrimStart', 'TrimEnd', 'Split', 'Replace', 'StartsWith', 'EndsWith',
|
||||
'Convert', 'ToInt32', 'ToDouble', 'ToBoolean', 'ToByte',
|
||||
'Math', 'Abs', 'Ceiling', 'Floor', 'Round', 'Pow', 'Sqrt',
|
||||
'Dispose', 'Close',
|
||||
'TryParse', 'Parse',
|
||||
'AddRange', 'RemoveAt', 'RemoveAll', 'FindAll', 'Exists', 'TrueForAll',
|
||||
'ContainsKey', 'TryGetValue', 'AddOrUpdate',
|
||||
'Throw', 'ThrowIfNull',
|
||||
// PHP built-ins
|
||||
'echo', 'isset', 'empty', 'unset', 'list', 'array', 'compact', 'extract',
|
||||
'count', 'strlen', 'strpos', 'strrpos', 'substr', 'strtolower', 'strtoupper', 'trim',
|
||||
'ltrim', 'rtrim', 'str_replace', 'str_contains', 'str_starts_with', 'str_ends_with',
|
||||
'sprintf', 'vsprintf', 'printf', 'number_format',
|
||||
'array_map', 'array_filter', 'array_reduce', 'array_push', 'array_pop', 'array_shift',
|
||||
'array_unshift', 'array_slice', 'array_splice', 'array_merge', 'array_keys', 'array_values',
|
||||
'array_key_exists', 'in_array', 'array_search', 'array_unique', 'usort', 'rsort',
|
||||
'json_encode', 'json_decode', 'serialize', 'unserialize',
|
||||
'intval', 'floatval', 'strval', 'boolval', 'is_null', 'is_string', 'is_int', 'is_array',
|
||||
'is_object', 'is_numeric', 'is_bool', 'is_float',
|
||||
'var_dump', 'print_r', 'var_export',
|
||||
'date', 'time', 'strtotime', 'mktime', 'microtime',
|
||||
'file_exists', 'file_get_contents', 'file_put_contents', 'is_file', 'is_dir',
|
||||
'preg_match', 'preg_match_all', 'preg_replace', 'preg_split',
|
||||
'header', 'session_start', 'session_destroy', 'ob_start', 'ob_end_clean', 'ob_get_clean',
|
||||
'dd', 'dump',
|
||||
// Swift/iOS built-ins and standard library
|
||||
'print', 'debugPrint', 'dump', 'fatalError', 'precondition', 'preconditionFailure',
|
||||
'assert', 'assertionFailure', 'NSLog',
|
||||
'abs', 'min', 'max', 'zip', 'stride', 'sequence', 'repeatElement',
|
||||
'swap', 'withUnsafePointer', 'withUnsafeMutablePointer', 'withUnsafeBytes',
|
||||
'autoreleasepool', 'unsafeBitCast', 'unsafeDowncast', 'numericCast',
|
||||
'type', 'MemoryLayout',
|
||||
// Swift collection/string methods (common noise)
|
||||
'map', 'flatMap', 'compactMap', 'filter', 'reduce', 'forEach', 'contains',
|
||||
'first', 'last', 'prefix', 'suffix', 'dropFirst', 'dropLast',
|
||||
'sorted', 'reversed', 'enumerated', 'joined', 'split',
|
||||
'append', 'insert', 'remove', 'removeAll', 'removeFirst', 'removeLast',
|
||||
'isEmpty', 'count', 'index', 'startIndex', 'endIndex',
|
||||
// UIKit/Foundation common methods (noise in call graph)
|
||||
'addSubview', 'removeFromSuperview', 'layoutSubviews', 'setNeedsLayout',
|
||||
'layoutIfNeeded', 'setNeedsDisplay', 'invalidateIntrinsicContentSize',
|
||||
'addTarget', 'removeTarget', 'addGestureRecognizer',
|
||||
'addConstraint', 'addConstraints', 'removeConstraint', 'removeConstraints',
|
||||
'NSLocalizedString', 'Bundle',
|
||||
'reloadData', 'reloadSections', 'reloadRows', 'performBatchUpdates',
|
||||
'register', 'dequeueReusableCell', 'dequeueReusableSupplementaryView',
|
||||
'beginUpdates', 'endUpdates', 'insertRows', 'deleteRows', 'insertSections', 'deleteSections',
|
||||
'present', 'dismiss', 'pushViewController', 'popViewController', 'popToRootViewController',
|
||||
'performSegue', 'prepare',
|
||||
// GCD / async
|
||||
'DispatchQueue', 'async', 'sync', 'asyncAfter',
|
||||
'Task', 'withCheckedContinuation', 'withCheckedThrowingContinuation',
|
||||
// Combine
|
||||
'sink', 'store', 'assign', 'receive', 'subscribe',
|
||||
// Notification / KVO
|
||||
'addObserver', 'removeObserver', 'post', 'NotificationCenter',
|
||||
// Rust standard library (common noise in call graphs)
|
||||
'unwrap', 'expect', 'unwrap_or', 'unwrap_or_else', 'unwrap_or_default',
|
||||
'ok', 'err', 'is_ok', 'is_err', 'map', 'map_err', 'and_then', 'or_else',
|
||||
'clone', 'to_string', 'to_owned', 'into', 'from', 'as_ref', 'as_mut',
|
||||
'iter', 'into_iter', 'collect', 'map', 'filter', 'fold', 'for_each',
|
||||
'len', 'is_empty', 'push', 'pop', 'insert', 'remove', 'contains',
|
||||
'format', 'write', 'writeln', 'panic', 'unreachable', 'todo', 'unimplemented',
|
||||
'vec', 'println', 'eprintln', 'dbg',
|
||||
'lock', 'read', 'write', 'try_lock',
|
||||
'spawn', 'join', 'sleep',
|
||||
'Some', 'None', 'Ok', 'Err',
|
||||
// Ruby built-ins and Kernel methods
|
||||
'puts', 'p', 'pp', 'raise', 'fail',
|
||||
'require', 'require_relative', 'load', 'autoload',
|
||||
'include', 'extend', 'prepend',
|
||||
'attr_accessor', 'attr_reader', 'attr_writer',
|
||||
'public', 'private', 'protected', 'module_function',
|
||||
'lambda', 'proc', 'block_given?',
|
||||
'nil?', 'is_a?', 'kind_of?', 'instance_of?', 'respond_to?',
|
||||
'freeze', 'frozen?', 'dup', 'tap', 'yield_self',
|
||||
// Dart / Flutter
|
||||
'setState', 'mounted', 'debugPrint',
|
||||
'runApp', 'showDialog', 'showModalBottomSheet',
|
||||
'Navigator', 'push', 'pushNamed', 'pushReplacement', 'pop', 'maybePop',
|
||||
'ScaffoldMessenger', 'showSnackBar',
|
||||
'deactivate', 'reassemble', 'debugDumpApp', 'debugDumpRenderTree',
|
||||
// Dart async
|
||||
'then', 'catchError', 'whenComplete', 'listen',
|
||||
// Ruby enumerables
|
||||
'each', 'select', 'reject', 'detect', 'collect',
|
||||
'inject', 'flat_map', 'each_with_object', 'each_with_index',
|
||||
'any?', 'all?', 'none?', 'count', 'first', 'last',
|
||||
'sort_by', 'min_by', 'max_by',
|
||||
'group_by', 'partition', 'compact', 'flatten', 'uniq',
|
||||
]);
|
||||
|
||||
/** Check if a name is a built-in function or common noise that should be filtered out */
|
||||
export const isBuiltInOrNoise = (name: string): boolean => BUILT_IN_NAMES.has(name);
|
||||
|
|
@ -29,7 +29,6 @@ try { Dart = _require('tree-sitter-dart'); } catch {}
|
|||
let Kotlin: any = null;
|
||||
try { Kotlin = _require('tree-sitter-kotlin'); } catch {}
|
||||
import { getLanguageFromFilename } from '../utils/language-detection.js';
|
||||
import { isBuiltInOrNoise } from '../utils/noise-filter.js';
|
||||
import {
|
||||
FUNCTION_NODE_TYPES,
|
||||
extractFunctionName,
|
||||
|
|
@ -1181,7 +1180,7 @@ const processFileGroup = (
|
|||
// kind === 'call' — fall through to normal call processing below
|
||||
}
|
||||
|
||||
if (!isBuiltInOrNoise(calledName)) {
|
||||
if (!provider.isBuiltInName(calledName)) {
|
||||
const callNode = captureMap['call'];
|
||||
const sourceId = findEnclosingFunctionId(callNode, file.path, provider)
|
||||
|| generateId('File', file.path);
|
||||
|
|
|
|||
|
|
@ -60,11 +60,12 @@ describe('Java heritage resolution', () => {
|
|||
expect(extends_.some(e => e.target === 'Validatable')).toBe(false);
|
||||
});
|
||||
|
||||
it('emits exactly 2 CALLS edges', () => {
|
||||
it('emits exactly 3 CALLS edges', () => {
|
||||
const calls = getRelationships(result, 'CALLS');
|
||||
expect(calls.length).toBe(2);
|
||||
expect(calls.length).toBe(3);
|
||||
expect(edgeSet(calls)).toEqual([
|
||||
'processUser → save',
|
||||
'processUser → serialize',
|
||||
'processUser → validate',
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getLanguageFromFilename } from '../../src/core/ingestion/utils/language-detection.js';
|
||||
import { isBuiltInOrNoise } from '../../src/core/ingestion/utils/noise-filter.js';
|
||||
import { getProvider } from '../../src/core/ingestion/languages/index.js';
|
||||
import { SupportedLanguages } from '../../src/config/supported-languages.js';
|
||||
import { extractFunctionName } from '../../src/core/ingestion/utils/ast-helpers.js';
|
||||
import { getTreeSitterBufferSize, TREE_SITTER_BUFFER_SIZE, TREE_SITTER_MAX_BUFFER } from '../../src/core/ingestion/constants.js';
|
||||
import { SupportedLanguages } from '../../src/config/supported-languages.js';
|
||||
import Parser from 'tree-sitter';
|
||||
import C from 'tree-sitter-c';
|
||||
import CPP from 'tree-sitter-cpp';
|
||||
|
|
@ -140,203 +140,212 @@ describe('getLanguageFromFilename', () => {
|
|||
});
|
||||
|
||||
describe('isBuiltInOrNoise', () => {
|
||||
const js = getProvider(SupportedLanguages.JavaScript);
|
||||
const py = getProvider(SupportedLanguages.Python);
|
||||
const php = getProvider(SupportedLanguages.PHP);
|
||||
const c = getProvider(SupportedLanguages.C);
|
||||
const kt = getProvider(SupportedLanguages.Kotlin);
|
||||
const swift = getProvider(SupportedLanguages.Swift);
|
||||
const rust = getProvider(SupportedLanguages.Rust);
|
||||
const cs = getProvider(SupportedLanguages.CSharp);
|
||||
|
||||
describe('JavaScript/TypeScript', () => {
|
||||
it('filters console methods', () => {
|
||||
expect(isBuiltInOrNoise('console')).toBe(true);
|
||||
expect(isBuiltInOrNoise('log')).toBe(true);
|
||||
expect(isBuiltInOrNoise('warn')).toBe(true);
|
||||
expect(js.isBuiltInName('console')).toBe(true);
|
||||
expect(js.isBuiltInName('log')).toBe(true);
|
||||
expect(js.isBuiltInName('warn')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters React hooks', () => {
|
||||
expect(isBuiltInOrNoise('useState')).toBe(true);
|
||||
expect(isBuiltInOrNoise('useEffect')).toBe(true);
|
||||
expect(isBuiltInOrNoise('useCallback')).toBe(true);
|
||||
expect(js.isBuiltInName('useState')).toBe(true);
|
||||
expect(js.isBuiltInName('useEffect')).toBe(true);
|
||||
expect(js.isBuiltInName('useCallback')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters array methods', () => {
|
||||
expect(isBuiltInOrNoise('map')).toBe(true);
|
||||
expect(isBuiltInOrNoise('filter')).toBe(true);
|
||||
expect(isBuiltInOrNoise('reduce')).toBe(true);
|
||||
expect(js.isBuiltInName('map')).toBe(true);
|
||||
expect(js.isBuiltInName('filter')).toBe(true);
|
||||
expect(js.isBuiltInName('reduce')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Python', () => {
|
||||
it('filters built-in functions', () => {
|
||||
expect(isBuiltInOrNoise('print')).toBe(true);
|
||||
expect(isBuiltInOrNoise('len')).toBe(true);
|
||||
expect(isBuiltInOrNoise('range')).toBe(true);
|
||||
expect(py.isBuiltInName('print')).toBe(true);
|
||||
expect(py.isBuiltInName('len')).toBe(true);
|
||||
expect(py.isBuiltInName('range')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('PHP', () => {
|
||||
it('filters PHP built-in functions', () => {
|
||||
expect(isBuiltInOrNoise('echo')).toBe(true);
|
||||
expect(isBuiltInOrNoise('isset')).toBe(true);
|
||||
expect(isBuiltInOrNoise('date')).toBe(true);
|
||||
expect(isBuiltInOrNoise('json_encode')).toBe(true);
|
||||
expect(isBuiltInOrNoise('array_map')).toBe(true);
|
||||
expect(php.isBuiltInName('echo')).toBe(true);
|
||||
expect(php.isBuiltInName('isset')).toBe(true);
|
||||
expect(php.isBuiltInName('date')).toBe(true);
|
||||
expect(php.isBuiltInName('json_encode')).toBe(true);
|
||||
expect(php.isBuiltInName('array_map')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters PHP string functions', () => {
|
||||
expect(isBuiltInOrNoise('strlen')).toBe(true);
|
||||
expect(isBuiltInOrNoise('substr')).toBe(true);
|
||||
expect(isBuiltInOrNoise('str_replace')).toBe(true);
|
||||
expect(php.isBuiltInName('strlen')).toBe(true);
|
||||
expect(php.isBuiltInName('substr')).toBe(true);
|
||||
expect(php.isBuiltInName('str_replace')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('C/C++', () => {
|
||||
it('filters standard library functions', () => {
|
||||
expect(isBuiltInOrNoise('printf')).toBe(true);
|
||||
expect(isBuiltInOrNoise('malloc')).toBe(true);
|
||||
expect(isBuiltInOrNoise('free')).toBe(true);
|
||||
expect(c.isBuiltInName('printf')).toBe(true);
|
||||
expect(c.isBuiltInName('malloc')).toBe(true);
|
||||
expect(c.isBuiltInName('free')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters Linux kernel macros', () => {
|
||||
expect(isBuiltInOrNoise('container_of')).toBe(true);
|
||||
expect(isBuiltInOrNoise('ARRAY_SIZE')).toBe(true);
|
||||
expect(isBuiltInOrNoise('pr_info')).toBe(true);
|
||||
expect(c.isBuiltInName('container_of')).toBe(true);
|
||||
expect(c.isBuiltInName('ARRAY_SIZE')).toBe(true);
|
||||
expect(c.isBuiltInName('pr_info')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Kotlin', () => {
|
||||
it('filters stdlib functions', () => {
|
||||
expect(isBuiltInOrNoise('println')).toBe(true);
|
||||
expect(isBuiltInOrNoise('listOf')).toBe(true);
|
||||
expect(isBuiltInOrNoise('TODO')).toBe(true);
|
||||
expect(kt.isBuiltInName('println')).toBe(true);
|
||||
expect(kt.isBuiltInName('listOf')).toBe(true);
|
||||
expect(kt.isBuiltInName('TODO')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters coroutine functions', () => {
|
||||
expect(isBuiltInOrNoise('launch')).toBe(true);
|
||||
expect(isBuiltInOrNoise('async')).toBe(true);
|
||||
expect(kt.isBuiltInName('launch')).toBe(true);
|
||||
expect(kt.isBuiltInName('async')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Swift', () => {
|
||||
it('filters built-in functions', () => {
|
||||
expect(isBuiltInOrNoise('print')).toBe(true);
|
||||
expect(isBuiltInOrNoise('fatalError')).toBe(true);
|
||||
expect(swift.isBuiltInName('print')).toBe(true);
|
||||
expect(swift.isBuiltInName('fatalError')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters UIKit methods', () => {
|
||||
expect(isBuiltInOrNoise('addSubview')).toBe(true);
|
||||
expect(isBuiltInOrNoise('reloadData')).toBe(true);
|
||||
expect(swift.isBuiltInName('addSubview')).toBe(true);
|
||||
expect(swift.isBuiltInName('reloadData')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Rust', () => {
|
||||
it('filters Result/Option methods', () => {
|
||||
expect(isBuiltInOrNoise('unwrap')).toBe(true);
|
||||
expect(isBuiltInOrNoise('expect')).toBe(true);
|
||||
expect(isBuiltInOrNoise('unwrap_or')).toBe(true);
|
||||
expect(isBuiltInOrNoise('unwrap_or_else')).toBe(true);
|
||||
expect(isBuiltInOrNoise('unwrap_or_default')).toBe(true);
|
||||
expect(isBuiltInOrNoise('ok')).toBe(true);
|
||||
expect(isBuiltInOrNoise('err')).toBe(true);
|
||||
expect(isBuiltInOrNoise('is_ok')).toBe(true);
|
||||
expect(isBuiltInOrNoise('is_err')).toBe(true);
|
||||
expect(isBuiltInOrNoise('map_err')).toBe(true);
|
||||
expect(isBuiltInOrNoise('and_then')).toBe(true);
|
||||
expect(isBuiltInOrNoise('or_else')).toBe(true);
|
||||
expect(rust.isBuiltInName('unwrap')).toBe(true);
|
||||
expect(rust.isBuiltInName('expect')).toBe(true);
|
||||
expect(rust.isBuiltInName('unwrap_or')).toBe(true);
|
||||
expect(rust.isBuiltInName('unwrap_or_else')).toBe(true);
|
||||
expect(rust.isBuiltInName('unwrap_or_default')).toBe(true);
|
||||
expect(rust.isBuiltInName('ok')).toBe(true);
|
||||
expect(rust.isBuiltInName('err')).toBe(true);
|
||||
expect(rust.isBuiltInName('is_ok')).toBe(true);
|
||||
expect(rust.isBuiltInName('is_err')).toBe(true);
|
||||
expect(rust.isBuiltInName('map_err')).toBe(true);
|
||||
expect(rust.isBuiltInName('and_then')).toBe(true);
|
||||
expect(rust.isBuiltInName('or_else')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters trait conversion methods', () => {
|
||||
expect(isBuiltInOrNoise('clone')).toBe(true);
|
||||
expect(isBuiltInOrNoise('to_string')).toBe(true);
|
||||
expect(isBuiltInOrNoise('to_owned')).toBe(true);
|
||||
expect(isBuiltInOrNoise('into')).toBe(true);
|
||||
expect(isBuiltInOrNoise('from')).toBe(true);
|
||||
expect(isBuiltInOrNoise('as_ref')).toBe(true);
|
||||
expect(isBuiltInOrNoise('as_mut')).toBe(true);
|
||||
expect(rust.isBuiltInName('clone')).toBe(true);
|
||||
expect(rust.isBuiltInName('to_string')).toBe(true);
|
||||
expect(rust.isBuiltInName('to_owned')).toBe(true);
|
||||
expect(rust.isBuiltInName('into')).toBe(true);
|
||||
expect(rust.isBuiltInName('from')).toBe(true);
|
||||
expect(rust.isBuiltInName('as_ref')).toBe(true);
|
||||
expect(rust.isBuiltInName('as_mut')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters iterator methods', () => {
|
||||
expect(isBuiltInOrNoise('iter')).toBe(true);
|
||||
expect(isBuiltInOrNoise('into_iter')).toBe(true);
|
||||
expect(isBuiltInOrNoise('collect')).toBe(true);
|
||||
expect(isBuiltInOrNoise('fold')).toBe(true);
|
||||
expect(isBuiltInOrNoise('for_each')).toBe(true);
|
||||
expect(rust.isBuiltInName('iter')).toBe(true);
|
||||
expect(rust.isBuiltInName('into_iter')).toBe(true);
|
||||
expect(rust.isBuiltInName('collect')).toBe(true);
|
||||
expect(rust.isBuiltInName('fold')).toBe(true);
|
||||
expect(rust.isBuiltInName('for_each')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters collection methods', () => {
|
||||
expect(isBuiltInOrNoise('len')).toBe(true);
|
||||
expect(isBuiltInOrNoise('is_empty')).toBe(true);
|
||||
expect(isBuiltInOrNoise('push')).toBe(true);
|
||||
expect(isBuiltInOrNoise('pop')).toBe(true);
|
||||
expect(isBuiltInOrNoise('insert')).toBe(true);
|
||||
expect(isBuiltInOrNoise('remove')).toBe(true);
|
||||
expect(isBuiltInOrNoise('contains')).toBe(true);
|
||||
expect(rust.isBuiltInName('len')).toBe(true);
|
||||
expect(rust.isBuiltInName('is_empty')).toBe(true);
|
||||
expect(rust.isBuiltInName('push')).toBe(true);
|
||||
expect(rust.isBuiltInName('pop')).toBe(true);
|
||||
expect(rust.isBuiltInName('insert')).toBe(true);
|
||||
expect(rust.isBuiltInName('remove')).toBe(true);
|
||||
expect(rust.isBuiltInName('contains')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters macro-like and panic functions', () => {
|
||||
expect(isBuiltInOrNoise('format')).toBe(true);
|
||||
expect(isBuiltInOrNoise('panic')).toBe(true);
|
||||
expect(isBuiltInOrNoise('unreachable')).toBe(true);
|
||||
expect(isBuiltInOrNoise('todo')).toBe(true);
|
||||
expect(isBuiltInOrNoise('unimplemented')).toBe(true);
|
||||
expect(isBuiltInOrNoise('vec')).toBe(true);
|
||||
expect(isBuiltInOrNoise('println')).toBe(true);
|
||||
expect(isBuiltInOrNoise('eprintln')).toBe(true);
|
||||
expect(isBuiltInOrNoise('dbg')).toBe(true);
|
||||
expect(rust.isBuiltInName('format')).toBe(true);
|
||||
expect(rust.isBuiltInName('panic')).toBe(true);
|
||||
expect(rust.isBuiltInName('unreachable')).toBe(true);
|
||||
expect(rust.isBuiltInName('todo')).toBe(true);
|
||||
expect(rust.isBuiltInName('unimplemented')).toBe(true);
|
||||
expect(rust.isBuiltInName('vec')).toBe(true);
|
||||
expect(rust.isBuiltInName('println')).toBe(true);
|
||||
expect(rust.isBuiltInName('eprintln')).toBe(true);
|
||||
expect(rust.isBuiltInName('dbg')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters sync primitives', () => {
|
||||
expect(isBuiltInOrNoise('lock')).toBe(true);
|
||||
expect(isBuiltInOrNoise('try_lock')).toBe(true);
|
||||
expect(isBuiltInOrNoise('spawn')).toBe(true);
|
||||
expect(isBuiltInOrNoise('join')).toBe(true);
|
||||
expect(isBuiltInOrNoise('sleep')).toBe(true);
|
||||
expect(rust.isBuiltInName('lock')).toBe(true);
|
||||
expect(rust.isBuiltInName('try_lock')).toBe(true);
|
||||
expect(rust.isBuiltInName('spawn')).toBe(true);
|
||||
expect(rust.isBuiltInName('join')).toBe(true);
|
||||
expect(rust.isBuiltInName('sleep')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters enum constructors', () => {
|
||||
expect(isBuiltInOrNoise('Some')).toBe(true);
|
||||
expect(isBuiltInOrNoise('None')).toBe(true);
|
||||
expect(isBuiltInOrNoise('Ok')).toBe(true);
|
||||
expect(isBuiltInOrNoise('Err')).toBe(true);
|
||||
expect(rust.isBuiltInName('Some')).toBe(true);
|
||||
expect(rust.isBuiltInName('None')).toBe(true);
|
||||
expect(rust.isBuiltInName('Ok')).toBe(true);
|
||||
expect(rust.isBuiltInName('Err')).toBe(true);
|
||||
});
|
||||
|
||||
it('does not filter user-defined Rust functions', () => {
|
||||
expect(isBuiltInOrNoise('process_request')).toBe(false);
|
||||
expect(isBuiltInOrNoise('handle_connection')).toBe(false);
|
||||
expect(isBuiltInOrNoise('build_response')).toBe(false);
|
||||
expect(rust.isBuiltInName('process_request')).toBe(false);
|
||||
expect(rust.isBuiltInName('handle_connection')).toBe(false);
|
||||
expect(rust.isBuiltInName('build_response')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('C#/.NET', () => {
|
||||
it('filters Console I/O', () => {
|
||||
expect(isBuiltInOrNoise('Console')).toBe(true);
|
||||
expect(isBuiltInOrNoise('WriteLine')).toBe(true);
|
||||
expect(isBuiltInOrNoise('ReadLine')).toBe(true);
|
||||
expect(cs.isBuiltInName('Console')).toBe(true);
|
||||
expect(cs.isBuiltInName('WriteLine')).toBe(true);
|
||||
expect(cs.isBuiltInName('ReadLine')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters LINQ methods', () => {
|
||||
expect(isBuiltInOrNoise('Where')).toBe(true);
|
||||
expect(isBuiltInOrNoise('Select')).toBe(true);
|
||||
expect(isBuiltInOrNoise('GroupBy')).toBe(true);
|
||||
expect(isBuiltInOrNoise('OrderBy')).toBe(true);
|
||||
expect(isBuiltInOrNoise('FirstOrDefault')).toBe(true);
|
||||
expect(isBuiltInOrNoise('ToList')).toBe(true);
|
||||
expect(cs.isBuiltInName('Where')).toBe(true);
|
||||
expect(cs.isBuiltInName('Select')).toBe(true);
|
||||
expect(cs.isBuiltInName('GroupBy')).toBe(true);
|
||||
expect(cs.isBuiltInName('OrderBy')).toBe(true);
|
||||
expect(cs.isBuiltInName('FirstOrDefault')).toBe(true);
|
||||
expect(cs.isBuiltInName('ToList')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters Task async methods', () => {
|
||||
expect(isBuiltInOrNoise('Task')).toBe(true);
|
||||
expect(isBuiltInOrNoise('Run')).toBe(true);
|
||||
expect(isBuiltInOrNoise('WhenAll')).toBe(true);
|
||||
expect(isBuiltInOrNoise('ConfigureAwait')).toBe(true);
|
||||
expect(cs.isBuiltInName('Task')).toBe(true);
|
||||
expect(cs.isBuiltInName('Run')).toBe(true);
|
||||
expect(cs.isBuiltInName('WhenAll')).toBe(true);
|
||||
expect(cs.isBuiltInName('ConfigureAwait')).toBe(true);
|
||||
});
|
||||
|
||||
it('filters Object base methods', () => {
|
||||
expect(isBuiltInOrNoise('ToString')).toBe(true);
|
||||
expect(isBuiltInOrNoise('GetType')).toBe(true);
|
||||
expect(isBuiltInOrNoise('Equals')).toBe(true);
|
||||
expect(isBuiltInOrNoise('GetHashCode')).toBe(true);
|
||||
expect(cs.isBuiltInName('ToString')).toBe(true);
|
||||
expect(cs.isBuiltInName('GetType')).toBe(true);
|
||||
expect(cs.isBuiltInName('Equals')).toBe(true);
|
||||
expect(cs.isBuiltInName('GetHashCode')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('user-defined functions', () => {
|
||||
it('does not filter custom function names', () => {
|
||||
expect(isBuiltInOrNoise('myCustomFunction')).toBe(false);
|
||||
expect(isBuiltInOrNoise('processData')).toBe(false);
|
||||
expect(isBuiltInOrNoise('handleUserRequest')).toBe(false);
|
||||
expect(js.isBuiltInName('myCustomFunction')).toBe(false);
|
||||
expect(py.isBuiltInName('processData')).toBe(false);
|
||||
expect(rust.isBuiltInName('handleUserRequest')).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
92
gitnexus/test/unit/noise-filter.test.ts
Normal file
92
gitnexus/test/unit/noise-filter.test.ts
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { getProvider } from '../../src/core/ingestion/languages/index.js';
|
||||
import { SupportedLanguages } from '../../src/config/supported-languages.js';
|
||||
|
||||
const isBuiltIn = (name: string, lang: SupportedLanguages) => getProvider(lang).isBuiltInName(name);
|
||||
|
||||
describe('isBuiltInOrNoise (per-language)', () => {
|
||||
describe('language-specific filtering', () => {
|
||||
it('filters console for JS but not Python', () => {
|
||||
expect(isBuiltIn('console', SupportedLanguages.JavaScript)).toBe(true);
|
||||
expect(isBuiltIn('console', SupportedLanguages.Python)).toBe(false);
|
||||
});
|
||||
|
||||
it('filters println for Kotlin but not Java', () => {
|
||||
expect(isBuiltIn('println', SupportedLanguages.Kotlin)).toBe(true);
|
||||
expect(isBuiltIn('println', SupportedLanguages.Java)).toBe(false);
|
||||
});
|
||||
|
||||
it('filters malloc for C but not JavaScript', () => {
|
||||
expect(isBuiltIn('malloc', SupportedLanguages.C)).toBe(true);
|
||||
expect(isBuiltIn('malloc', SupportedLanguages.JavaScript)).toBe(false);
|
||||
});
|
||||
|
||||
it('filters setState for Dart but not TypeScript', () => {
|
||||
expect(isBuiltIn('setState', SupportedLanguages.Dart)).toBe(true);
|
||||
expect(isBuiltIn('setState', SupportedLanguages.TypeScript)).toBe(false);
|
||||
});
|
||||
|
||||
it('filters unwrap for Rust but not Go', () => {
|
||||
expect(isBuiltIn('unwrap', SupportedLanguages.Rust)).toBe(true);
|
||||
expect(isBuiltIn('unwrap', SupportedLanguages.Go)).toBe(false);
|
||||
});
|
||||
|
||||
it('filters puts for Ruby but not PHP', () => {
|
||||
expect(isBuiltIn('puts', SupportedLanguages.Ruby)).toBe(true);
|
||||
expect(isBuiltIn('puts', SupportedLanguages.PHP)).toBe(false);
|
||||
});
|
||||
|
||||
it('filters echo for PHP but not Python', () => {
|
||||
expect(isBuiltIn('echo', SupportedLanguages.PHP)).toBe(true);
|
||||
expect(isBuiltIn('echo', SupportedLanguages.Python)).toBe(false);
|
||||
});
|
||||
|
||||
it('filters NSLog for Swift but not C', () => {
|
||||
expect(isBuiltIn('NSLog', SupportedLanguages.Swift)).toBe(true);
|
||||
expect(isBuiltIn('NSLog', SupportedLanguages.C)).toBe(false);
|
||||
});
|
||||
|
||||
it('filters ToString for C# but not Rust', () => {
|
||||
expect(isBuiltIn('ToString', SupportedLanguages.CSharp)).toBe(true);
|
||||
expect(isBuiltIn('ToString', SupportedLanguages.Rust)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cross-language pollution eliminated', () => {
|
||||
it('close is filtered for C# but not C (POSIX)', () => {
|
||||
expect(isBuiltIn('Close', SupportedLanguages.CSharp)).toBe(true);
|
||||
expect(isBuiltIn('close', SupportedLanguages.C)).toBe(false);
|
||||
});
|
||||
|
||||
it('then/catch are JS-specific, not filtered for Rust', () => {
|
||||
expect(isBuiltIn('then', SupportedLanguages.JavaScript)).toBe(true);
|
||||
expect(isBuiltIn('catch', SupportedLanguages.JavaScript)).toBe(true);
|
||||
expect(isBuiltIn('then', SupportedLanguages.Rust)).toBe(false);
|
||||
});
|
||||
|
||||
it('emit is Kotlin-specific, not filtered for Java', () => {
|
||||
expect(isBuiltIn('emit', SupportedLanguages.Kotlin)).toBe(true);
|
||||
expect(isBuiltIn('emit', SupportedLanguages.Java)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('languages without builtInNames', () => {
|
||||
it('Java has no language-specific noise', () => {
|
||||
expect(isBuiltIn('System', SupportedLanguages.Java)).toBe(false);
|
||||
expect(isBuiltIn('println', SupportedLanguages.Java)).toBe(false);
|
||||
});
|
||||
|
||||
it('Go has no language-specific noise', () => {
|
||||
expect(isBuiltIn('fmt', SupportedLanguages.Go)).toBe(false);
|
||||
expect(isBuiltIn('Println', SupportedLanguages.Go)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('domain names not filtered', () => {
|
||||
it('does not filter arbitrary names', () => {
|
||||
expect(isBuiltIn('processOrder', SupportedLanguages.TypeScript)).toBe(false);
|
||||
expect(isBuiltIn('UserService', SupportedLanguages.Java)).toBe(false);
|
||||
expect(isBuiltIn('handle_request', SupportedLanguages.Rust)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue